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 */
ctx[tim].mode &= (1 << 3);
}
ctx[tim].dev->CRB = ctx[tim].mode;
/* enable timer or stop it */
if (flags & TIM_FLAG_SET_STOPPED) {
ctx[tim].dev->CRB = 0;
} else {
ctx[tim].dev->CRB = ctx[tim].mode;
}
} else {
assert((flags & TIM_FLAG_RESET_ON_MATCH) == 0);
res = -1;

View File

@ -164,6 +164,10 @@ int timer_set_periodic(tim_t tim, int channel, unsigned int value,
return -1;
}
if (flags & TIM_FLAG_SET_STOPPED) {
timer_stop(tim);
}
clear_oneshot(tim, channel);
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;
}
bool stop = flags & TIM_FLAG_SET_STOPPED;
lpc23xx_timer_t *dev = get_dev(tim);
if (flags & TIM_FLAG_RESET_ON_SET) {
@ -218,7 +219,12 @@ int timer_set_periodic(tim_t tim, int channel, unsigned int value, uint8_t flags
* (reason: TCR is volatile control register.
Bit 2 will put the timer into Reset
Bit 1 will control if the timer is running) */
dev->TCR = 1;
if (!stop) {
dev->TCR = 1;
}
} else if (stop) {
/* stop the timer */
dev->TCR = 0;
}
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;
}
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__);
@ -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);
timer_start(dev);
}
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;
}
do_timer_set(dev, offset, false);
do_timer_set(offset, false);
timer_start(dev);
return 0;
}
@ -156,7 +155,11 @@ int timer_set_periodic(tim_t dev, int channel, unsigned int value, uint8_t flags
return -1;
}
do_timer_set(dev, value, true);
do_timer_set(value, true);
if (!(flags & TIM_FLAG_SET_STOPPED)) {
timer_start(dev);
}
return 0;
}
@ -165,7 +168,8 @@ int timer_clear(tim_t dev, int channel)
{
(void)channel;
do_timer_set(dev, 0, false);
do_timer_set(0, false);
timer_start(dev);
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;
}
/* stop timer to avoid race condition */
dev(tim)->TASKS_STOP = 1;
ctx[tim].flags |= (1 << chan);
ctx[tim].is_periodic |= (1 << chan);
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)->TASKS_START = 1;
/* re-start timer */
if (!(flags & TIM_FLAG_SET_STOPPED)) {
dev(tim)->TASKS_START = 1;
}
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) {
return -EINVAL;
}
if (flags & TIM_FLAG_SET_STOPPED) {
timer_stop(dev);
}
if (flags & TIM_FLAG_RESET_ON_SET) {
_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 */
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);
}
/**
@ -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);
timer_stop(tim);
/* set timeout value */
switch (channel) {
case 0:
/* clear interrupt */
dev(tim)->INTFLAG.reg = TC_INTFLAG_MC0;
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;
}
if (!(flags & TIM_FLAG_SET_STOPPED)) {
timer_start(tim);
}
clear_oneshot(tim, channel);
return 0;
@ -328,10 +329,12 @@ unsigned int timer_read(tim_t tim)
void timer_stop(tim_t tim)
{
dev(tim)->CTRLA.bit.ENABLE = 0;
wait_synchronization(tim);
}
void timer_start(tim_t tim)
{
wait_synchronization(tim);
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);
if (flags & TIM_FLAG_SET_STOPPED) {
timer_stop(tim);
}
if (flags & TIM_FLAG_RESET_ON_SET) {
/* setting COUNT gives us an interrupt on all channels */
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)
{
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_stop(DOSE_TIMER_DEV);
timer_set_periodic(DOSE_TIMER_DEV, 0, timeout_us,
TIM_FLAG_RESET_ON_MATCH | TIM_FLAG_SET_STOPPED);
}
#else
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)
#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
*

View File

@ -93,6 +93,18 @@ static const char* _print_ok(int chan, bool *succeeded)
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)
{
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) {
puts("TEST SUCCEEDED");
} else {