From: Nathael Pajani Date: Tue, 27 Sep 2016 22:11:56 +0000 (+0200) Subject: Changes to timers API X-Git-Url: http://git.techno-innov.fr/?a=commitdiff_plain;h=a19195908cc15d6256735052211425bf0bd4cbe0;p=soft%2Flpc82x%2Fcore Changes to timers API --- diff --git a/drivers/sctimers.c b/drivers/sctimers.c index 4009300..ea000ef 100644 --- a/drivers/sctimers.c +++ b/drivers/sctimers.c @@ -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 = { diff --git a/drivers/timers.c b/drivers/timers.c index 372090e..370dd46 100644 --- a/drivers/timers.c +++ b/drivers/timers.c @@ -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; } diff --git a/include/drivers/timers.h b/include/drivers/timers.h index 23b1c7c..214f4c2 100644 --- a/include/drivers/timers.h +++ b/include/drivers/timers.h @@ -39,8 +39,10 @@ #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 */