cpu/sam0_common: implement timer_set_periodic()
This commit is contained in:
parent
41a961be22
commit
8486e8c6d1
@ -5,6 +5,9 @@ endif
|
||||
# All SAM0 based CPUs provide PM
|
||||
USEMODULE += pm_layered
|
||||
|
||||
# the timer implements timer_set_periodic()
|
||||
FEATURES_PROVIDED += periph_timer_periodic
|
||||
|
||||
# include sam0 common periph drivers
|
||||
USEMODULE += sam0_common_periph
|
||||
|
||||
|
||||
@ -37,6 +37,23 @@
|
||||
*/
|
||||
static timer_isr_ctx_t config[TIMER_NUMOF];
|
||||
|
||||
static uint32_t _oneshot;
|
||||
|
||||
static inline void set_oneshot(tim_t tim, int chan)
|
||||
{
|
||||
_oneshot |= (1 << chan) << (TIMER_CHANNELS * tim);
|
||||
}
|
||||
|
||||
static inline void clear_oneshot(tim_t tim, int chan)
|
||||
{
|
||||
_oneshot &= ~((1 << chan) << (TIMER_CHANNELS * tim));
|
||||
}
|
||||
|
||||
static inline bool is_oneshot(tim_t tim, int chan)
|
||||
{
|
||||
return _oneshot & ((1 << chan) << (TIMER_CHANNELS * tim));
|
||||
}
|
||||
|
||||
static inline TcCount32 *dev(tim_t tim)
|
||||
{
|
||||
return &timer_config[tim].dev->COUNT32;
|
||||
@ -89,6 +106,32 @@ static uint8_t _get_prescaler(unsigned long freq_out, unsigned long freq_in)
|
||||
return scale;
|
||||
}
|
||||
|
||||
/* TOP value is CC0 */
|
||||
static inline void _set_mfrq(tim_t tim)
|
||||
{
|
||||
timer_stop(tim);
|
||||
wait_synchronization(tim);
|
||||
#ifdef TC_WAVE_WAVEGEN_MFRQ
|
||||
dev(tim)->WAVE.reg = TC_WAVE_WAVEGEN_MFRQ;
|
||||
#else
|
||||
dev(tim)->CTRLA.bit.WAVEGEN = TC_CTRLA_WAVEGEN_MFRQ_Val;
|
||||
#endif
|
||||
timer_start(tim);
|
||||
}
|
||||
|
||||
/* TOP value is MAX timer value */
|
||||
static inline void _set_nfrq(tim_t tim)
|
||||
{
|
||||
timer_stop(tim);
|
||||
wait_synchronization(tim);
|
||||
#ifdef TC_WAVE_WAVEGEN_NFRQ
|
||||
dev(tim)->WAVE.reg = TC_WAVE_WAVEGEN_NFRQ;
|
||||
#else
|
||||
dev(tim)->CTRLA.bit.WAVEGEN = TC_CTRLA_WAVEGEN_NFRQ_Val;
|
||||
#endif
|
||||
timer_start(tim);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Setup the given timer
|
||||
*/
|
||||
@ -187,7 +230,52 @@ int timer_set_absolute(tim_t tim, int channel, unsigned int value)
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
set_oneshot(tim, channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timer_set_periodic(tim_t tim, int channel, unsigned int value, uint8_t flags)
|
||||
{
|
||||
DEBUG("Setting timer %i channel %i to %i (repeating)\n", tim, channel, value);
|
||||
|
||||
/* set timeout value */
|
||||
switch (channel) {
|
||||
case 0:
|
||||
dev(tim)->INTFLAG.reg = TC_INTFLAG_MC0;
|
||||
|
||||
if (flags & TIM_FLAG_RESET_ON_MATCH) {
|
||||
_set_mfrq(tim);
|
||||
} else {
|
||||
_set_nfrq(tim);
|
||||
}
|
||||
|
||||
_set_cc(tim, 0, value);
|
||||
dev(tim)->INTENSET.reg = TC_INTENSET_MC0;
|
||||
break;
|
||||
case 1:
|
||||
|
||||
/* only CC0 can be used to set TOP */
|
||||
if (flags & TIM_FLAG_RESET_ON_MATCH) {
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev(tim)->INTFLAG.reg = TC_INTFLAG_MC1;
|
||||
_set_cc(tim, 1, value);
|
||||
dev(tim)->INTENSET.reg = TC_INTENSET_MC1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (flags & TIM_FLAG_RESET_ON_SET) {
|
||||
dev(tim)->COUNT.reg = 0;
|
||||
}
|
||||
|
||||
clear_oneshot(tim, channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -255,13 +343,22 @@ static inline void timer_isr(tim_t tim)
|
||||
tc->INTFLAG.reg = status;
|
||||
|
||||
if ((status & TC_INTFLAG_MC0) && tc->INTENSET.bit.MC0) {
|
||||
tc->INTENCLR.reg = TC_INTENCLR_MC0;
|
||||
|
||||
if (is_oneshot(tim, 0)) {
|
||||
tc->INTENCLR.reg = TC_INTENCLR_MC0;
|
||||
}
|
||||
|
||||
if (config[tim].cb) {
|
||||
config[tim].cb(config[tim].arg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if ((status & TC_INTFLAG_MC1) && tc->INTENSET.bit.MC1) {
|
||||
tc->INTENCLR.reg = TC_INTENCLR_MC1;
|
||||
|
||||
if (is_oneshot(tim, 1)) {
|
||||
tc->INTENCLR.reg = TC_INTENCLR_MC1;
|
||||
}
|
||||
|
||||
if (config[tim].cb) {
|
||||
config[tim].cb(config[tim].arg, 1);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user