/****************************************************************************** * The MIT License (c) 2017 night_ghost@ykoctpa.ru based on: * * Copyright (c) 2011 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. *****************************************************************************/ #pragma GCC optimize ("O2") /** * @file timer.c * @author Marti Bolivar * @brief New-style timer interface */ #include "timer.h" #include "dma.h" #include #include "nvic.h" /* Just like the corresponding DIER bits: * [0] = Update handler; * [1,2,3,4] = capture/compare 1,2,3,4 handlers, respectively; * [5] = COM; * [6] = TRG; * [7] = BRK. */ #define NR_ADV_HANDLERS 8 /* Update, capture/compare 1,2,3,4; ; trigger. */ #define NR_GEN_HANDLERS 7 /* Update only. */ #define NR_BAS_HANDLERS 1 static Handler tim1_handlers[NR_ADV_HANDLERS] IN_CCM; static Handler tim2_handlers[NR_GEN_HANDLERS] IN_CCM; static Handler tim3_handlers[NR_GEN_HANDLERS] IN_CCM; static Handler tim4_handlers[NR_GEN_HANDLERS] IN_CCM; static Handler tim5_handlers[NR_GEN_HANDLERS] IN_CCM; static Handler tim6_handlers[NR_BAS_HANDLERS] IN_CCM; static Handler tim7_handlers[NR_BAS_HANDLERS] IN_CCM; static Handler tim8_handlers[NR_ADV_HANDLERS] IN_CCM; static Handler tim9_handlers[NR_GEN_HANDLERS] IN_CCM; static Handler tim10_handlers[NR_GEN_HANDLERS] IN_CCM; static Handler tim11_handlers[NR_GEN_HANDLERS] IN_CCM; static Handler tim12_handlers[NR_GEN_HANDLERS] IN_CCM; static Handler tim13_handlers[NR_GEN_HANDLERS] IN_CCM; static Handler tim14_handlers[NR_GEN_HANDLERS] IN_CCM; static timerState timer_state[14] IN_CCM; const timer_dev timers[] = { { /** Timer 1 device (advanced) */ .regs = TIM1, .clk = RCC_APB2Periph_TIM1, .handlers = tim1_handlers, .af = GPIO_AF_TIM1, .type = TIMER_ADVANCED, .n_handlers = NR_ADV_HANDLERS, .bus = 1, .id = 1, .state = &timer_state[0], .ch_dma = { // dma per channel: stream, channel { DMA2_STREAM1, 6 }, { DMA2_STREAM2, 6 }, { DMA2_STREAM6, 6 }, { DMA2_STREAM4, 6 }, }, }, { /** Timer 2 device (general-purpose) */ .regs = TIM2, .clk = RCC_APB1Periph_TIM2, .handlers = tim2_handlers, .af = GPIO_AF_TIM2, .type = TIMER_GENERAL, .n_handlers = NR_GEN_HANDLERS, .bus = 0, .id = 2, .state = &timer_state[1], .ch_dma = { // dma per channel: stream, channel { DMA1_STREAM5, 3 }, { DMA1_STREAM6, 3 }, { DMA1_STREAM1, 3 }, { DMA1_STREAM7, 6 }, }, }, { /** Timer 3 device (general-purpose) */ .regs = TIM3, .clk = RCC_APB1Periph_TIM3, .handlers = tim3_handlers, .af = GPIO_AF_TIM3, .type = TIMER_GENERAL, .n_handlers = NR_GEN_HANDLERS, .bus = 0, .id = 3, .state = &timer_state[2], .ch_dma = { // dma per channel: stream, channel { DMA1_STREAM4, 5 }, { DMA1_STREAM5, 5 }, { DMA1_STREAM7, 5 }, { DMA1_STREAM2, 5 }, }, }, { /** Timer 4 device (general-purpose) */ .regs = TIM4, .clk = RCC_APB1Periph_TIM4, .handlers = tim4_handlers, .af = GPIO_AF_TIM4, .type = TIMER_GENERAL, .n_handlers = NR_GEN_HANDLERS, .bus = 0, .id = 4, .state = &timer_state[3], .ch_dma = { // dma per channel: stream, channel { DMA1_STREAM0, 2 }, { DMA1_STREAM3, 2 }, { DMA1_STREAM7, 2 }, { -1, -1 }, }, }, { /** Timer 5 device (general-purpose) */ .regs = TIM5, .clk = RCC_APB1Periph_TIM5, .handlers = tim5_handlers, .af = GPIO_AF_TIM5, .type = TIMER_GENERAL, .n_handlers = NR_GEN_HANDLERS, .bus = 0, .id = 5, .state = &timer_state[4], .ch_dma = { // dma per channel: stream, channel { DMA1_STREAM2, 6 }, { DMA1_STREAM4, 6 }, { DMA1_STREAM0, 6 }, { DMA1_STREAM1, 6 }, }, }, { /** Timer 6 device (basic) */ .regs = TIM6, .clk = RCC_APB1Periph_TIM6, .handlers = tim6_handlers, .af = 0, .type = TIMER_BASIC, .n_handlers = NR_BAS_HANDLERS, .bus = 0, .id = 6, .state = &timer_state[5], }, { /** Timer 7 device (basic) */ .regs = TIM7, .clk = RCC_APB1Periph_TIM7, .handlers = tim7_handlers, .af = 0, .type = TIMER_BASIC, .n_handlers = NR_BAS_HANDLERS, .bus = 0, .id = 7, .state = &timer_state[6], }, { /** Timer 8 device (advanced) */ .regs = TIM8, .clk = RCC_APB2Periph_TIM8, .handlers = tim8_handlers, .af = GPIO_AF_TIM8, .type = TIMER_ADVANCED, .n_handlers = NR_ADV_HANDLERS, .bus = 1, .id = 8, .state = &timer_state[7], .ch_dma = { // dma per channel: stream, channel { DMA2_STREAM2, 7 }, { DMA2_STREAM3, 7 }, { DMA2_STREAM4, 7 }, { DMA2_STREAM7, 7 }, }, }, // another timers don't has DMA { /** Timer 9 device (general-purpose) */ .regs = TIM9, .clk = RCC_APB2Periph_TIM9, .handlers = tim9_handlers, .af = GPIO_AF_TIM9, .type = TIMER_GENERAL, .n_handlers = NR_GEN_HANDLERS, .bus = 1, .id = 9, .state = &timer_state[8], }, { /** Timer 10 device (general-purpose) */ .regs = TIM10, .clk = RCC_APB2Periph_TIM10, .handlers = tim10_handlers, .af = GPIO_AF_TIM10, .type = TIMER_GENERAL, .n_handlers = NR_GEN_HANDLERS, .bus = 1, .id = 10, .state = &timer_state[9], }, { /** Timer 11 device (general-purpose) */ .regs = TIM11, .clk = RCC_APB2Periph_TIM11, .handlers = tim11_handlers, .af = GPIO_AF_TIM11, .type = TIMER_GENERAL, .n_handlers = NR_GEN_HANDLERS, .bus = 1, .id = 11, .state = &timer_state[10], }, { /** Timer 12 device (general-purpose) */ .regs = TIM12, .clk = RCC_APB1Periph_TIM12, .handlers = tim12_handlers, .af = GPIO_AF_TIM12, .type = TIMER_GENERAL, .n_handlers = NR_GEN_HANDLERS, .bus = 0, .id = 12, .state = &timer_state[11], }, { /** Timer 13 device (general-purpose) */ .regs = TIM13, .clk = RCC_APB1Periph_TIM13, .handlers = tim13_handlers, .af = GPIO_AF_TIM13, .type = TIMER_GENERAL, .n_handlers = NR_GEN_HANDLERS, .bus = 0, .id = 13, .state = &timer_state[12], }, { /** Timer 14 device (general-purpose) */ .regs = TIM14, .clk = RCC_APB1Periph_TIM14, .handlers = tim14_handlers, .af = GPIO_AF_TIM14, .type = TIMER_GENERAL, .n_handlers = NR_GEN_HANDLERS, .bus = 0, .id = 14, .state = &timer_state[13], } }; /* * Convenience routines */ static void disable_channel(const timer_dev *dev, uint8_t channel); static void pwm_mode(const timer_dev *dev, uint8_t channel); static void output_compare_mode(const timer_dev *dev, uint8_t channel); static inline void enable_irq(const timer_dev *dev, uint8_t interrupt, uint8_t priority); /** * Initialize a timer (enable timer clock) * @param dev Timer to initialize */ void timer_init(const timer_dev *dev) { if(dev->bus) RCC_APB2PeriphClockCmd(dev->clk, ENABLE); else RCC_APB1PeriphClockCmd(dev->clk, ENABLE); } /** * Initialize a timer, and reset its register map. * @param dev Timer to initialize */ void timer_reset(const timer_dev *dev) { memset(dev->handlers, 0, dev->n_handlers * sizeof(Handler)); memset(dev->state, 0, sizeof(*dev->state)); if(dev->bus) { RCC_APB2PeriphClockCmd(dev->clk, ENABLE); RCC_APB2PeriphResetCmd(dev->clk, ENABLE); RCC_APB2PeriphResetCmd(dev->clk, DISABLE); } else { RCC_APB1PeriphClockCmd(dev->clk, ENABLE); RCC_APB1PeriphResetCmd(dev->clk, ENABLE); RCC_APB1PeriphResetCmd(dev->clk, DISABLE); } } /** * @brief Disable a timer. * * The timer will stop counting, all DMA requests and interrupts will * be disabled, and no state changes will be output. * * @param dev Timer to disable. */ void timer_disable(const timer_dev *dev) { dev->regs->CR1 = 0; dev->regs->DIER = 0; switch (dev->type) { case TIMER_ADVANCED: case TIMER_GENERAL: (dev->regs)->CCER = 0; break; case TIMER_BASIC: break; } } // initial configuration - set required frequency (in kHz) and period (in ticks) // returns real timers freq uint32_t configTimeBase(const timer_dev *dev, uint16_t period, uint16_t khz) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TypeDef *tim = dev->regs; timer_init(dev); // turn it on timer_pause(dev); dev->regs->CR1 = TIMER_CR1_ARPE; dev->regs->PSC = 1; dev->regs->SR = 0; dev->regs->DIER = 0; dev->regs->EGR = TIMER_EGR_UG; TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Period = (period - 1) & get_timer_mask(dev); // AKA TIMx_ARR uint32_t freq = (uint32_t)khz * 1000; uint16_t prescaler; uint32_t tf; // timer's frequency if (tim == TIM1 || tim == TIM8 || tim == TIM9 || tim == TIM10 || tim == TIM11) { // 168MHz tf = SystemCoreClock; } else { // 84 MHz tf = SystemCoreClock / 2; } prescaler = ((tf + freq/4) / freq) - 1; // ==41 for 2MHz TIM_TimeBaseStructure.TIM_Prescaler = prescaler; freq = tf / prescaler; // real timer's frequency dev->state->freq = freq; // store TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(tim, &TIM_TimeBaseStructure); switch (dev->type) { case TIMER_ADVANCED: dev->regs->BDTR = TIMER_BDTR_MOE | TIMER_BDTR_LOCK_OFF; // break and dead-time register, enable output // fall-through case TIMER_GENERAL: case TIMER_BASIC: break; } timer_set_count(dev,0); dev->state->freq_scale = (float)freq / (khz * 1000); // remember ratio for correction return freq; } static void disable_channel(const timer_dev *dev, timer_Channel channel) { timer_detach_interrupt(dev, channel); timer_cc_disable(dev, channel); } static void pwm_mode(const timer_dev *dev, timer_Channel channel) { timer_disable_irq(dev, channel); timer_oc_set_mode(dev, channel, BOARD_PWM_MODE, TIMER_OC_PE); timer_cc_enable(dev, channel); } static void output_compare_mode(const timer_dev *dev, timer_Channel channel) { timer_oc_set_mode(dev, channel, TIMER_OC_MODE_ACTIVE_ON_MATCH, 0); timer_cc_enable(dev, channel); } /** * Sets the mode of an individual timer channel. * * Note that not all timers can be configured in every mode. For * example, basic timers cannot be configured to output compare mode. * Be sure to use a timer which is appropriate for the mode you want. * * @param dev Timer whose channel mode to set * @param channel Relevant channel * @param mode New timer mode for channel */ void timer_set_mode(const timer_dev *dev, timer_Channel channel, timer_mode mode) { assert_param(channel > 0 && channel <= 4); /* TODO decide about the basic timers */ if (!dev || dev->type == TIMER_BASIC) return; assert_param(dev->type != TIMER_BASIC); switch (mode) { case TIMER_DISABLED: disable_channel(dev, channel); break; case TIMER_PWM: pwm_mode(dev, channel); break; case TIMER_OUTPUT_COMPARE: output_compare_mode(dev, channel); break; } } /** * @brief Call a function on timer devices. * @param fn Function to call on each timer device. */ void timer_foreach(void (*fn)(const timer_dev*)) { uint8_t i; for(i=0; i<(sizeof(timers)/sizeof(timer_dev)); i++){ fn(&timers[i]); } } /** * @brief Attach a timer interrupt. * @param dev Timer device * @param interrupt Interrupt number to attach to; this may be any * timer_interrupt_id or timer_channel value appropriate * for the timer. * @param handler Handler to attach to the given interrupt. * @see timer_interrupt_id * @see timer_channel */ void timer_attach_interrupt(const timer_dev *dev, timer_interrupt_id interrupt, Handler handler, uint8_t priority) { if(interrupt>=dev->n_handlers) return; dev->handlers[interrupt] = handler; timer_enable_irq(dev, interrupt); enable_irq(dev, interrupt, priority); } // attach all timer's interrupts to one handler - for PWM/PPM input void timer_attach_all_interrupts(const timer_dev *dev, Handler handler) { uint16_t i; for(i=0; i < dev->n_handlers; i++) { dev->handlers[i] = handler; } // enabling by caller } /** * @brief Detach a timer interrupt. * @param dev Timer device * @param interrupt Interrupt number to detach; this may be any * timer_interrupt_id or timer_channel value appropriate * for the timer. * @see timer_interrupt_id * @see timer_channel */ void timer_detach_interrupt(const timer_dev *dev, timer_interrupt_id interrupt) { timer_disable_irq(dev, interrupt); if(interrupt>=dev->n_handlers) return; dev->handlers[interrupt] = 0; } /* * IRQ handlers */ static inline void dispatch_adv_brk(const timer_dev *dev); static inline void dispatch_adv_up(const timer_dev *dev); static inline void dispatch_adv_trg_com(const timer_dev *dev); static inline void dispatch_adv_cc(const timer_dev *dev); static inline void dispatch_general(const timer_dev *dev); static inline void dispatch_general_h(const timer_dev *dev); static inline void dispatch_basic(const timer_dev *dev); void TIM1_BRK_TIM9_IRQHandler(void); void TIM1_UP_TIM10_IRQHandler(void); void TIM1_TRG_COM_TIM11_IRQHandler(void); void TIM1_CC_IRQHandler(void); void TIM2_IRQHandler(void); void TIM3_IRQHandler(void); void TIM4_IRQHandler(void); void TIM5_IRQHandler(void); void TIM6_DAC_IRQHandler(void); void TIM7_IRQHandler(void); void TIM8_BRK_TIM12_IRQHandler(void); void TIM8_CC_IRQHandler(void); void TIM8_UP_TIM13_IRQHandler(void); void TIM8_TRG_COM_TIM14_IRQHandler(void); void TIM1_BRK_TIM9_IRQHandler(void) { dispatch_adv_brk(TIMER1); dispatch_general_h(TIMER9); } void TIM1_UP_TIM10_IRQHandler(void) { dispatch_adv_up(TIMER1); dispatch_general_h(TIMER10); } void TIM1_TRG_COM_TIM11_IRQHandler(void) { dispatch_adv_trg_com(TIMER1); dispatch_general_h(TIMER11); } void TIM1_CC_IRQHandler(void) { dispatch_adv_cc(TIMER1); } void TIM2_IRQHandler(void) { dispatch_general(TIMER2); } void TIM3_IRQHandler(void) { dispatch_general(TIMER3); } void TIM4_IRQHandler(void) { dispatch_general(TIMER4); } void TIM5_IRQHandler(void) { dispatch_general(TIMER5); } void TIM6_DAC_IRQHandler(void) { dispatch_basic(TIMER6); } void TIM7_IRQHandler(void) { dispatch_basic(TIMER7); } // used in PWM void TIM8_BRK_TIM12_IRQHandler(void) { // used in PWM tim12 dispatch_adv_brk(TIMER8); dispatch_general_h(TIMER12); } void TIM8_CC_IRQHandler(void) { // used in PWM tim8 dispatch_adv_cc(TIMER8); } void TIM8_UP_TIM13_IRQHandler(void) { // not conflicts with PWM dispatch_adv_up(TIMER8); dispatch_general_h(TIMER13); } void TIM8_TRG_COM_TIM14_IRQHandler(void) { dispatch_adv_trg_com(TIMER8); dispatch_general_h(TIMER14); } /* Note: the following dispatch routines make use of the fact that * DIER interrupt enable bits and SR interrupt flags have common bit * positions. Thus, ANDing DIER and SR lets us check if an interrupt * is enabled and if it has occurred simultaneously. */ static INLINE void dispatch_single_irq(const timer_dev *dev, timer_interrupt_id iid, uint32_t irq_mask) { uint32_t dsr = dev->regs->DIER & dev->regs->SR & irq_mask; if (dsr) { Handler handler = (dev->handlers)[iid]; if (handler) { revo_call_handler(handler, (uint32_t)dev->regs); } dev->regs->SR &= ~dsr; // reset IRQ inspite of installed handler! @NG } } /* For dispatch routines which service multiple interrupts. */ static INLINE void handle_irq(const timer_dev *dev, uint32_t dier_sr, uint32_t irq_mask, uint32_t iid) { if (dier_sr & irq_mask) { Handler handler = (dev->handlers)[iid]; if (handler) { revo_call_handler(handler, (uint32_t)dev->regs); } } } static inline void dispatch_adv_brk(const timer_dev *dev) { #ifdef ISR_PERF uint32_t t=stopwatch_getticks(); #endif dispatch_single_irq(dev, TIMER_BREAK_INTERRUPT, TIMER_SR_BIF); #ifdef ISR_PERF t = stopwatch_getticks() - t; isr_time += t; if(t>max_isr_time) max_isr_time=t; #endif } static inline void dispatch_adv_up(const timer_dev *dev) { #ifdef ISR_PERF uint32_t t=stopwatch_getticks(); #endif dispatch_single_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF); #ifdef ISR_PERF t = stopwatch_getticks() - t; isr_time += t; if(t>max_isr_time) max_isr_time=t; #endif } static inline void dispatch_adv_trg_com(const timer_dev *dev) { #ifdef ISR_PERF uint32_t t=stopwatch_getticks(); #endif uint32_t dsr = dev->regs->DIER & dev->regs->SR; /* Logical OR of SR interrupt flags we end up * handling. We clear these. User handlers * must clear overcapture flags, to avoid * wasting time in output mode. */ handle_irq(dev, dsr, TIMER_SR_TIF, TIMER_TRG_INTERRUPT); handle_irq(dev, dsr, TIMER_SR_COMIF, TIMER_COM_INTERRUPT); dev->regs->SR &= ~dsr; // handled ALL enabled interrupts! AFTER ISR itself! #ifdef ISR_PERF t = stopwatch_getticks() - t; isr_time += t; if(t>max_isr_time) max_isr_time=t; #endif } static inline void dispatch_adv_cc(const timer_dev *dev) { #ifdef ISR_PERF uint32_t t=stopwatch_getticks(); #endif uint32_t dsr = dev->regs->DIER & dev->regs->SR; handle_irq(dev, dsr, TIMER_SR_CC4IF, TIMER_CC4_INTERRUPT); handle_irq(dev, dsr, TIMER_SR_CC3IF, TIMER_CC3_INTERRUPT); handle_irq(dev, dsr, TIMER_SR_CC2IF, TIMER_CC2_INTERRUPT); handle_irq(dev, dsr, TIMER_SR_CC1IF, TIMER_CC1_INTERRUPT); dev->regs->SR &= ~dsr; // handled ALL enabled interrupts! AFTER ISR itself! #ifdef ISR_PERF t = stopwatch_getticks() - t; isr_time += t; if(t>max_isr_time) max_isr_time=t; #endif } static inline void dispatch_general(const timer_dev *dev) { #ifdef ISR_PERF uint32_t t=stopwatch_getticks(); #endif uint32_t dsr = dev->regs->DIER & dev->regs->SR; handle_irq(dev, dsr, TIMER_SR_TIF, TIMER_TRG_INTERRUPT); handle_irq(dev, dsr, TIMER_SR_CC4IF, TIMER_CC4_INTERRUPT); handle_irq(dev, dsr, TIMER_SR_CC3IF, TIMER_CC3_INTERRUPT); handle_irq(dev, dsr, TIMER_SR_CC2IF, TIMER_CC2_INTERRUPT); handle_irq(dev, dsr, TIMER_SR_CC1IF, TIMER_CC1_INTERRUPT); handle_irq(dev, dsr, TIMER_SR_UIF, TIMER_UPDATE_INTERRUPT); dev->regs->SR &= ~dsr; // handled ALL enabled interrupts! AFTER ISR itself! #ifdef ISR_PERF t = stopwatch_getticks() - t; isr_time += t; if(t>max_isr_time) max_isr_time=t; #endif } static inline void dispatch_general_h(const timer_dev *dev) { #ifdef ISR_PERF uint32_t t=stopwatch_getticks(); #endif uint32_t dsr = dev->regs->DIER & dev->regs->SR; handle_irq(dev, dsr, TIMER_SR_TIF, TIMER_TRG_INTERRUPT); handle_irq(dev, dsr, TIMER_SR_CC2IF, TIMER_CC2_INTERRUPT); handle_irq(dev, dsr, TIMER_SR_CC1IF, TIMER_CC1_INTERRUPT); handle_irq(dev, dsr, TIMER_SR_UIF, TIMER_UPDATE_INTERRUPT); dev->regs->SR &= ~dsr; // handled ALL enabled interrupts! AFTER ISR itself! #ifdef ISR_PERF t = stopwatch_getticks() - t; isr_time += t; if(t>max_isr_time) max_isr_time=t; #endif } // don't count time of basic timer because it used only as timer scheduler's interrupt static inline void dispatch_basic(const timer_dev *dev) { dispatch_single_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF); } /* * Utilities */ static void enable_advanced_irq(const timer_dev *dev, timer_interrupt_id id, uint8_t priority); #define PRIO_DISABLE_FLAG 0x80 static inline void enable_irq(const timer_dev *dev, timer_interrupt_id iid, uint8_t priority) { IRQn_Type irq; switch(dev->id){ case 1: /* 1 - advanced */ enable_advanced_irq(dev, iid, priority); return; case 2: irq=TIM2_IRQn; break; case 3: irq=TIM3_IRQn; break; case 4: irq=TIM4_IRQn; break; case 5: irq=TIM5_IRQn; break; case 6: irq=TIM6_DAC_IRQn; break; case 7: irq=TIM7_IRQn; break; case 8: /* 8 - advanced */ enable_advanced_irq(dev, iid, priority); return; case 9: irq=TIM1_BRK_TIM9_IRQn; break; case 10: irq=TIM1_UP_TIM10_IRQn; break; case 11: irq=TIM1_TRG_COM_TIM11_IRQn; break; case 12: irq=TIM8_BRK_TIM12_IRQn; break; case 13: irq=TIM8_UP_TIM13_IRQn; break; case 14: irq=TIM8_TRG_COM_TIM14_IRQn; break; default: return; } if(priority & PRIO_DISABLE_FLAG){ NVIC_DisableIRQ(irq); }else { enable_nvic_irq(irq, priority); } } static void enable_advanced_irq(const timer_dev *dev, timer_interrupt_id id, uint8_t priority) { uint8_t is_timer1 = (dev->id == 1); IRQn_Type irq=0; switch (id) { case TIMER_UPDATE_INTERRUPT: irq = is_timer1 ? TIM1_UP_TIM10_IRQn : TIM8_UP_TIM13_IRQn; break; case TIMER_CC1_INTERRUPT: case TIMER_CC2_INTERRUPT: case TIMER_CC3_INTERRUPT: case TIMER_CC4_INTERRUPT: irq = is_timer1 ? TIM1_CC_IRQn : TIM8_CC_IRQn; break; case TIMER_COM_INTERRUPT: case TIMER_TRG_INTERRUPT: irq = is_timer1 ? TIM1_TRG_COM_TIM11_IRQn : TIM8_TRG_COM_TIM14_IRQn; break; case TIMER_BREAK_INTERRUPT: irq = is_timer1 ? TIM1_BRK_TIM9_IRQn : TIM8_BRK_TIM12_IRQn; break; } if(!irq) return; if(priority & PRIO_DISABLE_FLAG){ NVIC_DisableIRQ(irq); }else { NVIC_EnableIRQ(irq); NVIC_SetPriority(irq,priority); } } void timer_enable_NVICirq(const timer_dev *dev, uint8_t interrupt, uint8_t priority) { enable_irq(dev,interrupt, priority); } void timer_disable_NVICirq(const timer_dev *dev, uint8_t interrupt){ enable_irq(dev,interrupt, PRIO_DISABLE_FLAG); }