Complete rewrite of timers API, now documented here : http://wiki.techno-innov.fr...
authorNathael Pajani <nathael.pajani@ed3l.fr>
Tue, 27 Sep 2016 21:08:21 +0000 (23:08 +0200)
committerNathael Pajani <nathael.pajani@ed3l.fr>
Tue, 8 Nov 2022 16:03:05 +0000 (17:03 +0100)
drivers/countertimers.c [new file with mode: 0644]
drivers/timers.c
include/drivers/countertimers.h [new file with mode: 0644]
include/drivers/timers.h

diff --git a/drivers/countertimers.c b/drivers/countertimers.c
new file mode 100644 (file)
index 0000000..eb678d6
--- /dev/null
@@ -0,0 +1,371 @@
+/****************************************************************************
+ *  drivers/countertimers.c
+ *
+ * Copyright 2012 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                                                       */
+/***************************************************************************** */
+
+/* Timers driver for the integrated timers of the LPC122x.
+ * The LPC122x Has two 16bits timers and two 32bits timers.
+ * Refer to LPC122x documentation (UM10441.pdf) for more information.
+ */
+
+#include "core/system.h"
+#include "lib/errno.h"
+#include "drivers/timers.h"
+#include "drivers/countertimers.h"
+
+
+/* These are local to our file */
+struct countertimer_device
+{
+       struct lpc_timer* regs;
+       uint32_t power_bit;
+       uint8_t irq;
+       uint8_t configured;
+       void (*callback)(uint32_t); /* Possible RX callback */
+};
+
+static struct countertimer_device countertimers[NUM_COUNTERTIMERS] = {
+       {
+               .regs = LPC_TMR16B0,
+               .power_bit = LPC_SYS_ABH_CLK_CTRL_CT16B0,
+               .irq = TIMER0_IRQ,
+               .configured = 0,
+               .callback = NULL,
+       }, 
+       {
+               .regs = LPC_TMR16B1,
+               .power_bit = LPC_SYS_ABH_CLK_CTRL_CT16B1,
+               .irq = TIMER1_IRQ,
+               .configured = 0,
+               .callback = NULL,
+       }, 
+       {
+               .regs = LPC_TMR32B0,
+               .power_bit = LPC_SYS_ABH_CLK_CTRL_CT32B0,
+               .irq = TIMER2_IRQ,
+               .configured = 0,
+               .callback = NULL,
+       }, 
+       {
+               .regs = LPC_TMR32B1,
+               .power_bit = LPC_SYS_ABH_CLK_CTRL_CT32B1,
+               .irq = TIMER3_IRQ,
+               .configured = 0,
+               .callback = NULL,
+       }, 
+};
+
+/* Handlers */
+void TIMER_Handler(struct countertimer_device* timer)
+{
+       uint32_t intr_flags = timer->regs->int_reg; /* Backup the flags */
+
+       /* Clear the interrupt */
+       timer->regs->int_reg = intr_flags;
+       /* And call the user routine if one has been registered */
+       if (timer->callback != NULL) {
+               timer->callback(intr_flags);
+       }
+}
+void TIMER_0_Handler(void)
+{
+       TIMER_Handler(&countertimers[0]);
+}
+void TIMER_1_Handler(void)
+{
+       TIMER_Handler(&countertimers[1]);
+}
+void TIMER_2_Handler(void)
+{
+       TIMER_Handler(&countertimers[2]);
+}
+void TIMER_3_Handler(void)
+{
+       TIMER_Handler(&countertimers[3]);
+}
+
+
+
+/* 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 countertimer_start(uint8_t timer_num)
+{
+       /* Remove reset flag and set timer enable flag */
+       countertimers[timer_num].regs->timer_ctrl = LPC_TIMER_COUNTER_ENABLE;
+}
+
+/* Pause the timer counter, does not reset */
+void countertimer_pause(uint8_t timer_num)
+{
+       /* Remove timer enable flag */
+       countertimers[timer_num].regs->timer_ctrl = 0;
+}
+
+/* Stops and resets the timer counter */
+void countertimer_stop(uint8_t timer_num)
+{
+       /* Remove timer enable flag and request reset */
+       countertimers[timer_num].regs->timer_ctrl = LPC_TIMER_COUNTER_RESET;
+       /* Remove reset flag */
+       countertimers[timer_num].regs->timer_ctrl = 0;
+}
+
+/* Resets the timer and lets it count again imediately */
+void countertimer_restart(uint8_t timer_num)
+{
+       /* Set timer reset flag */
+       countertimers[timer_num].regs->timer_ctrl = LPC_TIMER_COUNTER_RESET;
+       /* Remove reset flag and start counter */
+       countertimers[timer_num].regs->timer_ctrl = LPC_TIMER_COUNTER_ENABLE;
+}
+
+int countertimer_get_counter_val(uint8_t timer_num, uint32_t* val)
+{
+       *val = countertimers[timer_num].regs->timer_counter;
+       return 0;
+}
+
+int countertimer_get_capture_val(uint8_t timer_num, uint8_t channel, uint32_t* val)
+{
+       if (channel >= MAX_CHANNELS) {
+               return -EINVAL;
+       }
+       *val = countertimers[timer_num].regs->capture_reg[channel];
+       return 0;
+}
+
+
+/* Change the match value of a single timer channel */
+int countertimer_set_match(uint8_t timer_num, uint8_t channel, uint32_t val)
+{
+       if (channel > NUM_COUNTERTIMERS_CHANS)
+               return -EINVAL;
+
+       countertimers[timer_num].regs->match_reg[channel] = val;
+       return 0;
+}
+
+struct common_operations countertimer_ops = {
+       .start = countertimer_start,
+       .cont = countertimer_start,
+       .pause = countertimer_pause,
+       .stop = countertimer_stop,
+       .restart = countertimer_restart,
+       .halt = countertimer_stop,
+       .get_counter = countertimer_get_counter_val,
+       .get_capture = countertimer_get_capture_val,
+       .set_match = countertimer_set_match,
+};
+
+
+
+/*******************************************************************************/
+/* Configuration operations */
+
+
+/*   Timer Setup as PWM */
+/* Returns 0 on success
+ * Takes a timer number and a timer PWM config structure as arguments.
+ * Refer to timer PWM config structure for details.
+ */
+int countertimer_pwm_setup(uint8_t timer_num, const struct lpc_timer_pwm_config* conf)
+{
+       struct countertimer_device* timer = &(countertimers[timer_num]);
+       uint8_t max_chan = 0;
+       uint8_t active_chans = 0;
+       int i = 0;
+
+       /* Make sure we have a PWM cycle length */
+       if (conf->period == 0) {
+               return -EINVAL;
+       }
+       switch (timer_num) {
+               case LPC_TIMER_16B0:
+               case LPC_TIMER_16B1:
+                       if (conf->nb_channels > NUM_COUNTERTIMERS_16B_PWM_CHANS) {
+                               return -EINVAL;
+                       }
+                       max_chan = NUM_COUNTERTIMERS_16B_PWM_CHANS;
+                       break;
+               case LPC_TIMER_32B0:
+               case LPC_TIMER_32B1:
+                       if (conf->nb_channels > NUM_COUNTERTIMERS_32B_PWM_CHANS) {
+                               return -EINVAL;
+                       }
+                       max_chan = NUM_COUNTERTIMERS_32B_PWM_CHANS;
+                       break;
+       }
+
+       if (conf->period_chan >= MAX_CHANNELS) {
+                return -EINVAL;
+       }
+       /* Setup selected PWM channels */
+       for (i = 0; i < conf->nb_channels; i++) {
+               if (conf->outputs[i] >= max_chan) {
+                       continue;
+               }
+               timer->regs->match_reg[ conf->outputs[i] ] = conf->match_values[i];
+               /* Mark channel as active */
+               active_chans |= LPC_PWM_CHANNEL_ENABLE(conf->outputs[i]);
+       }
+
+       /* Setup period */
+       timer->regs->match_reg[ conf->period_chan ] = conf->period;
+       /* Setup selected channel as PWM cycle length control */
+       timer->regs->match_ctrl &= ~(LPC_TIMER_MATCH_ERASE(conf->period_chan));
+       timer->regs->match_ctrl |= (LPC_TIMER_RESET_ON_MATCH << LPC_TIMER_MATCH_SHIFT(conf->period_chan));
+       active_chans |= LPC_PWM_CHANNEL_ENABLE(conf->period_chan);
+
+       /* Setup count mode as timer */
+       timer->regs->count_ctrl = LPC_COUNTER_IS_TIMER;
+
+       /* Activate selected PWM channels and period channel */
+       timer->regs->pwm_ctrl = active_chans;
+
+       return 0; /* Config OK */
+}
+
+
+/* Timer Setup in timer or counter mode, with optionnal capture and match configuration
+ * Takes a timer number and a timer counter config structure as arguments.
+ * Returns 0 on success
+ */
+int countertimer_tc_setup(uint8_t timer_num, const struct lpc_tc_config* conf)
+{
+       struct countertimer_device* timer = &(countertimers[timer_num]);
+       int i = 0;
+
+       if (conf->mode & LPC_TIMER_MODE_SPECIFIC) {
+               return -EINVAL;
+       }
+       /* Erase existing configuration */
+       timer->regs->capture_ctrl = 0;
+       timer->regs->match_ctrl = 0;
+       timer->regs->external_match = 0;
+
+       /* Override the prescaler value if requested */
+       if (conf->prescale_val != 0) {
+               timer->regs->prescale = conf->prescale_val;
+       }
+       /* Select between timer (counts on PCLK) and counter mode (counts on CAP events) */
+       if (conf->mode & LPC_TIMER_MODE_COUNTER) {
+               /* Configure the counter */
+               timer->regs->count_ctrl = (conf->count_control & 0x0F);
+               timer->regs->count_ctrl |= LPC_COUNTER_INC_INPUT(conf->count_chan);
+       } else {
+               /* Timer mode */
+               timer->regs->count_ctrl = LPC_COUNTER_IS_TIMER;
+       }
+
+       /* Configure the reset on capture functionality when selected */
+       if (conf->reset_on_cap & LPC_COUNTER_CLEAR_ON_EVENT_EN) {
+               timer->regs->count_ctrl = LPC_COUNTER_CLEAR_ON_EVENT_EN;
+               timer->regs->count_ctrl |= ((conf->reset_on_cap & 0x07) << LPC_COUNTER_CLEAR_ON_EVENT_SHIFT);
+       }
+
+       if (conf->mode & LPC_TIMER_MODE_CAPTURE) {
+               for (i = 0; i < MAX_CHANNELS; i++) {
+                       timer->regs->capture_ctrl |= ((conf->cap_control[i] & 0x07) << LPC_TIMER_CAPTURE_SHIFT(i));
+               }
+       }
+
+       if (conf->mode & LPC_TIMER_MODE_MATCH) {
+               for (i = 0; i < MAX_CHANNELS; i++) {
+                       timer->regs->match_ctrl |= ((conf->match_control[i] & 0x07) << LPC_TIMER_MATCH_SHIFT(i));
+                       timer->regs->match_reg[i] = conf->match[i];
+                       timer->regs->external_match |= ((conf->ext_match_config[i] & 0x03) << LPC_TIMER_EXT_MATCH_SHIFT(i));
+               }
+       }
+
+       /* Ensure that counter input chan has not been configured to reset or stop the timer or as a
+        * capture channel (See remarks in user manual UM10441 page 268 section 14.7.11) when the ct is
+        * configured in counter mode. */
+       if (conf->mode & LPC_TIMER_MODE_COUNTER) {
+               timer->regs->match_ctrl &= ~LPC_TIMER_MATCH_ERASE(conf->count_chan);
+               timer->regs->capture_ctrl &= ~LPC_TIMER_CAPTURE_ERASE(conf->count_chan);
+               timer->regs->external_match &= ~LPC_TIMER_EXT_MATCH_ERASE(conf->count_chan);
+       }
+
+       return 0; /* Config OK */
+}
+
+struct config_operations countertimer_cfg_ops = {
+       .pwm_config = countertimer_pwm_setup,
+       .tc_config = countertimer_tc_setup,
+};
+
+
+
+
+/*******************************************************************************/
+/* Init operations */
+
+/* Power up a timer.
+ * clkrate is the desired timer clock rate. It will be used to divide the main clock
+ *   to get the timer prescaler value.
+ * Set clkrate to 0 to disable the prescaler.
+ */
+int countertimer_on(uint8_t timer_num, uint32_t clkrate, void (*callback)(uint32_t))
+{
+       struct countertimer_device* timer = NULL;
+       uint32_t prescale; /* The clock divider for the counter */
+
+       timer = &(countertimers[timer_num]);
+
+       NVIC_DisableIRQ( timer->irq );
+       /* Power up the timer */
+       subsystem_power(timer->power_bit, 1);
+       /* Reset counter on next PCLK positive edge, and disable counter */
+       timer->regs->timer_ctrl = LPC_TIMER_COUNTER_RESET;
+
+       /* Store the callback, OK even if none given */
+       timer->callback = callback;
+
+       /* Set the prescaler value */
+       if (clkrate == 0) {
+               prescale = 0;
+       } else {
+               prescale = (get_main_clock() / clkrate) - 1;
+       }
+       timer->regs->prescale = prescale;
+
+       NVIC_EnableIRQ(countertimers[timer_num].irq);
+       return 0;
+}
+
+/* Removes the main clock from the selected timer block */
+int countertimer_off(uint8_t timer_num)
+{
+       NVIC_DisableIRQ( countertimers[timer_num].irq );
+       subsystem_power(countertimers[timer_num].power_bit, 0);
+       return 0;
+}
+
+struct init_operations countertimer_init_ops = {
+       .timer_on = countertimer_on,
+       .timer_off = countertimer_off,
+};
+
index 4e1e451..994c9fc 100644 (file)
 /*                Timers                                                       */
 /***************************************************************************** */
 
-/* Timers driver for the integrated timers of the LPC1224.
- * The LPC1224 Has two 16bits timers and 2 32bits timers.
- * Refer to LPC1224 documentation (UM10441.pdf) for more information.
+/* Driver for the different kinds of timers available in the LPC122x
+ *
+ * This inludes :
+ * - 32 bits Timers driver
+ *   The LPC122x has two 32 bits Timer.
+ * - 16 bits Timers driver
+ *   The LPC122x has two 16 bits Timer.
+ *
+ * Refer to LPC122x documentation (UM10441.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.
  */
 
 
 
 
 /* These are local to our file */
-struct timer_device
-{
-       struct lpc_timer* regs;
-       uint32_t power_bit;
-       uint32_t irq;
-       void (*callback)(uint32_t); /* Possible RX callback */
+struct timer_device {
+       uint8_t num;
+       struct common_operations* ops;
+       struct config_operations* cfg_ops;
+       struct init_operations* init_ops;
 };
-static struct timer_device timer_devices[NUM_TIMERS] = {
-       { LPC_TMR16B0, LPC_SYS_ABH_CLK_CTRL_CT16B0, TIMER0_IRQ }, 
-       { LPC_TMR16B1, LPC_SYS_ABH_CLK_CTRL_CT16B1, TIMER1_IRQ },
-       { LPC_TMR32B0, LPC_SYS_ABH_CLK_CTRL_CT32B0, TIMER2_IRQ },
-       { LPC_TMR32B1, LPC_SYS_ABH_CLK_CTRL_CT32B1, TIMER3_IRQ },
-};
-
 
 
-/* Handlers */
-void TIMER_Handler(struct timer_device* timer)
-{
-       uint32_t intr_flags = timer->regs->int_reg; /* Backup the flags */
+/* 32 bits and 16 bits Counter Timers */
+extern struct common_operations countertimer_ops;
+extern struct config_operations countertimer_cfg_ops;
+extern struct init_operations countertimer_init_ops;
+
+
+struct timer_device timers[NUM_TIMERS] = {
+       {
+               .num = LPC_TIMER_16B0,
+               .ops = &countertimer_ops,
+               .cfg_ops = &countertimer_cfg_ops,
+               .init_ops = &countertimer_init_ops,
+       },
+       {
+               .num = LPC_TIMER_16B1,
+               .ops = &countertimer_ops,
+               .cfg_ops = &countertimer_cfg_ops,
+               .init_ops = &countertimer_init_ops,
+       },
+       {
+               .num = LPC_TIMER_32B0,
+               .ops = &countertimer_ops,
+               .cfg_ops = &countertimer_cfg_ops,
+               .init_ops = &countertimer_init_ops,
+       },
+       {
+               .num = LPC_TIMER_32B1,
+               .ops = &countertimer_ops,
+               .cfg_ops = &countertimer_cfg_ops,
+               .init_ops = &countertimer_init_ops,
+       },
+};
 
-       /* Clear the interrupt */
-       timer->regs->int_reg = intr_flags;
-       /* And call the user routine if one has been registered */
-       if (timer->callback != NULL) {
-               timer->callback(intr_flags);
-       }
-}
-void TIMER_0_Handler(void)
-{
-       TIMER_Handler(&timer_devices[0]);
-}
-void TIMER_1_Handler(void)
-{
-       TIMER_Handler(&timer_devices[1]);
-}
-void TIMER_2_Handler(void)
-{
-       TIMER_Handler(&timer_devices[2]);
-}
-void TIMER_3_Handler(void)
-{
-       TIMER_Handler(&timer_devices[3]);
-}
 
+/*******************************************************************************/
+/* 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); \
+               } \
+       }
 
-/* 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).
+/* 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);
+
+
+/* Get the current counter value
+ * Return 0 if the value is valid.
  */
-void timer_start(uint32_t timer_num)
-{
-       if (timer_num >= NUM_TIMERS)
-               return;
-       /* Remove reset flag and set timer enable flag */
-       timer_devices[timer_num].regs->timer_ctrl = LPC_TIMER_COUNTER_ENABLE;
-}
-void timer_continue(uint32_t timer_num) __attribute__ ((alias ("timer_start")));
-/* Pause the timer counter, does not reset */
-void timer_pause(uint32_t timer_num)
-{
-       if (timer_num >= NUM_TIMERS)
-               return;
-       /* Remove timer enable flag */
-       timer_devices[timer_num].regs->timer_ctrl = 0;
-}
-/* Stops and resets the timer counter */
-void timer_stop(uint32_t timer_num)
-{
-       if (timer_num >= NUM_TIMERS)
-               return;
-       /* Remove timer enable flag and request reset */
-       timer_devices[timer_num].regs->timer_ctrl = LPC_TIMER_COUNTER_RESET;
-       /* Remove reset flag */
-       timer_devices[timer_num].regs->timer_ctrl = 0;
-}
-/* Resets the timer and lets it count again imediately */
-void timer_restart(uint32_t timer_num)
+int timer_get_counter_val(uint8_t timer_num, uint32_t* val)
 {
        if (timer_num >= NUM_TIMERS)
-               return;
-       /* Set timer reset flag */
-       timer_devices[timer_num].regs->timer_ctrl = LPC_TIMER_COUNTER_RESET;
-       /* Remove reset flag and start counter */
-       timer_devices[timer_num].regs->timer_ctrl = LPC_TIMER_COUNTER_ENABLE;
+               return -EINVAL;
+       if (timers[timer_num].ops && timers[timer_num].ops->get_counter) {
+               return timers[timer_num].ops->get_counter(timer_num, val);
+       }
+       return -ENODEV;
 }
 
-uint32_t timer_get_capture_val(uint32_t timer_num, uint32_t channel)
+
+/* Get the value of the timer when the capture event last triggered
+ * Return 0 if the value is valid.
+ */
+int timer_get_capture_val(uint8_t timer_num, uint8_t channel, uint32_t* val)
 {
        if (timer_num >= NUM_TIMERS)
-               return 0;
-       /* FIXME */
-       return 0;
+               return -EINVAL;
+       if (timers[timer_num].ops && timers[timer_num].ops->get_capture) {
+               return timers[timer_num].ops->get_capture(timer_num, channel, val);
+       }
+       return -ENODEV;
 }
-uint32_t timer_get_counter_val(uint32_t timer_num)
+
+
+/* Change the match value of a single timer channel */
+int timer_set_match(uint8_t timer_num, uint8_t channel, uint32_t val)
 {
        if (timer_num >= NUM_TIMERS)
-               return 0;
-       return timer_devices[timer_num].regs->timer_counter;
+               return -EINVAL;
+       if (timers[timer_num].ops && timers[timer_num].ops->set_match) {
+               return timers[timer_num].ops->set_match(timer_num, channel, val);
+       }
+       return -ENODEV;
 }
 
-/* Change the match value of a single timer channel */
-void timer_set_match(uint32_t timer_num, uint32_t channel, uint32_t val)
+
+/*******************************************************************************/
+/* Configuration */
+
+/* Configure the timer as PWM. Call to timer-specific function */
+int timer_pwm_config(uint8_t timer_num, const struct lpc_timer_pwm_config* conf)
 {
        if (timer_num >= NUM_TIMERS)
-               return;
-       if (channel > 3)
-               return;
-
-       timer_devices[timer_num].regs->match_reg[channel] = val;
+               return -EINVAL;
+       if (timers[timer_num].cfg_ops && timers[timer_num].cfg_ops->pwm_config) {
+               return timers[timer_num].cfg_ops->pwm_config(timer_num, conf);
+       }
+       return -ENODEV;
 }
 
 
-/***************************************************************************** */
-/*   Timer Setup */
-/* Returns 0 on success
- * Takes a timer number and a timer config structure as arguments.
- * Refer to timer config structure for details.
+/* Timer Setup in timer or counter mode, with optionnal capture and match configuration
+ * Takes a timer number and a timer counter config structure as arguments.
+ * Returns 0 on success
  */
-int timer_setup(uint32_t timer_num, const struct timer_config* conf)
+int timer_counter_config(uint8_t timer_num, const struct lpc_tc_config* conf)
 {
-       struct timer_device* timer = NULL;
-       int i = 0;
        if (timer_num >= NUM_TIMERS)
-               return -ENODEV;
-       timer = &(timer_devices[timer_num]);
-
-       /* Configure the reset on capture functionality */
-       if (conf->reset_on_capture != 0x00) {
-               timer->regs->count_ctrl = LPC_COUNTER_CLEAR_ON_EVENT_EN;
-               timer->regs->count_ctrl |= ((conf->reset_on_capture & 0x07) << LPC_COUNTER_CLEAR_ON_EVENT_SHIFT);
+               return -EINVAL;
+       if (timers[timer_num].cfg_ops && timers[timer_num].cfg_ops->tc_config) {
+               return timers[timer_num].cfg_ops->tc_config(timer_num, conf);
        }
-
-       switch (conf->mode) {
-               case LPC_TIMER_MODE_TIMER:
-                       timer->regs->capture_ctrl = 0; /* Timer mode ! */
-                       timer->regs->count_ctrl = LPC_COUNTER_IS_TIMER;
-                       break;
-               case LPC_TIMER_MODE_COUNTER:
-                       if ((conf->config[0] & 0x03) == 0x00) {
-                               return -EINVAL;
-                       }
-                       /* Must set capture chanel N config to 0b000 in capture control register,
-                        * (see remarks in user manual UM10441 page 268 section 14.7.11)
-                        * Use the LPC_COUNTER_INC_INPUT(x) set by the user to do so automatically
-                        */
-                       timer->regs->capture_ctrl &= ~LPC_TIMER_CAPTURE_ERASE(((conf->config[0] >> LPC_COUNTER_INC_INPUT_SHIFT) & 0x03) * 3);
-                       /* Configure the counter */
-                       timer->regs->count_ctrl |= (conf->config[0] & 0x0F);
-                       break;
-               case LPC_TIMER_MODE_CAPTURE:
-                       timer->regs->capture_ctrl = 0;
-                       for (i = 0; i < NUM_CHANS; i++) {
-                               timer->regs->capture_ctrl |= ((conf->config[i] & 0x07) << LPC_TIMER_CAPTURE_SHIFT(i));
-                       }
-                       break;
-               case LPC_TIMER_MODE_MATCH:
-                       timer->regs->match_ctrl = 0;
-                       timer->regs->external_match = 0;
-                       for (i = 0; i < NUM_CHANS; i++) {
-                               timer->regs->match_ctrl |= ((conf->config[i] & 0x07) << LPC_TIMER_MATCH_SHIFT(i));
-                               timer->regs->match_reg[i] = conf->match[i];
-                               timer->regs->external_match |= ((conf->ext_match_config[i] & 0x03) << (LPC_TIMER_EXT_MATCH0_SHIFT + i*2));
-                       }
-                       break;
-               case LPC_TIMER_MODE_PWM:
-                       /* Make sure we have a PWM cycle length */
-                       if (conf->match[ conf->config[1] ] == 0) {
-                               return -EINVAL;
-                       }
-                       /* Activate selected PWM channels 0 to 3 */
-                       timer->regs->pwm_ctrl = (conf->config[0] & 0x0F);
-                       timer->regs->match_ctrl &= ~(LPC_TIMER_MATCH_ERASE(conf->config[1]));
-                       timer->regs->match_ctrl |= (LPC_TIMER_RESET_ON_MATCH << LPC_TIMER_MATCH_SHIFT(conf->config[1]));
-                       for (i = 0; i < NUM_CHANS; i++) {
-                               timer->regs->match_reg[i] = conf->match[i];
-                       }
-                       break;
-               case LPC_TIMER_MODE_PWD:
-                       break;
-       }
-       return 0; /* Config OK */
+       return -ENODEV;
 }
 
+/*******************************************************************************/
+/* Init operations */
 
 /* Power up a timer.
- * Note that clkrate should be a divider of the main clock frequency chosed
- *   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.
+ * clkrate is the desired timer clock rate. It will be used to divide the main clock
+ *   to get the timer prescaler value.
+ *   Set clkrate to 0 to disable the prescaler.
+ * callback is the interrupt callback for this timer.
  */
-void timer_on(uint32_t timer_num, uint32_t clkrate, void (*callback)(uint32_t))
+int timer_on(uint8_t timer_num, uint32_t clkrate, void (*callback)(uint32_t))
 {
-       struct timer_device* timer = NULL;
-       uint32_t prescale; /* The clock divider for the counter */
-
        if (timer_num >= NUM_TIMERS)
-               return;
-       timer = &(timer_devices[timer_num]);
-
-       NVIC_DisableIRQ( timer->irq );
-       /* Power up the timer */
-       subsystem_power(timer->power_bit, 1);
-       /* Reset counter on next PCLK positive edge, and disable counter */
-       timer->regs->timer_ctrl = LPC_TIMER_COUNTER_RESET;
-
-       /* Store the callback, OK even if none given */
-       timer->callback = callback;
-
-       /* Set the prescaler value */
-       if (clkrate == 0) {
-               prescale = 0;
-       } else {
-               prescale = (get_main_clock() / clkrate) - 1;
+               return -EINVAL;
+       if (timers[timer_num].init_ops && timers[timer_num].init_ops->timer_on) {
+               timers[timer_num].init_ops->timer_on(timer_num, clkrate, callback);
        }
-       timer->regs->prescale = prescale;
-
-       NVIC_EnableIRQ(timer_devices[timer_num].irq);
+       return -ENODEV;
 }
 
 /* Removes the main clock from the selected timer block */
-void timer_off(uint32_t timer_num)
+int timer_off(uint8_t timer_num)
 {
        if (timer_num >= NUM_TIMERS)
-               return;
-       NVIC_DisableIRQ( timer_devices[timer_num].irq );
-       subsystem_power(timer_devices[timer_num].power_bit, 0);
+               return -EINVAL;
+       if (timers[timer_num].init_ops && timers[timer_num].init_ops->timer_off) {
+               return timers[timer_num].init_ops->timer_off(timer_num);
+       }
+       return -ENODEV;
 }
+
diff --git a/include/drivers/countertimers.h b/include/drivers/countertimers.h
new file mode 100644 (file)
index 0000000..fa758ba
--- /dev/null
@@ -0,0 +1,116 @@
+/****************************************************************************
+ *  drivers/countertimers.h
+ *
+ * Copyright 2012-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_COUNTER_TIMERS_H
+#define DRIVERS_COUNTER_TIMERS_H
+
+
+#include "lib/stdint.h"
+#include "core/lpc_regs.h"
+
+/***************************************************************************** */
+/*                  Counter Timer                                              */
+/***************************************************************************** */
+/* Timers driver for the integrated timers of the LPC122x.
+ * The LPC122x Has two 16bits timers and two 32bits timers.
+ * Refer to LPC122x documentation (UM10441.pdf) for more information.
+ */
+#define NUM_COUNTERTIMERS     4
+#define NUM_COUNTERTIMERS_CHANS  4
+#define NUM_COUNTERTIMERS_16B_PWM_CHANS 2
+#define NUM_COUNTERTIMERS_32B_PWM_CHANS 4
+
+/* 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_INT_RESET_AND_STOP_ON_MATCH  \
+                       (LPC_TIMER_INTERRUPT_ON_MATCH | LPC_TIMER_RESET_ON_MATCH | LPC_TIMER_STOP_ON_MATCH)
+#define LPC_TIMER_MATCH_SHIFT(x)       (((x) & 0x03) * 3)
+#define LPC_TIMER_MATCH_ERASE(x)       (0x07 << LPC_TIMER_MATCH_SHIFT(x))
+
+/* 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_SHIFT(x)     (((x) & 0x03) * 3)
+#define LPC_TIMER_CAPTURE_ERASE(x)     (0x07 << LPC_TIMER_CAPTURE_SHIFT(x))
+
+/* 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_MATCH_SHIFT(x)   (((x) * 2)  + 4)
+#define LPC_TIMER_EXT_MATCH_ERASE(x)   (0x03 << LPC_TIMER_EXT_MATCH_SHIFT(x))
+
+/* 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 /* DRIVERS_COUNTER_TIMERS_H */
+
+
index d5008a2..b735ddb 100644 (file)
@@ -1,7 +1,7 @@
 /****************************************************************************
  *  drivers/timers.h
  *
- * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ * Copyright 2012-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
 /***************************************************************************** */
 /*                Timers                                                       */
 /***************************************************************************** */
-/* Timers driver for the integrated timers of the LPC1224.
- * Four timers are available, Two 16 bits and two 32 bits
- * All timers have 4 channels though 32 bits timers have all 4 channels available
- *   on capture /match pins while 16bits ones have only two (channels 0 and 1).
- * Refer to LPC1224 documentation (UM10441.pdf) for more information.
+
+/* Driver for the different kinds of timers available in the LPC122x
+ *
+ * This inludes :
+ * - 32 bits Timers driver
+ *   The LPC122x has two 32 bits Timer.
+ * - 16 bits Timers driver
+ *   The LPC122x has two 16 bits Timer.
+ *
+ * Refer to LPC122x documentation (UM10441.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/countertimers.h"
+
+/***************************************************************************** */
+/* All timers have 4 channels. 32 bits timers have all 4 channels available
+ *   on capture / match pins while 16 bits timers have only two (channels 0 and 1).
  */
 #define NUM_TIMERS 4
-#define NUM_CHANS 4
+#define MAX_CHANNELS 4
 
 /* Timer numbers to be used for functions from this driver. */
-#define LPC_TIMER_16B0  0
-#define LPC_TIMER_16B1  1
-#define LPC_TIMER_32B0  2
-#define LPC_TIMER_32B1  3
-
-
-/* Timer modes for the "mode" timer config structure field */
-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 */
+enum lpc_timers {
+       LPC_TIMER_16B0 = 0,  /* 16 bits timer 0 */
+       LPC_TIMER_16B1,  /* 16 bits timer 1 */
+       LPC_TIMER_32B0,  /* 32 bits timer 0 */
+       LPC_TIMER_32B1,  /* 32 bits timer 1 */
 };
 
-/* Structure used to pass parameters to configure a timer */
-/* Notes:
- * In counter or PWM mode, the config is done using config[0] for enabled channels and config[1] holds
- *   the channel number used to control PWM cycle.
- *   Note that the manual recommends Channel 3 be used for PWM cycle length.
- * The field "reset_on_capture" must be set to LPC_COUNTER_CLEAR_ON_EVENT_EN ored with one
- *   of the LPC_COUNTER_CLEAR_ON_CHAN*_* to activate the clear timer on event functionality
+/* Available timer modes *
+ * Some mode may be combined, and some are exlusive :
+ * Values here are important :
+ *   PWM and PWD and any further mode handled by a specific configure function will have
+ *   bit 2 set
  */
-struct timer_config
-{
-       uint32_t mode; /* Counter, Timer Capture, Timer Match or PWM */
-       uint8_t config[NUM_CHANS]; /* Configure the internal behavior when a capture or a match occurs */
-       uint8_t ext_match_config[NUM_CHANS]; /* Configure the external behavior when a match occurs */
-       uint32_t match[NUM_CHANS]; /* The match values if the timer is used in match mode */
-       uint32_t reset_on_capture;
+#define LPC_TIMER_MODE_TIMER     (0x00 << 0)
+#define LPC_TIMER_MODE_COUNTER   (0x01 << 0)
+#define LPC_TIMER_MODE_SPECIFIC  (0x02 << 0)
+#define LPC_TIMER_MODE_CAPTURE   (0x01 << 6)
+#define LPC_TIMER_MODE_MATCH     (0x01 << 7)
+/* Specific modes */
+#define LPC_TIMER_MODE_PWM       (LPC_TIMER_MODE_SPECIFIC | (0x01 << 2))  /* Pulse Width Modulation */
+#define LPC_TIMER_MODE_PWD       (LPC_TIMER_MODE_SPECIFIC | (0x02 << 2))  /* Pulse Width Demodulation */
+
+
+/*******************************************************************************/
+/* Configurations */
+
+/* PWM
+ * This structure is used for the timer_pwm_config() function.
+ * nb_channels is the number of PWM channels used
+ * period_chan is the channel number used to generate the period.
+ * period is the PWM cycle period, in timer clock cycles. It is the value to wich the timer
+ *   will count.
+ * outputs[] is the list of outputs / channels corresponding to each 'match_values'
+ * match_values[] control the PWM channels duty-cycle. They are the timer values at wich
+ *   the corresponding outputs will toggle. They must be lower than or equal to the period
+ *   value.
+ * outputs_initial_state defines whether the outputs start low or high at the beginning of
+ *   the PWM cycle. Support for this depends on the target.
+ *   The LPC122x enforces a low state initial output.
+ */
+struct lpc_timer_pwm_config {
+       uint8_t nb_channels;
+       uint8_t period_chan;
+       uint32_t period;
+       uint8_t outputs[MAX_CHANNELS];
+       uint32_t match_values[MAX_CHANNELS];
+       uint32_t outputs_initial_state;
+};
+
+/* This structure is used for the timer_counter_config() function.
+ * mode is a mask of LPC_TIMER_MODE_* values. Note that some can be combined, and some are
+ *   exclusive : only one of these : LPC_TIMER_MODE_TIMER or LPC_TIMER_MODE_COUNTER and
+ *   possibly one or both of these : LPC_TIMER_MODE_CAPTURE and LPC_TIMER_MODE_MATCH
+ * prescale_val: if not nul, override the prescaler value computed during timer_on() with this
+ *   value. It is not clear in the documentation whether the prescaler is used in counter mode
+ *   or not.
+ * count_control selects the capture channel used to increment the counter when in counter mode.
+ *   count_control is one of LPC_COUNTER_INC_ON_RISING or LPC_COUNTER_INC_ON_FALLING or
+ *   LPC_COUNTER_INC_ON_BOTH.
+ * count_chann selects the channel used to increment the counter (value between 0 and MAX_CHANS).
+ * reset_on_cap is activated by adding LPC_COUNTER_CLEAR_ON_EVENT_EN to a capture reset event (one
+ *   of LPC_COUNTER_CLEAR_ON_*** whith *** Going from CHAN0_RISE, CHAN0_FALL, ... to CHAN3_FALL)
+ * match_control[] is a combination of LPC_TIMER_INTERRUPT_ON_MATCH, LPC_TIMER_RESET_ON_MATCH and
+ *   LPC_TIMER_STOP_ON_MATCH for each match channel.
+ *   This controls the internal behaviour on each match event.
+ * match[] holds the match values.
+ * ext_match_config[] is one of LPC_TIMER_NOTHING_ON_MATCH, LPC_TIMER_CLEAR_ON_MATCH,
+ *   LPC_TIMER_SET_ON_MATCH or LPC_TIMER_TOGGLE_ON_MATCH for each match channel.
+ *   This controls the behavior of the output associated to the corresponding match channel. The
+ *   corresponding pin must be configured as match output by the user.
+ * cap_control[] is a combination of LPC_TIMER_CAP_ON_RISING_EDGE, LPC_TIMER_CAP_ON_FALLING_EDGE
+ *   and LPC_TIMER_INTERRUPT_ON_CAPTURE.
+ *   This controls when the TC current value is loaded to the corresponding match value register,
+ *   and whether this triggers an interrupt or not.
+ */
+struct lpc_tc_config {
+       uint16_t mode;
+       uint32_t prescale_val;
+       uint8_t count_control;
+       uint8_t count_chan;
+       uint8_t reset_on_cap;
+       uint8_t match_control[MAX_CHANNELS];
+       uint32_t match[MAX_CHANNELS];
+       uint8_t ext_match_config[MAX_CHANNELS];
+       uint8_t cap_control[MAX_CHANNELS];
 };
 
 
 
+/*******************************************************************************/
+/* Operation structures, not for use by user programms */
+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 */
+       int (*get_counter)(uint8_t, uint32_t*);
+       int (*get_capture)(uint8_t, uint8_t, uint32_t*);
+       int (*set_match)(uint8_t, uint8_t, uint32_t);
+};
+struct config_operations {
+       int (*pwm_config)(uint8_t, const struct lpc_timer_pwm_config*);
+       int (*tc_config)(uint8_t, const struct lpc_tc_config*);
+};
+struct init_operations {
+       int (*timer_on)(uint8_t, uint32_t, void (*)(uint32_t));
+       int (*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(uint32_t timer_num);
-void timer_continue(uint32_t timer_num);
+void timer_start(uint8_t timer_num);
+void timer_continue(uint8_t timer_num);
 
 /* Pause the timer counter, does not reset */
-void timer_pause(uint32_t timer_num);
+void timer_pause(uint8_t timer_num);
 
 /* Stop and reset the timer counter */
-void timer_stop(uint32_t timer_num);
+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(uint32_t timer_num);
+void timer_restart(uint8_t timer_num);
 
-uint32_t timer_get_capture_val(uint32_t timer_num, uint32_t channel);
 
-uint32_t timer_get_counter_val(uint32_t timer_num);
+/* Get the current counter value
+ * Return 0 if the value is valid.
+ */
+int timer_get_counter_val(uint8_t timer_num, uint32_t* val);
+
+
+/* Get the value of the timer when the capture event last triggered
+  * Return 0 if the value is valid.
+ */
+int timer_get_capture_val(uint8_t timer_num, uint8_t channel, uint32_t* val);
 
 /* Change the match value of a single timer channel */
-void timer_set_match(uint32_t timer_num, uint32_t channel, uint32_t val);
+int timer_set_match(uint8_t timer_num, uint8_t channel, uint32_t val);
 
-/***************************************************************************** */
-/*   Timer Setup */
-/* Returns 0 on success
- * Takes a timer number and a timer config structure as arguments.
- * Refer to timer config structure for details.
- * Note: use of channel 3 for PWM cycle length is enforced.
+
+/*******************************************************************************/
+/* Configuration */
+
+/* PWM configuration in order to use the timer as a PWM controller.
+ * For the pwm_conf structure, refer to it's definition above..
+ * The Timer must be "on" (call timer_on() for this timer before the call to
+ *   timer_pwm_config(), with the disired clock rate, which will define the
+ *   length of a timer clock cycle, which is the base for the timer period
+ *   definition).
+ * The timer will not be started. User code must call timer_start() in order
+ *   to start the PWM.
+ */
+int timer_pwm_config(uint8_t timer_num, const struct lpc_timer_pwm_config* pwm_conf);
+
+
+/* Timer Setup in timer or counter mode, with optionnal capture and match configuration
+ * Takes a timer number and a timer counter config structure as arguments.
+ * Returns 0 on success
  */
-int timer_setup(uint32_t timer_num, const struct timer_config* conf);
+int timer_counter_config(uint8_t timer_num, const struct lpc_tc_config* conf);
 
 
+/*******************************************************************************/
+/* Init */
 
 /* Power up a timer.
- * Note that clkrate should be a divider of the main clock frequency chosed
- *   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.
+ * clkrate is the desired timer clock rate. It will be used to divide the main clock
+ *   to get the timer 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(uint32_t timer_num, uint32_t clkrate, void (*callback)(uint32_t));
+int 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(uint32_t timer_num);
+int timer_off(uint8_t timer_num);
+
 
 #endif /* DRIVERS_TIMERS_H */