libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
hpm_pwm.cpp
1#include "hpm_pwm.hpp"
2
3#if __has_include("board.h")
4#include "board.h"
5#define LIBXR_HPM_PWM_HAS_BOARD_HELPER 1
6#else
7#define LIBXR_HPM_PWM_HAS_BOARD_HELPER 0
8#endif
9
10using namespace LibXR;
11
12uint8_t HPMPWM::ResolveGptmrReloadCmpIndex(uint8_t duty_cmp_index)
13{
14 if (duty_cmp_index >= GPTMR_CH_CMP_COUNT)
15 {
16 return kInvalidCmpIndex;
17 }
18 return static_cast<uint8_t>(duty_cmp_index == 0u ? 1u : 0u);
19}
20
31HPMPWM::HPMPWM(LibXRHpmPwmType* pwm, clock_name_t clock, uint8_t pwm_index,
32 uint8_t cmp_index, bool invert, bool auto_board_init)
33 : pwm_(pwm),
34 gptmr_(reinterpret_cast<GPTMR_Type*>(pwm)),
35 clock_(clock),
36 pwm_index_(pwm_index),
37 cmp_index_(cmp_index),
38 invert_(invert),
39 auto_board_init_(auto_board_init),
40 reload_(0),
41 configured_(false)
42{
43}
44
45ErrorCode HPMPWM::SetDutyCycle(float value)
46{
47 if (!configured_)
48 {
49 return ErrorCode::INIT_ERR;
50 }
51
52 if (value < 0.0f)
53 {
54 value = 0.0f;
55 }
56 else if (value > 1.0f)
57 {
58 value = 1.0f;
59 }
60
61#if LIBXR_HPM_PWM_SUPPORTED
62 const float duty_percent = value * 100.0f;
63 if (pwm_update_duty_edge_aligned(pwm_, cmp_index_, duty_percent) != status_success)
64 {
65 return ErrorCode::FAILED;
66 }
67#elif LIBXR_HPM_GPTMR_PWM_FALLBACK
68 // GPTMR 比较值不允许落在 0 或 reload,避免输出退化成常高/常低。
69 // Keep compare away from 0/reload to avoid constant-high/constant-low output.
70 uint32_t cmp = static_cast<uint32_t>(static_cast<float>(reload_) * value);
71 if (cmp == 0u)
72 {
73 cmp = 1u;
74 }
75 else if (cmp >= reload_)
76 {
77 cmp = reload_ - 1u;
78 }
79 gptmr_update_cmp(gptmr_, pwm_index_, cmp_index_, cmp);
80#else
81 (void)value;
82 return ErrorCode::NOT_SUPPORT;
83#endif
84
85 return ErrorCode::OK;
86}
87
89{
90 if (config.frequency == 0u)
91 {
92 return ErrorCode::ARG_ERR;
93 }
94
95 uint32_t clock_hz = 0u;
96
97#if LIBXR_HPM_GPTMR_PWM_FALLBACK && LIBXR_HPM_PWM_HAS_BOARD_HELPER
98 if (auto_board_init_ && gptmr_ != nullptr)
99 {
100 // 为了与 STM32 风格一致,应用层可不显式调用 board_init_*。
101 // To keep STM32-like app style, board_init_* can be hidden inside driver.
102 clock_hz = board_init_gptmr_clock(gptmr_);
103 board_init_gptmr_channel_pin(gptmr_, pwm_index_, true);
104 }
105#endif
106
107 if (clock_hz == 0u)
108 {
109 clock_hz = clock_get_frequency(clock_);
110 }
111
112 if (clock_hz == 0u)
113 {
114 return ErrorCode::INIT_ERR;
115 }
116
117 uint32_t reload = clock_hz / config.frequency;
118 if (reload == 0u || reload > 0xFFFFFFu)
119 {
120 return ErrorCode::INIT_ERR;
121 }
122 reload_ = reload;
123
124#if LIBXR_HPM_PWM_SUPPORTED
125 pwm_stop_counter(pwm_);
126
127 pwm_config_t pwm_config{};
128 pwm_cmp_config_t cmp_config{};
129
130 pwm_get_default_pwm_config(pwm_, &pwm_config);
131 pwm_get_default_cmp_config(pwm_, &cmp_config);
132
133 pwm_config.enable_output = true;
134 pwm_config.invert_output = invert_;
135 pwm_config.dead_zone_in_half_cycle = 0;
136
137 pwm_set_reload(pwm_, 0, reload_);
138 pwm_set_start_count(pwm_, 0, 0);
139
140 cmp_config.mode = pwm_cmp_mode_output_compare;
141 cmp_config.cmp = reload_ + 1;
142 cmp_config.update_trigger = pwm_shadow_register_update_on_modify;
143
144 if (pwm_setup_waveform(pwm_, pwm_index_, &pwm_config, cmp_index_, &cmp_config, 1) !=
145 status_success)
146 {
147 return ErrorCode::INIT_ERR;
148 }
149
150 pwm_issue_shadow_register_lock_event(pwm_);
151#elif LIBXR_HPM_GPTMR_PWM_FALLBACK
152 if (gptmr_ == nullptr)
153 {
154 return ErrorCode::ARG_ERR;
155 }
156
157 const uint8_t reload_cmp_index = ResolveGptmrReloadCmpIndex(cmp_index_);
158 if (reload_cmp_index == kInvalidCmpIndex)
159 {
160 return ErrorCode::ARG_ERR;
161 }
162
163 // 重新配置前先停计数器,避免切换参数时输出毛刺。
164 // Stop counter before reconfiguration to avoid output glitches.
165 gptmr_stop_counter(gptmr_, pwm_index_);
166
167 gptmr_channel_config_t cfg;
168 gptmr_channel_get_default_config(gptmr_, &cfg);
169 cfg.mode = gptmr_work_mode_no_capture;
170 cfg.cmp_initial_polarity_high = invert_;
171 cfg.enable_cmp_output = true;
172 cfg.reload = reload_;
173 cfg.cmp[cmp_index_] = reload_ / 2u;
174 cfg.cmp[reload_cmp_index] = reload_;
175
176 if (gptmr_channel_config(gptmr_, pwm_index_, &cfg, false) != status_success)
177 {
178 return ErrorCode::INIT_ERR;
179 }
180 gptmr_channel_reset_count(gptmr_, pwm_index_);
181#else
182 return ErrorCode::NOT_SUPPORT;
183#endif
184
185 configured_ = true;
186 return ErrorCode::OK;
187}
188
189ErrorCode HPMPWM::Enable()
190{
191 if (!configured_)
192 {
193 return ErrorCode::INIT_ERR;
194 }
195
196#if LIBXR_HPM_PWM_SUPPORTED
197 pwm_start_counter(pwm_);
198#elif LIBXR_HPM_GPTMR_PWM_FALLBACK
199 gptmr_start_counter(gptmr_, pwm_index_);
200#else
201 return ErrorCode::NOT_SUPPORT;
202#endif
203
204 return ErrorCode::OK;
205}
206
208{
209#if LIBXR_HPM_PWM_SUPPORTED
210 pwm_stop_counter(pwm_);
211#elif LIBXR_HPM_GPTMR_PWM_FALLBACK
212 gptmr_stop_counter(gptmr_, pwm_index_);
213#else
214 return ErrorCode::NOT_SUPPORT;
215#endif
216 return ErrorCode::OK;
217}
HPMPWM(LibXRHpmPwmType *pwm, clock_name_t clock, uint8_t pwm_index, uint8_t cmp_index, bool invert=false, bool auto_board_init=true)
构造 HPM PWM 对象 / Construct an HPM PWM object.
Definition hpm_pwm.cpp:31
ErrorCode Disable() override
停止 PWM 输出 / Stop PWM output.
Definition hpm_pwm.cpp:207
ErrorCode SetDutyCycle(float value) override
设置占空比 / Set PWM duty cycle.
Definition hpm_pwm.cpp:45
ErrorCode Enable() override
启动 PWM 输出 / Start PWM output.
Definition hpm_pwm.cpp:189
ErrorCode SetConfig(Configuration config) override
配置 PWM 频率 / Configure PWM frequency.
Definition hpm_pwm.cpp:88
LibXR 命名空间
Definition ch32_can.hpp:14
Configuration parameters for PWM. PWM 配置参数。
Definition pwm.hpp:23
uint32_t frequency
PWM signal frequency in Hz. PWM 信号的频率(Hz)。
Definition pwm.hpp:24