diff options
-rw-r--r-- | board/daisy/board.h | 4 | ||||
-rw-r--r-- | board/snow/board.h | 4 | ||||
-rw-r--r-- | board/spring/board.h | 4 | ||||
-rw-r--r-- | chip/stm32/hwtimer.c | 136 |
4 files changed, 88 insertions, 60 deletions
diff --git a/board/daisy/board.h b/board/daisy/board.h index b2308abc6f..da85579d7d 100644 --- a/board/daisy/board.h +++ b/board/daisy/board.h @@ -47,6 +47,10 @@ #define I2C_PORT_CHARGER I2C_PORT_HOST #define I2C_PORT_SLAVE 1 +/* Timer selection */ +#define TIM_CLOCK_MSB 3 +#define TIM_CLOCK_LSB 4 + /* GPIO signal list */ enum gpio_signal { /* Inputs with interrupt handlers are first for efficiency */ diff --git a/board/snow/board.h b/board/snow/board.h index 749960bc6f..072b5ec40e 100644 --- a/board/snow/board.h +++ b/board/snow/board.h @@ -59,6 +59,10 @@ /* Battery */ #define CONFIG_BATTERY_BQ20Z453 +/* Timer selection */ +#define TIM_CLOCK_MSB 3 +#define TIM_CLOCK_LSB 4 + /* GPIO signal list */ enum gpio_signal { /* Inputs with interrupt handlers are first for efficiency */ diff --git a/board/spring/board.h b/board/spring/board.h index e31a635fad..192eddc550 100644 --- a/board/spring/board.h +++ b/board/spring/board.h @@ -55,6 +55,10 @@ /* Battery */ #define CONFIG_BATTERY_BQ20Z453 +/* Timer selection */ +#define TIM_CLOCK_MSB 2 +#define TIM_CLOCK_LSB 4 + /* ADC signal */ #define CONFIG_ADC enum adc_channel { diff --git a/chip/stm32/hwtimer.c b/chip/stm32/hwtimer.c index 3a58e9dcd1..ef09a8dd5e 100644 --- a/chip/stm32/hwtimer.c +++ b/chip/stm32/hwtimer.c @@ -21,6 +21,15 @@ #define TIM_WD 1 /* Timer to use for watchdog */ #endif +/* + * TIM_CLOCK_MSB and TIM_CLOCK_LSB must be defined per board. The available + * values are 2, 3, and 4. This gives us flexibility to make any of the three + * timer as a PWM source. + */ +#define IRQ_TIM(n) STM32_CAT(STM32_IRQ_TIM, n, ) +#define IRQ_MSB IRQ_TIM(TIM_CLOCK_MSB) +#define IRQ_LSB IRQ_TIM(TIM_CLOCK_LSB) + enum { TIM_WD_BASE = STM32_TIM1_BASE, }; @@ -31,33 +40,33 @@ void __hw_clock_event_set(uint32_t deadline) { last_deadline = deadline; - if ((deadline >> 16) > STM32_TIM_CNT(3)) { + if ((deadline >> 16) > STM32_TIM_CNT(TIM_CLOCK_MSB)) { /* first set a match on the MSB */ - STM32_TIM_CCR1(3) = deadline >> 16; + STM32_TIM_CCR1(TIM_CLOCK_MSB) = deadline >> 16; /* disable LSB match */ - STM32_TIM_DIER(4) &= ~2; + STM32_TIM_DIER(TIM_CLOCK_LSB) &= ~2; /* Clear the match flags */ - STM32_TIM_SR(3) = ~2; - STM32_TIM_SR(4) = ~2; + STM32_TIM_SR(TIM_CLOCK_MSB) = ~2; + STM32_TIM_SR(TIM_CLOCK_LSB) = ~2; /* Set the match interrupt */ - STM32_TIM_DIER(3) |= 2; + STM32_TIM_DIER(TIM_CLOCK_MSB) |= 2; } /* - * In the unlikely case where the MSB on TIM3 has increased and matched + * In the unlikely case where the MSB has increased and matched * the deadline MSB before we set the match interrupt, as the STM * hardware timer won't trigger an interrupt, we fall back to the * following LSB event code to set another interrupt. */ - if ((deadline >> 16) == STM32_TIM_CNT(3)) { + if ((deadline >> 16) == STM32_TIM_CNT(TIM_CLOCK_MSB)) { /* we can set a match on the LSB only */ - STM32_TIM_CCR1(4) = deadline & 0xffff; + STM32_TIM_CCR1(TIM_CLOCK_LSB) = deadline & 0xffff; /* disable MSB match */ - STM32_TIM_DIER(3) &= ~2; + STM32_TIM_DIER(TIM_CLOCK_MSB) &= ~2; /* Clear the match flags */ - STM32_TIM_SR(3) = ~2; - STM32_TIM_SR(4) = ~2; + STM32_TIM_SR(TIM_CLOCK_MSB) = ~2; + STM32_TIM_SR(TIM_CLOCK_LSB) = ~2; /* Set the match interrupt */ - STM32_TIM_DIER(4) |= 2; + STM32_TIM_DIER(TIM_CLOCK_LSB) |= 2; } /* * If the LSB deadline is already in the past and won't trigger an @@ -75,8 +84,8 @@ uint32_t __hw_clock_event_get(void) void __hw_clock_event_clear(void) { /* Disable the match interrupts */ - STM32_TIM_DIER(4) &= ~2; - STM32_TIM_DIER(3) &= ~2; + STM32_TIM_DIER(TIM_CLOCK_LSB) &= ~2; + STM32_TIM_DIER(TIM_CLOCK_MSB) &= ~2; } uint32_t __hw_clock_source_read(void) @@ -86,89 +95,95 @@ uint32_t __hw_clock_source_read(void) /* Ensure the two half-words are coherent */ do { - hi = STM32_TIM_CNT(3); - lo = STM32_TIM_CNT(4); - } while (hi != STM32_TIM_CNT(3)); + hi = STM32_TIM_CNT(TIM_CLOCK_MSB); + lo = STM32_TIM_CNT(TIM_CLOCK_LSB); + } while (hi != STM32_TIM_CNT(TIM_CLOCK_MSB)); return (hi << 16) | lo; } void __hw_clock_source_set(uint32_t ts) { - STM32_TIM_CNT(3) = ts >> 16; - STM32_TIM_CNT(4) = ts & 0xffff; + STM32_TIM_CNT(TIM_CLOCK_MSB) = ts >> 16; + STM32_TIM_CNT(TIM_CLOCK_LSB) = ts & 0xffff; } static void __hw_clock_source_irq(void) { - uint32_t stat_tim3 = STM32_TIM_SR(3); + uint32_t stat_tim_msb = STM32_TIM_SR(TIM_CLOCK_MSB); /* Clear status */ - STM32_TIM_SR(4) = 0; - STM32_TIM_SR(3) = 0; + STM32_TIM_SR(TIM_CLOCK_LSB) = 0; + STM32_TIM_SR(TIM_CLOCK_MSB) = 0; /* * Find expired timers and set the new timer deadline * signal overflow if the 16-bit MSB counter has overflowed. */ - process_timers(stat_tim3 & 0x01); + process_timers(stat_tim_msb & 0x01); } -DECLARE_IRQ(STM32_IRQ_TIM3, __hw_clock_source_irq, 1); -DECLARE_IRQ(STM32_IRQ_TIM4, __hw_clock_source_irq, 1); +DECLARE_IRQ(IRQ_MSB, __hw_clock_source_irq, 1); +DECLARE_IRQ(IRQ_LSB, __hw_clock_source_irq, 1); int __hw_clock_source_init(uint32_t start_t) { /* * we use 2 chained 16-bit counters to emulate a 32-bit one : - * TIM3 is the MSB (Slave) - * TIM4 is the LSB (Master) + * TIM_CLOCK_MSB is the MSB (Slave) + * TIM_CLOCK_LSB is the LSB (Master) */ - /* Enable TIM3 and TIM4 clocks */ - STM32_RCC_APB1ENR |= 0x6; + /* Enable TIM_CLOCK_MSB and TIM_CLOCK_LSB clocks */ + STM32_RCC_APB1ENR |= (1 << (TIM_CLOCK_MSB - 2)) | + (1 << (TIM_CLOCK_LSB - 2)); /* * Timer configuration : Upcounter, counter disabled, update event only * on overflow. */ - STM32_TIM_CR1(3) = 0x0004; - STM32_TIM_CR1(4) = 0x0004; - /* TIM4 (master mode) generates a periodic trigger signal on each UEV */ - STM32_TIM_CR2(3) = 0x0000; - STM32_TIM_CR2(4) = 0x0020; - /* TIM3 (slave mode) uses ITR3 as internal trigger */ - STM32_TIM_SMCR(3) = 0x0037; - STM32_TIM_SMCR(4) = 0x0000; + STM32_TIM_CR1(TIM_CLOCK_MSB) = 0x0004; + STM32_TIM_CR1(TIM_CLOCK_LSB) = 0x0004; + /* + * TIM_CLOCK_LSB (master mode) generates a periodic trigger signal on + * each UEV + */ + STM32_TIM_CR2(TIM_CLOCK_MSB) = 0x0000; + STM32_TIM_CR2(TIM_CLOCK_LSB) = 0x0020; + /* TIM_CLOCK_MSB (slave mode) uses TIM_CLOCK_LSB as internal trigger */ + STM32_TIM_SMCR(TIM_CLOCK_MSB) = 0x0007 | ((TIM_CLOCK_LSB - 1) << 4); + STM32_TIM_SMCR(TIM_CLOCK_LSB) = 0x0000; /* Auto-reload value : 16-bit free-running counters */ - STM32_TIM_ARR(3) = 0xffff; - STM32_TIM_ARR(4) = 0xffff; - /* Pre-scaler value : - * TIM4 is counting microseconds, TIM3 is counting every TIM4 overflow. + STM32_TIM_ARR(TIM_CLOCK_MSB) = 0xffff; + STM32_TIM_ARR(TIM_CLOCK_LSB) = 0xffff; + /* + * Pre-scaler value : + * TIM_CLOCK_LSB is counting microseconds, TIM_CLOCK_MSB is counting + * every TIM_CLOCK_LSB overflow. */ - STM32_TIM_PSC(3) = 0; - STM32_TIM_PSC(4) = CLOCKSOURCE_DIVIDER - 1; + STM32_TIM_PSC(TIM_CLOCK_MSB) = 0; + STM32_TIM_PSC(TIM_CLOCK_LSB) = CLOCKSOURCE_DIVIDER - 1; /* Reload the pre-scaler */ - STM32_TIM_EGR(3) = 0x0001; - STM32_TIM_EGR(4) = 0x0001; + STM32_TIM_EGR(TIM_CLOCK_MSB) = 0x0001; + STM32_TIM_EGR(TIM_CLOCK_LSB) = 0x0001; - /* setup the overflow interrupt on TIM3 */ - STM32_TIM_DIER(3) = 0x0001; - STM32_TIM_DIER(4) = 0x0000; + /* setup the overflow interrupt on TIM_CLOCK_MSB */ + STM32_TIM_DIER(TIM_CLOCK_MSB) = 0x0001; + STM32_TIM_DIER(TIM_CLOCK_LSB) = 0x0000; /* Start counting */ - STM32_TIM_CR1(3) |= 1; - STM32_TIM_CR1(4) |= 1; + STM32_TIM_CR1(TIM_CLOCK_MSB) |= 1; + STM32_TIM_CR1(TIM_CLOCK_LSB) |= 1; /* Override the count with the start value now that counting has * started. */ __hw_clock_source_set(start_t); /* Enable timer interrupts */ - task_enable_irq(STM32_IRQ_TIM3); - task_enable_irq(STM32_IRQ_TIM4); + task_enable_irq(IRQ_MSB); + task_enable_irq(IRQ_LSB); - return STM32_IRQ_TIM4; + return IRQ_LSB; } /* @@ -224,18 +239,19 @@ void hwtimer_setup_watchdog(void) */ timer->cr1 = 0x0014 | (1 << 7); - /* TIM (slave mode) uses ITR3 as internal trigger */ - timer->smcr = 0x0037; + /* TIM (slave mode) uses TIM_CLOCK_LSB as internal trigger */ + timer->smcr = 0x0007 | ((TIM_CLOCK_LSB - 1) << 4); /* * The auto-reload value is based on the period between rollovers for - * TIM4. Since TIM4 runs at 1MHz, it will overflow in 65.536ms. We - * divide our required watchdog period by this amount to obtain the - * number of times TIM4 can overflow before we generate an interrupt. + * TIM_CLOCK_LSB. Since TIM_CLOCK_LSB runs at 1MHz, it will overflow + * in 65.536ms. We divide our required watchdog period by this amount + * to obtain the number of times TIM_CLOCK_LSB can overflow before we + * generate an interrupt. */ timer->arr = timer->cnt = WATCHDOG_PERIOD_MS * 1000 / (1 << 16); - /* count on every TIM4 overflow */ + /* count on every TIM_CLOCK_LSB overflow */ timer->psc = 0; /* Reload the pre-scaler from arr when it goes below zero */ |