31 #include <string_view>
36 #include <cmsis_gcc.h>
52 template<auto Context, u8 Channel,
typename Size>
54 static_assert(Channel >= 1 && Channel <= 4,
"Channel index out of range");
63 if(!hasPwmModule())
return false;
65 case 1: Context->Instance->CCER |= TIM_CCER_CC1E;
break;
66 case 2: Context->Instance->CCER |= TIM_CCER_CC2E;
break;
67 case 3: Context->Instance->CCER |= TIM_CCER_CC3E;
break;
68 case 4: Context->Instance->CCER |= TIM_CCER_CC4E;
break;
69 default: bsp::unreachable();
71 Context->Instance->CR1 = TIM_CR1_CEN;
82 if(!hasPwmModule())
return false;
84 case 1: Context->Instance->CCER &= ~TIM_CCER_CC1E;
break;
85 case 2: Context->Instance->CCER &= ~TIM_CCER_CC2E;
break;
86 case 3: Context->Instance->CCER &= ~TIM_CCER_CC3E;
break;
87 case 4: Context->Instance->CCER &= ~TIM_CCER_CC4E;
break;
88 default: bsp::unreachable();
90 if(Context->Instance->CCER == 0) Context->Instance->CR1 &= ~TIM_CR1_CEN;
101 if(!hasPwmModule())
return false;
104 case 1: Context->Instance->CCER |= TIM_CCER_CC1P;
break;
105 case 2: Context->Instance->CCER |= TIM_CCER_CC2P;
break;
106 case 3: Context->Instance->CCER |= TIM_CCER_CC3P;
break;
107 case 4: Context->Instance->CCER |= TIM_CCER_CC4P;
break;
108 default: bsp::unreachable();
113 case 1: Context->Instance->CCER &= ~TIM_CCER_CC1P;
break;
114 case 2: Context->Instance->CCER &= ~TIM_CCER_CC2P;
break;
115 case 3: Context->Instance->CCER &= ~TIM_CCER_CC3P;
break;
116 case 4: Context->Instance->CCER &= ~TIM_CCER_CC4P;
break;
117 default: bsp::unreachable();
131 if(!hasPwmModule())
return false;
132 dutyCycle = std::abs(dutyCycle);
133 if(dutyCycle > 100) dutyCycle = 100;
134 Size arr = Context->Instance->ARR;
136 if(dutyCycle != 0) ccr = arr / 100 * dutyCycle;
138 case 1: Context->Instance->CCR1 = ccr;
break;
139 case 2: Context->Instance->CCR2 = ccr;
break;
140 case 3: Context->Instance->CCR3 = ccr;
break;
141 case 4: Context->Instance->CCR4 = ccr;
break;
142 default: bsp::unreachable();
154 bool hasPwmModule() const noexcept{
155 if ((Context->Instance == TIM6) ||
156 (Context->Instance == TIM7) ||
157 (Context->Instance == TIM10) ||
158 (Context->Instance == TIM13) ||
159 (Context->Instance == TIM14)) {
175 template<auto Context,
typename Size>
201 if(!hasEncoderModule())
return false;
202 Context->Instance->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E;
203 Context->Instance->CR1 = TIM_CR1_CEN;
214 if(!hasEncoderModule())
return false;
215 Context->Instance->CR1 &= ~TIM_CR1_CEN;
216 Context->Instance->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC2E);
227 return Context->Instance->CNT;
236 Context->Instance->CNT = cnt;
255 Context->Instance->CR1 &= ~TIM_CR1_CEN;
256 Context->Instance->SMCR &= ~(TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1);
261 Context->Instance->CR1 = TIM_CR1_CEN;
271 if(!hasEncoderModule())
return false;
272 Context->Instance->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E;
273 Context->Instance->SMCR |= TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1;
274 Context->Instance->CR1 = TIM_CR1_CEN;
284 bool hasEncoderModule() const noexcept{
285 if ((Context->Instance == TIM1) ||
286 (Context->Instance == TIM2) ||
287 (Context->Instance == TIM3) ||
288 (Context->Instance == TIM4) ||
289 (Context->Instance == TIM5) ||
290 (Context->Instance == TIM8)) {
304 template<auto Context,
typename Size>
312 Context->Instance->CR1 = TIM_CR1_CEN;
319 Context->Instance->CR1 &= ~TIM_CR1_CEN;
326 Context->Instance->CNT = 0;
335 return cntToNanoSeconds(std::numeric_limits<Size>::max());
344 return formatToString(cntToNanoSeconds(std::numeric_limits<Size>::max()));
353 return cntToNanoSeconds(Context->Instance->CNT);
372 std::string buffer(0xFF, 0x00);
373 u32 s = passedTime / 1E9;
374 u16 ms =
static_cast<u32>(passedTime / 1E6) % 1000;
375 u16 us =
static_cast<u32>(passedTime / 1E3) % 1000;
376 u16 ns = passedTime % 1000;
378 snprintf(buffer.data(), buffer.size(),
"%lus %dms %dus %dns", s, ms, us, ns);
392 u64 cntToNanoSeconds(Size cntValue)
const noexcept {
393 float timerFrequency;
395 if ((Context->Instance == TIM1) ||
396 (Context->Instance == TIM8) ||
397 (Context->Instance == TIM9) ||
398 (Context->Instance == TIM10) ||
399 (Context->Instance == TIM11)) {
400 float pclk2 =
static_cast<float>(SystemCoreClock >> APBPrescTable[(RCC->CFGR & RCC_CFGR_PPRE2) >> RCC_CFGR_PPRE2_Pos]);
401 if ((RCC->CFGR & RCC_CFGR_PPRE2) == 0) timerFrequency = pclk2;
402 else timerFrequency = 2 * pclk2;
406 float pclk1 =
static_cast<float>(SystemCoreClock >> APBPrescTable[(RCC->CFGR & RCC_CFGR_PPRE1) >> RCC_CFGR_PPRE1_Pos]);
407 if ((RCC->CFGR & RCC_CFGR_PPRE1) == 0) timerFrequency = pclk1;
408 else timerFrequency = 2 * pclk1;
411 return static_cast<u64>(((cntValue) / timerFrequency) * 1E9);
424 template<auto Context,
typename Size>
468 Context->Instance->CR1 = TIM_CR1_CEN;
475 Context->Instance->CR1 &= ~TIM_CR1_CEN;
485 return Context->Instance->CNT;
494 Context->Instance->CNT = cnt;
504 auto arr = Context->Instance->ARR;
505 auto psc = (Context->Instance->PSC + 1);
506 if(psc == 0) psc = 1;
508 if ((Context->Instance == TIM1) ||
509 (Context->Instance == TIM8) ||
510 (Context->Instance == TIM9) ||
511 (Context->Instance == TIM10) ||
512 (Context->Instance == TIM11)) {
514 u32 pclk2 = (SystemCoreClock >> APBPrescTable[(RCC->CFGR & RCC_CFGR_PPRE2) >> RCC_CFGR_PPRE2_Pos]);
515 if ((RCC->CFGR & RCC_CFGR_PPRE2) == 0)
return (pclk2 / psc) / arr;
516 else return 2 * (pclk2 / psc) / arr;
520 u32 pclk1 = (SystemCoreClock >> APBPrescTable[(RCC->CFGR & RCC_CFGR_PPRE1) >> RCC_CFGR_PPRE1_Pos]);
521 if ((RCC->CFGR & RCC_CFGR_PPRE1) == 0)
return (pclk1 / psc) / arr;
522 else return 2 * (pclk1 / psc) / arr;
542 std::array<float, 4> dutyCycle;
543 dutyCycle[0] = intToDuty(Context->Instance->CCR1);
544 dutyCycle[1] = intToDuty(Context->Instance->CCR2);
545 dutyCycle[2] = intToDuty(Context->Instance->CCR3);
546 dutyCycle[3] = intToDuty(Context->Instance->CCR4);
552 Context->Instance->ARR = resolution;
554 arr = Context->Instance->ARR;
556 if ((Context->Instance == TIM1) ||
557 (Context->Instance == TIM8) ||
558 (Context->Instance == TIM9) ||
559 (Context->Instance == TIM10) ||
560 (Context->Instance == TIM11)) {
561 u32 pclk2 = (SystemCoreClock >> APBPrescTable[(RCC->CFGR & RCC_CFGR_PPRE2) >> RCC_CFGR_PPRE2_Pos]);
562 if ((RCC->CFGR & RCC_CFGR_PPRE2) == 0) timerFrequency = pclk2;
563 else timerFrequency = 2 * pclk2;
567 u32 pclk1 = (SystemCoreClock >> APBPrescTable[(RCC->CFGR & RCC_CFGR_PPRE1) >> RCC_CFGR_PPRE1_Pos]);
568 if ((RCC->CFGR & RCC_CFGR_PPRE1) == 0) timerFrequency = pclk1;
569 else timerFrequency = 2 * pclk1;
572 if((f_hz * arr) > timerFrequency)
return false;
574 psc = std::round((timerFrequency / (f_hz * arr)) - 1);
576 if(psc > 0xFFFF)
return false;
578 Context->Instance->CR1 &= ~TIM_CR1_CEN;
579 Context->Instance->PSC = psc;
583 Context->Instance->CCR1 = dutyToInt(dutyCycle[0]);
584 Context->Instance->CCR2 = dutyToInt(dutyCycle[1]);
585 Context->Instance->CCR3 = dutyToInt(dutyCycle[2]);
586 Context->Instance->CCR4 = dutyToInt(dutyCycle[3]);
588 Context->Instance->CR1 = TIM_CR1_CEN;
603 static constexpr Size dutyToInt(
float dutyCycle){
604 if(dutyCycle > 100) dutyCycle = 100;
605 else if(dutyCycle <= 0)
return 0;
606 Size arr = Context->Instance->ARR;
607 return static_cast<Size
>(arr / 100 * dutyCycle);
616 static constexpr
float intToDuty(Size intDutyCycle){
617 Size arr = Context->Instance->ARR;
618 if(arr == 0)
return 0;
619 return static_cast<float>(intDutyCycle) /
static_cast<float>(arr) * 100.0F;