/* * Copyright (c) 2017 The Fuchsia Authors. * * Use of this source code is governed by a MIT-style * license that can be found in the LICENSE file or at * https://opensource.org/licenses/MIT */ #include #include #include #include typedef enum { STM32_TIM_NOT_FOUND = -1, STM32_TIM1_INDEX = 0, STM32_TIM2_INDEX, STM32_TIM3_INDEX, STM32_TIM6_INDEX, STM32_TIM7_INDEX, STM32_TIM14_INDEX, STM32_TIM15_INDEX, STM32_TIM16_INDEX, STM32_TIM17_INDEX, STM32_NUM_TIMERS, } stm32_timer_index_t; typedef TIM_TypeDef stm32_timer_regs_t; #define STM32_TIMER_FLAGS_32_BIT (1 << 0) typedef struct stm32_timer_config_ { stm32_timer_regs_t *regs; uint32_t flags; stm32_rcc_clk_t clock; int irq; } stm32_timer_config_t; static const stm32_timer_config_t stm32_timer_config[] = { #ifdef TIM1 [STM32_TIM1_INDEX] = { .regs = TIM1, .flags = 0, .clock = STM32_RCC_CLK_TIM1, // TIM1 has two interrupts. This one and TIM1_BRK_UP_TRG_COM_IRQn. // This will need to be supported when more than just capture is // supported. .irq = TIM1_CC_IRQn, }, #endif #ifdef TIM2 [STM32_TIM2_INDEX] = { .regs = TIM2, .flags = STM32_TIMER_FLAGS_32_BIT, .clock = STM32_RCC_CLK_TIM2, .irq = TIM2_IRQn, }, #endif #ifdef TIM3 [STM32_TIM3_INDEX] = { .regs = TIM3, .flags = 0, .clock = STM32_RCC_CLK_TIM3, .irq = TIM3_IRQn, }, #endif #ifdef TIM6 [STM32_TIM6_INDEX] = { .regs = TIM6, .flags = 0, .clock = STM32_RCC_CLK_TIM6, .irq = TIM6_IRQn, }, #endif #ifdef TIM7 [STM32_TIM7_INDEX] = { .regs = TIM7, .flags = 0, .clock = STM32_RCC_CLK_TIM7, .irq = TIM7_IRQn, }, #endif #ifdef TIM14 [STM32_TIM14_INDEX] = { .regs = TIM14, .flags = 0, .clock = STM32_RCC_CLK_TIM14, .irq = TIM14_IRQn, }, #endif #ifdef TIM15 [STM32_TIM15_INDEX] = { .regs = TIM15, .flags = 0, .clock = STM32_RCC_CLK_TIM15, .irq = TIM15_IRQn, }, #endif #ifdef TIM16 [STM32_TIM16_INDEX] = { .regs = TIM16, .flags = 0, .clock = STM32_RCC_CLK_TIM16, .irq = TIM16_IRQn, }, #endif #ifdef TIM17 [STM32_TIM17_INDEX] = { .regs = TIM17, .flags = 0, .clock = STM32_RCC_CLK_TIM17, .irq = TIM17_IRQn, }, #endif }; static stm32_timer_capture_t *stm32_timer_capture_data[STM32_NUM_TIMERS]; static void stm32_timer_enable(const stm32_timer_config_t *config) { stm32_rcc_set_enable(config->clock, true); } static stm32_timer_index_t stm32_timer_get_index(int timer) { switch (timer) { case 1: return STM32_TIM1_INDEX; case 2: return STM32_TIM2_INDEX; case 3: return STM32_TIM3_INDEX; case 6: return STM32_TIM6_INDEX; case 7: return STM32_TIM7_INDEX; case 14: return STM32_TIM14_INDEX; case 15: return STM32_TIM15_INDEX; case 16: return STM32_TIM16_INDEX; case 17: return STM32_TIM17_INDEX; default: return STM32_TIM_NOT_FOUND; } } static const stm32_timer_config_t *stm32_timer_get_config(int timer) { stm32_timer_index_t index = stm32_timer_get_index(timer); if (index == STM32_TIM_NOT_FOUND) { return NULL; } return &stm32_timer_config[index]; } static bool stm32_timer_is_32_bit(int timer) { switch (timer) { case 2: return true; default: return false; } } static void stm32_timer_capture_setup_chan(stm32_timer_capture_t *tc, int chan) { stm32_timer_regs_t *regs = tc->config->regs; volatile uint32_t *ccmr = chan & 0x2 ? ®s->CCMR2 : ®s->CCMR1; int shift = 8 * (chan & 1); uint32_t val = *ccmr; val &= 0xff << shift; val |= TIM_CCMR1_CC1S_0 << shift; *ccmr = val; uint32_t config = TIM_CCER_CC1E; uint32_t flags = tc->chan[chan].flags; if (flags & STM32_TIMER_CAPTURE_CHAN_FLAG_FALLING) { config |= TIM_CCER_CC1P; if (flags & STM32_TIMER_CAPTURE_CHAN_FLAG_RISING) { config |= TIM_CCER_CC1NP; } } shift = 4 * (chan & 3); val = regs->CCER; val &= 0xf << shift; val |= config << shift; regs->CCER = val; } static uint32_t stm32_timer_get_ccr(stm32_timer_capture_t *tc, int chan) { assert(0 <= chan && chan <= 3); switch (chan) { case 0: return tc->config->regs->CCR1; case 1: return tc->config->regs->CCR2; case 2: return tc->config->regs->CCR3; default: // 3 return tc->config->regs->CCR4; } } static uint64_t stm32_timer_inc_overflow(stm32_timer_capture_t *tc, uint64_t overflow) { uint64_t inc; if (tc->config->flags & STM32_TIMER_FLAGS_32_BIT) { inc = 0x100000000ULL; } else { inc = 0x10000ULL; } return overflow + inc; } static uint32_t stm32_timer_median_val(stm32_timer_capture_t *tc) { if (tc->config->flags & STM32_TIMER_FLAGS_32_BIT) { return 0x7fffffff; } else { return 0x7fff; } } // Assumes interrupts are disabled. static uint64_t stm32_timer_calc_value(stm32_timer_capture_t *tc, uint32_t sr, uint32_t val) { uint64_t overflow = tc->overflow; // Since we could be processing an overflow and capture interrupts at the // same time, we don't know the ordering of the two. Here we assume // that if the capture event occurred in the lower half of the counter // range, the overflow happened before the capture. if (sr & TIM_SR_UIF && val < stm32_timer_median_val(tc)) { overflow = stm32_timer_inc_overflow(tc, overflow); } return overflow | val; } static bool stm32_timer_capture_chan_irq(stm32_timer_capture_t *tc, uint32_t sr, int chan) { if (tc->chan[chan].cb == NULL) { return false; } if (sr & (TIM_SR_CC1IF << chan)) { uint32_t val = stm32_timer_get_ccr(tc, chan); return tc->chan[chan].cb(stm32_timer_calc_value(tc, sr, val)); } return false; } static void stm32_timer_capture_irq(stm32_timer_index_t index) { arm_cm_irq_entry(); bool resched = false; stm32_timer_capture_t *tc = stm32_timer_capture_data[index]; if (tc == NULL) { goto out; } uint32_t sr = tc->config->regs->SR; uint32_t irq_ack = ~0U; // Since these read their corresponding CCR registers, the status flags // do not need to be explicitly cleared. resched |= stm32_timer_capture_chan_irq(tc, sr, 0); resched |= stm32_timer_capture_chan_irq(tc, sr, 1); resched |= stm32_timer_capture_chan_irq(tc, sr, 2); resched |= stm32_timer_capture_chan_irq(tc, sr, 3); // We process overflow after compares in order to handle overflow race // detection there. spin_lock_saved_state_t state; spin_lock_irqsave(&tc->overflow_lock, state); if (sr & TIM_SR_UIF) { tc->overflow = stm32_timer_inc_overflow(tc, tc->overflow); irq_ack &= ~TIM_SR_UIF; } tc->config->regs->SR = irq_ack; spin_unlock_irqrestore(&tc->overflow_lock, state); out: arm_cm_irq_exit(resched); } void stm32_TIM1_IRQ(void) { stm32_timer_capture_irq(STM32_TIM1_INDEX); } void stm32_TIM2_IRQ(void) { stm32_timer_capture_irq(STM32_TIM2_INDEX); } void stm32_TIM3_IRQ(void) { stm32_timer_capture_irq(STM32_TIM3_INDEX); } void stm32_TIM6_IRQ(void) { stm32_timer_capture_irq(STM32_TIM6_INDEX); } void stm32_TIM7_IRQ(void) { stm32_timer_capture_irq(STM32_TIM7_INDEX); } void stm32_TIM14_IRQ(void) { stm32_timer_capture_irq(STM32_TIM14_INDEX); } void stm32_TIM15_IRQ(void) { stm32_timer_capture_irq(STM32_TIM15_INDEX); } void stm32_TIM16_IRQ(void) { stm32_timer_capture_irq(STM32_TIM16_INDEX); } void stm32_TIM17_IRQ(void) { stm32_timer_capture_irq(STM32_TIM17_INDEX); } status_t stm32_timer_capture_setup(stm32_timer_capture_t *tc, int timer, uint16_t prescaler) { assert(prescaler > 0); tc->config = stm32_timer_get_config(timer); if (tc->config == NULL) { return ERR_NOT_FOUND; } stm32_timer_enable(tc->config); stm32_timer_capture_data[stm32_timer_get_index(timer)] = tc; tc->overflow = 0; spin_lock_init(&tc->overflow_lock); tc->config->regs->CR1 = 0; // The prescaler value applied by hardware is PSC + 1. tc->config->regs->PSC = prescaler > 0 ? prescaler - 1 : 0; uint32_t dier = TIM_DIER_UIE; int i; for (i = 0; i < 4; i++) { if (tc->chan[i].flags & STM32_TIMER_CAPTURE_CHAN_FLAG_ENABLE) { dier |= TIM_DIER_CC1IE << i; stm32_timer_capture_setup_chan(tc, i); } } tc->config->regs->DIER = dier; tc->config->regs->CR1 |= TIM_CR1_CEN; NVIC_EnableIRQ(tc->config->irq); return NO_ERROR; } uint64_t stm32_timer_capture_get_counter(stm32_timer_capture_t *tc) { // Protect against tc->overflow being updated while we calculate the value. spin_lock_saved_state_t state; spin_lock_irqsave(&tc->overflow_lock, state); uint32_t cnt = tc->config->regs->CNT; uint32_t sr = tc->config->regs->SR; uint64_t value = stm32_timer_calc_value(tc, sr, cnt); spin_unlock_irqrestore(&tc->overflow_lock, state); return value; } void stm32_timer_init(void) { } void stm32_timer_early_init(void) { }