2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
20 #include "build/assert.h"
22 #include "common/utils.h"
24 #include "drivers/io.h"
25 #include "drivers/io_impl.h"
26 #include "drivers/rcc.h"
28 // io ports defs are stored in array by index now
34 const struct ioPortDef_s ioPortDefs
[] = {
42 #elif defined(STM32F7)
43 const struct ioPortDef_s ioPortDefs
[] = {
51 #elif defined(STM32H7)
52 const struct ioPortDef_s ioPortDefs
[] = {
63 #elif defined(AT32F43x)
64 const struct ioPortDef_s ioPortDefs
[] = {
76 ioRec_t
* IO_Rec(IO_t io
)
79 ASSERT((ioRec_t
*)io
>= &ioRecs
[0]);
80 ASSERT((ioRec_t
*)io
< &ioRecs
[DEFIO_IO_USED_COUNT
]);
86 gpio_type
* IO_GPIO(IO_t io
)
88 const ioRec_t
*ioRec
= IO_Rec(io
);
92 GPIO_TypeDef
* IO_GPIO(IO_t io
)
94 const ioRec_t
*ioRec
= IO_Rec(io
);
99 uint16_t IO_Pin(IO_t io
)
101 const ioRec_t
*ioRec
= IO_Rec(io
);
105 // port index, GPIOA == 0
106 int IO_GPIOPortIdx(IO_t io
)
111 return (((size_t)IO_GPIO(io
) - GPIOA_BASE
) >> 10); // ports are 0x400 apart
114 int IO_EXTI_PortSourceGPIO(IO_t io
)
116 return IO_GPIOPortIdx(io
);
119 int IO_GPIO_PortSource(IO_t io
)
121 return IO_GPIOPortIdx(io
);
124 // zero based pin index
125 int IO_GPIOPinIdx(IO_t io
)
130 return 31 - __builtin_clz(IO_Pin(io
)); // CLZ is a bit faster than FFS
133 int IO_EXTI_PinSource(IO_t io
)
135 return IO_GPIOPinIdx(io
);
138 int IO_GPIO_PinSource(IO_t io
)
140 return IO_GPIOPinIdx(io
);
143 uint32_t IO_EXTI_Line(IO_t io
)
148 #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(AT32F43x)
149 return 1 << IO_GPIOPinIdx(io
);
150 #elif defined (SITL_BUILD)
153 # error "Unknown target type"
162 #if defined(USE_HAL_DRIVER)
163 return !! HAL_GPIO_ReadPin(IO_GPIO(io
),IO_Pin(io
));
164 #elif defined(AT32F43x)
165 return !! (IO_GPIO(io
)->idt
& IO_Pin(io
));
167 return !! (IO_GPIO(io
)->IDR
& IO_Pin(io
));
171 void IOWrite(IO_t io
, bool hi
)
176 #if defined(USE_HAL_DRIVER)
178 HAL_GPIO_WritePin(IO_GPIO(io
),IO_Pin(io
),GPIO_PIN_SET
);
180 HAL_GPIO_WritePin(IO_GPIO(io
),IO_Pin(io
),GPIO_PIN_RESET
);
182 #elif defined(STM32F4)
184 IO_GPIO(io
)->BSRRL
= IO_Pin(io
);
186 IO_GPIO(io
)->BSRRH
= IO_Pin(io
);
188 #elif defined(AT32F43x)
189 IO_GPIO(io
)->scr
= IO_Pin(io
) << (hi
? 0 : 16);
191 IO_GPIO(io
)->BSRR
= IO_Pin(io
) << (hi
? 0 : 16);
200 #if defined(USE_HAL_DRIVER)
201 HAL_GPIO_WritePin(IO_GPIO(io
),IO_Pin(io
),GPIO_PIN_SET
);
202 #elif defined(STM32F4)
203 IO_GPIO(io
)->BSRRL
= IO_Pin(io
);
204 #elif defined(AT32F43x)
205 IO_GPIO(io
)->scr
= IO_Pin(io
);
207 IO_GPIO(io
)->BSRR
= IO_Pin(io
);
216 #if defined(USE_HAL_DRIVER)
217 HAL_GPIO_WritePin(IO_GPIO(io
),IO_Pin(io
),GPIO_PIN_RESET
);
218 #elif defined(STM32F4)
219 IO_GPIO(io
)->BSRRH
= IO_Pin(io
);
220 #elif defined(AT32F43x)
221 IO_GPIO(io
)->clr
= IO_Pin(io
);
223 IO_GPIO(io
)->BRR
= IO_Pin(io
);
227 void IOToggle(IO_t io
)
233 uint32_t mask
= IO_Pin(io
);
234 // Read pin state from ODR but write to BSRR because it only changes the pins
235 // high in the mask value rather than all pins. XORing ODR directly risks
236 // setting other pins incorrectly because it change all pins' state.
237 #if defined(USE_HAL_DRIVER)
239 HAL_GPIO_TogglePin(IO_GPIO(io
),IO_Pin(io
));
240 #elif defined(STM32F4)
241 if (IO_GPIO(io
)->ODR
& mask
) {
242 IO_GPIO(io
)->BSRRH
= mask
;
244 IO_GPIO(io
)->BSRRL
= mask
;
246 #elif defined(AT32F43x)
247 if (IO_GPIO(io
)->odt
& mask
)
248 mask
<<= 16; // bit is set, shift mask to reset half
250 IO_GPIO(io
)->scr
= IO_Pin(io
);
252 if (IO_GPIO(io
)->ODR
& mask
)
253 mask
<<= 16; // bit is set, shift mask to reset half
255 IO_GPIO(io
)->BSRR
= mask
;
259 // claim IO pin, set owner and resources
260 void IOInit(IO_t io
, resourceOwner_e owner
, resourceType_e resource
, uint8_t index
)
265 ioRec_t
*ioRec
= IO_Rec(io
);
266 ioRec
->owner
= owner
;
267 ioRec
->resource
= resource
;
268 ioRec
->index
= index
;
271 void IORelease(IO_t io
)
276 ioRec_t
*ioRec
= IO_Rec(io
);
277 ioRec
->owner
= OWNER_FREE
;
280 resourceOwner_e
IOGetOwner(IO_t io
)
285 const ioRec_t
*ioRec
= IO_Rec(io
);
289 resourceType_e
IOGetResource(IO_t io
)
291 const ioRec_t
*ioRec
= IO_Rec(io
);
292 return ioRec
->resource
;
295 #if defined(STM32F7) || defined(STM32H7)
297 void IOConfigGPIO(IO_t io
, ioConfig_t cfg
)
302 const rccPeriphTag_t rcc
= ioPortDefs
[IO_GPIOPortIdx(io
)].rcc
;
303 RCC_ClockCmd(rcc
, ENABLE
);
305 GPIO_InitTypeDef init
= {
307 .Mode
= (cfg
>> 0) & 0x13,
308 .Speed
= (cfg
>> 2) & 0x03,
309 .Pull
= (cfg
>> 5) & 0x03,
311 HAL_GPIO_Init(IO_GPIO(io
), &init
);
314 void IOConfigGPIOAF(IO_t io
, ioConfig_t cfg
, uint8_t af
)
319 const rccPeriphTag_t rcc
= ioPortDefs
[IO_GPIOPortIdx(io
)].rcc
;
320 RCC_ClockCmd(rcc
, ENABLE
);
321 GPIO_InitTypeDef init
= {
323 .Mode
= (cfg
>> 0) & 0x13,
324 .Speed
= (cfg
>> 2) & 0x03,
325 .Pull
= (cfg
>> 5) & 0x03,
328 HAL_GPIO_Init(IO_GPIO(io
), &init
);
331 #elif defined(STM32F4)
333 void IOConfigGPIO(IO_t io
, ioConfig_t cfg
)
338 const rccPeriphTag_t rcc
= ioPortDefs
[IO_GPIOPortIdx(io
)].rcc
;
339 RCC_ClockCmd(rcc
, ENABLE
);
341 GPIO_InitTypeDef init
= {
342 .GPIO_Pin
= IO_Pin(io
),
343 .GPIO_Mode
= (cfg
>> 0) & 0x03,
344 .GPIO_Speed
= (cfg
>> 2) & 0x03,
345 .GPIO_OType
= (cfg
>> 4) & 0x01,
346 .GPIO_PuPd
= (cfg
>> 5) & 0x03,
348 GPIO_Init(IO_GPIO(io
), &init
);
351 void IOConfigGPIOAF(IO_t io
, ioConfig_t cfg
, uint8_t af
)
356 const rccPeriphTag_t rcc
= ioPortDefs
[IO_GPIOPortIdx(io
)].rcc
;
357 RCC_ClockCmd(rcc
, ENABLE
);
358 GPIO_PinAFConfig(IO_GPIO(io
), IO_GPIO_PinSource(io
), af
);
360 GPIO_InitTypeDef init
= {
361 .GPIO_Pin
= IO_Pin(io
),
362 .GPIO_Mode
= (cfg
>> 0) & 0x03,
363 .GPIO_Speed
= (cfg
>> 2) & 0x03,
364 .GPIO_OType
= (cfg
>> 4) & 0x01,
365 .GPIO_PuPd
= (cfg
>> 5) & 0x03,
367 GPIO_Init(IO_GPIO(io
), &init
);
369 #elif defined(AT32F43x)
371 void IOConfigGPIO(IO_t io
, ioConfig_t cfg
)
376 const rccPeriphTag_t rcc
= ioPortDefs
[IO_GPIOPortIdx(io
)].rcc
;
377 RCC_ClockCmd(rcc
, ENABLE
);
379 gpio_init_type init
= {
380 .gpio_pins
= IO_Pin(io
),
381 .gpio_out_type
= (cfg
>> 4) & 0x01,
382 .gpio_pull
= (cfg
>> 5) & 0x03,
383 .gpio_mode
= (cfg
>> 0) & 0x03,
384 .gpio_drive_strength
= (cfg
>> 2) & 0x03,
387 gpio_init(IO_GPIO(io
), &init
);
390 void IOConfigGPIOAF(IO_t io
, ioConfig_t cfg
, uint8_t af
)
395 const rccPeriphTag_t rcc
= ioPortDefs
[IO_GPIOPortIdx(io
)].rcc
;
396 RCC_ClockCmd(rcc
, ENABLE
);
397 // Must run configure the pin's muxing function
398 gpio_pin_mux_config(IO_GPIO(io
), IO_GPIO_PinSource(io
), af
);
400 gpio_init_type init
= {
401 .gpio_pins
= IO_Pin(io
),
402 .gpio_out_type
= (cfg
>> 4) & 0x01,
403 .gpio_pull
= (cfg
>> 5) & 0x03,
404 .gpio_mode
= (cfg
>> 0) & 0x03,
405 .gpio_drive_strength
= (cfg
>> 2) & 0x03,
407 gpio_init(IO_GPIO(io
), &init
);
412 #if DEFIO_PORT_USED_COUNT > 0
413 static const uint16_t ioDefUsedMask
[DEFIO_PORT_USED_COUNT
] = { DEFIO_PORT_USED_LIST
};
414 static const uint8_t ioDefUsedOffset
[DEFIO_PORT_USED_COUNT
] = { DEFIO_PORT_OFFSET_LIST
};
416 // Avoid -Wpedantic warning
417 static const uint16_t ioDefUsedMask
[1] = {0};
418 static const uint8_t ioDefUsedOffset
[1] = {0};
420 ioRec_t ioRecs
[DEFIO_IO_USED_COUNT
];
422 // initialize all ioRec_t structures from ROM
423 // currently only bitmask is used, this may change in future
424 void IOInitGlobal(void)
426 ioRec_t
*ioRec
= ioRecs
;
428 for (unsigned port
= 0; port
< ARRAYLEN(ioDefUsedMask
); port
++) {
429 for (unsigned pin
= 0; pin
< sizeof(ioDefUsedMask
[0]) * 8; pin
++) {
430 if (ioDefUsedMask
[port
] & (1 << pin
)) {
431 #if defined(AT32F43x)
432 ioRec
->gpio
= (gpio_type
*)(GPIOA_BASE
+ (port
<< 10)); // ports are 0x400 apart
434 ioRec
->gpio
= (GPIO_TypeDef
*)(GPIOA_BASE
+ (port
<< 10)); // ports are 0x400 apart
436 ioRec
->pin
= 1 << pin
;
443 IO_t
IOGetByTag(ioTag_t tag
)
445 const int portIdx
= DEFIO_TAG_GPIOID(tag
);
446 const int pinIdx
= DEFIO_TAG_PIN(tag
);
448 if (portIdx
< 0 || portIdx
>= DEFIO_PORT_USED_COUNT
) {
451 // Check if pin exists
452 if (!(ioDefUsedMask
[portIdx
] & (1 << pinIdx
))) {
455 // Count bits before this pin on single port
456 int offset
= __builtin_popcount(((1 << pinIdx
) - 1) & ioDefUsedMask
[portIdx
]);
458 offset
+= ioDefUsedOffset
[portIdx
];
459 return ioRecs
+ offset
;