1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #17723 from benpicco/periph_timer_periodic-set_stopped

drivers/periph/timer: add TIM_FLAG_SET_STOPPED flag
This commit is contained in:
Marian Buschsieweke 2022-05-03 12:06:37 +02:00 committed by GitHub
commit bae91c1660
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 80 additions and 17 deletions

View File

@ -224,7 +224,12 @@ int timer_set_periodic(tim_t tim, int channel, unsigned int value, uint8_t flags
/* disable CTC mode */ /* disable CTC mode */
ctx[tim].mode &= (1 << 3); ctx[tim].mode &= (1 << 3);
} }
/* enable timer or stop it */
if (flags & TIM_FLAG_SET_STOPPED) {
ctx[tim].dev->CRB = 0;
} else {
ctx[tim].dev->CRB = ctx[tim].mode; ctx[tim].dev->CRB = ctx[tim].mode;
}
} else { } else {
assert((flags & TIM_FLAG_RESET_ON_MATCH) == 0); assert((flags & TIM_FLAG_RESET_ON_MATCH) == 0);
res = -1; res = -1;

View File

@ -164,6 +164,10 @@ int timer_set_periodic(tim_t tim, int channel, unsigned int value,
return -1; return -1;
} }
if (flags & TIM_FLAG_SET_STOPPED) {
timer_stop(tim);
}
clear_oneshot(tim, channel); clear_oneshot(tim, channel);
if (flags & TIM_FLAG_RESET_ON_SET) { if (flags & TIM_FLAG_RESET_ON_SET) {

View File

@ -208,6 +208,7 @@ int timer_set_periodic(tim_t tim, int channel, unsigned int value, uint8_t flags
return -1; return -1;
} }
bool stop = flags & TIM_FLAG_SET_STOPPED;
lpc23xx_timer_t *dev = get_dev(tim); lpc23xx_timer_t *dev = get_dev(tim);
if (flags & TIM_FLAG_RESET_ON_SET) { if (flags & TIM_FLAG_RESET_ON_SET) {
@ -218,8 +219,13 @@ int timer_set_periodic(tim_t tim, int channel, unsigned int value, uint8_t flags
* (reason: TCR is volatile control register. * (reason: TCR is volatile control register.
Bit 2 will put the timer into Reset Bit 2 will put the timer into Reset
Bit 1 will control if the timer is running) */ Bit 1 will control if the timer is running) */
if (!stop) {
dev->TCR = 1; dev->TCR = 1;
} }
} else if (stop) {
/* stop the timer */
dev->TCR = 0;
}
clear_oneshot(tim, channel); clear_oneshot(tim, channel);

View File

@ -105,7 +105,7 @@ int timer_init(tim_t dev, uint32_t freq, timer_cb_t cb, void *arg)
return 0; return 0;
} }
static void do_timer_set(tim_t dev, unsigned int offset, bool periodic) static void do_timer_set(unsigned int offset, bool periodic)
{ {
DEBUG("%s\n", __func__); DEBUG("%s\n", __func__);
@ -121,8 +121,6 @@ static void do_timer_set(tim_t dev, unsigned int offset, bool periodic)
} }
DEBUG("timer_set(): setting %lu.%06lu\n", itv.it_value.tv_sec, itv.it_value.tv_usec); DEBUG("timer_set(): setting %lu.%06lu\n", itv.it_value.tv_sec, itv.it_value.tv_usec);
timer_start(dev);
} }
int timer_set(tim_t dev, int channel, unsigned int offset) int timer_set(tim_t dev, int channel, unsigned int offset)
@ -137,7 +135,8 @@ int timer_set(tim_t dev, int channel, unsigned int offset)
offset = NATIVE_TIMER_MIN_RES; offset = NATIVE_TIMER_MIN_RES;
} }
do_timer_set(dev, offset, false); do_timer_set(offset, false);
timer_start(dev);
return 0; return 0;
} }
@ -156,7 +155,11 @@ int timer_set_periodic(tim_t dev, int channel, unsigned int value, uint8_t flags
return -1; return -1;
} }
do_timer_set(dev, value, true); do_timer_set(value, true);
if (!(flags & TIM_FLAG_SET_STOPPED)) {
timer_start(dev);
}
return 0; return 0;
} }
@ -165,7 +168,8 @@ int timer_clear(tim_t dev, int channel)
{ {
(void)channel; (void)channel;
do_timer_set(dev, 0, false); do_timer_set(0, false);
timer_start(dev);
return 0; return 0;
} }

View File

@ -114,6 +114,9 @@ int timer_set_periodic(tim_t tim, int chan, unsigned int value, uint8_t flags)
return -1; return -1;
} }
/* stop timer to avoid race condition */
dev(tim)->TASKS_STOP = 1;
ctx[tim].flags |= (1 << chan); ctx[tim].flags |= (1 << chan);
ctx[tim].is_periodic |= (1 << chan); ctx[tim].is_periodic |= (1 << chan);
dev(tim)->CC[chan] = value; dev(tim)->CC[chan] = value;
@ -125,7 +128,10 @@ int timer_set_periodic(tim_t tim, int chan, unsigned int value, uint8_t flags)
} }
dev(tim)->INTENSET = (TIMER_INTENSET_COMPARE0_Msk << chan); dev(tim)->INTENSET = (TIMER_INTENSET_COMPARE0_Msk << chan);
/* re-start timer */
if (!(flags & TIM_FLAG_SET_STOPPED)) {
dev(tim)->TASKS_START = 1; dev(tim)->TASKS_START = 1;
}
return 0; return 0;
} }

View File

@ -183,6 +183,9 @@ int timer_set_periodic(tim_t dev, int channel, unsigned int value, uint8_t flags
if (channel < 0 || channel >= timer_config[dev].ch_numof) { if (channel < 0 || channel >= timer_config[dev].ch_numof) {
return -EINVAL; return -EINVAL;
} }
if (flags & TIM_FLAG_SET_STOPPED) {
timer_stop(dev);
}
if (flags & TIM_FLAG_RESET_ON_SET) { if (flags & TIM_FLAG_RESET_ON_SET) {
_timer_reset(dev); _timer_reset(dev);
} }

View File

@ -110,27 +110,21 @@ static uint8_t _get_prescaler(uint32_t freq_out, uint32_t freq_in)
/* TOP value is CC0 */ /* TOP value is CC0 */
static inline void _set_mfrq(tim_t tim) static inline void _set_mfrq(tim_t tim)
{ {
timer_stop(tim);
wait_synchronization(tim);
#ifdef TC_WAVE_WAVEGEN_MFRQ #ifdef TC_WAVE_WAVEGEN_MFRQ
dev(tim)->WAVE.reg = TC_WAVE_WAVEGEN_MFRQ; dev(tim)->WAVE.reg = TC_WAVE_WAVEGEN_MFRQ;
#else #else
dev(tim)->CTRLA.bit.WAVEGEN = TC_CTRLA_WAVEGEN_MFRQ_Val; dev(tim)->CTRLA.bit.WAVEGEN = TC_CTRLA_WAVEGEN_MFRQ_Val;
#endif #endif
timer_start(tim);
} }
/* TOP value is MAX timer value */ /* TOP value is MAX timer value */
static inline void _set_nfrq(tim_t tim) static inline void _set_nfrq(tim_t tim)
{ {
timer_stop(tim);
wait_synchronization(tim);
#ifdef TC_WAVE_WAVEGEN_NFRQ #ifdef TC_WAVE_WAVEGEN_NFRQ
dev(tim)->WAVE.reg = TC_WAVE_WAVEGEN_NFRQ; dev(tim)->WAVE.reg = TC_WAVE_WAVEGEN_NFRQ;
#else #else
dev(tim)->CTRLA.bit.WAVEGEN = TC_CTRLA_WAVEGEN_NFRQ_Val; dev(tim)->CTRLA.bit.WAVEGEN = TC_CTRLA_WAVEGEN_NFRQ_Val;
#endif #endif
timer_start(tim);
} }
/** /**
@ -242,9 +236,12 @@ 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); DEBUG("Setting timer %i channel %i to %i (repeating)\n", tim, channel, value);
timer_stop(tim);
/* set timeout value */ /* set timeout value */
switch (channel) { switch (channel) {
case 0: case 0:
/* clear interrupt */
dev(tim)->INTFLAG.reg = TC_INTFLAG_MC0; dev(tim)->INTFLAG.reg = TC_INTFLAG_MC0;
if (flags & TIM_FLAG_RESET_ON_MATCH) { if (flags & TIM_FLAG_RESET_ON_MATCH) {
@ -276,6 +273,10 @@ int timer_set_periodic(tim_t tim, int channel, unsigned int value, uint8_t flags
dev(tim)->COUNT.reg = 0; dev(tim)->COUNT.reg = 0;
} }
if (!(flags & TIM_FLAG_SET_STOPPED)) {
timer_start(tim);
}
clear_oneshot(tim, channel); clear_oneshot(tim, channel);
return 0; return 0;
@ -328,10 +329,12 @@ unsigned int timer_read(tim_t tim)
void timer_stop(tim_t tim) void timer_stop(tim_t tim)
{ {
dev(tim)->CTRLA.bit.ENABLE = 0; dev(tim)->CTRLA.bit.ENABLE = 0;
wait_synchronization(tim);
} }
void timer_start(tim_t tim) void timer_start(tim_t tim)
{ {
wait_synchronization(tim);
dev(tim)->CTRLA.bit.ENABLE = 1; dev(tim)->CTRLA.bit.ENABLE = 1;
} }

View File

@ -149,6 +149,10 @@ int timer_set_periodic(tim_t tim, int channel, unsigned int value, uint8_t flags
clear_oneshot(tim, channel); clear_oneshot(tim, channel);
if (flags & TIM_FLAG_SET_STOPPED) {
timer_stop(tim);
}
if (flags & TIM_FLAG_RESET_ON_SET) { if (flags & TIM_FLAG_RESET_ON_SET) {
/* setting COUNT gives us an interrupt on all channels */ /* setting COUNT gives us an interrupt on all channels */
unsigned state = irq_disable(); unsigned state = irq_disable();

View File

@ -177,8 +177,8 @@ static void _dose_watchdog_cb(void *arg, int chan)
static void _watchdog_init(unsigned timeout_us) static void _watchdog_init(unsigned timeout_us)
{ {
timer_init(DOSE_TIMER_DEV, US_PER_SEC, _dose_watchdog_cb, NULL); timer_init(DOSE_TIMER_DEV, US_PER_SEC, _dose_watchdog_cb, NULL);
timer_set_periodic(DOSE_TIMER_DEV, 0, timeout_us, TIM_FLAG_RESET_ON_MATCH); timer_set_periodic(DOSE_TIMER_DEV, 0, timeout_us,
timer_stop(DOSE_TIMER_DEV); TIM_FLAG_RESET_ON_MATCH | TIM_FLAG_SET_STOPPED);
} }
#else #else
static inline void _watchdog_start(void) {} static inline void _watchdog_start(void) {}

View File

@ -89,6 +89,16 @@ typedef uint_fast8_t tim_t;
#define TIM_FLAG_RESET_ON_MATCH (0x02) #define TIM_FLAG_RESET_ON_MATCH (0x02)
#endif #endif
/**
* @brief Keep the timer stopped after setting alarm.
*
* When set, the timer will remained stopped after a timer_set_periodic() and
* can be started manually with timer_start().
*/
#ifndef TIM_FLAG_SET_STOPPED
#define TIM_FLAG_SET_STOPPED (0x04)
#endif
/** /**
* @brief Signature of event callback functions triggered from interrupts * @brief Signature of event callback functions triggered from interrupts
* *

View File

@ -93,6 +93,18 @@ static const char* _print_ok(int chan, bool *succeeded)
return "ERROR"; return "ERROR";
} }
static void _cb_set_stopped(void *arg, int chan)
{
(void)chan;
bool *succeeded = arg;
*succeeded = false;
puts("TIM_FLAG_SET_STOPPED failed");
timer_stop(TIMER_CYCL);
}
int main(void) int main(void)
{ {
mutex_t lock = MUTEX_INIT; mutex_t lock = MUTEX_INIT;
@ -144,6 +156,12 @@ int main(void)
} }
} }
expect(timer_init(TIMER_CYCL, timer_hz, _cb_set_stopped, &succeeded) == 0);
timer_set_periodic(TIMER_CYCL, 0, 25, TIM_FLAG_RESET_ON_SET | TIM_FLAG_SET_STOPPED);
/* busy wait */
for (volatile uint32_t i = 0; i < CLOCK_CORECLOCK / 10; ++i) {}
if (succeeded) { if (succeeded) {
puts("TEST SUCCEEDED"); puts("TEST SUCCEEDED");
} else { } else {