* 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"
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;
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,
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 = {
.restart = sctimer_restart,
.halt = sctimer_stop,
.get_counter = sctimer_get_counter_val,
+ .get_capture = NULL,
+ .set_match = sctimer_set_match,
};
.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);
/* 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,
};
* 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);
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;
}
};
-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) {
NVIC_EnableIRQ(sctimer.irq);
}
+ return 0;
}
struct init_operations sct16_init_ops = {
*/
#include "lib/stdint.h"
+#include "lib/errno.h"
#include "drivers/timers.h"
} \
}
-/* void timer_start(uint32_t timer_num)
- * Start a timer */
+/* Start a timer */
GENERIC_TIMER_OPS(start);
/* Pause timer operation */
GENERIC_TIMER_OPS(pause);
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
* 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;
}
#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_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)
/*******************************************************************************/
/* 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;
};
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);
};
/*******************************************************************************/
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..
* 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);
* 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 */