mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-25 14:33:52 +01:00
Merge pull request #14391 from benpicco/cpu/stm32-timer_periodic
cpu/stm32: implement periph_timer_periodic
This commit is contained in:
commit
7d9aed7f66
@ -13,6 +13,7 @@ config CPU_STM32
|
||||
select HAS_PERIPH_GPIO
|
||||
select HAS_PERIPH_GPIO_IRQ
|
||||
select HAS_PUF_SRAM
|
||||
select HAS_PERIPH_TIMER_PERIODIC
|
||||
select HAS_PERIPH_UART_MODECFG
|
||||
select HAS_PERIPH_UART_NONBLOCKING
|
||||
select HAS_PERIPH_WDT
|
||||
|
||||
@ -5,6 +5,7 @@ FEATURES_PROVIDED += cpu_stm32$(CPU_FAM)
|
||||
FEATURES_PROVIDED += periph_cpuid
|
||||
FEATURES_PROVIDED += periph_gpio periph_gpio_irq
|
||||
FEATURES_PROVIDED += puf_sram
|
||||
FEATURES_PROVIDED += periph_timer_periodic
|
||||
FEATURES_PROVIDED += periph_uart_modecfg
|
||||
FEATURES_PROVIDED += periph_uart_nonblocking
|
||||
FEATURES_PROVIDED += periph_wdt
|
||||
|
||||
@ -36,6 +36,57 @@ static inline TIM_TypeDef *dev(tim_t tim)
|
||||
return timer_config[tim].dev;
|
||||
}
|
||||
|
||||
#ifdef MODULE_PERIPH_TIMER_PERIODIC
|
||||
|
||||
/**
|
||||
* @brief Helper macro to get channel bit in timer/channel bitmap
|
||||
*/
|
||||
#define CHAN_BIT(tim, chan) (1 << chan) << (TIMER_CHANNEL_NUMOF * (tim & 1))
|
||||
|
||||
/**
|
||||
* @brief Bitmap for compare channel disable after match
|
||||
*/
|
||||
static uint8_t _oneshot[(TIMER_NUMOF+1)/2];
|
||||
|
||||
/**
|
||||
* @brief Clear interrupt enable after the interrupt has fired
|
||||
*/
|
||||
static inline void set_oneshot(tim_t tim, int chan)
|
||||
{
|
||||
_oneshot[tim >> 1] |= CHAN_BIT(tim, chan);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable interrupt with every wrap-around of the timer
|
||||
*/
|
||||
static inline void clear_oneshot(tim_t tim, int chan)
|
||||
{
|
||||
_oneshot[tim >> 1] &= ~CHAN_BIT(tim, chan);
|
||||
}
|
||||
|
||||
static inline bool is_oneshot(tim_t tim, int chan)
|
||||
{
|
||||
return _oneshot[tim >> 1] & CHAN_BIT(tim, chan);
|
||||
}
|
||||
|
||||
#else /* !MODULE_PERIPH_TIMER_PERIODIC */
|
||||
|
||||
static inline void set_oneshot(tim_t tim, int chan)
|
||||
{
|
||||
(void)tim;
|
||||
(void)chan;
|
||||
}
|
||||
|
||||
static inline bool is_oneshot(tim_t tim, int chan)
|
||||
{
|
||||
(void)tim;
|
||||
(void)chan;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* MODULE_PERIPH_TIMER_PERIODIC */
|
||||
|
||||
int timer_init(tim_t tim, unsigned long freq, timer_cb_t cb, void *arg)
|
||||
{
|
||||
/* check if device is valid */
|
||||
@ -74,13 +125,53 @@ int timer_set_absolute(tim_t tim, int channel, unsigned int value)
|
||||
return -1;
|
||||
}
|
||||
|
||||
set_oneshot(tim, channel);
|
||||
|
||||
TIM_CHAN(tim, channel) = (value & timer_config[tim].max);
|
||||
dev(tim)->SR &= ~(TIM_SR_CC1IF << channel);
|
||||
|
||||
#ifdef MODULE_PERIPH_TIMER_PERIODIC
|
||||
if (dev(tim)->ARR == TIM_CHAN(tim, channel)) {
|
||||
dev(tim)->ARR = timer_config[tim].max;
|
||||
}
|
||||
#endif
|
||||
|
||||
dev(tim)->DIER |= (TIM_DIER_CC1IE << channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MODULE_PERIPH_TIMER_PERIODIC
|
||||
int timer_set_periodic(tim_t tim, int channel, unsigned int value, uint8_t flags)
|
||||
{
|
||||
if (channel >= (int)TIMER_CHANNEL_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
clear_oneshot(tim, channel);
|
||||
|
||||
if (flags & TIM_FLAG_RESET_ON_SET) {
|
||||
/* setting COUNT gives us an interrupt on all channels */
|
||||
unsigned state = irq_disable();
|
||||
dev(tim)->CNT = 0;
|
||||
|
||||
/* wait for the interrupt & clear it */
|
||||
while(dev(tim)->SR == 0) {}
|
||||
dev(tim)->SR = 0;
|
||||
|
||||
irq_restore(state);
|
||||
}
|
||||
|
||||
TIM_CHAN(tim, channel) = value;
|
||||
dev(tim)->DIER |= (TIM_DIER_CC1IE << channel);
|
||||
|
||||
if (flags & TIM_FLAG_RESET_ON_MATCH) {
|
||||
dev(tim)->ARR = value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* MODULE_PERIPH_TIMER_PERIODIC */
|
||||
|
||||
int timer_clear(tim_t tim, int channel)
|
||||
{
|
||||
if (channel >= (int)TIMER_CHANNEL_NUMOF) {
|
||||
@ -88,6 +179,13 @@ int timer_clear(tim_t tim, int channel)
|
||||
}
|
||||
|
||||
dev(tim)->DIER &= ~(TIM_DIER_CC1IE << channel);
|
||||
|
||||
#ifdef MODULE_PERIPH_TIMER_PERIODIC
|
||||
if (dev(tim)->ARR == TIM_CHAN(tim, channel)) {
|
||||
dev(tim)->ARR = timer_config[tim].max;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -108,13 +206,30 @@ void timer_stop(tim_t tim)
|
||||
|
||||
static inline void irq_handler(tim_t tim)
|
||||
{
|
||||
uint32_t status = (dev(tim)->SR & dev(tim)->DIER);
|
||||
uint32_t top = dev(tim)->ARR;
|
||||
uint32_t status = dev(tim)->SR & dev(tim)->DIER;
|
||||
dev(tim)->SR = 0;
|
||||
|
||||
for (unsigned int i = 0; i < TIMER_CHANNEL_NUMOF; i++) {
|
||||
if (status & (TIM_SR_CC1IF << i)) {
|
||||
dev(tim)->DIER &= ~(TIM_DIER_CC1IE << i);
|
||||
isr_ctx[tim].cb(isr_ctx[tim].arg, i);
|
||||
for (unsigned int i = 0; status; i++) {
|
||||
uint32_t msk = TIM_SR_CC1IF << i;
|
||||
|
||||
/* check if interrupt flag is set */
|
||||
if ((status & msk) == 0) {
|
||||
continue;
|
||||
}
|
||||
status &= ~msk;
|
||||
|
||||
/* interrupt flag gets set for all channels > ARR */
|
||||
if (TIM_CHAN(tim, i) > top) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* disable Interrupt */
|
||||
if (is_oneshot(tim, i)) {
|
||||
dev(tim)->DIER &= ~msk;
|
||||
}
|
||||
|
||||
isr_ctx[tim].cb(isr_ctx[tim].arg, i);
|
||||
}
|
||||
cortexm_isr_end();
|
||||
}
|
||||
|
||||
@ -4,4 +4,6 @@ BOARD_INSUFFICIENT_MEMORY := \
|
||||
arduino-nano \
|
||||
arduino-uno \
|
||||
atmega328p \
|
||||
nucleo-f031k6 \
|
||||
stm32f030f4-demo \
|
||||
#
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
* provides a configuration for it.
|
||||
*/
|
||||
#define TIMER_CYCL XTIMER_DEV
|
||||
#define CYCLE_MS 100UL
|
||||
#define CYCLE_MS 25UL
|
||||
#define CYCLES_MAX 10
|
||||
|
||||
static unsigned count[TIMER_CHANNEL_NUMOF];
|
||||
|
||||
@ -16,9 +16,9 @@ def testfunc(child):
|
||||
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
|
||||
# test should run 10 cycles with 25ms each
|
||||
assert (end - start) > 0.25
|
||||
assert (end - start) < 0.35
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user