Merge pull request #11198 from SteveCEvans/sce_rc2
[betaflight.git] / src / main / drivers / io.c
blob8487bb3fb89f7d12cbcda7c731b06bd42e9714e1
1 /*
2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
8 * any later version.
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
21 #include "platform.h"
23 #include "drivers/io.h"
24 #include "drivers/io_impl.h"
25 #include "drivers/rcc.h"
27 #include "common/utils.h"
29 // io ports defs are stored in array by index now
30 struct ioPortDef_s {
31 rccPeriphTag_t rcc;
34 #if defined(STM32F1)
35 const struct ioPortDef_s ioPortDefs[] = {
36 { RCC_APB2(IOPA) },
37 { RCC_APB2(IOPB) },
38 { RCC_APB2(IOPC) },
39 { RCC_APB2(IOPD) },
40 { RCC_APB2(IOPE) },
42 #if defined (STM32F10X_HD) || defined (STM32F10X_XL) || defined (STM32F10X_HD_VL)
43 RCC_APB2(IOPF),
44 #else
46 #endif
49 #if defined (STM32F10X_HD) || defined (STM32F10X_XL) || defined (STM32F10X_HD_VL)
50 RCC_APB2(IOPG),
51 #else
53 #endif
56 #elif defined(STM32F3)
57 const struct ioPortDef_s ioPortDefs[] = {
58 { RCC_AHB(GPIOA) },
59 { RCC_AHB(GPIOB) },
60 { RCC_AHB(GPIOC) },
61 { RCC_AHB(GPIOD) },
62 { RCC_AHB(GPIOE) },
63 { RCC_AHB(GPIOF) },
65 #elif defined(STM32F4)
66 const struct ioPortDef_s ioPortDefs[] = {
67 { RCC_AHB1(GPIOA) },
68 { RCC_AHB1(GPIOB) },
69 { RCC_AHB1(GPIOC) },
70 { RCC_AHB1(GPIOD) },
71 { RCC_AHB1(GPIOE) },
72 { RCC_AHB1(GPIOF) },
74 #elif defined(STM32F7)
75 const struct ioPortDef_s ioPortDefs[] = {
76 { RCC_AHB1(GPIOA) },
77 { RCC_AHB1(GPIOB) },
78 { RCC_AHB1(GPIOC) },
79 { RCC_AHB1(GPIOD) },
80 { RCC_AHB1(GPIOE) },
81 { RCC_AHB1(GPIOF) },
83 #elif defined(STM32H7)
84 const struct ioPortDef_s ioPortDefs[] = {
85 { RCC_AHB4(GPIOA) },
86 { RCC_AHB4(GPIOB) },
87 { RCC_AHB4(GPIOC) },
88 { RCC_AHB4(GPIOD) },
89 { RCC_AHB4(GPIOE) },
90 { RCC_AHB4(GPIOF) },
91 { RCC_AHB4(GPIOG) },
92 { RCC_AHB4(GPIOH) },
93 #if !(defined(STM32H723xx) || defined(STM32H725xx) || defined(STM32H730xx))
94 { RCC_AHB4(GPIOI) },
95 #endif
97 #elif defined(STM32G4)
98 const struct ioPortDef_s ioPortDefs[] = {
99 { RCC_AHB2(GPIOA) },
100 { RCC_AHB2(GPIOB) },
101 { RCC_AHB2(GPIOC) },
102 { RCC_AHB2(GPIOD) },
103 { RCC_AHB2(GPIOE) },
104 { RCC_AHB2(GPIOF) },
106 #endif
108 ioRec_t* IO_Rec(IO_t io)
110 return io;
113 GPIO_TypeDef* IO_GPIO(IO_t io)
115 const ioRec_t *ioRec = IO_Rec(io);
116 return ioRec->gpio;
119 uint16_t IO_Pin(IO_t io)
121 const ioRec_t *ioRec = IO_Rec(io);
122 return ioRec->pin;
125 // port index, GPIOA == 0
126 int IO_GPIOPortIdx(IO_t io)
128 if (!io) {
129 return -1;
131 return (((size_t)IO_GPIO(io) - GPIOA_BASE) >> 10); // ports are 0x400 apart
134 int IO_EXTI_PortSourceGPIO(IO_t io)
136 return IO_GPIOPortIdx(io);
139 int IO_GPIO_PortSource(IO_t io)
141 return IO_GPIOPortIdx(io);
144 // zero based pin index
145 int IO_GPIOPinIdx(IO_t io)
147 if (!io) {
148 return -1;
150 return 31 - __builtin_clz(IO_Pin(io)); // CLZ is a bit faster than FFS
153 int IO_EXTI_PinSource(IO_t io)
155 return IO_GPIOPinIdx(io);
158 int IO_GPIO_PinSource(IO_t io)
160 return IO_GPIOPinIdx(io);
163 // mask on stm32f103, bit index on stm32f303
164 uint32_t IO_EXTI_Line(IO_t io)
166 if (!io) {
167 return 0;
169 #if defined(STM32F1) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
170 return 1 << IO_GPIOPinIdx(io);
171 #elif defined(STM32F3)
172 return IO_GPIOPinIdx(io);
173 #elif defined(SIMULATOR_BUILD)
174 return 0;
175 #else
176 # error "Unknown target type"
177 #endif
180 bool IORead(IO_t io)
182 if (!io) {
183 return false;
185 #if defined(USE_FULL_LL_DRIVER)
186 return (LL_GPIO_ReadInputPort(IO_GPIO(io)) & IO_Pin(io));
187 #elif defined(USE_HAL_DRIVER)
188 return !! HAL_GPIO_ReadPin(IO_GPIO(io), IO_Pin(io));
189 #else
190 return (IO_GPIO(io)->IDR & IO_Pin(io));
191 #endif
194 void IOWrite(IO_t io, bool hi)
196 if (!io) {
197 return;
199 #if defined(USE_FULL_LL_DRIVER)
200 LL_GPIO_SetOutputPin(IO_GPIO(io), IO_Pin(io) << (hi ? 0 : 16));
201 #elif defined(USE_HAL_DRIVER)
202 HAL_GPIO_WritePin(IO_GPIO(io), IO_Pin(io), hi ? GPIO_PIN_SET : GPIO_PIN_RESET);
203 #elif defined(STM32F4)
204 if (hi) {
205 IO_GPIO(io)->BSRRL = IO_Pin(io);
206 } else {
207 IO_GPIO(io)->BSRRH = IO_Pin(io);
209 #else
210 IO_GPIO(io)->BSRR = IO_Pin(io) << (hi ? 0 : 16);
211 #endif
214 void IOHi(IO_t io)
216 if (!io) {
217 return;
219 #if defined(USE_FULL_LL_DRIVER)
220 LL_GPIO_SetOutputPin(IO_GPIO(io), IO_Pin(io));
221 #elif defined(USE_HAL_DRIVER)
222 HAL_GPIO_WritePin(IO_GPIO(io), IO_Pin(io), GPIO_PIN_SET);
223 #elif defined(STM32F4)
224 IO_GPIO(io)->BSRRL = IO_Pin(io);
225 #else
226 IO_GPIO(io)->BSRR = IO_Pin(io);
227 #endif
230 void IOLo(IO_t io)
232 if (!io) {
233 return;
235 #if defined(USE_FULL_LL_DRIVER)
236 LL_GPIO_ResetOutputPin(IO_GPIO(io), IO_Pin(io));
237 #elif defined(USE_HAL_DRIVER)
238 HAL_GPIO_WritePin(IO_GPIO(io), IO_Pin(io), GPIO_PIN_RESET);
239 #elif defined(STM32F4)
240 IO_GPIO(io)->BSRRH = IO_Pin(io);
241 #else
242 IO_GPIO(io)->BRR = IO_Pin(io);
243 #endif
246 void IOToggle(IO_t io)
248 if (!io) {
249 return;
252 uint32_t mask = IO_Pin(io);
253 // Read pin state from ODR but write to BSRR because it only changes the pins
254 // high in the mask value rather than all pins. XORing ODR directly risks
255 // setting other pins incorrectly because it change all pins' state.
256 #if defined(USE_FULL_LL_DRIVER)
257 if (LL_GPIO_ReadOutputPort(IO_GPIO(io)) & mask) {
258 mask <<= 16; // bit is set, shift mask to reset half
260 LL_GPIO_SetOutputPin(IO_GPIO(io), mask);
261 #elif defined(USE_HAL_DRIVER)
262 UNUSED(mask);
263 HAL_GPIO_TogglePin(IO_GPIO(io), IO_Pin(io));
264 #elif defined(STM32F4)
265 if (IO_GPIO(io)->ODR & mask) {
266 IO_GPIO(io)->BSRRH = mask;
267 } else {
268 IO_GPIO(io)->BSRRL = mask;
270 #else
271 if (IO_GPIO(io)->ODR & mask)
272 mask <<= 16; // bit is set, shift mask to reset half
274 IO_GPIO(io)->BSRR = mask;
275 #endif
278 // claim IO pin, set owner and resources
279 void IOInit(IO_t io, resourceOwner_e owner, uint8_t index)
281 if (!io) {
282 return;
284 ioRec_t *ioRec = IO_Rec(io);
285 ioRec->owner = owner;
286 ioRec->index = index;
289 void IORelease(IO_t io)
291 if (!io) {
292 return;
294 ioRec_t *ioRec = IO_Rec(io);
295 ioRec->owner = OWNER_FREE;
298 resourceOwner_e IOGetOwner(IO_t io)
300 if (!io) {
301 return OWNER_FREE;
303 const ioRec_t *ioRec = IO_Rec(io);
304 return ioRec->owner;
307 bool IOIsFreeOrPreinit(IO_t io)
309 resourceOwner_e owner = IOGetOwner(io);
311 if (owner == OWNER_FREE || owner == OWNER_PREINIT) {
312 return true;
315 return false;
318 #if defined(STM32F1)
320 void IOConfigGPIO(IO_t io, ioConfig_t cfg)
322 if (!io) {
323 return;
326 const rccPeriphTag_t rcc = ioPortDefs[IO_GPIOPortIdx(io)].rcc;
327 RCC_ClockCmd(rcc, ENABLE);
329 GPIO_InitTypeDef init = {
330 .GPIO_Pin = IO_Pin(io),
331 .GPIO_Speed = cfg & 0x03,
332 .GPIO_Mode = cfg & 0x7c,
334 GPIO_Init(IO_GPIO(io), &init);
337 #elif defined(STM32H7) || defined(STM32G4)
339 void IOConfigGPIO(IO_t io, ioConfig_t cfg)
341 IOConfigGPIOAF(io, cfg, 0);
344 void IOConfigGPIOAF(IO_t io, ioConfig_t cfg, uint8_t af)
346 if (!io) {
347 return;
350 rccPeriphTag_t rcc = ioPortDefs[IO_GPIOPortIdx(io)].rcc;
351 RCC_ClockCmd(rcc, ENABLE);
353 GPIO_InitTypeDef init = {
354 .Pin = IO_Pin(io),
355 .Mode = (cfg >> 0) & 0x13,
356 .Speed = (cfg >> 2) & 0x03,
357 .Pull = (cfg >> 5) & 0x03,
358 .Alternate = af
361 HAL_GPIO_Init(IO_GPIO(io), &init);
364 #elif defined(STM32F7)
366 void IOConfigGPIO(IO_t io, ioConfig_t cfg)
368 IOConfigGPIOAF(io, cfg, 0);
371 void IOConfigGPIOAF(IO_t io, ioConfig_t cfg, uint8_t af)
373 if (!io) {
374 return;
377 const rccPeriphTag_t rcc = ioPortDefs[IO_GPIOPortIdx(io)].rcc;
378 RCC_ClockCmd(rcc, ENABLE);
380 LL_GPIO_InitTypeDef init = {
381 .Pin = IO_Pin(io),
382 .Mode = (cfg >> 0) & 0x03,
383 .Speed = (cfg >> 2) & 0x03,
384 .OutputType = (cfg >> 4) & 0x01,
385 .Pull = (cfg >> 5) & 0x03,
386 .Alternate = af
389 LL_GPIO_Init(IO_GPIO(io), &init);
392 #elif defined(STM32F3) || defined(STM32F4)
394 void IOConfigGPIO(IO_t io, ioConfig_t cfg)
396 if (!io) {
397 return;
400 const rccPeriphTag_t rcc = ioPortDefs[IO_GPIOPortIdx(io)].rcc;
401 RCC_ClockCmd(rcc, ENABLE);
403 GPIO_InitTypeDef init = {
404 .GPIO_Pin = IO_Pin(io),
405 .GPIO_Mode = (cfg >> 0) & 0x03,
406 .GPIO_Speed = (cfg >> 2) & 0x03,
407 .GPIO_OType = (cfg >> 4) & 0x01,
408 .GPIO_PuPd = (cfg >> 5) & 0x03,
410 GPIO_Init(IO_GPIO(io), &init);
413 void IOConfigGPIOAF(IO_t io, ioConfig_t cfg, uint8_t af)
415 if (!io) {
416 return;
419 const rccPeriphTag_t rcc = ioPortDefs[IO_GPIOPortIdx(io)].rcc;
420 RCC_ClockCmd(rcc, ENABLE);
421 GPIO_PinAFConfig(IO_GPIO(io), IO_GPIO_PinSource(io), af);
423 GPIO_InitTypeDef init = {
424 .GPIO_Pin = IO_Pin(io),
425 .GPIO_Mode = (cfg >> 0) & 0x03,
426 .GPIO_Speed = (cfg >> 2) & 0x03,
427 .GPIO_OType = (cfg >> 4) & 0x01,
428 .GPIO_PuPd = (cfg >> 5) & 0x03,
430 GPIO_Init(IO_GPIO(io), &init);
432 #endif
434 #if DEFIO_PORT_USED_COUNT > 0
435 static const uint16_t ioDefUsedMask[DEFIO_PORT_USED_COUNT] = { DEFIO_PORT_USED_LIST };
436 static const uint8_t ioDefUsedOffset[DEFIO_PORT_USED_COUNT] = { DEFIO_PORT_OFFSET_LIST };
437 #else
438 // Avoid -Wpedantic warning
439 static const uint16_t ioDefUsedMask[1] = {0};
440 static const uint8_t ioDefUsedOffset[1] = {0};
441 #endif
442 #if DEFIO_IO_USED_COUNT
443 ioRec_t ioRecs[DEFIO_IO_USED_COUNT];
444 #else
445 // Avoid -Wpedantic warning
446 ioRec_t ioRecs[1];
447 #endif
449 // initialize all ioRec_t structures from ROM
450 // currently only bitmask is used, this may change in future
451 void IOInitGlobal(void)
453 ioRec_t *ioRec = ioRecs;
455 for (unsigned port = 0; port < ARRAYLEN(ioDefUsedMask); port++) {
456 for (unsigned pin = 0; pin < sizeof(ioDefUsedMask[0]) * 8; pin++) {
457 if (ioDefUsedMask[port] & (1 << pin)) {
458 ioRec->gpio = (GPIO_TypeDef *)(GPIOA_BASE + (port << 10)); // ports are 0x400 apart
459 ioRec->pin = 1 << pin;
460 ioRec++;
466 IO_t IOGetByTag(ioTag_t tag)
468 const int portIdx = DEFIO_TAG_GPIOID(tag);
469 const int pinIdx = DEFIO_TAG_PIN(tag);
471 if (portIdx < 0 || portIdx >= DEFIO_PORT_USED_COUNT) {
472 return NULL;
474 // check if pin exists
475 if (!(ioDefUsedMask[portIdx] & (1 << pinIdx))) {
476 return NULL;
478 // count bits before this pin on single port
479 int offset = __builtin_popcount(((1 << pinIdx) - 1) & ioDefUsedMask[portIdx]);
480 // and add port offset
481 offset += ioDefUsedOffset[portIdx];
482 return ioRecs + offset;
485 void IOTraversePins(IOTraverseFuncPtr_t fnPtr)
487 for (int i = 0; i < DEFIO_IO_USED_COUNT; i++) {
488 fnPtr(&ioRecs[i]);