libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
mspm0_gpio.cpp
1#include "mspm0_gpio.hpp"
2
3#include "mspm0_group1_shared.hpp"
4
5using namespace LibXR;
6
7MSPM0GPIO* MSPM0GPIO::instance_map_[MAX_PORTS][32] = {{nullptr}};
8
16static constexpr uint32_t MSPM0_GPIO_GetPolarityMask(uint8_t pin, // NOLINT
17 LibXR::GPIO::Direction direction)
18{
19 uint32_t config_bits = 0;
20 switch (direction)
21 {
23 config_bits = GPIO_POLARITY15_0_DIO0_RISE;
24 break;
26 config_bits = GPIO_POLARITY15_0_DIO0_FALL;
27 break;
29 config_bits = GPIO_POLARITY15_0_DIO0_RISE_FALL;
30 break;
31 default:
32 return 0;
33 }
34
35 uint32_t shift = (pin % 16) * 2;
36 return config_bits << shift;
37}
38#ifdef GPIOA_BASE
39static void gpioa_irq_thunk() { LibXR::MSPM0GPIO::OnInterrupt(GPIOA); }
40#endif
41
42#ifdef GPIOB_BASE
43static void gpiob_irq_thunk() { LibXR::MSPM0GPIO::OnInterrupt(GPIOB); }
44#endif
45
46#ifdef GPIOC_BASE
47static void gpioc_irq_thunk() { LibXR::MSPM0GPIO::OnInterrupt(GPIOC); }
48#endif
49
50MSPM0GPIO::MSPM0GPIO(GPIO_Regs* port, uint32_t pin_mask, uint32_t pincm)
51 : port_(port), pin_mask_(pin_mask), pincm_(pincm)
52{
53 int pin_idx = __builtin_ctz(pin_mask_);
54 int port_idx = GetPortIndex(reinterpret_cast<uint32_t>(port_));
55
56 ASSERT(port_idx >= 0 && port_idx < LibXR::MAX_PORTS);
57 // 端口来自固定配置,前提已由 ASSERT 检查;关闭检查时告知编译器该前提成立。
58 // The port is fixed configuration checked by the ASSERT above; with checks off, tell
59 // the compiler that the precondition holds.
60 if (port_idx < 0 || port_idx >= LibXR::MAX_PORTS)
61 {
62 __builtin_unreachable();
63 }
64 ASSERT(instance_map_[port_idx][pin_idx] == nullptr);
65
66 instance_map_[port_idx][pin_idx] = this;
67
68 switch (port_idx)
69 {
70 case 0:
71#ifdef GPIOA_BASE
72 LibXR::MSPM0Group1Shared::RegisterGPIOA(&gpioa_irq_thunk);
73#endif
74 break;
75
76 case 1:
77#ifdef GPIOB_BASE
78 LibXR::MSPM0Group1Shared::RegisterGPIOB(&gpiob_irq_thunk);
79#endif
80 break;
81
82 case 2:
83#ifdef GPIOC_BASE
84 LibXR::MSPM0Group1Shared::RegisterGPIOC(&gpioc_irq_thunk);
85#endif
86 break;
87 default:
88 return;
89 }
90}
91
92bool MSPM0GPIO::Read() { return DL_GPIO_readPins(port_, pin_mask_) == pin_mask_; }
93
94void MSPM0GPIO::Write(bool value)
95{
96 if (current_direction_ == LibXR::GPIO::Direction::OUTPUT_OPEN_DRAIN)
97 {
98 if (value)
99 {
100 DL_GPIO_disableOutput(port_, pin_mask_);
101 }
102 else
103 {
104 DL_GPIO_enableOutput(port_, pin_mask_);
105 }
106 }
107 else
108 {
109 if (value)
110 {
111 DL_GPIO_setPins(port_, pin_mask_);
112 }
113 else
114 {
115 DL_GPIO_clearPins(port_, pin_mask_);
116 }
117 }
118}
119
121{
122 DL_GPIO_enableInterrupt(port_, pin_mask_);
123 return ErrorCode::OK;
124}
125
127{
128 DL_GPIO_disableInterrupt(port_, pin_mask_);
129 return ErrorCode::OK;
130}
131
133{
134 current_direction_ = config.direction;
135
136 DL_GPIO_disableOutput(port_, pin_mask_);
137 DL_GPIO_disableInterrupt(port_, pin_mask_);
138 DL_GPIO_clearInterruptStatus(port_, pin_mask_);
139
140 switch (config.direction)
141 {
142 case Direction::INPUT:
143 {
144 DL_GPIO_RESISTOR res = DL_GPIO_RESISTOR_NONE;
145 if (config.pull == Pull::UP)
146 {
147 res = DL_GPIO_RESISTOR_PULL_UP;
148 }
149 else if (config.pull == Pull::DOWN)
150 {
151 res = DL_GPIO_RESISTOR_PULL_DOWN;
152 }
153 DL_GPIO_initDigitalInputFeatures(pincm_, DL_GPIO_INVERSION_DISABLE, res,
154 DL_GPIO_HYSTERESIS_DISABLE,
155 DL_GPIO_WAKEUP_DISABLE);
156 break;
157 }
158
160 {
161 DL_GPIO_RESISTOR res = DL_GPIO_RESISTOR_NONE;
162 if (config.pull == Pull::UP)
163 {
164 res = DL_GPIO_RESISTOR_PULL_UP;
165 }
166 else if (config.pull == Pull::DOWN)
167 {
168 res = DL_GPIO_RESISTOR_PULL_DOWN;
169 }
170
171 DL_GPIO_initDigitalOutputFeatures(pincm_, DL_GPIO_INVERSION_DISABLE, res,
172 DL_GPIO_DRIVE_STRENGTH_LOW, DL_GPIO_HIZ_DISABLE);
173
174 volatile uint32_t* pincm_reg = &IOMUX->SECCFG.PINCM[pincm_];
175 *pincm_reg |= IOMUX_PINCM_INENA_ENABLE;
176
177 DL_GPIO_clearPins(port_, pin_mask_);
178
179 DL_GPIO_enableOutput(port_, pin_mask_);
180 break;
181 }
182
184 {
185 /* 伪开漏:输入模式(高阻) + 软件控制拉低 / Pseudo open-drain: Input mode(HiZ) +
186 * software pull-low */
187 DL_GPIO_RESISTOR res = DL_GPIO_RESISTOR_NONE;
188 if (config.pull == Pull::UP)
189 {
190 res = DL_GPIO_RESISTOR_PULL_UP;
191 }
192
193 DL_GPIO_initDigitalInputFeatures(pincm_, DL_GPIO_INVERSION_DISABLE, res,
194 DL_GPIO_HYSTERESIS_DISABLE,
195 DL_GPIO_WAKEUP_DISABLE);
196
197 DL_GPIO_clearPins(port_, pin_mask_);
198 DL_GPIO_disableOutput(port_, pin_mask_);
199 break;
200 }
201
205 {
206 DL_GPIO_RESISTOR res = DL_GPIO_RESISTOR_NONE;
207 if (config.pull == Pull::UP)
208 {
209 res = DL_GPIO_RESISTOR_PULL_UP;
210 }
211 else if (config.pull == Pull::DOWN)
212 {
213 res = DL_GPIO_RESISTOR_PULL_DOWN;
214 }
215
216 DL_GPIO_initDigitalInputFeatures(pincm_, DL_GPIO_INVERSION_DISABLE, res,
217 DL_GPIO_HYSTERESIS_DISABLE,
218 DL_GPIO_WAKEUP_DISABLE);
219
220 uint32_t pol_mask =
221 MSPM0_GPIO_GetPolarityMask(__builtin_ctz(pin_mask_), config.direction);
222 if (pol_mask)
223 {
224 uint32_t pin_idx = __builtin_ctz(pin_mask_);
225
226 constexpr uint32_t BITS_PER_PIN = 2;
227 constexpr uint32_t CLEAR_PATTERN = 0x3U;
228
229 uint32_t shift = (pin_idx % 16) * BITS_PER_PIN;
230 uint32_t clear_mask = CLEAR_PATTERN << shift;
231
232 if (pin_idx < 16)
233 {
234 uint32_t current_polarity = DL_GPIO_getLowerPinsPolarity(port_);
235 current_polarity &= ~clear_mask;
236 current_polarity |= pol_mask;
237 port_->POLARITY15_0 = current_polarity;
238 }
239 else
240 {
241 uint32_t current_polarity = DL_GPIO_getUpperPinsPolarity(port_);
242 current_polarity &= ~clear_mask;
243 current_polarity |= pol_mask;
244 port_->POLARITY31_16 = current_polarity;
245 }
246 }
247
248 DL_GPIO_clearInterruptStatus(port_, pin_mask_);
249 DL_GPIO_enableInterrupt(port_, pin_mask_);
250 }
251 break;
252
253 default:
254 return ErrorCode::FAILED;
255 }
256
257 return ErrorCode::OK;
258}
259
260void MSPM0GPIO::OnInterruptDispatch(GPIO_Regs* port, int port_idx)
261{
262 if (port_idx < 0 || port_idx >= LibXR::MAX_PORTS)
263 {
264 return;
265 }
266
267 uint32_t pending_pins = DL_GPIO_getEnabledInterruptStatus(port, 0xFFFFFFFF);
268
269 if (pending_pins != 0)
270 {
271 DL_GPIO_clearInterruptStatus(port, pending_pins);
272 }
273
274 while (pending_pins)
275 {
276 uint32_t pin_idx = __builtin_ctz(pending_pins);
277 uint32_t pin_mask = (1U << pin_idx);
278
279 pending_pins &= ~pin_mask;
280
281 auto* instance = instance_map_[port_idx][pin_idx];
282 if (instance)
283 {
284 instance->callback_.Run(true);
285 }
286 }
287}
Direction
定义 GPIO 引脚的方向类型 / Defines the direction types for GPIO pins.
Definition gpio.hpp:21
@ 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.
@ DOWN
下拉模式 / Pull-down mode.
@ UP
上拉模式 / Pull-up mode.
MSPM0 GPIO / MSPM0 GPIO.
ErrorCode DisableInterrupt() override
禁用 GPIO 引脚中断 / Disables the GPIO pin interrupt.
bool Read() override
读取 GPIO 引脚状态 / Reads the GPIO pin state.
ErrorCode EnableInterrupt() override
使能 GPIO 引脚中断 / Enables the GPIO pin interrupt.
void Write(bool value) override
写入 GPIO 引脚状态 / Writes the GPIO pin state.
ErrorCode SetConfig(Configuration config) override
配置 GPIO 引脚参数 / Configures the GPIO pin settings.
LibXR 命名空间 / LibXR namespace.
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ FAILED
操作失败 / Operation failed
@ OK
操作成功 / Operation successful
存储 GPIO 配置参数的结构体 / Structure storing GPIO configuration parameters.
Definition gpio.hpp:47
Pull pull
GPIO 上拉/下拉配置 / GPIO pull-up/pull-down configuration.
Definition gpio.hpp:49
Direction direction
GPIO 引脚方向 / GPIO pin direction.
Definition gpio.hpp:48