#include "timer.h" extern Clock_t sysclks; //------------------------------------------------------------------------------ static OnTick callback1 = 0; static OnTick callback2 = 0; static OnTick callback3 = 0; static OnTick callback4 = 0; void TIM1_UP_IRQHandler(void) { if (callback1) callback1(); TIM1->SR &= ~0x1F; } void TIM2_IRQHandler(void) { if (callback2) callback2(); TIM2->SR &= ~0x1F; } void TIM3_IRQHandler(void) { if (callback3) callback3(); TIM3->SR &= ~0x1F; } void TIM4_IRQHandler(void) { if (callback4) callback4(); TIM4->SR &= ~0x1F; } //------------------------------------------------------------------------------ int timer_config_cb(TIM_TypeDef* tmr, uint32_t* clk, OnTick cb) { IRQn_Type irqn; uint32_t irq_priority; switch((uint32_t)tmr) { case (uint32_t)TIM1: // get clocks config *clk = sysclks.apb2_timer_freq; // register callback function callback1 = cb; irqn = TIM1_UP_IRQn; //every update irq_priority = TIM1_IRQ_PRIORITY; // enable timer clocking RCC->APB2ENR |= 1<<11; break; case (uint32_t)TIM2: // get clocks config *clk = sysclks.apb1_timer_freq; // register callback function callback2 = cb; irqn = TIM2_IRQn; irq_priority = TIM2_IRQ_PRIORITY; // enable timer clocking RCC->APB1ENR |= 1<<0; break; case (uint32_t)TIM3: // get clocks config *clk = sysclks.apb1_timer_freq; // register callback function callback3 = cb; irqn = TIM3_IRQn; irq_priority = TIM3_IRQ_PRIORITY; // enable timer clocking RCC->APB1ENR |= 1<<1; break; case (uint32_t)TIM4: // get clocks config *clk = sysclks.apb1_timer_freq; // register callback function callback4 = cb; irqn = TIM4_IRQn; irq_priority = TIM4_IRQ_PRIORITY; // enable timer clocking RCC->APB1ENR |= 1<<2; break; default: return -1; } // clear pending interrupts tmr->SR &= !1; // Enable interrupts tmr->DIER = (1<<0); NVIC_SetPriority(irqn,irq_priority); NVIC_EnableIRQ(irqn); return 0; } //------------------------------------------------------------------------------ int timer_wait_ms(TIM_TypeDef* tmr, uint16_t ms, OnTick cb) { uint32_t clk = 0; if(!cb) { //blocking //get clocks config if (tmr == TIM1) { clk = sysclks.apb2_timer_freq; RCC->APB2ENR |= 1<<11; } else { clk = sysclks.apb1_timer_freq; if (tmr == TIM2) RCC->APB1ENR |= 1<<0; else if (tmr == TIM3) RCC->APB1ENR |= 1<<1; else if (tmr == TIM4) RCC->APB1ENR |= 1<<2; else return -1; // no such timer } // set period tmr->ARR = 0xFFFFFFFF; } else { //non-blocking if(timer_config_cb(tmr, &clk, cb)) return -1; // set period tmr->ARR = ms-1; } // set mode tmr->CR1 = (1<<7) | (1<<2); //buffering and update settings tmr->CR1 |= (1<<3); //one pulse mode // set prescaler 1ms tmr->PSC = 8*(clk/1000)-1; //PSC = clk/f - 1 | don't know why 8 times.. timer_start(tmr); if(!cb) { while(tmr->CNT < ms); //waiting for end of delay } return 0; } int timer_wait_us(TIM_TypeDef* tmr, uint16_t us, OnTick cb) { uint32_t clk = 0; if(!cb) { //blocking //get clocks config if (tmr == TIM1) { clk = sysclks.apb2_timer_freq; RCC->APB2ENR |= 1<<11; } else { clk = sysclks.apb1_timer_freq; if (tmr == TIM2) RCC->APB1ENR |= 1<<0; else if (tmr == TIM3) RCC->APB1ENR |= 1<<1; else if (tmr == TIM4) RCC->APB1ENR |= 1<<2; else return -1; // no such timer } // set period tmr->ARR = 0xFFFFFFFF; } else { //non-blocking if(timer_config_cb(tmr, &clk, cb)) return -1; // set period tmr->ARR = us-1; } // set mode tmr->CR1 = (1<<7) | (1<<2); //buffering and update settings tmr->CR1 |= (1<<3); //one pulse mode // set prescaler 1us tmr->PSC = 8*(clk/1000000)-1; //PSC = clk/f - 1 | don't know why 8 times.. timer_start(tmr); if(!cb) { while(tmr->CNT < us); //waiting for end of delay } return 0; } //------------------------------------------------------------------------------ int timer_tick_init(TIM_TypeDef *tmr, uint16_t tick_ms, OnTick cb) { IRQn_Type irqn; uint32_t irq_priority, clk; switch((uint32_t)tmr) { case (uint32_t)TIM1: // get back the clock frequency clk = sysclks.apb2_timer_freq; // register callback function callback1 = cb; irqn = TIM1_UP_IRQn; //every update irq_priority = TIM1_IRQ_PRIORITY; // enable timer clocking RCC->APB2ENR |= 1<<11; break; case (uint32_t)TIM2: // get back the clock frequency clk = sysclks.apb1_timer_freq; // register callback function callback2 = cb; irqn = TIM2_IRQn; irq_priority = TIM2_IRQ_PRIORITY; // enable timer clocking RCC->APB1ENR |= 1<<0; break; case (uint32_t)TIM3: // get back the clock frequency clk = sysclks.apb1_timer_freq; // register callback function callback3 = cb; irqn = TIM3_IRQn; irq_priority = TIM3_IRQ_PRIORITY; // enable timer clocking RCC->APB1ENR |= 1<<1; break; case (uint32_t)TIM4: // get back the clock frequency clk = sysclks.apb1_timer_freq; // register callback function callback4 = cb; irqn = TIM4_IRQn; irq_priority = TIM4_IRQ_PRIORITY; // enable timer clocking RCC->APB1ENR |= 1<<2; break; default: return -1; } // clear pending interrupts tmr->SR &= !1; // set mode tmr->CR1 = (1<<7) | (1<<2); //buffering and update settings tmr->DIER = (1<<0); //Enable interrupts // set prescaler 0.5ms tmr->PSC = 8*(clk/2000)-1; //PSC = clk/f - 1 | don't know why 8 times... // set period if(timer_set_period(tmr, tick_ms)) return -1; if (cb) { NVIC_SetPriority(irqn,irq_priority); NVIC_EnableIRQ(irqn); //unmask IRQ } return 0; } int timer_set_period(TIM_TypeDef *tmr, uint16_t tick) { // set period tmr->ARR = tick*2-1; //tickms = (ARR+1)Tpsc // force update to reset counter and apply prescaler tmr->EGR |= 1; return 0; } void timer_start(TIM_TypeDef *tmr) { // force update to reset counter and prescaler tmr->EGR |= 1; // enable counting tmr->CR1 |= 1; } void timer_stop(TIM_TypeDef *tmr) { // disable counting tmr->CR1 &= !1; } //------------------------------------------------------------------------------ int timer_enc_init(TIM_TypeDef* tmr) { // enable timer switch((uint32_t)tmr) { case (uint32_t)TIM1: RCC->APB2ENR |= 1<<11; break; case (uint32_t)TIM2: RCC->APB1ENR |= 1<<0; break; case (uint32_t)TIM3: RCC->APB1ENR |= 1<<1; break; case (uint32_t)TIM4: RCC->APB1ENR |= 1<<2; break; default: return -1; //no such timer } //TODO set registers at reset value tmr->SMCR |= 0x1; //count on only one edge tmr->ARR = (1 << 16)-1; // map inputs tmr->CCMR1 |= 0x9; tmr->CCMR1 |= 0x9 << 8; // enable input channels and invert them //TODO add an otpion for that tmr->CCER |= 0x3; tmr->CCER |= 0x3 << 4; tmr->CR1 |= 0x1; //enable timer return 0; }