libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
stm32_pwm.cpp
1#include "stm32_pwm.hpp"
2
3#ifdef HAL_TIM_MODULE_ENABLED
4
5using namespace LibXR;
6
7#if defined(STM32H5)
8namespace
9{
10uint32_t GetH5TimerClock(uint32_t peripheral_clock, uint32_t apb_prescaler)
11{
12 const bool timpre = (RCC->CFGR1 & RCC_CFGR1_TIMPRE) != 0U;
13 // APB 编码 0..3 为不分频,4 为二分频,5 为四分频。
14 // APB encodings 0..3 mean divide by one, 4 by two, and 5 by four.
15 if (apb_prescaler <= (timpre ? 5U : 4U))
16 {
17 return HAL_RCC_GetHCLKFreq();
18 }
19 return peripheral_clock * (timpre ? 4U : 2U);
20}
21} // namespace
22#endif
23
24#if defined(STM32H7)
25namespace
26{
27uint32_t GetH7TimerClock(uint32_t peripheral_clock)
28{
29 const uint32_t hclk = HAL_RCC_GetHCLKFreq();
30 const uint32_t multiplier = (RCC->CFGR & RCC_CFGR_TIMPRE) != 0U ? 4U : 2U;
31 // APB 分频为 1/2/4/8/16;TIMPRE 倍频后的时钟不超过 HCLK。
32 // APB divisors are 1/2/4/8/16; the TIMPRE multiplier is capped at HCLK.
33 // 使用 HAL 解析 PCLK,兼容 D2CFGR 和 CDCFGR 的 H7 型号。
34 // Let HAL resolve PCLK for both D2CFGR and CDCFGR H7 variants.
35 const uint32_t timer_clock = peripheral_clock * multiplier;
36 return timer_clock < hclk ? timer_clock : hclk;
37}
38} // namespace
39#endif
40
41STM32PWM::STM32PWM(TIM_HandleTypeDef* htim, uint32_t channel, bool complementary)
42 : htim_(htim), channel_(channel), complementary_(complementary)
43{
44}
45
47{
48 if (value < 0.0f)
49 {
50 value = 0.0f;
51 }
52 else if (value > 1.0f)
53 {
54 value = 1.0f;
55 }
56
57 uint32_t pulse =
58 static_cast<uint32_t>(static_cast<float>(htim_->Init.Period + 1) * value);
59
60 // 按通道直接写比较寄存器,映射与 __HAL_TIM_SET_COMPARE 相同(未列出的通道值写最后一个
61 // 寄存器)。HAL 宏用条件表达式取用 volatile 赋值的结果,C++20 下会产生弃用警告。
62 // Write the compare register of the channel directly, with the same mapping as
63 // __HAL_TIM_SET_COMPARE (an unlisted channel value writes the last register). The HAL
64 // macro uses the result of a volatile assignment in a conditional expression, which is
65 // deprecated in C++20.
66 switch (channel_)
67 {
68 case TIM_CHANNEL_1:
69 htim_->Instance->CCR1 = pulse;
70 break;
71 case TIM_CHANNEL_2:
72 htim_->Instance->CCR2 = pulse;
73 break;
74 case TIM_CHANNEL_3:
75 htim_->Instance->CCR3 = pulse;
76 break;
77#if defined(TIM_CHANNEL_5) && defined(TIM_CHANNEL_6)
78 case TIM_CHANNEL_4:
79 htim_->Instance->CCR4 = pulse;
80 break;
81 case TIM_CHANNEL_5:
82 htim_->Instance->CCR5 = pulse;
83 break;
84 default:
85 htim_->Instance->CCR6 = pulse;
86 break;
87#else
88 default:
89 htim_->Instance->CCR4 = pulse;
90 break;
91#endif
92 }
93
94 return ErrorCode::OK;
95}
96
98{
99 uint32_t clock_freq = 0; // NOLINT
100
101#if defined(STM32F0) || defined(STM32G0)
102 // STM32F0 and STM32 G0 do not have PCLK1/PCLK2,use HCLK as reference clock
103 clock_freq = HAL_RCC_GetHCLKFreq();
104#else
105 uint32_t& target_freq = config.frequency;
106 if (target_freq == 0)
107 {
108 return ErrorCode::ARG_ERR;
109 }
110 else if (
111#if defined(TIM1)
112 htim_->Instance == TIM1 ||
113#endif
114#if defined(TIM8)
115 htim_->Instance == TIM8 ||
116#endif
117#if defined(TIM9)
118 htim_->Instance == TIM9 ||
119#endif
120#if defined(TIM10)
121 htim_->Instance == TIM10 ||
122#endif
123#if defined(TIM11)
124 htim_->Instance == TIM11 ||
125#endif
126#if defined(TIM15)
127 htim_->Instance == TIM15 ||
128#endif
129#if defined(TIM16)
130 htim_->Instance == TIM16 ||
131#endif
132#if defined(TIM17)
133 htim_->Instance == TIM17 ||
134#endif
135#if defined(TIM20)
136 htim_->Instance == TIM20 ||
137#endif
138 false)
139 {
140 clock_freq = HAL_RCC_GetPCLK2Freq();
141#if defined(STM32H5)
142 clock_freq = GetH5TimerClock(clock_freq,
143 (RCC->CFGR2 & RCC_CFGR2_PPRE2) >> RCC_CFGR2_PPRE2_Pos);
144#elif defined(STM32H7)
145 clock_freq = GetH7TimerClock(clock_freq);
146#elif defined(RCC_CFGR_PPRE2)
147 if ((RCC->CFGR & RCC_CFGR_PPRE2) != RCC_CFGR_PPRE2_DIV1)
148 {
149 clock_freq *= 2;
150 }
151#endif
152 }
153 else if (
154#if defined(TIM2)
155 htim_->Instance == TIM2 ||
156#endif
157#if defined(TIM3)
158 htim_->Instance == TIM3 ||
159#endif
160#if defined(TIM4)
161 htim_->Instance == TIM4 ||
162#endif
163#if defined(TIM5)
164 htim_->Instance == TIM5 ||
165#endif
166#if defined(TIM6)
167 htim_->Instance == TIM6 ||
168#endif
169#if defined(TIM7)
170 htim_->Instance == TIM7 ||
171#endif
172#if defined(TIM12)
173 htim_->Instance == TIM12 ||
174#endif
175#if defined(TIM13)
176 htim_->Instance == TIM13 ||
177#endif
178#if defined(TIM14)
179 htim_->Instance == TIM14 ||
180#endif
181 false)
182 {
183 clock_freq = HAL_RCC_GetPCLK1Freq();
184#if defined(STM32H5)
185 clock_freq = GetH5TimerClock(clock_freq,
186 (RCC->CFGR2 & RCC_CFGR2_PPRE1) >> RCC_CFGR2_PPRE1_Pos);
187#elif defined(STM32H7)
188 clock_freq = GetH7TimerClock(clock_freq);
189#elif defined(RCC_CFGR_PPRE1)
190 if ((RCC->CFGR & RCC_CFGR_PPRE1) != RCC_CFGR_PPRE1_DIV1)
191 {
192 clock_freq *= 2;
193 }
194#endif
195 }
196 else
197 {
199 }
200#endif
201
202 if (clock_freq == 0)
203 {
204 return ErrorCode::INIT_ERR;
205 }
206
207 bool found = false;
208
209 uint32_t prescaler = 1;
210 uint32_t period = 0;
211
212 for (prescaler = 1; prescaler <= 0xFFFF; ++prescaler)
213 {
214 uint32_t temp_period = clock_freq / (prescaler * config.frequency);
215 if (temp_period <= 0x10000)
216 {
217 period = temp_period;
218 found = true;
219 break;
220 }
221 }
222
223 if (!found || period == 0)
224 {
225 return ErrorCode::INIT_ERR;
226 }
227
228 htim_->Init.Prescaler = prescaler - 1;
229 htim_->Init.Period = period - 1;
230
231 if (HAL_TIM_PWM_Init(htim_) != HAL_OK)
232 {
233 return ErrorCode::INIT_ERR;
234 }
235 return ErrorCode::OK;
236}
237
239{
240 if (!complementary_)
241 {
242 if (HAL_TIM_PWM_Start(htim_, channel_) != HAL_OK)
243 {
244 return ErrorCode::FAILED;
245 }
246 }
247 else
248 {
249 if (HAL_TIMEx_PWMN_Start(htim_, channel_) != HAL_OK)
250 {
251 return ErrorCode::FAILED;
252 }
253 }
254 return ErrorCode::OK;
255}
256
258{
259 if (!complementary_)
260 {
261 if (HAL_TIM_PWM_Stop(htim_, channel_) != HAL_OK)
262 {
263 return ErrorCode::FAILED;
264 }
265 }
266 else
267 {
268 if (HAL_TIMEx_PWMN_Stop(htim_, channel_) != HAL_OK)
269 {
270 return ErrorCode::FAILED;
271 }
272 }
273 return ErrorCode::OK;
274}
275
276#endif
ErrorCode SetConfig(Configuration config) override
配置 PWM 参数 / Configures the PWM settings.
Definition stm32_pwm.cpp:97
ErrorCode Disable() override
禁用 PWM 输出 / Disables the PWM output.
STM32PWM(TIM_HandleTypeDef *htim, uint32_t channel, bool complementary=false)
构造 PWM 对象 / Construct PWM object
Definition stm32_pwm.cpp:41
ErrorCode SetDutyCycle(float value) override
设置 PWM 信号的占空比 / Sets the duty cycle of the PWM signal.
Definition stm32_pwm.cpp:46
ErrorCode Enable() override
启用 PWM 输出 / Enables the PWM output.
LibXR 命名空间 / LibXR namespace.
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ INIT_ERR
初始化错误 / Initialization error
@ NOT_SUPPORT
不支持 / Not supported
@ FAILED
操作失败 / Operation failed
@ OK
操作成功 / Operation successful
@ ARG_ERR
参数错误 / Argument error
PWM 配置参数 / Configuration parameters for PWM.
Definition pwm.hpp:23
uint32_t frequency
PWM 信号的频率(Hz) / PWM signal frequency in Hz.
Definition pwm.hpp:24