6CH32PWM::CH32PWM(TIM_TypeDef* tim, uint16_t channel,
bool active_high, GPIO_TypeDef* gpio,
7 uint16_t pin, uint32_t pin_remap,
bool complementary)
10 active_high_(active_high),
11 complementary_(complementary),
18bool CH32PWM::OnAPB2(TIM_TypeDef* t)
33bool CH32PWM::IsAdvancedTimer(TIM_TypeDef* t)
48uint32_t CH32PWM::GetTimerClockHz(TIM_TypeDef* t)
50 RCC_ClocksTypeDef c{};
51 RCC_GetClocksFreq(&c);
53 const bool on_apb2 = OnAPB2(t);
54 const uint32_t pclk = on_apb2 ? c.PCLK2_Frequency : c.PCLK1_Frequency;
55 const uint32_t hclk = c.HCLK_Frequency;
57 if (pclk == 0u || hclk == 0u)
return 0u;
60 const uint32_t apb_div = hclk / pclk;
61 const uint32_t timclk = (apb_div > 1u) ? (pclk * 2u) : pclk;
66void CH32PWM::EnableGPIOClock(GPIO_TypeDef* gpio)
69 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
70 else if (gpio == GPIOB)
71 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
72 else if (gpio == GPIOC)
73 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
74 else if (gpio == GPIOD)
75 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
77 else if (gpio == GPIOE)
78 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
82void CH32PWM::EnableTIMClock(TIM_TypeDef* tim)
84 if (tim == TIM1) RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
85#if defined(TIM8) && defined(RCC_APB2Periph_TIM8)
87 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
89#if defined(TIM9) && defined(RCC_APB2Periph_TIM9)
91 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9, ENABLE);
93#if defined(TIM10) && defined(RCC_APB2Periph_TIM10)
94 else if (tim == TIM10)
95 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM10, ENABLE);
97#if defined(TIM2) && defined(RCC_APB1Periph_TIM2)
99 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
101#if defined(TIM3) && defined(RCC_APB1Periph_TIM3)
102 else if (tim == TIM3)
103 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
105#if defined(TIM4) && defined(RCC_APB1Periph_TIM4)
106 else if (tim == TIM4)
107 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
109#if defined(TIM5) && defined(RCC_APB1Periph_TIM5)
110 else if (tim == TIM5)
111 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
113#if defined(TIM6) && defined(RCC_APB1Periph_TIM6)
114 else if (tim == TIM6)
115 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
117#if defined(TIM7) && defined(RCC_APB1Periph_TIM7)
118 else if (tim == TIM7)
119 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
121#if defined(TIM12) && defined(RCC_APB1Periph_TIM12)
122 else if (tim == TIM12)
123 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM12, ENABLE);
125#if defined(TIM13) && defined(RCC_APB1Periph_TIM13)
126 else if (tim == TIM13)
127 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM13, ENABLE);
129#if defined(TIM14) && defined(RCC_APB1Periph_TIM14)
130 else if (tim == TIM14)
131 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE);
135void CH32PWM::ConfigureGPIO()
138 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
141 if (pin_remap_ != 0u)
143 GPIO_PinRemapConfig(pin_remap_, ENABLE);
147 EnableGPIOClock(gpio_);
148 GPIO_InitTypeDef io{};
150 io.GPIO_Speed = GPIO_Speed_50MHz;
151 io.GPIO_Mode = GPIO_Mode_AF_PP;
152 GPIO_Init(gpio_, &io);
157ErrorCode CH32PWM::SetDutyCycle(
float value)
159 if (!tim_)
return ErrorCode::ARG_ERR;
161 if (value < 0.0f) value = 0.0f;
162 if (value > 1.0f) value = 1.0f;
164 const uint32_t arr = ReadARR32(tim_);
165 const uint32_t pulse =
static_cast<uint32_t
>((arr + 1u) * value + 0.5f);
168 return ErrorCode::OK;
173 if (!tim_)
return ErrorCode::ARG_ERR;
174 if (cfg.
frequency == 0u)
return ErrorCode::ARG_ERR;
180 EnableTIMClock(tim_);
182 const uint32_t timclk = GetTimerClockHz(tim_);
183 if (timclk == 0u)
return ErrorCode::INIT_ERR;
187 uint32_t best_psc = 1, best_arr = 0;
189 for (uint32_t psc = 1; psc <= 0xFFFFu; ++psc)
191 const uint32_t arr = timclk / (psc * cfg.
frequency);
192 if (arr == 0u)
break;
201 if (!found || best_arr == 0u)
return ErrorCode::INIT_ERR;
203 TIM_TimeBaseInitTypeDef tb{};
204 tb.TIM_Prescaler =
static_cast<uint16_t
>(best_psc - 1u);
205 tb.TIM_CounterMode = TIM_CounterMode_Up;
206 tb.TIM_Period =
static_cast<uint16_t
>(best_arr - 1u);
207 tb.TIM_ClockDivision = TIM_CKD_DIV1;
208 tb.TIM_RepetitionCounter = 0;
209 TIM_TimeBaseInit(tim_, &tb);
212 TIM_ARRPreloadConfig(tim_, ENABLE);
218 TIM_GenerateEvent(tim_, TIM_EventSource_Update);
221 if (IsAdvancedTimer(tim_))
223 TIM_CtrlPWMOutputs(tim_, ENABLE);
225 return ErrorCode::OK;
228ErrorCode CH32PWM::Enable()
230 if (!tim_)
return ErrorCode::ARG_ERR;
234 if (complementary_ && IsAdvancedTimer(tim_))
236 EnableChannelN(
true);
238 if (IsAdvancedTimer(tim_))
240 TIM_CtrlPWMOutputs(tim_, ENABLE);
242 TIM_Cmd(tim_, ENABLE);
243 return ErrorCode::OK;
246ErrorCode CH32PWM::Disable()
248 if (!tim_)
return ErrorCode::ARG_ERR;
250 if (complementary_ && IsAdvancedTimer(tim_))
252 EnableChannelN(
false);
254 EnableChannel(
false);
256 return ErrorCode::OK;
261void CH32PWM::ApplyCompare(uint32_t pulse)
263 const uint16_t ccr =
static_cast<uint16_t
>(std::min<uint32_t>(pulse, 0xFFFFu));
267 TIM_SetCompare1(tim_, ccr);
270 TIM_SetCompare2(tim_, ccr);
273 TIM_SetCompare3(tim_, ccr);
276 TIM_SetCompare4(tim_, ccr);
283void CH32PWM::OcInitForChannel(uint32_t pulse)
285 TIM_OCInitTypeDef oc{};
286 oc.TIM_OCMode = TIM_OCMode_PWM1;
287 oc.TIM_OutputState = TIM_OutputState_Enable;
288 oc.TIM_Pulse =
static_cast<uint16_t
>(pulse);
289 oc.TIM_OCPolarity = active_high_ ? TIM_OCPolarity_High : TIM_OCPolarity_Low;
291#if defined(TIM_OCNPolarity_High)
292 if (complementary_ && IsAdvancedTimer(tim_))
294 oc.TIM_OutputNState = TIM_OutputNState_Enable;
295 oc.TIM_OCNPolarity = active_high_ ? TIM_OCNPolarity_High : TIM_OCNPolarity_Low;
302 TIM_OC1Init(tim_, &oc);
303 TIM_OC1PreloadConfig(tim_, TIM_OCPreload_Enable);
306 TIM_OC2Init(tim_, &oc);
307 TIM_OC2PreloadConfig(tim_, TIM_OCPreload_Enable);
310 TIM_OC3Init(tim_, &oc);
311 TIM_OC3PreloadConfig(tim_, TIM_OCPreload_Enable);
314 TIM_OC4Init(tim_, &oc);
315 TIM_OC4PreloadConfig(tim_, TIM_OCPreload_Enable);
322void CH32PWM::EnableChannel(
bool en)
324#if defined(TIM_CCx_Enable)
328 TIM_CCxCmd(tim_, TIM_Channel_1, en ? TIM_CCx_Enable : TIM_CCx_Disable);
331 TIM_CCxCmd(tim_, TIM_Channel_2, en ? TIM_CCx_Enable : TIM_CCx_Disable);
334 TIM_CCxCmd(tim_, TIM_Channel_3, en ? TIM_CCx_Enable : TIM_CCx_Disable);
337 TIM_CCxCmd(tim_, TIM_Channel_4, en ? TIM_CCx_Enable : TIM_CCx_Disable);
347void CH32PWM::EnableChannelN(
bool en)
349 if (!IsAdvancedTimer(tim_))
return;
353 TIM_CCxNCmd(tim_, TIM_Channel_1, en ? TIM_CCxN_Enable : TIM_CCxN_Disable);
356 TIM_CCxNCmd(tim_, TIM_Channel_2, en ? TIM_CCxN_Enable : TIM_CCxN_Disable);
359 TIM_CCxNCmd(tim_, TIM_Channel_3, en ? TIM_CCxN_Enable : TIM_CCxN_Disable);
Configuration parameters for PWM. PWM 配置参数。
uint32_t frequency
PWM signal frequency in Hz. PWM 信号的频率(Hz)。