stm32f1xx_HBL/src/drivers/timer.c
Steins7 4a12fa7a3d Reorganize repository to be used as a library
Project was organized as an application, wich makes it less practical
to include in other projects. A template project may be added back to
make up for the missing files
2023-02-11 21:55:32 +01:00

339 lines
7.1 KiB
C

#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;
}