--- /dev/null
+/****************************************************************************
+ * drivers/sctimers.c
+ *
+ * Copyright 2016 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+
+/***************************************************************************** */
+/* State Configurable Timer */
+/***************************************************************************** */
+
+/* State Configurable Timers driver for the integrated SCT of the LPC82x
+ * The LPC82x has one State Configurable Timer.
+ * Refer to LPC82x documentation (UM10800.pdf) for more information.
+ */
+
+#include "lib/stdint.h"
+#include "core/system.h"
+#include "drivers/timers.h"
+#include "drivers/sctimers.h"
+
+
+/* These are local to our file */
+enum sct_config_states {
+ SCT_UNCONFIGURED = 0,
+ SCT_CONFIGURED_AS_32,
+ SCT_CONFIGURED_AS_16,
+};
+struct sctimer_device {
+ struct lpc_sct_timer* regs;
+ uint32_t power_bit;
+ uint32_t reset;
+ uint8_t mode;
+ uint8_t irq;
+ uint8_t configured;
+ void (*callback)(uint32_t); /* Possible Interrupt callback */
+};
+struct sctimer_device sctimer = {
+ .regs = LPC_SCTIMER,
+ .power_bit = LPC_SYS_ABH_CLK_CTRL_SCT,
+ .reset = LPC_SCT_RESET_N,
+ .irq = SCT_IRQ,
+ .configured = 0,
+ .callback = NULL,
+};
+
+/* Handlers */
+void SCT_Handler(void)
+{
+ struct lpc_sct_timer* sct = LPC_SCTIMER;
+ uint32_t event_flags = sct->event_flag; /* Backup the flags */
+
+ /* Clear the interrupt */
+ sct->event_flag = event_flags;
+ /* And call the user routine if one has been registered */
+ if (sctimer.callback != NULL) {
+ sctimer.callback(event_flags);
+ }
+}
+
+
+
+/*******************************************************************************/
+/* Common operations - Unified 32bits timer */
+
+/* Start a timer :
+ * Remove the reset and stop flag if present.
+ * Timer must be turned on and configured (no checks done here).
+ */
+void sctimer_start(uint8_t timer_num)
+{
+ struct lpc_sct_timer* sct = LPC_SCTIMER;
+ if (timer_num != LPC_SCT)
+ return;
+ sct->control &= ~(LPC_SCT_STOP | LPC_SCT_HALT);
+}
+
+/* Pause the SCT counter, does not reset */
+void sctimer_pause(uint8_t timer_num)
+{
+ struct lpc_sct_timer* sct = LPC_SCTIMER;
+ if (timer_num != LPC_SCT)
+ return;
+ /* Set the STOP Flag */
+ sct->control |= LPC_SCT_STOP;
+}
+
+/* Stops and resets the timer counter */
+void sctimer_stop(uint8_t timer_num)
+{
+ struct lpc_sct_timer* sct = LPC_SCTIMER;
+ if (timer_num != LPC_SCT)
+ return;
+ sct->control |= (LPC_SCT_STOP | LPC_SCT_HALT | LPC_SCT_CLEAR);
+}
+
+/* Resets the timer and lets it count again imediately */
+void sctimer_restart(uint8_t timer_num)
+{
+ struct lpc_sct_timer* sct = LPC_SCTIMER;
+ if (timer_num != LPC_SCT)
+ return;
+ sct->control |= LPC_SCT_CLEAR;
+ /* If it was stoped, let it start */
+ sct->control &= ~(LPC_SCT_STOP | LPC_SCT_HALT);
+}
+
+uint32_t sctimer_get_counter_val(uint8_t timer_num)
+{
+ struct lpc_sct_timer* sct = LPC_SCTIMER;
+ if (timer_num != LPC_SCT)
+ return 0;
+ return sct->count;
+}
+
+struct common_operations sct_ops = {
+ .start = sctimer_start,
+ .cont = sctimer_start,
+ .pause = sctimer_pause,
+ .stop = sctimer_stop,
+ .restart = sctimer_restart,
+ .halt = sctimer_stop,
+ .get_counter = sctimer_get_counter_val,
+};
+
+
+/*******************************************************************************/
+/* Common operations - 16bits timers */
+
+void sctimer16_start(uint8_t timer_num)
+{
+ struct lpc_sct_timer_16* sct = LPC_SCTIMER_16;
+ int num = 0;
+
+ if (timer_num == LPC_SCT16_T1) {
+ num = 1;
+ } else if (timer_num != LPC_SCT16_T0) {
+ return;
+ }
+ sct->control[num] = 0;
+}
+
+struct common_operations sct16_ops = {
+ .start = sctimer16_start,
+ .cont = sctimer16_start,
+};
+
+
+/*******************************************************************************/
+/* Configuration operations - Unified 32bits timer */
+
+/* Change the match value of a single timer channel */
+void sctimer_set_match(uint8_t timer_num, uint8_t channel, uint32_t val)
+{
+}
+
+void sctimer_pwm_config(uint8_t timer_num, const struct lpc_timer_pwm_config* pwm)
+{
+ struct lpc_sct_timer* sct = LPC_SCTIMER;
+ int i = 0;
+
+ if (timer_num != LPC_SCT)
+ return;
+
+ /* Some configs require the timer to be halted (setting the initial output values */
+ sctimer_stop(timer_num);
+
+ /* Use a single state */
+ sct->state_var = 0;
+ /* No need to reload, match registers will keep their values */
+ sct->config |= LPC_SCT_NORELOAD;
+ /* All match/capture regs act as match registers */
+ sct->mode = 0;
+
+ /* Set all match values for each PWM channels and the limit channel */
+ for (i = 0; ((i < pwm->nb_channels) && (i < NUM_SCT_CHANS)); i++) {
+ uint32_t evt_ctrl = 0;
+
+ sct->match[ i + 1 ] = pwm->match_values[i];
+ /* Enable one event for state 0 for this match */
+ sct->event[ i + 1 ].state = LPC_SCT_EVT_EN_STATE(0);
+ /* Setup the event to happen on given match channel and control the requested output */
+ evt_ctrl = (LPC_SCT_MATCHSEL(i + 1) | LPC_SCT_COMB_MODE_MATCH);
+ evt_ctrl |= (LPC_SCT_OUTSEL | LPC_SCT_IOSEL(pwm->outputs[i]));
+ sct->event[ i + 1 ].control = evt_ctrl;
+ /* Setup the event to toggle the requested output by configuring both set and clear and
+ * using the toggle solution to conflict resolution */
+ sct->out_evt_sel[ pwm->outputs[i] ].set = LPC_SCT_OUTPUT_EVT_SET(i + 1);
+ sct->out_evt_sel[ pwm->outputs[i] ].clear = LPC_SCT_OUTPUT_EVT_CLR(i + 1);
+ sct->conflict_res |= LPC_SCT_CONFLICT_TOGGLE( pwm->outputs[i] );
+ /* And configure the limit event (channel 0) to toggle this output too */
+ sct->out_evt_sel[ pwm->outputs[i] ].set |= LPC_SCT_OUTPUT_EVT_SET(0);
+ sct->out_evt_sel[ pwm->outputs[i] ].clear |= LPC_SCT_OUTPUT_EVT_CLR(0);
+ }
+
+ /* Select the channel 0 as the timer limit value to generate the PWM period.
+ * Use autolimit, but configure an event anyway as we want to toggle the outputs as well */
+ sct->match[0] = pwm->period;
+ sct->config |= LPC_SCT_AUTOLIMIT;
+ sct->event[0].state = LPC_SCT_EVT_EN_STATE(0);
+ sct->event[0].control = (LPC_SCT_MATCHSEL(0) | LPC_SCT_COMB_MODE_MATCH);
+
+ /* Set all outputs initial states */
+ sct->output = LPC_SCT_OUT_SET_ALL(pwm->outputs_initial_state);
+}
+
+struct config_operations sct_cfg_ops = {
+ .set_match = sctimer_set_match,
+ .pwm_config = sctimer_pwm_config,
+};
+
+
+
+
+
+/*******************************************************************************/
+/* Init operations */
+
+/* Power up SCT.
+ * clkrate is a divider of the main clock frequency chosen for your application
+ * as it will be used to divide the main clock to get the prescaler value.
+ * Set clkrate to 0 to disable the prescaler.
+ */
+void sctimer_on(uint8_t timer_num, uint32_t clkrate, void (*callback)(uint32_t))
+{
+ struct lpc_sct_timer* sct = LPC_SCTIMER;
+ uint32_t prescale; /* The clock divider for the counter */
+
+ if (timer_num != LPC_SCT) {
+ return;
+ }
+
+ NVIC_DisableIRQ(sctimer.irq);
+ /* Power up the timer and perform subsystem reset */
+ subsystem_power(sctimer.power_bit, 1);
+ subsystem_reset(sctimer.reset);
+
+ /* Compute the prescaler value */
+ if (clkrate == 0) {
+ prescale = 0;
+ } else {
+ prescale = (get_main_clock() / clkrate) - 1;
+ }
+
+ /* Set main configurations */
+ if (timer_num == LPC_SCT) {
+ sct->config = (LPC_SCT_UNIFIED_TIMER | LPC_SCT_CLK_SYSCLK);
+ /* Reset and disable counter */
+ sct->control = (LPC_SCT_CLEAR | LPC_SCT_HALT | LPC_SCT_PRESCALE(prescale));
+ } else {
+ sct->config = LPC_SCT_CLK_SYSCLK;
+ if (timer_num == LPC_SCT16_T0) {
+ sct->control = (LPC_SCT_CLEAR | LPC_SCT_HALT | LPC_SCT_PRESCALE(prescale));
+ } else {
+ sct->control = ((LPC_SCT_CLEAR | LPC_SCT_HALT | LPC_SCT_PRESCALE(prescale)) << 16);
+ }
+ }
+
+ /* Store the callback, OK even if none given */
+ sctimer.callback = callback;
+ sctimer.configured = SCT_CONFIGURED_AS_32;
+
+ /* Disable all interrupt events */
+ sct->event_int_en = 0;
+
+ NVIC_EnableIRQ(sctimer.irq);
+}
+
+
+/* Removes the main clock from the selected sctimer block */
+void sctimer_off(uint8_t timer_num)
+{
+ if ((timer_num != LPC_SCT) && (timer_num != LPC_SCT16_T0) && (timer_num != LPC_SCT16_T1))
+ return;
+
+ NVIC_DisableIRQ(sctimer.irq);
+ /* Power down the timer */
+ subsystem_power(sctimer.power_bit, 0);
+ sctimer.callback = NULL;
+ sctimer.configured = SCT_UNCONFIGURED;
+}
+
+
+struct init_operations sct_init_ops = {
+ .timer_on = sctimer_on,
+ .timer_off = sctimer_off,
+};
+
+
+void sctimer16_on(uint8_t timer_num, uint32_t clkrate, void (*callback)(uint32_t))
+{
+ struct lpc_sct_timer_16* sct = LPC_SCTIMER_16;
+
+ uint32_t prescale; /* The clock divider for the counter */
+
+ if ((timer_num != LPC_SCT16_T0) && (timer_num != LPC_SCT16_T1)) {
+ return;
+ }
+ if (sctimer.configured == SCT_CONFIGURED_AS_32) {
+ return;
+ }
+
+ if (sctimer.configured == SCT_UNCONFIGURED) {
+ NVIC_DisableIRQ(sctimer.irq);
+ /* Power up the timer and perform subsystem reset */
+ subsystem_power(sctimer.power_bit, 1);
+ subsystem_reset(sctimer.reset);
+
+ /* Set main configurations */
+ sct->config = LPC_SCT_CLK_SYSCLK;
+ }
+
+ /* Compute the prescaler value */
+ if (clkrate == 0) {
+ prescale = 0;
+ } else {
+ prescale = (get_main_clock() / clkrate) - 1;
+ }
+
+ if (timer_num == LPC_SCT16_T0) {
+ sct->control[0] |= (LPC_SCT_CLEAR | LPC_SCT_HALT | LPC_SCT_PRESCALE(prescale));
+ } else {
+ sct->control[1] |= (LPC_SCT_CLEAR | LPC_SCT_HALT | LPC_SCT_PRESCALE(prescale));
+ }
+
+ if (sctimer.configured == SCT_UNCONFIGURED) {
+ /* Store the callback, OK even if none given */
+ sctimer.callback = callback;
+ sctimer.configured = SCT_CONFIGURED_AS_16;
+
+ /* Disable all interrupt events */
+ sct->event_int_en = 0;
+
+ NVIC_EnableIRQ(sctimer.irq);
+ }
+}
+
+struct init_operations sct16_init_ops = {
+ .timer_on = sctimer16_on,
+ .timer_off = sctimer_off,
+};
+
--- /dev/null
+/****************************************************************************
+ * drivers/timers.c
+ *
+ * Copyright 2016 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+
+/***************************************************************************** */
+/* Timers */
+/***************************************************************************** */
+
+/* Driver for the different kinds of timers available in the LPC82x
+ *
+ * This inludes :
+ * - State Configurable Timers driver for the integrated SCT of the LPC82x
+ * The LPC82x has one State Configurable Timer.
+ *
+ * Refer to LPC82x documentation (UM10800.pdf) for more information.
+ *
+ * All common functions are available using a common interface. Only specific
+ * functions have a specific interface, described in separate headers files.
+ */
+
+#include "lib/stdint.h"
+#include "drivers/timers.h"
+
+
+/* These are local to our file */
+struct timer_device {
+ uint8_t num;
+ struct common_operations* ops;
+ struct config_operations* cfg_ops;
+ struct init_operations* init_ops;
+};
+
+
+/* 32 bits State Configurable Timer */
+extern struct common_operations sct_ops;
+extern struct config_operations sct_cfg_ops;
+extern struct init_operations sct_init_ops;
+/* 16 bits State Configurable Timer */
+extern struct common_operations sct16_ops;
+extern struct config_operations sct16_cfg_ops;
+extern struct init_operations sct16_init_ops;
+/* Multi Rate Timer */
+
+
+struct timer_device timers[NUM_TIMERS] = {
+ {
+ .num = LPC_SCT,
+ .ops = &sct_ops,
+ .cfg_ops = &sct_cfg_ops,
+ .init_ops = &sct_init_ops,
+ },
+ {
+ .num = LPC_SCT16_T0,
+ .ops = &sct16_ops,
+ .init_ops = &sct16_init_ops,
+ },
+ {
+ .num = LPC_SCT16_T1,
+ .ops = &sct16_ops,
+ .init_ops = &sct16_init_ops,
+ },
+};
+
+
+/*******************************************************************************/
+/* Wrappers to common functions */
+
+#define GENERIC_TIMER_OPS(name) \
+ void timer_ ## name(uint8_t timer_num) \
+ { \
+ if (timer_num >= NUM_TIMERS) \
+ return; \
+ if (timers[timer_num].ops && timers[timer_num].ops->name) { \
+ timers[timer_num].ops->name(timer_num); \
+ } \
+ }
+
+/* void timer_start(uint32_t timer_num)
+ * Start a timer */
+GENERIC_TIMER_OPS(start);
+/* Pause timer operation */
+GENERIC_TIMER_OPS(pause);
+/* Continue timer operation when the timer got paused */
+GENERIC_TIMER_OPS(cont);
+/* Reset the timer and let it count again imediately */
+GENERIC_TIMER_OPS(restart);
+/* Stop timer counting and reset timer counter to reload value / initial state */
+GENERIC_TIMER_OPS(stop);
+/* Same as stop */
+GENERIC_TIMER_OPS(halt);
+
+
+/* Return the current counter value
+ * Note that for 32 bits timers there is not much possibilities to differentiate
+ * between an error and a real value
+ */
+uint32_t timer_get_counter_val(uint8_t timer_num)
+{
+ if (timer_num >= NUM_TIMERS)
+ return 0;
+ if (timers[timer_num].ops && timers[timer_num].ops->get_counter) {
+ return timers[timer_num].ops->get_counter(timer_num);
+ }
+ return 0;
+}
+
+
+/*******************************************************************************/
+/* Configuration */
+
+/* Change the match value of a single timer channel */
+void timer_set_match(uint8_t timer_num, uint8_t channel, uint32_t val)
+{
+ if (timer_num >= NUM_TIMERS)
+ return;
+ if (timers[timer_num].cfg_ops && timers[timer_num].cfg_ops->set_match) {
+ timers[timer_num].cfg_ops->set_match(timer_num, channel, val);
+ }
+}
+
+void timer_pwm_config(uint8_t timer_num, const struct lpc_timer_pwm_config* conf)
+{
+ if (timer_num >= NUM_TIMERS)
+ return;
+ if (timers[timer_num].cfg_ops && timers[timer_num].cfg_ops->pwm_config) {
+ timers[timer_num].cfg_ops->pwm_config(timer_num, conf);
+ }
+}
+
+
+
+
+/* Power up a timer.
+ * clkrate is a divider of the main clock frequency chosen for your application
+ * as it will be used to divide the main clock to get the prescaler value.
+ * Set clkrate to 0 to disable the prescaler.
+ * callback is the interrupt callback for this timer.
+ */
+void timer_on(uint8_t timer_num, uint32_t clkrate, void (*callback)(uint32_t))
+{
+ if (timer_num >= NUM_TIMERS)
+ return;
+ if (timers[timer_num].init_ops && timers[timer_num].init_ops->timer_on) {
+ timers[timer_num].init_ops->timer_on(timer_num, clkrate, callback);
+ }
+}
+
+/* Removes the main clock from the selected timer block */
+void timer_off(uint8_t timer_num)
+{
+ if (timer_num >= NUM_TIMERS)
+ return;
+ if (timers[timer_num].init_ops && timers[timer_num].init_ops->timer_off) {
+ timers[timer_num].init_ops->timer_off(timer_num);
+ }
+}
+
#define LPC_RAM_BASE (0x10000000UL)
#define LPC_APB_BASE (0x40000000UL)
#define LPC_CRC_BASE (0x50000000UL)
-#define LPC_SCT_PWM_BASE (0x50004000UL)
+#define LPC_SCT_BASE (0x50004000UL)
#define LPC_DMA_BASE (0x50008000UL)
#define LPC_GPIO_BASE (0xA0000000UL)
#define LPC_GPIO_INTR_BASE (0xA0004000UL)
-
/***************************************************************************** */
/* Power Management Unit */
/***************************************************************************** */
#define LPC_SSP_TX_DMA_EN (0x01 << 1)
-
-/***************************************************************************** */
-/* Timer */
-/***************************************************************************** */
-/* Timer (TMR) */
-struct lpc_timer
-{
- volatile uint32_t int_reg; /* 0x000 : Interrupt Register (R/W) */
- volatile uint32_t timer_ctrl; /* 0x004 : Timer Control Register (R/W) */
- volatile uint32_t timer_counter; /* 0x008 : Timer Counter Register (R/W) */
- volatile uint32_t prescale; /* 0x00C : Prescale Register (R/W) */
- volatile uint32_t prescale_counter; /* 0x010 : Prescale Counter Register (R/W) */
- volatile uint32_t match_ctrl; /* 0x014 : Match Control Register (R/W) */
- volatile uint32_t match_reg[4]; /* 0x018 : Match Register 0 to 3 (R/W) */
- volatile uint32_t capture_ctrl; /* 0x028 : Capture Control Register (R/W) */
- volatile const uint32_t capture_reg[4]; /* 0x02C : Capture Register 0 to 3 (R/ ) */
- volatile uint32_t external_match; /* 0x03C : External Match Register (R/W) */
- uint32_t reserved_2[12];
- volatile uint32_t count_ctrl; /* 0x070 : Count Control Register (R/W) */
- volatile uint32_t pwm_ctrl; /* 0x074 : PWM Control Register (R/W) */
-};
-#define LPC_TMR16B0 ((struct lpc_timer *) LPC_TIMER0_BASE)
-#define LPC_TMR16B1 ((struct lpc_timer *) LPC_TIMER1_BASE)
-#define LPC_TMR32B0 ((struct lpc_timer *) LPC_TIMER2_BASE)
-#define LPC_TMR32B1 ((struct lpc_timer *) LPC_TIMER3_BASE)
-#define LPC_TIMER_REGS(x) ((struct lpc_timer *) (LPC_TIMER0_BASE + ((x) * 0x4000)))
-
-#define LPC_TIMER_COUNTER_ENABLE (1 << 0) /* CEN */
-#define LPC_TIMER_COUNTER_RESET (1 << 1) /* CRST */
-
-/* Match internal configuration */
-#define LPC_TIMER_INTERRUPT_ON_MATCH 0x01
-#define LPC_TIMER_RESET_ON_MATCH 0x02
-#define LPC_TIMER_STOP_ON_MATCH 0x04
-#define LPC_TIMER_MATCH_ERASE(x) (0x07 << (((x) & 0x03) * 3))
-#define LPC_TIMER_MATCH_SHIFT(x) (((x) & 0x03) * 3)
-/* Capture internal configuration */
-#define LPC_TIMER_CAP_ON_RISING_EDGE 0x01
-#define LPC_TIMER_CAP_ON_FALLING_EDGE 0x02
-#define LPC_TIMER_INTERRUPT_ON_CAPTURE 0x04
-#define LPC_TIMER_CAPTURE_ERASE(x) (0x07 << (((x) & 0x03) * 3))
-#define LPC_TIMER_CAPTURE_SHIFT(x) (((x) & 0x03) * 3)
-/* Match external configuration */
-#define LPC_TIMER_NOTHING_ON_MATCH 0x00
-#define LPC_TIMER_CLEAR_ON_MATCH 0x01
-#define LPC_TIMER_SET_ON_MATCH 0x02
-#define LPC_TIMER_TOGGLE_ON_MATCH 0x03
-#define LPC_TIMER_EXT_MATCH0_SHIFT 4
-#define LPC_TIMER_EXT_MATCH1_SHIFT 6
-#define LPC_TIMER_EXT_MATCH2_SHIFT 8
-#define LPC_TIMER_EXT_MATCH3_SHIFT 10
-/* Counter */
-#define LPC_COUNTER_IS_TIMER 0x00
-#define LPC_COUNTER_INC_ON_RISING 0x01
-#define LPC_COUNTER_INC_ON_FALLING 0x02
-#define LPC_COUNTER_INC_ON_BOTH 0x03
-#define LPC_COUNTER_INC_INPUT_SHIFT 2
-#define LPC_COUNTER_INC_INPUT(x) (((x) & 0x03) << LPC_COUNTER_INC_INPUT_SHIFT)
-#define LPC_COUNTER_CLEAR_ON_EVENT_EN (0x01 << 4)
-#define LPC_COUNTER_CLEAR_ON_EVENT_SHIFT 5
-#define LPC_COUNTER_CLEAR_ON_CHAN0_RISE 0x00
-#define LPC_COUNTER_CLEAR_ON_CHAN0_FALL 0x01
-#define LPC_COUNTER_CLEAR_ON_CHAN1_RISE 0x02
-#define LPC_COUNTER_CLEAR_ON_CHAN1_FALL 0x03
-#define LPC_COUNTER_CLEAR_ON_CHAN2_RISE 0x04
-#define LPC_COUNTER_CLEAR_ON_CHAN2_FALL 0x05
-#define LPC_COUNTER_CLEAR_ON_CHAN3_RISE 0x06
-#define LPC_COUNTER_CLEAR_ON_CHAN3_FALL 0x07
-/* PWM */
-#define LPC_PWM_CHANNEL_ENABLE(x) (0x01 << ((x) & 0x03))
-
-
-
-
-
-
#endif /* LPC_REGS_H */
--- /dev/null
+/****************************************************************************
+ * drivers/sctimers.h
+ *
+ * Copyright 2016 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef DRIVERS_SCTIMERS_H
+#define DRIVERS_SCTIMERS_H
+
+#include "lib/stdint.h"
+
+/***************************************************************************** */
+/* State Configurable Timers */
+/***************************************************************************** */
+/* State Configurable Timers driver for the integrated SCT of the LPC82x
+ * The LPC82x has one State Configurable Timer.
+ * Refer to LPC82x documentation (UM10800.pdf) for more information.
+ */
+#define NUM_SCTIMERS 1
+#define NUM_SCT_CHANS 8
+#define NUM_SCT_OUTPUTS 6
+
+
+/* Many functions are accessible through the common timer interface and are not
+ * included here.
+ * Use the common interface to access timer_on(), timer_off(), and all the
+ * start, stop, pause, continue, ... functions.
+ */
+
+
+
+
+/***************************************************************************** */
+/* State Configurable Timer */
+/***************************************************************************** */
+/* State Configurable Timer (SCT) */
+struct lpc_sct_event {
+ volatile uint32_t state;
+ volatile uint32_t control;
+};
+struct lpc_sct_out {
+ volatile uint32_t set;
+ volatile uint32_t clear;
+};
+struct lpc_sct_timer
+{
+ volatile uint32_t config; /* 0x000 : SCT configuration register (R/W) */
+ volatile uint32_t control; /* 0x004 : SCT control register (R/W) */
+ volatile uint32_t limit_evt_sel; /* 0x008 : SCT limit event select register (R/W) */
+ volatile uint32_t halt_evt_sel; /* 0x00C : SCT halt event select register (R/W) */
+ volatile uint32_t stop_evt_sel; /* 0x010 : SCT stop event select register (R/W) */
+ volatile uint32_t start_evt_sel; /* 0x014 : SCT start event select register (R/W) */
+ uint32_t reserved_0[10];
+ volatile uint32_t count; /* 0x040 : SCT counter register (R/W) */
+ volatile uint32_t state_var; /* 0x044 : SCT state variable register (R/W) */
+ volatile uint32_t input; /* 0x048 : SCT input register (R/-) */
+ volatile uint32_t mode; /* 0x04C : SCT match/capture mode register (R/W) */
+ volatile uint32_t output; /* 0x050 : SCT output register (R/W) */
+ volatile uint32_t out_dir_ctrl; /* 0x054 : SCT output counter direction control register (R/W) */
+ volatile uint32_t conflict_res; /* 0x058 : SCT conflict resolution register (R/W) */
+ volatile uint32_t dma_req[2]; /* 0x05C - 0x060 : SCT DMA request 0 and 1 registers (R/W) */
+ uint32_t reserved_1[35];
+ volatile uint32_t event_int_en; /* 0x0F0 : SCT event interrupt enable register (R/W) */
+ volatile uint32_t event_flag; /* 0x0F4 : SCT event flag register (R/W) */
+ volatile uint32_t conflict_int_en; /* 0x0F8 : SCT conflict interrupt enable register (R/W) */
+ volatile uint32_t conflict_flag; /* 0x0FC : SCT conflict flag register (R/W) */
+ union {
+ volatile uint32_t match[8]; /* 0x100 - 0x11C : SCT match value for channels 0 to 7 (R/W) */
+ volatile uint32_t capture[8]; /* 0x100 - 0x11C : SCT capture value for channels 0 to 7 (R/W) */
+ };
+ uint32_t reserved_2[56];
+ union {
+ volatile uint32_t match_reload[8]; /* 0x200 - 0x21C : SCT match reload value register 0 to 7 (R/W) */
+ volatile uint32_t capture_ctrl[8]; /* 0x200 - 0x21C : SCT capture control register 0 to 7 (R/W) */
+ };
+ uint32_t reserved_3[56];
+ struct lpc_sct_event event[8]; /* 0x300 - 0x33C : SCT event state and control register 0 to 7 (R/W) */
+ uint32_t reserved_4[112];
+ struct lpc_sct_out out_evt_sel[6]; /* 0x500 - 0x52C : SCT event state and control register 0 to 7 (R/W) */
+};
+#define LPC_SCTIMER ((struct lpc_sct_timer *) LPC_SCT_BASE)
+
+
+/* Configuration register */
+#define LPC_SCT_UNIFIED_TIMER (0x01 << 0)
+/* Clock */
+#define LPC_SCT_CLK_SYSCLK (0x00 << 1)
+#define LPC_SCT_CLK_SAMPLE_SYSCLK (0x01 << 1)
+#define LPC_SCT_CLK_SCT_INPUT (0x02 << 1)
+#define LPC_SCT_CLK_SCT_ASYNC (0x03 << 1)
+#define LPC_SCT_CLK_RISING_IN(x) (((x) * 2 ) << 3)
+#define LPC_SCT_CLK_FALLING_IN(x) ((((x) * 2 ) + 1) << 3)
+/* Other */
+#define LPC_SCT_NORELOAD (0x01 << 7)
+#define LPC_SCT_IN_EVT_SYNC(x) ((0x01 << ((x) & 0x03)) << 9)
+#define LPC_SCT_AUTOLIMIT (0x01 << 17)
+
+/* Control register */
+#define LPC_SCT_DOWN (0x01 << 0)
+#define LPC_SCT_STOP (0x01 << 1)
+#define LPC_SCT_HALT (0x01 << 2)
+#define LPC_SCT_CLEAR (0x01 << 3)
+#define LPC_SCT_BIDIR (0x01 << 4)
+#define LPC_SCT_PRESCALE(x) (((x) & 0xFF) << 5)
+
+/* Limit event */
+#define LPC_SCT_LIMIT_BY_EVT(x) (0x01 << ((x) & 0x07))
+#define LPC_SCT_HALT_BY_EVT(x) (0x01 << ((x) & 0x07))
+#define LPC_SCT_STOP_BY_EVT(x) (0x01 << ((x) & 0x07))
+#define LPC_SCT_START_BY_EVT(x) (0x01 << ((x) & 0x07))
+
+/* State variable */
+#define LPC_SCT_STATE_VAR(x) (((x) & 0x1F) << 0)
+
+/* Input states register */
+#define LPC_SCT_ASYNC_IN(reg, num) (((reg) >> ((num) & 0x03)) & 0x01)
+#define LPC_SCT_SYNC_IN(reg, num) (((reg) >> (((num) & 0x03) + 16)) & 0x01)
+
+/* Mode register */
+#define LPC_SCT_MATCH(x) (0)
+#define LPC_SCT_MATCH_CLR(x) (0x01 << ((x) & 0x07))
+#define LPC_SCT_CAPTURE(x) (0x01 << ((x) & 0x07))
+
+/* Output register */
+#define LPC_SCT_OUT_SET(x) (0x01 << ((x) & 0x07))
+#define LPC_SCT_OUT_SET_ALL(all) ((all) & 0x3F)
+#define LPC_SCT_OUT_VAL(reg, num) (((reg) >> ((num) & 0x07)) & 0x01)
+
+/* Bi-directionnal Output control register */
+#define LPC_SCT_BIDIR_INDEP (0)
+#define LPC_SCT_BIDIR_REV(x) (0x01 << (((x) & 0x07) * 2))
+
+/* Conflict resolution */
+#define LPC_SCT_CONFLICT_SET(x) (0x01 << (((x) & 0x07) * 2))
+#define LPC_SCT_CONFLICT_CLR(x) (0x02 << (((x) & 0x07) * 2))
+#define LPC_SCT_CONFLICT_TOGGLE(x) (0x03 << (((x) & 0x07) * 2))
+
+/* Event interrupt enable and flag registers */
+#define LPC_SCT_EVT_INT(x) (0x01 << ((x) & 0x07))
+
+/* Conflict interrupt enable and flag register */
+#define LPC_SCT_CONFLICT_INT(x) (0x01 << ((x) & 0x07))
+
+/* Event enable */
+#define LPC_SCT_EVT_EN_STATE(x) (0x01 << ((x) & 0x07))
+
+/* Event control register */
+#define LPC_SCT_MATCHSEL(x) ((x) & 0x0F)
+#define LPC_SCT_OUTSEL (0x01 << 5)
+#define LPC_SCT_IOSEL(x) (((x) & 0x0F) << 6)
+#define LPC_SCT_IOCOND_LOW (0x0 << 10)
+#define LPC_SCT_IOCOND_RISE (0x1 << 10)
+#define LPC_SCT_IOCOND_FALL (0x2 << 10)
+#define LPC_SCT_IOCOND_HIGH (0x3 << 10)
+#define LPC_SCT_COMB_MODE_OR (0x0 << 12)
+#define LPC_SCT_COMB_MODE_MATCH (0x1 << 12)
+#define LPC_SCT_COMB_MODE_IO (0x2 << 12)
+#define LPC_SCT_COMB_MODE_AND (0x3 << 12)
+#define LPC_SCT_STATE_ADD (0x0 << 14)
+#define LPC_SCT_STATE_LOAD (0x1 << 14)
+#define LPC_SCT_STATE_VAL(x) (((x) & 0x1F) << 15)
+#define LPC_SCT_MATCH_EQUAL (0x0 << 20)
+#define LPC_SCT_MATCH_LT_GT (0x1 << 20)
+#define LPC_SCT_CNTDIR_INDEP (0x0 << 21)
+#define LPC_SCT_CNTDIR_UP (0x1 << 21)
+#define LPC_SCT_CNTDIR_DOWN (0x2 << 21)
+
+/* Event output set */
+#define LPC_SCT_OUTPUT_EVT_SET(x) (0x01 << ((x) & 0x07))
+
+/* Event output clear */
+#define LPC_SCT_OUTPUT_EVT_CLR(x) (0x01 << ((x) & 0x07))
+
+
+
+
+
+struct lpc_sct_timer_16
+{
+ volatile uint32_t config; /* 0x000 : SCT configuration register (R/W) */
+ volatile uint16_t control[2]; /* 0x004 : SCT control register (R/W) */
+ volatile uint16_t limit[2]; /* 0x008 : SCT limit event select register (R/W) */
+ volatile uint16_t halt[2]; /* 0x00C : SCT halt event select register (R/W) */
+ volatile uint16_t stop[2]; /* 0x010 : SCT stop event select register (R/W) */
+ volatile uint16_t start[2]; /* 0x014 : SCT start event select register (R/W) */
+ uint32_t reserved_0[10];
+ volatile uint16_t count[2]; /* 0x040 : SCT counter register (R/W) */
+ volatile uint16_t state[2]; /* 0x044 : SCT state register (R/W) */
+ volatile uint32_t input; /* 0x048 : SCT input register (R/-) */
+ volatile uint16_t mode[2]; /* 0x04C : SCT match/capture mode register (R/W) */
+ volatile uint32_t output; /* 0x050 : SCT output register (R/W) */
+ volatile uint32_t out_dir_ctrl; /* 0x054 : SCT output counter direction control register (R/W) */
+ volatile uint32_t conflict_res; /* 0x058 : SCT conflict resolution register (R/W) */
+ volatile uint32_t dma_req[2]; /* 0x05C - 0x060 : SCT DMA request 0 and 1 registers (R/W) */
+ uint32_t reserved_1[35];
+ volatile uint32_t event_int_en; /* 0x0F0 : SCT event interrupt enable register (R/W) */
+ volatile uint32_t event_flag; /* 0x0F4 : SCT event flag register (R/W) */
+ volatile uint32_t conflict_int_en; /* 0x0F8 : SCT conflict interrupt enable register (R/W) */
+ volatile uint32_t conflict_flag; /* 0x0FC : SCT conflict flag register (R/W) */
+ union {
+ volatile uint16_t match[8][2]; /* 0x100 - 0x11C : SCT match value for channels 0 to 7 (R/W) */
+ volatile uint16_t capture[8][2]; /* 0x100 - 0x11C : SCT capture value for channels 0 to 7 (R/W) */
+ };
+ uint32_t reserved_2[56];
+ union {
+ volatile uint16_t match_reload[8][2]; /* 0x200 - 0x21C : SCT match reload value register 0 to 7 (R/W) */
+ volatile uint16_t capture_ctrl[8][2]; /* 0x200 - 0x21C : SCT capture control register 0 to 7 (R/W) */
+ };
+ uint32_t reserved_3[56];
+ struct lpc_sct_event event[8]; /* 0x300 - 0x33C : SCT event state and control register 0 to 7 (R/W) */
+ uint32_t reserved_4[112];
+ struct lpc_sct_out out_evt_sel[6]; /* 0x500 - 0x52C : SCT event state and control register 0 to 7 (R/W) */
+};
+#define LPC_SCTIMER_16 ((struct lpc_sct_timer_16 *) LPC_SCT_BASE)
+
+#endif /* DRIVERS_SCTIMERS_H */
+
--- /dev/null
+/****************************************************************************
+ * drivers/timers.h
+ *
+ * Copyright 2016 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef DRIVERS_TIMERS_H
+#define DRIVERS_TIMERS_H
+
+/***************************************************************************** */
+/* Timers */
+/***************************************************************************** */
+
+/* Driver for the different kinds of timers available in the LPC82x
+ *
+ * This inludes :
+ * - State Configurable Timers driver for the integrated SCT of the LPC82x
+ * The LPC82x has one State Configurable Timer.
+ *
+ * Refer to LPC82x documentation (UM10800.pdf) for more information.
+ *
+ * All common functions are available using a common interface. Only specific
+ * functions have a specific interface, described in separate headers files.
+ */
+
+#include "lib/stdint.h"
+
+#define NUM_TIMERS 4
+#define MAX_CHANNELS 8
+enum lpc_timers {
+ LPC_SCT = 0, /* Unified 32 bits SCT timer */
+ LPC_SCT16_T0, /* _L 16 bits SCT timer */
+ LPC_SCT16_T1, /* _H 16 bits SCT timer */
+ LPC_MRT,
+};
+
+/* Available timer modes */
+enum lpc_timer_mode {
+ LPC_TIMER_MODE_TIMER = 0,
+ LPC_TIMER_MODE_COUNTER,
+ LPC_TIMER_MODE_CAPTURE,
+ LPC_TIMER_MODE_MATCH,
+ LPC_TIMER_MODE_PWM, /* Pulse Width Modulation */
+ LPC_TIMER_MODE_PWD, /* Pulse Width Demodulation */
+};
+
+
+/* Configurations */
+struct lpc_timer_pwm_config {
+ uint8_t nb_channels;
+ uint8_t outputs_initial_state;
+ uint32_t period;
+ uint32_t match_values[MAX_CHANNELS];
+ uint8_t outputs[MAX_CHANNELS];
+};
+
+
+
+struct common_operations {
+ /* Running control */
+ void (*start)(uint8_t);
+ void (*stop)(uint8_t);
+ void (*pause)(uint8_t);
+ void (*cont)(uint8_t);
+ void (*restart)(uint8_t);
+ void (*halt)(uint8_t);
+ /* Counter */
+ uint32_t (*get_counter)(uint8_t);
+};
+struct config_operations {
+ void (*set_match)(uint8_t, uint8_t, uint32_t);
+ void (*pwm_config)(uint8_t, const struct lpc_timer_pwm_config*);
+};
+struct init_operations {
+ void (*timer_on)(uint8_t, uint32_t, void (*)(uint32_t));
+ void (*timer_off)(uint8_t);
+};
+
+/*******************************************************************************/
+/* Common operations */
+
+/* Start the timer :
+ * Remove the reset flag if present and set timer enable flag.
+ * Timer must be turned on and configured (no checks done here).
+ */
+void timer_start(uint8_t timer_num);
+void timer_continue(uint8_t timer_num);
+
+/* Pause the timer counter, does not reset */
+void timer_pause(uint8_t timer_num);
+
+/* Stop and reset the timer counter */
+void timer_stop(uint8_t timer_num);
+void timer_halt(uint8_t timer_num);
+
+/* Resets the timer and lets it count again imediately */
+void timer_restart(uint8_t timer_num);
+
+
+/* Return the current counter value
+ * Note that for 32 bits timers there is not much possibilities to differentiate
+ * between an error and a real value
+ */
+uint32_t timer_get_counter_val(uint8_t timer_num);
+
+
+/*******************************************************************************/
+/* Configuration */
+
+/* Change the match value of a single timer channel */
+void timer_set_match(uint8_t timer_num, uint8_t channel, uint32_t val);
+
+void timer_pwm_config(uint8_t timer_num, const struct lpc_timer_pwm_config* pwm_conf);
+
+
+
+/*******************************************************************************/
+/* Init */
+
+/* Power up a timer.
+ * clkrate is a divider of the main clock frequency chosen for your application
+ * as it will be used to divide the main clock to get the prescaler value.
+ * Set clkrate to 0 to disable the prescaler.
+ * callback is used for all the possible timer interrupts (activated using the
+ * config field in timer_config struct upon timer setup)
+ * The interrupt flags are passed to the interrupt routine as argument.
+ */
+void timer_on(uint8_t timer_num, uint32_t clkrate, void (*callback)(uint32_t));
+
+/* Removes the main clock from the selected timer block */
+void timer_off(uint8_t timer_num);
+
+#endif /* DRIVERS_TIMERS_H */
+