Blackbox device type 'file' (SITL) considered working when file handler is available
[inav.git] / src / main / drivers / io.c
blobb13b73cbfd2e4dd96fe95d06052be452c61d6b37
1 /*
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/>.
18 #include "platform.h"
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
29 struct ioPortDef_s {
30 rccPeriphTag_t rcc;
33 #if defined(STM32F4)
34 const struct ioPortDef_s ioPortDefs[] = {
35 { RCC_AHB1(GPIOA) },
36 { RCC_AHB1(GPIOB) },
37 { RCC_AHB1(GPIOC) },
38 { RCC_AHB1(GPIOD) },
39 { RCC_AHB1(GPIOE) },
40 { RCC_AHB1(GPIOF) },
42 #elif defined(STM32F7)
43 const struct ioPortDef_s ioPortDefs[] = {
44 { RCC_AHB1(GPIOA) },
45 { RCC_AHB1(GPIOB) },
46 { RCC_AHB1(GPIOC) },
47 { RCC_AHB1(GPIOD) },
48 { RCC_AHB1(GPIOE) },
49 { RCC_AHB1(GPIOF) },
51 #elif defined(STM32H7)
52 const struct ioPortDef_s ioPortDefs[] = {
53 { RCC_AHB4(GPIOA) },
54 { RCC_AHB4(GPIOB) },
55 { RCC_AHB4(GPIOC) },
56 { RCC_AHB4(GPIOD) },
57 { RCC_AHB4(GPIOE) },
58 { RCC_AHB4(GPIOF) },
59 { RCC_AHB4(GPIOG) },
60 { RCC_AHB4(GPIOH) },
61 { RCC_AHB4(GPIOI) },
63 #elif defined(AT32F43x)
64 const struct ioPortDef_s ioPortDefs[] = {
65 { RCC_AHB1(GPIOA) },
66 { RCC_AHB1(GPIOB) },
67 { RCC_AHB1(GPIOC) },
68 { RCC_AHB1(GPIOD) },
69 { RCC_AHB1(GPIOE) },
70 { RCC_AHB1(GPIOF) },
71 { RCC_AHB1(GPIOG) },
72 { RCC_AHB1(GPIOH) },
74 # endif
76 ioRec_t* IO_Rec(IO_t io)
78 ASSERT(io != NULL);
79 ASSERT((ioRec_t*)io >= &ioRecs[0]);
80 ASSERT((ioRec_t*)io < &ioRecs[DEFIO_IO_USED_COUNT]);
82 return io;
85 #if defined(AT32F43x)
86 gpio_type * IO_GPIO(IO_t io)
88 const ioRec_t *ioRec = IO_Rec(io);
89 return ioRec->gpio;
91 #else
92 GPIO_TypeDef * IO_GPIO(IO_t io)
94 const ioRec_t *ioRec = IO_Rec(io);
95 return ioRec->gpio;
97 # endif
99 uint16_t IO_Pin(IO_t io)
101 const ioRec_t *ioRec = IO_Rec(io);
102 return ioRec->pin;
105 // port index, GPIOA == 0
106 int IO_GPIOPortIdx(IO_t io)
108 if (!io) {
109 return -1;
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)
127 if (!io) {
128 return -1;
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)
145 if (!io) {
146 return 0;
148 #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(AT32F43x)
149 return 1 << IO_GPIOPinIdx(io);
150 #elif defined (SITL_BUILD)
151 return 0;
152 #else
153 # error "Unknown target type"
154 #endif
157 bool IORead(IO_t io)
159 if (!io) {
160 return false;
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));
166 #else
167 return !! (IO_GPIO(io)->IDR & IO_Pin(io));
168 #endif
171 void IOWrite(IO_t io, bool hi)
173 if (!io) {
174 return;
176 #if defined(USE_HAL_DRIVER)
177 if (hi) {
178 HAL_GPIO_WritePin(IO_GPIO(io),IO_Pin(io),GPIO_PIN_SET);
179 } else {
180 HAL_GPIO_WritePin(IO_GPIO(io),IO_Pin(io),GPIO_PIN_RESET);
182 #elif defined(STM32F4)
183 if (hi) {
184 IO_GPIO(io)->BSRRL = IO_Pin(io);
185 } else {
186 IO_GPIO(io)->BSRRH = IO_Pin(io);
188 #elif defined(AT32F43x)
189 IO_GPIO(io)->scr = IO_Pin(io) << (hi ? 0 : 16);
190 #else
191 IO_GPIO(io)->BSRR = IO_Pin(io) << (hi ? 0 : 16);
192 #endif
195 void IOHi(IO_t io)
197 if (!io) {
198 return;
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);
206 #else
207 IO_GPIO(io)->BSRR = IO_Pin(io);
208 #endif
211 void IOLo(IO_t io)
213 if (!io) {
214 return;
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);
222 #else
223 IO_GPIO(io)->BRR = IO_Pin(io);
224 #endif
227 void IOToggle(IO_t io)
229 if (!io) {
230 return;
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)
238 (void)mask;
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;
243 } else {
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);
251 #else
252 if (IO_GPIO(io)->ODR & mask)
253 mask <<= 16; // bit is set, shift mask to reset half
255 IO_GPIO(io)->BSRR = mask;
256 #endif
259 // claim IO pin, set owner and resources
260 void IOInit(IO_t io, resourceOwner_e owner, resourceType_e resource, uint8_t index)
262 if (!io) {
263 return;
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)
273 if (!io) {
274 return;
276 ioRec_t *ioRec = IO_Rec(io);
277 ioRec->owner = OWNER_FREE;
280 resourceOwner_e IOGetOwner(IO_t io)
282 if (!io) {
283 return OWNER_FREE;
285 const ioRec_t *ioRec = IO_Rec(io);
286 return ioRec->owner;
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)
299 if (!io) {
300 return;
302 const rccPeriphTag_t rcc = ioPortDefs[IO_GPIOPortIdx(io)].rcc;
303 RCC_ClockCmd(rcc, ENABLE);
305 GPIO_InitTypeDef init = {
306 .Pin = IO_Pin(io),
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)
316 if (!io) {
317 return;
319 const rccPeriphTag_t rcc = ioPortDefs[IO_GPIOPortIdx(io)].rcc;
320 RCC_ClockCmd(rcc, ENABLE);
321 GPIO_InitTypeDef init = {
322 .Pin = IO_Pin(io),
323 .Mode = (cfg >> 0) & 0x13,
324 .Speed = (cfg >> 2) & 0x03,
325 .Pull = (cfg >> 5) & 0x03,
326 .Alternate = af
328 HAL_GPIO_Init(IO_GPIO(io), &init);
331 #elif defined(STM32F4)
333 void IOConfigGPIO(IO_t io, ioConfig_t cfg)
335 if (!io) {
336 return;
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)
353 if (!io) {
354 return;
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)
373 if (!io) {
374 return;
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)
392 if (!io) {
393 return;
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);
410 #endif
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 };
415 #else
416 // Avoid -Wpedantic warning
417 static const uint16_t ioDefUsedMask[1] = {0};
418 static const uint8_t ioDefUsedOffset[1] = {0};
419 #endif
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
433 #else
434 ioRec->gpio = (GPIO_TypeDef *)(GPIOA_BASE + (port << 10)); // ports are 0x400 apart
435 # endif
436 ioRec->pin = 1 << pin;
437 ioRec++;
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) {
449 return NULL;
451 // Check if pin exists
452 if (!(ioDefUsedMask[portIdx] & (1 << pinIdx))) {
453 return NULL;
455 // Count bits before this pin on single port
456 int offset = __builtin_popcount(((1 << pinIdx) - 1) & ioDefUsedMask[portIdx]);
457 // Add port offset
458 offset += ioDefUsedOffset[portIdx];
459 return ioRecs + offset;