libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
hpm_gpio.cpp
1#include "hpm_gpio.hpp"
2
3#include <atomic>
4
5#include "hpm_interrupt.h"
6#include "hpm_ioc_regs.h"
7
8using namespace LibXR;
9
17GPIO_Type* HPMGPIO::port_controller_map[HPMGPIO::PORT_COUNT] = {};
18HPMGPIO::PortIrqRouteState HPMGPIO::port_irq_route_map[HPMGPIO::PORT_COUNT] = {};
19
20namespace
21{
22// Serialize shared per-port IRQ routing updates against task/ISR races on the local core.
23std::atomic_flag g_hpm_gpio_irq_route_lock = ATOMIC_FLAG_INIT;
24
25bool HPM_GPIO_IsFastController(GPIO_Type* gpio)
26{
27#if defined(HPM_FGPIO)
28 return gpio == HPM_FGPIO;
29#else
30 (void)gpio;
31 return false;
32#endif
33}
34
35class HPMGPIOIrqRouteGuard
36{
37 public:
38 HPMGPIOIrqRouteGuard()
39 : irq_state_(disable_global_irq(CSR_MSTATUS_MIE_MASK) & CSR_MSTATUS_MIE_MASK)
40 {
41 while (g_hpm_gpio_irq_route_lock.test_and_set(std::memory_order_acquire))
42 {
43 }
44 }
45
46 ~HPMGPIOIrqRouteGuard()
47 {
48 g_hpm_gpio_irq_route_lock.clear(std::memory_order_release);
49 restore_global_irq(irq_state_);
50 }
51
52 HPMGPIOIrqRouteGuard(const HPMGPIOIrqRouteGuard&) = delete;
53 HPMGPIOIrqRouteGuard& operator=(const HPMGPIOIrqRouteGuard&) = delete;
54
55 private:
56 uint32_t irq_state_;
57};
58} // namespace
59
70static inline void HPM_GPIO_ConfigMuxToGPIO(GPIO_Type* gpio, uint32_t port,
71 uint16_t pad_index,
72 bool enable_loopback = true)
73{
74 uint32_t func_ctl = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(0);
75 if (enable_loopback)
76 {
77 func_ctl |= IOC_PAD_FUNC_CTL_LOOP_BACK_MASK;
78 }
79 HPM_IOC->PAD[pad_index].FUNC_CTL = func_ctl;
80
81 // GPIOY 端口需要额外通过 PIOC 选择 SOC GPIO 信号 / GPIOY needs extra PIOC routing.
82#if defined(GPIO_DI_GPIOY) && defined(HPM_PIOC)
83 if (port == GPIO_DI_GPIOY && (gpio == HPM_GPIO0 || HPM_GPIO_IsFastController(gpio)))
84 {
85 HPM_PIOC->PAD[pad_index].FUNC_CTL = IOC_PAD_FUNC_CTL_ALT_SELECT_SET(3);
86 }
87#else
88 (void)gpio;
89 (void)port;
90#endif
91}
92
97HPMGPIO::HPMGPIO(GPIO_Type* gpio, uint32_t port, uint8_t pin, uint32_t irq,
98 uint16_t pad_index)
99 : gpio_(gpio),
100 port_(port),
101 pin_(pin),
102 irq_(irq),
103 pad_index_(pad_index == INVALID_PAD_INDEX ? ResolvePadIndex(gpio, port, pin)
104 : pad_index)
105{
106 if (port_ < PORT_COUNT && pin_ < PIN_COUNT && !HPM_GPIO_IsFastController(gpio_))
107 {
108 map[port_][pin_] = this;
109 if (port_controller_map[port_] == nullptr)
110 {
111 port_controller_map[port_] = gpio_;
112 }
113 }
114}
115
130{
131 if (irq_ == INVALID_IRQ || port_ >= PORT_COUNT || pin_ >= PIN_COUNT)
132 {
133 return ErrorCode::ARG_ERR;
134 }
135 if (HPM_GPIO_IsFastController(gpio_))
136 {
138 }
139
140 HPMGPIOIrqRouteGuard guard;
142 {
143 return ErrorCode::OK;
144 }
145
146 PortIrqRouteState& route = port_irq_route_map[port_];
147 const bool needs_port_irq_enable = (route.enabled_pin_count == 0u);
148 if (!needs_port_irq_enable && (route.controller != gpio_ || route.irq != irq_))
149 {
151 }
152
153 gpio_enable_pin_interrupt(gpio_, port_, pin_);
154
155 if (needs_port_irq_enable)
156 {
157 route.controller = gpio_;
158 route.irq = irq_;
159 intc_m_enable_irq_with_priority(irq_, 1);
160 }
161
162 ++route.enabled_pin_count;
163 interrupt_enabled_ = true;
164 return ErrorCode::OK;
165}
166
179{
180 if (irq_ == INVALID_IRQ || port_ >= PORT_COUNT || pin_ >= PIN_COUNT)
181 {
182 return ErrorCode::ARG_ERR;
183 }
184 if (HPM_GPIO_IsFastController(gpio_))
185 {
187 }
188
189 HPMGPIOIrqRouteGuard guard;
191 {
192 return ErrorCode::OK;
193 }
194
195 gpio_disable_pin_interrupt(gpio_, port_, pin_);
196
197 PortIrqRouteState& route = port_irq_route_map[port_];
198 if (route.enabled_pin_count == 0u)
199 {
200 route = {};
201 interrupt_enabled_ = false;
203 }
204
205 if (route.controller != gpio_ || route.irq != irq_)
206 {
207 interrupt_enabled_ = false;
209 }
210
211 --route.enabled_pin_count;
212 if (route.enabled_pin_count == 0u)
213 {
214 const uint32_t route_irq = route.irq;
215 route = {};
216 intc_m_disable_irq(route_irq);
217 }
218
219 interrupt_enabled_ = false;
220 return ErrorCode::OK;
221}
222
235{
236 if (port_ >= PORT_COUNT || pin_ >= PIN_COUNT)
237 {
238 return ErrorCode::ARG_ERR;
239 }
240
241 switch (config.pull)
242 {
243 case Pull::NONE:
244 case Pull::UP:
245 case Pull::DOWN:
246 break;
247 default:
248 return ErrorCode::ARG_ERR;
249 }
250
251 const bool is_interrupt_direction =
255 if (is_interrupt_direction && HPM_GPIO_IsFastController(gpio_))
256 {
258 }
260 {
261#if !defined(GPIO_SOC_HAS_EDGE_BOTH_INTERRUPT) || (GPIO_SOC_HAS_EDGE_BOTH_INTERRUPT != 1)
263#endif
264 }
265
267 {
268 // 保持接口自洽:先确保 PAD 复用到 GPIO / Keep API self-contained: force GPIO mux
269 // first.
270 HPM_GPIO_ConfigMuxToGPIO(gpio_, port_, pad_index_);
271 }
272
273 switch (config.direction)
274 {
275 case Direction::INPUT:
276 gpio_set_pin_input(gpio_, port_, pin_);
277 break;
280 gpio_set_pin_output(gpio_, port_, pin_);
281 break;
283 gpio_set_pin_input(gpio_, port_, pin_);
284 gpio_config_pin_interrupt(gpio_, port_, pin_, gpio_interrupt_trigger_edge_falling);
285 break;
287 gpio_set_pin_input(gpio_, port_, pin_);
288 gpio_config_pin_interrupt(gpio_, port_, pin_, gpio_interrupt_trigger_edge_rising);
289 break;
291#if defined(GPIO_SOC_HAS_EDGE_BOTH_INTERRUPT) && (GPIO_SOC_HAS_EDGE_BOTH_INTERRUPT == 1)
292 gpio_set_pin_input(gpio_, port_, pin_);
293 gpio_config_pin_interrupt(gpio_, port_, pin_, gpio_interrupt_trigger_edge_both);
294 break;
295#else
297#endif
298 default:
299 return ErrorCode::ARG_ERR;
300 }
301
303 {
304 uint32_t pad_ctl = HPM_IOC->PAD[pad_index_].PAD_CTL;
305
306 // 仅更新上下拉与开漏位,保留其他电气属性 / Update pull + open-drain bits only.
307 pad_ctl &=
308 ~(IOC_PAD_PAD_CTL_PE_MASK | IOC_PAD_PAD_CTL_PS_MASK | IOC_PAD_PAD_CTL_OD_MASK);
309
310 switch (config.pull)
311 {
312 case Pull::NONE:
313 break;
314 case Pull::UP:
315 pad_ctl |= IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1);
316 break;
317 case Pull::DOWN:
318 pad_ctl |= IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(0);
319 break;
320 }
321
323 {
324 pad_ctl |= IOC_PAD_PAD_CTL_OD_SET(1);
325 }
326
327 HPM_IOC->PAD[pad_index_].PAD_CTL = pad_ctl;
328 }
329
330 return ErrorCode::OK;
331}
332
344{
345 if (port_ >= PORT_COUNT || pin_ >= PIN_COUNT)
346 {
347 return ErrorCode::ARG_ERR;
348 }
349
351 {
353 }
354
356 {
358 if (ans != ErrorCode::OK)
359 {
360 return ans;
361 }
362 }
363 else
364 {
365 gpio_disable_pin_interrupt(gpio_, port_, pin_);
366 }
367
368 gpio_set_pin_input(gpio_, port_, pin_);
369
370 HPM_IOC->PAD[pad_index_].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK;
371
372 uint32_t pad_ctl = HPM_IOC->PAD[pad_index_].PAD_CTL;
373 pad_ctl &= ~(IOC_PAD_PAD_CTL_PE_MASK | IOC_PAD_PAD_CTL_OD_MASK);
374 HPM_IOC->PAD[pad_index_].PAD_CTL = pad_ctl;
375
376 return ErrorCode::OK;
377}
378
393void HPMGPIO::CheckInterrupt(uint32_t port)
394{
395 if (port >= PORT_COUNT)
396 {
397 return;
398 }
399
400 GPIO_Type* controller = port_controller_map[port];
401 if (controller == nullptr)
402 {
403 return;
404 }
405
406 const uint32_t flags = gpio_get_port_interrupt_flags(controller, port);
407 if (flags == 0u)
408 {
409 return;
410 }
411
412 for (uint8_t pin = 0; pin < PIN_COUNT; ++pin)
413 {
414 if ((flags & (1u << pin)) == 0u)
415 {
416 continue;
417 }
418
419 gpio_clear_pin_interrupt_flag(controller, port, pin);
420 if (auto* gpio = map[port][pin]; gpio != nullptr && gpio->interrupt_enabled_)
421 {
422 gpio->callback_.Run(true);
423 }
424 }
425}
426
430uint16_t HPMGPIO::ResolvePadIndex(GPIO_Type* gpio, uint32_t port, uint8_t pin)
431{
432 if (gpio != HPM_GPIO0 && !HPM_GPIO_IsFastController(gpio))
433 {
434 return INVALID_PAD_INDEX;
435 }
436
437 switch (port)
438 {
439#if defined(GPIO_DI_GPIOA) && defined(IOC_PAD_PA00)
440 case GPIO_DI_GPIOA:
441 return static_cast<uint16_t>(IOC_PAD_PA00 + pin);
442#endif
443#if defined(GPIO_DI_GPIOB) && defined(IOC_PAD_PB00)
444 case GPIO_DI_GPIOB:
445 return static_cast<uint16_t>(IOC_PAD_PB00 + pin);
446#endif
447#if defined(GPIO_DI_GPIOX) && defined(IOC_PAD_PX00)
448 case GPIO_DI_GPIOX:
449 return pin < 8u ? static_cast<uint16_t>(IOC_PAD_PX00 + pin) : INVALID_PAD_INDEX;
450#endif
451#if defined(GPIO_DI_GPIOY) && defined(IOC_PAD_PY00)
452 case GPIO_DI_GPIOY:
453 return pin < 8u ? static_cast<uint16_t>(IOC_PAD_PY00 + pin) : INVALID_PAD_INDEX;
454#endif
455 default:
456 return INVALID_PAD_INDEX;
457 }
458}
459
464extern "C" void libxr_hpm_gpio_check_interrupt(uint32_t port)
465{
467}
@ OUTPUT_PUSH_PULL
推挽输出模式。Push-pull output mode.
@ RISING_INTERRUPT
上升沿中断模式。Rising edge interrupt mode.
@ FALL_RISING_INTERRUPT
双沿触发中断模式。Both edge interrupt mode.
@ OUTPUT_OPEN_DRAIN
开漏输出模式。Open-drain output mode.
@ INPUT
输入模式。Input mode.
@ FALL_INTERRUPT
下降沿中断模式。Falling edge interrupt mode.
@ NONE
无上拉或下拉。No pull-up or pull-down.
@ DOWN
下拉模式。Pull-down mode.
@ UP
上拉模式。Pull-up mode.
HPM 平台 GPIO 驱动实现 / GPIO driver implementation for HPM platform.
Definition hpm_gpio.hpp:60
GPIO_Type * gpio_
GPIO 控制器实例 / GPIO controller instance.
Definition hpm_gpio.hpp:241
ErrorCode EnableInterrupt() override
使能当前引脚中断 / Enable GPIO interrupt for current pin.
Definition hpm_gpio.cpp:129
static constexpr uint32_t INVALID_IRQ
无效 IRQ 标记 / Invalid IRQ marker.
Definition hpm_gpio.hpp:206
static constexpr uint32_t PORT_COUNT
支持的端口数量 / Supported port count.
Definition hpm_gpio.hpp:203
static constexpr uint16_t INVALID_PAD_INDEX
无效 PAD 标记 / Invalid PAD marker.
Definition hpm_gpio.hpp:207
ErrorCode SetAnalogHighImpedance()
将当前 PAD 配置为模拟高阻 / Configure current pad to analog high-impedance.
Definition hpm_gpio.cpp:343
static uint16_t ResolvePadIndex(GPIO_Type *gpio, uint32_t port, uint8_t pin)
根据控制器与端口引脚推导 IOC PAD 编号 / Resolve IOC PAD index from controller/port/pin tuple.
Definition hpm_gpio.cpp:430
bool interrupt_enabled_
当前 pin IRQ 使能状态 / Per-instance IRQ enabled flag.
Definition hpm_gpio.hpp:246
ErrorCode SetConfig(Configuration config) override
配置当前引脚模式 / Configure GPIO mode for current pin.
Definition hpm_gpio.cpp:234
uint16_t pad_index_
IOC PAD 编号 / IOC PAD index.
Definition hpm_gpio.hpp:245
static void CheckInterrupt(uint32_t port)
分发某一端口的 GPIO 中断回调 / Dispatch GPIO interrupt callbacks for one port.
Definition hpm_gpio.cpp:393
uint32_t irq_
当前 port 对应 IRQ 号 / IRQ number for the current port.
Definition hpm_gpio.hpp:244
ErrorCode DisableInterrupt() override
失能当前引脚中断 / Disable GPIO interrupt for current pin.
Definition hpm_gpio.cpp:178
static constexpr uint32_t PIN_COUNT
每个端口引脚数 / Pins per port.
Definition hpm_gpio.hpp:205
HPMGPIO(GPIO_Type *gpio, uint32_t port, uint8_t pin, uint32_t irq=INVALID_IRQ, uint16_t pad_index=INVALID_PAD_INDEX)
构造 HPM GPIO 对象 / Construct an HPM GPIO object.
Definition hpm_gpio.cpp:97
uint8_t pin_
GPIO 引脚号 / GPIO pin index.
Definition hpm_gpio.hpp:243
uint32_t port_
GPIO 端口号 / GPIO port index.
Definition hpm_gpio.hpp:242
static HPMGPIO * map[PORT_COUNT][PIN_COUNT]
GPIO 对象映射表 / GPIO object dispatch map.
Definition hpm_gpio.hpp:237
HPM GPIO 驱动适配头文件 / Adapter header for the HPM GPIO driver.
LibXR 命名空间
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举
@ STATE_ERR
状态错误 | State error
@ NOT_SUPPORT
不支持 | Not supported
@ OK
操作成功 | Operation successful
@ ARG_ERR
参数错误 | Argument error
存储 GPIO 配置参数的结构体。Structure storing GPIO configuration parameters.
Definition gpio.hpp:46
Pull pull
GPIO 上拉/下拉配置。GPIO pull-up/pull-down configuration.
Definition gpio.hpp:48
Direction direction
GPIO 引脚方向。GPIO pin direction.
Definition gpio.hpp:47
端口级 IRQ 路由状态 / Shared port-level IRQ routing state.
Definition hpm_gpio.hpp:218