OpenSolo/artoo/src/stm32/hwtimer.cpp

102 lines
2.8 KiB
C++

#include "hwtimer.h"
bool ALWAYS_INLINE IS_ADVANCED(volatile TIM_t *t) {
return t == &TIM1 || t == &TIM8;
}
void HwTimer::init(uint16_t period_, uint16_t prescaler) const
{
if (tim == &TIM1) {
RCC.APB2ENR |= (1 << 11); // TIM1 enable
RCC.APB2RSTR = (1 << 11); // TIM1 reset
RCC.APB2RSTR = 0;
} else if (tim >= &TIM2 && tim <= &TIM7) {
unsigned bit = 1 << ((((uintptr_t)tim) >> 10) & 7);
RCC.APB1ENR |= bit; // TIM2-TIM7 enable
RCC.APB1RSTR = bit; // TIM2-TIM7 reset
RCC.APB1RSTR = 0;
}
// Timer configuration
tim->PSC = prescaler;
tim->ARR = period_;
if (IS_ADVANCED(tim)) {
tim->BDTR = (1 << 15); // MOE - main output enable
}
tim->DIER = 0;
tim->CR2 = 0;
tim->CCER = 0;
tim->EGR = 1;
tim->SR = 0; // clear status register
tim->CR1 = (1 << 7) | // ARPE - auto reload preload enable
(1 << 2) | // URS - update request source
(1 << 0); // EN - enable
}
void HwTimer::deinit() const
{
tim->CR1 = 0; // control disabled
tim->DIER = 0; // IRQs disabled
tim->SR = 0; // clear status
if (tim == &TIM2) {
RCC.APB1ENR &= ~(1 << 0); // TIM2 disable
}
else if (tim == &TIM3) {
RCC.APB1ENR &= ~(1 << 1); // TIM3 disable
}
else if (tim == &TIM4) {
RCC.APB1ENR &= ~(1 << 2); // TIM4 disable
}
else if (tim == &TIM5) {
RCC.APB1ENR &= ~(1 << 3); // TIM5 disable
}
else if (tim == &TIM1) {
RCC.APB2ENR &= ~(1 << 11); // TIM1 disable
}
}
// channels are numbered 1-4
void HwTimer::configureChannelAsOutput(int ch, Polarity polarity, TimerMode timmode, OutputMode outmode, DmaMode dmamode) const
{
uint8_t mode, pol;
(void)dmamode;
mode = (1 << 3) | // OCxPE - output compare preload enable
(timmode << 4); // OCxM - output compare mode
if (ch <= 2) {
tim->CCMR1 |= mode << ((ch - 1) * 8);
}
else {
tim->CCMR2 |= mode << ((ch - 3) * 8);
}
pol = ((unsigned)polarity << 1); // enable OCxE (and OCxP based on polarity)
if (IS_ADVANCED(tim) && outmode == ComplementaryOutput) {
pol |= 1 << 2; // enable OCxNE
}
tim->compareCapRegs[ch - 1].CCR = 0;
tim->CCER |= (pol << ((ch - 1) * 4));
}
void HwTimer::configureChannelAsInput(int ch, InputCaptureEdge edge, uint8_t filterFreq, uint8_t prescaler) const
{
uint8_t mode = (1 << 0) | // configured as input, mapped on TI1
((filterFreq & 0xF) << 4) |
((prescaler & 0x3) << 2);
if (ch <= 2) {
tim->CCMR1 |= mode << ((ch - 1) * 8);
}
else {
tim->CCMR2 |= mode << ((ch - 3) * 8);
}
tim->CCER |= edge << ((ch - 1) * 4);
}