7CH32PWM::CH32PWM(TIM_TypeDef* tim, uint16_t channel,
bool active_high, GPIO_TypeDef* gpio,
8 uint16_t pin, uint32_t pin_remap,
bool complementary)
11 active_high_(active_high),
12 complementary_(complementary),
19bool CH32PWM::OnAPB2(TIM_TypeDef* t)
36bool CH32PWM::IsAdvancedTimer(TIM_TypeDef* t)
53uint32_t CH32PWM::GetTimerClockHz(TIM_TypeDef* t)
55 RCC_ClocksTypeDef c{};
56 RCC_GetClocksFreq(&c);
58 const bool ON_APB2 = OnAPB2(t);
59 const uint32_t PCLK = ON_APB2 ? c.PCLK2_Frequency : c.PCLK1_Frequency;
60 const uint32_t HCLK = c.HCLK_Frequency;
62 if (PCLK == 0u || HCLK == 0u)
68 const uint32_t APB_DIV = HCLK / PCLK;
69 const uint32_t TIMCLK = (APB_DIV > 1u) ? (PCLK * 2u) : PCLK;
74void CH32PWM::EnableGPIOClock(GPIO_TypeDef* gpio)
78 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
80 else if (gpio == GPIOB)
82 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
84 else if (gpio == GPIOC)
86 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
88 else if (gpio == GPIOD)
90 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
93 else if (gpio == GPIOE)
95 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
100void CH32PWM::EnableTIMClock(TIM_TypeDef* tim)
103#if defined(TIM1) && defined(RCC_APB2Periph_TIM1)
106 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
110#if defined(TIM8) && defined(RCC_APB2Periph_TIM8)
113 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
117#if defined(TIM9) && defined(RCC_APB2Periph_TIM9)
120 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9, ENABLE);
124#if defined(TIM10) && defined(RCC_APB2Periph_TIM10)
127 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM10, ENABLE);
131#if defined(TIM2) && defined(RCC_APB1Periph_TIM2)
134 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
138#if defined(TIM3) && defined(RCC_APB1Periph_TIM3)
141 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
145#if defined(TIM4) && defined(RCC_APB1Periph_TIM4)
148 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
152#if defined(TIM5) && defined(RCC_APB1Periph_TIM5)
155 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
159#if defined(TIM6) && defined(RCC_APB1Periph_TIM6)
162 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
166#if defined(TIM7) && defined(RCC_APB1Periph_TIM7)
169 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
173#if defined(TIM12) && defined(RCC_APB1Periph_TIM12)
176 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM12, ENABLE);
180#if defined(TIM13) && defined(RCC_APB1Periph_TIM13)
183 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM13, ENABLE);
187#if defined(TIM14) && defined(RCC_APB1Periph_TIM14)
190 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE);
195void CH32PWM::ConfigureGPIO()
198 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
201 if (pin_remap_ != 0u)
203 GPIO_PinRemapConfig(pin_remap_, ENABLE);
207 EnableGPIOClock(gpio_);
208 GPIO_InitTypeDef io{};
210 io.GPIO_Speed = GPIO_Speed_50MHz;
211 io.GPIO_Mode = GPIO_Mode_AF_PP;
212 GPIO_Init(gpio_, &io);
217ErrorCode CH32PWM::SetDutyCycle(
float value)
221 return ErrorCode::ARG_ERR;
233 const uint32_t ARR = ReadARR32(tim_);
234 const uint32_t PULSE =
static_cast<uint32_t
>((ARR + 1u) * value + 0.5f);
237 return ErrorCode::OK;
240ErrorCode CH32PWM::SetConfig(Configuration cfg)
244 return ErrorCode::ARG_ERR;
246 if (cfg.frequency == 0u)
248 return ErrorCode::ARG_ERR;
255 EnableTIMClock(tim_);
257 const uint32_t TIMCLK = GetTimerClockHz(tim_);
260 return ErrorCode::INIT_ERR;
265 uint32_t best_psc = 1, best_arr = 0;
267 for (uint32_t psc = 1; psc <= 0xFFFFu; ++psc)
269 const uint32_t ARR = TIMCLK / (psc * cfg.frequency);
282 if (!found || best_arr == 0u)
284 return ErrorCode::INIT_ERR;
287 TIM_TimeBaseInitTypeDef tb{};
288 tb.TIM_Prescaler =
static_cast<uint16_t
>(best_psc - 1u);
289 tb.TIM_CounterMode = TIM_CounterMode_Up;
290 tb.TIM_Period =
static_cast<uint16_t
>(best_arr - 1u);
291 tb.TIM_ClockDivision = TIM_CKD_DIV1;
292 tb.TIM_RepetitionCounter = 0;
293 TIM_TimeBaseInit(tim_, &tb);
296 TIM_ARRPreloadConfig(tim_, ENABLE);
302 TIM_GenerateEvent(tim_, TIM_EventSource_Update);
305 if (IsAdvancedTimer(tim_))
307 TIM_CtrlPWMOutputs(tim_, ENABLE);
309 return ErrorCode::OK;
312ErrorCode CH32PWM::Enable()
316 return ErrorCode::ARG_ERR;
321 if (complementary_ && IsAdvancedTimer(tim_))
323 EnableChannelN(
true);
325 if (IsAdvancedTimer(tim_))
327 TIM_CtrlPWMOutputs(tim_, ENABLE);
329 TIM_Cmd(tim_, ENABLE);
330 return ErrorCode::OK;
333ErrorCode CH32PWM::Disable()
337 return ErrorCode::ARG_ERR;
340 if (complementary_ && IsAdvancedTimer(tim_))
342 EnableChannelN(
false);
344 EnableChannel(
false);
346 return ErrorCode::OK;
351void CH32PWM::ApplyCompare(uint32_t pulse)
353 const uint16_t CCR =
static_cast<uint16_t
>(std::min<uint32_t>(pulse, 0xFFFFu));
357 TIM_SetCompare1(tim_, CCR);
360 TIM_SetCompare2(tim_, CCR);
363 TIM_SetCompare3(tim_, CCR);
366 TIM_SetCompare4(tim_, CCR);
373void CH32PWM::OcInitForChannel(uint32_t pulse)
375 TIM_OCInitTypeDef oc{};
376 oc.TIM_OCMode = TIM_OCMode_PWM1;
377 oc.TIM_OutputState = TIM_OutputState_Enable;
378 oc.TIM_Pulse =
static_cast<uint16_t
>(pulse);
379 oc.TIM_OCPolarity = active_high_ ? TIM_OCPolarity_High : TIM_OCPolarity_Low;
381#if defined(TIM_OCNPolarity_High)
382 if (complementary_ && IsAdvancedTimer(tim_))
384 oc.TIM_OutputNState = TIM_OutputNState_Enable;
385 oc.TIM_OCNPolarity = active_high_ ? TIM_OCNPolarity_High : TIM_OCNPolarity_Low;
392 TIM_OC1Init(tim_, &oc);
393 TIM_OC1PreloadConfig(tim_, TIM_OCPreload_Enable);
396 TIM_OC2Init(tim_, &oc);
397 TIM_OC2PreloadConfig(tim_, TIM_OCPreload_Enable);
400 TIM_OC3Init(tim_, &oc);
401 TIM_OC3PreloadConfig(tim_, TIM_OCPreload_Enable);
404 TIM_OC4Init(tim_, &oc);
405 TIM_OC4PreloadConfig(tim_, TIM_OCPreload_Enable);
412void CH32PWM::EnableChannel(
bool en)
414#if defined(TIM_CCx_Enable)
418 TIM_CCxCmd(tim_, TIM_Channel_1, en ? TIM_CCx_Enable : TIM_CCx_Disable);
421 TIM_CCxCmd(tim_, TIM_Channel_2, en ? TIM_CCx_Enable : TIM_CCx_Disable);
424 TIM_CCxCmd(tim_, TIM_Channel_3, en ? TIM_CCx_Enable : TIM_CCx_Disable);
427 TIM_CCxCmd(tim_, TIM_Channel_4, en ? TIM_CCx_Enable : TIM_CCx_Disable);
437void CH32PWM::EnableChannelN(
bool en)
439 if (!IsAdvancedTimer(tim_))
446 TIM_CCxNCmd(tim_, TIM_Channel_1, en ? TIM_CCxN_Enable : TIM_CCxN_Disable);
449 TIM_CCxNCmd(tim_, TIM_Channel_2, en ? TIM_CCxN_Enable : TIM_CCxN_Disable);
452 TIM_CCxNCmd(tim_, TIM_Channel_3, en ? TIM_CCxN_Enable : TIM_CCxN_Disable);
CH32PWM(TIM_TypeDef *tim, uint16_t channel, bool active_high, GPIO_TypeDef *gpio, uint16_t pin, uint32_t pin_remap=0, bool complementary=false)
构造 PWM 对象 / Construct PWM object