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)
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/>.
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
35 const struct ioPortDef_s ioPortDefs
[] = {
42 #if defined (STM32F10X_HD) || defined (STM32F10X_XL) || defined (STM32F10X_HD_VL)
49 #if defined (STM32F10X_HD) || defined (STM32F10X_XL) || defined (STM32F10X_HD_VL)
56 #elif defined(STM32F3)
57 const struct ioPortDef_s ioPortDefs
[] = {
65 #elif defined(STM32F4)
66 const struct ioPortDef_s ioPortDefs
[] = {
74 #elif defined(STM32F7)
75 const struct ioPortDef_s ioPortDefs
[] = {
83 #elif defined(STM32H7)
84 const struct ioPortDef_s ioPortDefs
[] = {
93 #if !(defined(STM32H723xx) || defined(STM32H725xx) || defined(STM32H730xx))
97 #elif defined(STM32G4)
98 const struct ioPortDef_s ioPortDefs
[] = {
108 ioRec_t
* IO_Rec(IO_t io
)
113 GPIO_TypeDef
* IO_GPIO(IO_t io
)
115 const ioRec_t
*ioRec
= IO_Rec(io
);
119 uint16_t IO_Pin(IO_t io
)
121 const ioRec_t
*ioRec
= IO_Rec(io
);
125 // port index, GPIOA == 0
126 int IO_GPIOPortIdx(IO_t io
)
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
)
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
)
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)
176 # error "Unknown target type"
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
));
190 return (IO_GPIO(io
)->IDR
& IO_Pin(io
));
194 void IOWrite(IO_t io
, bool hi
)
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)
205 IO_GPIO(io
)->BSRRL
= IO_Pin(io
);
207 IO_GPIO(io
)->BSRRH
= IO_Pin(io
);
210 IO_GPIO(io
)->BSRR
= IO_Pin(io
) << (hi
? 0 : 16);
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
);
226 IO_GPIO(io
)->BSRR
= IO_Pin(io
);
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
);
242 IO_GPIO(io
)->BRR
= IO_Pin(io
);
246 void IOToggle(IO_t io
)
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)
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
;
268 IO_GPIO(io
)->BSRRL
= mask
;
271 if (IO_GPIO(io
)->ODR
& mask
)
272 mask
<<= 16; // bit is set, shift mask to reset half
274 IO_GPIO(io
)->BSRR
= mask
;
278 // claim IO pin, set owner and resources
279 void IOInit(IO_t io
, resourceOwner_e owner
, uint8_t index
)
284 ioRec_t
*ioRec
= IO_Rec(io
);
285 ioRec
->owner
= owner
;
286 ioRec
->index
= index
;
289 void IORelease(IO_t io
)
294 ioRec_t
*ioRec
= IO_Rec(io
);
295 ioRec
->owner
= OWNER_FREE
;
298 resourceOwner_e
IOGetOwner(IO_t io
)
303 const ioRec_t
*ioRec
= IO_Rec(io
);
307 bool IOIsFreeOrPreinit(IO_t io
)
309 resourceOwner_e owner
= IOGetOwner(io
);
311 if (owner
== OWNER_FREE
|| owner
== OWNER_PREINIT
) {
320 void IOConfigGPIO(IO_t io
, ioConfig_t cfg
)
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
)
350 rccPeriphTag_t rcc
= ioPortDefs
[IO_GPIOPortIdx(io
)].rcc
;
351 RCC_ClockCmd(rcc
, ENABLE
);
353 GPIO_InitTypeDef init
= {
355 .Mode
= (cfg
>> 0) & 0x13,
356 .Speed
= (cfg
>> 2) & 0x03,
357 .Pull
= (cfg
>> 5) & 0x03,
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
)
377 const rccPeriphTag_t rcc
= ioPortDefs
[IO_GPIOPortIdx(io
)].rcc
;
378 RCC_ClockCmd(rcc
, ENABLE
);
380 LL_GPIO_InitTypeDef init
= {
382 .Mode
= (cfg
>> 0) & 0x03,
383 .Speed
= (cfg
>> 2) & 0x03,
384 .OutputType
= (cfg
>> 4) & 0x01,
385 .Pull
= (cfg
>> 5) & 0x03,
389 LL_GPIO_Init(IO_GPIO(io
), &init
);
392 #elif defined(STM32F3) || defined(STM32F4)
394 void IOConfigGPIO(IO_t io
, ioConfig_t cfg
)
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
)
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
);
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
};
438 // Avoid -Wpedantic warning
439 static const uint16_t ioDefUsedMask
[1] = {0};
440 static const uint8_t ioDefUsedOffset
[1] = {0};
442 #if DEFIO_IO_USED_COUNT
443 ioRec_t ioRecs
[DEFIO_IO_USED_COUNT
];
445 // Avoid -Wpedantic warning
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
;
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
) {
474 // check if pin exists
475 if (!(ioDefUsedMask
[portIdx
] & (1 << pinIdx
))) {
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
++) {