Merge pull request #13902 from benpicco/periph_timer_periodic
periph/timer: add timer_set_periodic()
This commit is contained in:
commit
49aef1b678
@ -1050,6 +1050,10 @@ ifneq (,$(filter periph_gpio_irq,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_gpio
|
||||
endif
|
||||
|
||||
ifneq (,$(filter periph_timer_periodic,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_timer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter devfs_hwrng,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_hwrng
|
||||
endif
|
||||
|
||||
@ -5,6 +5,7 @@ FEATURES_PROVIDED += periph_cpuid
|
||||
FEATURES_PROVIDED += periph_eeprom
|
||||
FEATURES_PROVIDED += periph_gpio periph_gpio_irq
|
||||
FEATURES_PROVIDED += periph_pm
|
||||
FEATURES_PROVIDED += periph_timer_periodic
|
||||
FEATURES_PROVIDED += periph_wdt
|
||||
FEATURES_PROVIDED += puf_sram
|
||||
|
||||
|
||||
@ -74,6 +74,23 @@ static ctx_t ctx[] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
static unsigned _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));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Setup the given timer
|
||||
*/
|
||||
@ -109,7 +126,7 @@ int timer_init(tim_t tim, unsigned long freq, timer_cb_t cb, void *arg)
|
||||
}
|
||||
}
|
||||
if (pre == PRESCALE_NUMOF) {
|
||||
DEBUG("timer.c: prescaling failed!\n");
|
||||
DEBUG("timer.c: prescaling from %lu Hz failed!\n", CLOCK_CORECLOCK);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -138,9 +155,12 @@ int timer_set_absolute(tim_t tim, int channel, unsigned int value)
|
||||
}
|
||||
|
||||
unsigned state = irq_disable();
|
||||
|
||||
ctx[tim].dev->OCR[channel] = (uint16_t)value;
|
||||
*ctx[tim].flag &= ~(1 << (channel + OCF1A));
|
||||
*ctx[tim].mask |= (1 << (channel + OCIE1A));
|
||||
set_oneshot(tim, channel);
|
||||
|
||||
irq_restore(state);
|
||||
|
||||
return 0;
|
||||
@ -154,9 +174,11 @@ int timer_set(tim_t tim, int channel, unsigned int timeout)
|
||||
|
||||
unsigned state = irq_disable();
|
||||
unsigned absolute = ctx[tim].dev->CNT + timeout;
|
||||
|
||||
ctx[tim].dev->OCR[channel] = absolute;
|
||||
uint8_t mask = 1 << (channel + OCIE1A);
|
||||
*ctx[tim].mask |= mask;
|
||||
*ctx[tim].mask |= (1 << (channel + OCIE1A));
|
||||
set_oneshot(tim, channel);
|
||||
|
||||
if ((absolute - ctx[tim].dev->CNT) > timeout) {
|
||||
/* Timer already expired. Trigger the interrupt now and loop until it
|
||||
* is triggered.
|
||||
@ -164,13 +186,53 @@ int timer_set(tim_t tim, int channel, unsigned int timeout)
|
||||
while (!(*ctx[tim].flag & (1 << (OCF1A + channel)))) {
|
||||
ctx[tim].dev->OCR[channel] = ctx[tim].dev->CNT;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
irq_restore(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timer_set_periodic(tim_t tim, int channel, unsigned int value, uint8_t flags)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if (channel >= TIMER_CHANNELS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (flags & TIM_FLAG_RESET_ON_SET) {
|
||||
ctx[tim].dev->CNT = 0;
|
||||
}
|
||||
|
||||
unsigned state = irq_disable();
|
||||
|
||||
ctx[tim].dev->OCR[channel] = (uint16_t)value;
|
||||
|
||||
*ctx[tim].flag &= ~(1 << (channel + OCF1A));
|
||||
*ctx[tim].mask |= (1 << (channel + OCIE1A));
|
||||
|
||||
clear_oneshot(tim, channel);
|
||||
|
||||
/* only OCR0 can be use to set TOP */
|
||||
if (channel == 0) {
|
||||
if (flags & TIM_FLAG_RESET_ON_MATCH) {
|
||||
/* enable CTC mode */
|
||||
ctx[tim].dev->CRB |= (1 << 3);
|
||||
} else {
|
||||
/* disable CTC mode */
|
||||
ctx[tim].dev->CRB &= (1 << 3);
|
||||
}
|
||||
} else {
|
||||
assert((flags & TIM_FLAG_RESET_ON_MATCH) == 0);
|
||||
res = -1;
|
||||
}
|
||||
|
||||
irq_restore(state);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int timer_clear(tim_t tim, int channel)
|
||||
{
|
||||
if (channel >= TIMER_CHANNELS) {
|
||||
@ -216,7 +278,9 @@ static inline void _isr(tim_t tim, int chan)
|
||||
|
||||
atmega_enter_isr();
|
||||
|
||||
if (is_oneshot(tim, chan)) {
|
||||
*ctx[tim].mask &= ~(1 << (chan + OCIE1A));
|
||||
}
|
||||
ctx[tim].cb(ctx[tim].arg, chan);
|
||||
|
||||
#if defined(DEBUG_TIMER_PORT)
|
||||
|
||||
@ -2,5 +2,6 @@
|
||||
FEATURES_PROVIDED += backup_ram
|
||||
FEATURES_PROVIDED += periph_dac
|
||||
FEATURES_PROVIDED += periph_gpio periph_gpio_irq
|
||||
FEATURES_PROVIDED += periph_timer_periodic
|
||||
|
||||
-include $(RIOTCPU)/arm7_common/Makefile.features
|
||||
|
||||
@ -126,7 +126,7 @@ typedef struct {
|
||||
/**
|
||||
* @brief Number of available timer channels
|
||||
*/
|
||||
#define TIMER_CHAN_NUMOF (4U)
|
||||
#define TIMER_CHANNELS (4U)
|
||||
|
||||
/**
|
||||
* @brief Declare needed generic SPI functions
|
||||
|
||||
@ -38,6 +38,23 @@
|
||||
*/
|
||||
static timer_isr_ctx_t isr_ctx[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));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Forward declarations for interrupt functions
|
||||
* @{
|
||||
@ -139,19 +156,53 @@ int timer_init(tim_t tim, unsigned long freq, timer_cb_t cb, void *arg)
|
||||
|
||||
int timer_set_absolute(tim_t tim, int channel, unsigned int value)
|
||||
{
|
||||
if (((unsigned) tim >= TIMER_NUMOF) || ((unsigned) channel >= TIMER_CHAN_NUMOF)) {
|
||||
if (((unsigned) tim >= TIMER_NUMOF) || ((unsigned) channel >= TIMER_CHANNELS)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
lpc23xx_timer_t *dev = get_dev(tim);
|
||||
|
||||
set_oneshot(tim, channel);
|
||||
|
||||
dev->MR[channel] = value;
|
||||
/* Match Interrupt */
|
||||
dev->MCR |= (1 << (channel * 3));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timer_set_periodic(tim_t tim, int channel, unsigned int value, uint8_t flags)
|
||||
{
|
||||
if (((unsigned) tim >= TIMER_NUMOF) || ((unsigned) channel >= TIMER_CHANNELS)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
lpc23xx_timer_t *dev = get_dev(tim);
|
||||
|
||||
if (flags & TIM_FLAG_RESET_ON_SET) {
|
||||
/* reset the timer */
|
||||
dev->TCR = 2;
|
||||
/* start the timer */
|
||||
/* cppcheck-suppress redundantAssignment
|
||||
* (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;
|
||||
}
|
||||
|
||||
clear_oneshot(tim, channel);
|
||||
|
||||
uint8_t cfg = (flags & TIM_FLAG_RESET_ON_MATCH)
|
||||
? 0x3 /* Match Interrupt & Reset on Match */
|
||||
: 0x1; /* Match Interrupt */
|
||||
|
||||
dev->MR[channel] = value;
|
||||
dev->MCR |= (cfg << (channel * 3));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timer_clear(tim_t tim, int channel)
|
||||
{
|
||||
if (((unsigned) tim >= TIMER_NUMOF) || ((unsigned) channel >= TIMER_CHAN_NUMOF)) {
|
||||
if (((unsigned) tim >= TIMER_NUMOF) || ((unsigned) channel >= TIMER_CHANNELS)) {
|
||||
return -1;
|
||||
}
|
||||
get_dev(tim)->MCR &= ~(1 << (channel * 3));
|
||||
@ -173,15 +224,28 @@ void timer_stop(tim_t tim)
|
||||
get_dev(tim)->TCR = 0;
|
||||
}
|
||||
|
||||
static inline void chan_handler(lpc23xx_timer_t *dev, unsigned tim_num, unsigned chan_num)
|
||||
{
|
||||
const uint32_t mask = (1 << chan_num);
|
||||
|
||||
if ((dev->IR & mask) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
dev->IR |= mask;
|
||||
if (is_oneshot(tim_num, chan_num)) {
|
||||
dev->MCR &= ~(1 << (chan_num * 3));
|
||||
}
|
||||
|
||||
isr_ctx[tim_num].cb(isr_ctx[tim_num].arg, chan_num);
|
||||
}
|
||||
|
||||
static inline void isr_handler(lpc23xx_timer_t *dev, int tim_num)
|
||||
{
|
||||
for (unsigned i = 0; i < TIMER_CHAN_NUMOF; i++) {
|
||||
if (dev->IR & (1 << i)) {
|
||||
dev->IR |= (1 << i);
|
||||
dev->MCR &= ~(1 << (i * 3));
|
||||
isr_ctx[tim_num].cb(isr_ctx[tim_num].arg, i);
|
||||
}
|
||||
for (unsigned i = 0; i < TIMER_CHANNELS; ++i) {
|
||||
chan_handler(dev, tim_num, i);
|
||||
}
|
||||
|
||||
/* we must not forget to acknowledge the handling of the interrupt */
|
||||
VICVectAddr = 0;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -343,6 +343,11 @@ typedef struct {
|
||||
uint16_t flags; /**< flags for CTRA, e.g. TC_CTRLA_MODE_COUNT32 */
|
||||
} tc32_conf_t;
|
||||
|
||||
/**
|
||||
* @brief Number of available timer channels
|
||||
*/
|
||||
#define TIMER_CHANNELS (2)
|
||||
|
||||
/**
|
||||
* @brief Set up alternate function (PMUX setting) for a PORT pin
|
||||
*
|
||||
|
||||
@ -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
|
||||
*/
|
||||
@ -189,6 +232,51 @@ int timer_set_absolute(tim_t tim, int channel, unsigned int value)
|
||||
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) {
|
||||
|
||||
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) {
|
||||
|
||||
if (is_oneshot(tim, 1)) {
|
||||
tc->INTENCLR.reg = TC_INTENCLR_MC1;
|
||||
}
|
||||
|
||||
if (config[tim].cb) {
|
||||
config[tim].cb(config[tim].arg, 1);
|
||||
}
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
#define PERIPH_TIMER_H
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "periph_cpu.h"
|
||||
/** @todo remove dev_enums.h include once all platforms are ported to the updated periph interface */
|
||||
@ -69,6 +70,26 @@ extern "C" {
|
||||
typedef unsigned int tim_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Reset the timer when the set() function is called
|
||||
*
|
||||
* When set, calling the timer_set_periodic() function resets the timer count value.
|
||||
*/
|
||||
#ifndef TIM_FLAG_RESET_ON_SET
|
||||
#define TIM_FLAG_RESET_ON_SET (0x01)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Reset the timer on match
|
||||
*
|
||||
* When set, a match on this channel will reset the timer count value.
|
||||
* When set on multiple channels, only the channel with the lowest match value
|
||||
* will be reached.
|
||||
*/
|
||||
#ifndef TIM_FLAG_RESET_ON_MATCH
|
||||
#define TIM_FLAG_RESET_ON_MATCH (0x02)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Signature of event callback functions triggered from interrupts
|
||||
*
|
||||
@ -138,6 +159,21 @@ int timer_set(tim_t dev, int channel, unsigned int timeout);
|
||||
*/
|
||||
int timer_set_absolute(tim_t dev, int channel, unsigned int value);
|
||||
|
||||
/**
|
||||
* @brief Set an absolute timeout value for the given channel of the given timer
|
||||
* The timeout will be called periodically for each iteration
|
||||
*
|
||||
* @param[in] dev the timer device to set
|
||||
* @param[in] channel the channel to set
|
||||
* @param[in] value the absolute compare value when the callback will be
|
||||
* triggered
|
||||
* @param[in] flags options
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on error
|
||||
*/
|
||||
int timer_set_periodic(tim_t dev, int channel, unsigned int value, uint8_t flags);
|
||||
|
||||
/**
|
||||
* @brief Clear the given channel of the given timer device
|
||||
*
|
||||
|
||||
5
tests/periph_timer_periodic/Makefile
Normal file
5
tests/periph_timer_periodic/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
include ../Makefile.tests_common
|
||||
|
||||
FEATURES_REQUIRED = periph_timer_periodic
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
||||
107
tests/periph_timer_periodic/main.c
Normal file
107
tests/periph_timer_periodic/main.c
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Beuth Hochschule für Technik Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Periodic timer test application
|
||||
*
|
||||
* @author Benjamin Valentin <benpicco@beuth-hochschule.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "test_utils/expect.h"
|
||||
|
||||
#include "mutex.h"
|
||||
#include "periph/timer.h"
|
||||
#include "xtimer.h"
|
||||
|
||||
/* We use the timer used for xtimer with the frequency used by xtimer here
|
||||
* to make sure we have a known valid timer configuration.
|
||||
*
|
||||
* DO NOT USE any low-level timer functions demonstrated here when xtimer
|
||||
* is used with that timer!
|
||||
* Configure a separate timer, XTIMER_DEV is usually 'owned' by xtimer, but
|
||||
* as xtimer is not used in this test, we can use it and the fact that every board
|
||||
* provides a configuration for it.
|
||||
*/
|
||||
#define TIMER_CYCL XTIMER_DEV
|
||||
#define CYCLE_MS 100UL
|
||||
#define CYCLES_MAX 10
|
||||
|
||||
static unsigned count[TIMER_CHANNELS];
|
||||
|
||||
static void cb(void *arg, int chan)
|
||||
{
|
||||
unsigned c = count[chan]++;
|
||||
|
||||
printf("[%d] tick\n", chan);
|
||||
|
||||
if (c > CYCLES_MAX) {
|
||||
timer_stop(TIMER_CYCL);
|
||||
mutex_unlock(arg);
|
||||
}
|
||||
}
|
||||
|
||||
static const char* _print_ok(int chan, bool *succeeded)
|
||||
{
|
||||
if (chan == 0 && count[chan] > 0) {
|
||||
return "OK";
|
||||
}
|
||||
|
||||
if (chan > 0 && count[chan] == 0) {
|
||||
return "OK";
|
||||
}
|
||||
|
||||
*succeeded = false;
|
||||
return "ERROR";
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
mutex_t lock = MUTEX_INIT_LOCKED;
|
||||
const unsigned long timer_hz = XTIMER_HZ;
|
||||
const unsigned steps = (CYCLE_MS * timer_hz) / 1000;
|
||||
|
||||
printf("\nRunning Timer %d at %lu Hz.\n", TIMER_CYCL, timer_hz);
|
||||
printf("One counter cycle is %u ticks or %lu ms\n", steps, CYCLE_MS);
|
||||
puts("Will print 'tick' every cycle.\n");
|
||||
|
||||
expect(timer_init(TIMER_CYCL, timer_hz, cb, &lock) == 0);
|
||||
|
||||
puts("TEST START");
|
||||
|
||||
/* Only the first channel should trigger and reset the counter */
|
||||
/* If subsequent channels trigger this is an error. */
|
||||
timer_set_periodic(TIMER_CYCL, 1, 2 * steps, TIM_FLAG_RESET_ON_SET);
|
||||
timer_set_periodic(TIMER_CYCL, 0, steps, TIM_FLAG_RESET_ON_MATCH);
|
||||
|
||||
mutex_lock(&lock);
|
||||
|
||||
puts("\nCycles:");
|
||||
|
||||
bool succeeded = true;
|
||||
for (unsigned i = 0; i < TIMER_CHANNELS; ++i) {
|
||||
printf("channel %u = %02u\t[%s]\n", i, count[i], _print_ok(i, &succeeded));
|
||||
}
|
||||
|
||||
if (succeeded) {
|
||||
puts("TEST SUCCEEDED");
|
||||
} else {
|
||||
puts("TEST FAILED");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
25
tests/periph_timer_periodic/tests/01-run.py
Executable file
25
tests/periph_timer_periodic/tests/01-run.py
Executable file
@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (C) 2020 Benjamin Valentin <benpicco@beuth-hochschule.de>
|
||||
#
|
||||
# This file is subject to the terms and conditions of the GNU Lesser
|
||||
# General Public License v2.1. See the file LICENSE in the top level
|
||||
# directory for more details.
|
||||
|
||||
import sys
|
||||
import time
|
||||
from testrunner import run
|
||||
|
||||
|
||||
def testfunc(child):
|
||||
child.expect_exact('TEST START')
|
||||
start = time.time()
|
||||
child.expect_exact('TEST SUCCEEDED')
|
||||
end = time.time()
|
||||
# test should run 10 cycles with 100ms each
|
||||
assert (end - start) > 1
|
||||
assert (end - start) < 1.5
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(run(testfunc))
|
||||
Loading…
x
Reference in New Issue
Block a user