Changes to timers API
authorNathael Pajani <nathael.pajani@ed3l.fr>
Tue, 27 Sep 2016 22:11:56 +0000 (00:11 +0200)
committerNathael Pajani <nathael.pajani@ed3l.fr>
Tue, 27 Sep 2016 22:11:56 +0000 (00:11 +0200)
apps/base/pwm/main.c
drivers/sctimers.c
drivers/timers.c
include/drivers/timers.h

index 3021155..6312592 100644 (file)
@@ -107,8 +107,10 @@ int main(void)
        uprintf(UART0, "Timer started\n");
 
        while (1) {
+               uint32_t val = 0;
                msleep(100);
-               uprintf(UART0, "Timer value: %d\n", timer_get_counter_val(LPC_SCT));
+               timer_get_counter_val(LPC_SCT, &val);
+               uprintf(UART0, "Timer value: %d\n", val);
        }
        return 0;
 }
index 4009300..ea000ef 100644 (file)
@@ -29,8 +29,8 @@
  * Refer to LPC82x documentation (UM10800.pdf) for more information.
  */
 
-#include "lib/stdint.h"
 #include "core/system.h"
+#include "lib/errno.h"
 #include "drivers/timers.h"
 #include "drivers/sctimers.h"
 
@@ -41,7 +41,9 @@ enum sct_config_states {
        SCT_CONFIGURED_AS_32,
        SCT_CONFIGURED_AS_16,
 };
-struct sctimer_device {
+
+struct sctimer_device
+{
        struct lpc_sct_timer* regs;
        uint32_t power_bit;
        uint32_t reset;
@@ -50,6 +52,7 @@ struct sctimer_device {
        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,
@@ -120,12 +123,20 @@ void sctimer_restart(uint8_t timer_num)
        sct->control &= ~(LPC_SCT_STOP | LPC_SCT_HALT);
 }
 
-uint32_t sctimer_get_counter_val(uint8_t timer_num)
+int sctimer_get_counter_val(uint8_t timer_num, uint32_t* val)
 {
        struct lpc_sct_timer* sct = LPC_SCTIMER;
        if (timer_num != LPC_SCT)
-               return 0;
-       return sct->count;
+               return -EINVAL;
+       *val = sct->count;
+       return 0;
+}
+
+/* Change the match value of a single timer channel */
+int sctimer_set_match(uint8_t timer_num, uint8_t channel, uint32_t val)
+{
+       /* FIXME : To be done */
+       return 0;
 }
 
 struct common_operations sct_ops = {
@@ -136,6 +147,8 @@ struct common_operations sct_ops = {
        .restart = sctimer_restart,
        .halt = sctimer_stop,
        .get_counter = sctimer_get_counter_val,
+       .get_capture = NULL,
+       .set_match = sctimer_set_match,
 };
 
 
@@ -160,22 +173,19 @@ struct common_operations sct16_ops = {
        .cont = sctimer16_start,
 };
 
+/* FIXME : Continue implementation of 16 bits timers */
+
 
 /*******************************************************************************/
 /* 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)
+int 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;
+               return -EINVAL;
 
        /* Some configs require the timer to be halted (setting the initial output values */
        sctimer_stop(timer_num);
@@ -217,10 +227,10 @@ void sctimer_pwm_config(uint8_t timer_num, const struct lpc_timer_pwm_config* pw
 
        /* Set all outputs initial states */
        sct->output = LPC_SCT_OUT_SET_ALL(pwm->outputs_initial_state);
+       return 0;
 }
 
 struct config_operations sct_cfg_ops = {
-       .set_match = sctimer_set_match,
        .pwm_config = sctimer_pwm_config,
 };
 
@@ -236,13 +246,13 @@ struct config_operations sct_cfg_ops = {
  *   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))
+int 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;
+               return -EINVAL;
        }
 
        NVIC_DisableIRQ(sctimer.irq);
@@ -279,20 +289,22 @@ void sctimer_on(uint8_t timer_num, uint32_t clkrate, void (*callback)(uint32_t))
        sct->event_int_en = 0;
 
        NVIC_EnableIRQ(sctimer.irq);
+       return 0;
 }
 
 
 /* Removes the main clock from the selected sctimer block */
-void sctimer_off(uint8_t timer_num)
+int sctimer_off(uint8_t timer_num)
 {
        if ((timer_num != LPC_SCT) && (timer_num != LPC_SCT16_T0) && (timer_num != LPC_SCT16_T1))
-               return;
+               return -EINVAL;
 
        NVIC_DisableIRQ(sctimer.irq);
        /* Power down the timer */
        subsystem_power(sctimer.power_bit, 0);
        sctimer.callback = NULL;
        sctimer.configured = SCT_UNCONFIGURED;
+       return 0;
 }
 
 
@@ -302,17 +314,17 @@ struct init_operations sct_init_ops = {
 };
 
 
-void sctimer16_on(uint8_t timer_num, uint32_t clkrate, void (*callback)(uint32_t))
+int 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;
+               return -EINVAL;
        }
        if (sctimer.configured == SCT_CONFIGURED_AS_32) {
-               return;
+               return -EINVAL;
        }
 
        if (sctimer.configured == SCT_UNCONFIGURED) {
@@ -348,6 +360,7 @@ void sctimer16_on(uint8_t timer_num, uint32_t clkrate, void (*callback)(uint32_t
 
                NVIC_EnableIRQ(sctimer.irq);
        }
+       return 0;
 }
 
 struct init_operations sct16_init_ops = {
index 372090e..370dd46 100644 (file)
@@ -37,6 +37,7 @@
  */
 
 #include "lib/stdint.h"
+#include "lib/errno.h"
 #include "drivers/timers.h"
 
 
@@ -93,8 +94,7 @@ struct timer_device timers[NUM_TIMERS] = {
                } \
        }
 
-/* void timer_start(uint32_t timer_num)
- * Start a timer */
+/* Start a timer */
 GENERIC_TIMER_OPS(start);
 /* Pause timer operation */
 GENERIC_TIMER_OPS(pause);
@@ -108,46 +108,61 @@ GENERIC_TIMER_OPS(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
+/* Get the current counter value
+ * Return 0 if the value is valid.
  */
-uint32_t timer_get_counter_val(uint8_t timer_num)
+int timer_get_counter_val(uint8_t timer_num, uint32_t* val)
 {
        if (timer_num >= NUM_TIMERS)
-               return 0;
+               return -EINVAL;
        if (timers[timer_num].ops && timers[timer_num].ops->get_counter) {
-               return timers[timer_num].ops->get_counter(timer_num);
+               return timers[timer_num].ops->get_counter(timer_num, val);
        }
-       return 0;
+       return -ENODEV;
 }
 
-
-/*******************************************************************************/
-/* Configuration */
+/* 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 -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;
+}
 
 /* Change the match value of a single timer channel */
-void timer_set_match(uint8_t timer_num, uint8_t channel, uint32_t val)
+int 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);
+               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;
 }
 
+/*******************************************************************************/
+/* Configuration */
+
 /* Configure the timer as PWM. Call to timer-specific function */
-void timer_pwm_config(uint8_t timer_num, const struct lpc_timer_pwm_config* conf)
+int timer_pwm_config(uint8_t timer_num, const struct lpc_timer_pwm_config* conf)
 {
        if (timer_num >= NUM_TIMERS)
-               return;
+               return -EINVAL;
        if (timers[timer_num].cfg_ops && timers[timer_num].cfg_ops->pwm_config) {
-               timers[timer_num].cfg_ops->pwm_config(timer_num, conf);
+               return timers[timer_num].cfg_ops->pwm_config(timer_num, conf);
        }
+       return -ENODEV;
 }
 
 
 
+/*******************************************************************************/
+/* Init operations */
 
 /* Power up a timer.
  * clkrate is the desired timer clock rate. It will be used to divide the main clock
@@ -155,22 +170,24 @@ void timer_pwm_config(uint8_t timer_num, const struct lpc_timer_pwm_config* conf
  *   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))
+int timer_on(uint8_t timer_num, uint32_t clkrate, void (*callback)(uint32_t))
 {
        if (timer_num >= NUM_TIMERS)
-               return;
+               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);
+               return timers[timer_num].init_ops->timer_on(timer_num, clkrate, callback);
        }
+       return -ENODEV;
 }
 
 /* Removes the main clock from the selected timer block */
-void timer_off(uint8_t timer_num)
+int timer_off(uint8_t timer_num)
 {
        if (timer_num >= NUM_TIMERS)
-               return;
+               return -EINVAL;
        if (timers[timer_num].init_ops && timers[timer_num].init_ops->timer_off) {
-               timers[timer_num].init_ops->timer_off(timer_num);
+               return timers[timer_num].init_ops->timer_off(timer_num);
        }
+       return -ENODEV;
 }
 
index 23b1c7c..214f4c2 100644 (file)
 
 #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 */
@@ -48,15 +50,15 @@ enum lpc_timers {
        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 */
-};
+/* Available timer modes *
+ * Some mode may be combined, and some are exlusive
+ */
+#define LPC_TIMER_MODE_TIMER     (0x00 << 0)
+#define LPC_TIMER_MODE_COUNTER   (0x01 << 0)
+#define LPC_TIMER_MODE_PWM       (0x02 << 0)  /* Pulse Width Modulation */
+#define LPC_TIMER_MODE_PWD       (0x03 << 0)  /* Pulse Width Demodulation */
+#define LPC_TIMER_MODE_CAPTURE   (0x01 << 6)
+#define LPC_TIMER_MODE_MATCH     (0x01 << 7)
 
 
 /*******************************************************************************/
@@ -65,24 +67,27 @@ enum lpc_timer_mode {
 /* PWM
  * This structure is used for the timer_pwm_config() function.
  * nb_channels is the number of PWM channels used
- * 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. Some will allow a different
- *   state for each output (then use one bit for each output, bit 0 for output 0, ...) while
- *   some will require the same initial state for all output (then outputs_initial_state
- *   can be either 0 for "low" or any positive value for "high")
- * outputs[] is the list of outputs / channels corresponding to each 'match_values'
+ * period_chan is the channel number used to generate the period. On LPC82x it is always
+ *   channel 0.
  * 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. Some will allow a different
+ *   state for each output (then use one bit for each output, bit 0 for output 0, ...) while
+ *   some will require the same initial state for all output (then outputs_initial_state
+ *   can be either 0 for "low" or any positive value for "high")
  */
 struct lpc_timer_pwm_config {
        uint8_t nb_channels;
-       uint8_t outputs_initial_state;
-       uint8_t outputs[MAX_CHANNELS];
+       uint8_t period_chan;
        uint32_t period;
+       uint8_t outputs[MAX_CHANNELS];
        uint32_t match_values[MAX_CHANNELS];
+       uint32_t outputs_initial_state;
 };
 
 
@@ -98,15 +103,16 @@ struct common_operations {
        void (*restart)(uint8_t);
        void (*halt)(uint8_t);
        /* Counter */
-       uint32_t (*get_counter)(uint8_t);
+       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 {
-       void (*set_match)(uint8_t, uint8_t, uint32_t);
-       void (*pwm_config)(uint8_t, const struct lpc_timer_pwm_config*);
+       int (*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);
+       int (*timer_on)(uint8_t, uint32_t, void (*)(uint32_t));
+       int (*timer_off)(uint8_t);
 };
 
 /*******************************************************************************/
@@ -130,18 +136,23 @@ void timer_halt(uint8_t timer_num);
 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
+/* Get the current counter value
+ * Return 0 if the value is valid.
  */
-uint32_t timer_get_counter_val(uint8_t timer_num);
+int timer_get_counter_val(uint8_t timer_num, uint32_t* val);
 
 
-/*******************************************************************************/
-/* Configuration */
+/* 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(uint8_t timer_num, uint8_t channel, uint32_t val);
+int timer_set_match(uint8_t timer_num, uint8_t channel, uint32_t val);
+
+
+/*******************************************************************************/
+/* Configuration */
 
 /* PWM configuration in order to use the timer as a PWM controller.
  * For the pwm_conf structure, refer to it's definition above..
@@ -152,7 +163,7 @@ void timer_set_match(uint8_t timer_num, uint8_t channel, uint32_t val);
  * The timer will not be started. User code must call timer_start() in order
  *   to start the PWM.
  */
-void timer_pwm_config(uint8_t timer_num, const struct lpc_timer_pwm_config* pwm_conf);
+int timer_pwm_config(uint8_t timer_num, const struct lpc_timer_pwm_config* pwm_conf);
 
 
 
@@ -167,10 +178,10 @@ void timer_pwm_config(uint8_t timer_num, const struct lpc_timer_pwm_config* pwm_
  *   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));
+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(uint8_t timer_num);
+int timer_off(uint8_t timer_num);
 
 #endif /* DRIVERS_TIMERS_H */