-
Notifications
You must be signed in to change notification settings - Fork 829
/
gpio.h
650 lines (585 loc) · 22.6 KB
/
gpio.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _HARDWARE_GPIO_H_
#define _HARDWARE_GPIO_H_
#include "pico.h"
#include "hardware/structs/sio.h"
#include "hardware/structs/padsbank0.h"
#ifdef __cplusplus
extern "C" {
#endif
// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_GPIO, Enable/disable assertions in the GPIO module, type=bool, default=0, group=hardware_gpio
#ifndef PARAM_ASSERTIONS_ENABLED_GPIO
#define PARAM_ASSERTIONS_ENABLED_GPIO 0
#endif
/** \file gpio.h
* \defgroup hardware_gpio hardware_gpio
*
* General Purpose Input/Output (GPIO) API
*
* RP2040 has 36 multi-functional General Purpose Input / Output (GPIO) pins, divided into two banks. In a typical use case,
* the pins in the QSPI bank (QSPI_SS, QSPI_SCLK and QSPI_SD0 to QSPI_SD3) are used to execute code from an external
* flash device, leaving the User bank (GPIO0 to GPIO29) for the programmer to use. All GPIOs support digital input and
* output, but GPIO26 to GPIO29 can also be used as inputs to the chip’s Analogue to Digital Converter (ADC). Each GPIO
* can be controlled directly by software running on the processors, or by a number of other functional blocks.
*
* The function allocated to each GPIO is selected by calling the \ref gpio_set_function function. \note Not all functions
* are available on all pins.
*
* Each GPIO can have one function selected at a time. Likewise, each peripheral input (e.g. UART0 RX) should only be selected on
* one _GPIO_ at a time. If the same peripheral input is connected to multiple GPIOs, the peripheral sees the logical OR of these
* GPIO inputs. Please refer to the datasheet for more information on GPIO function select.
*
* ### Function Select Table
*
* GPIO | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9
* -------|----------|-----------|----------|--------|-----|------|------|---------------|----
* 0 | SPI0 RX | UART0 TX | I2C0 SDA | PWM0 A | SIO | PIO0 | PIO1 | | USB OVCUR DET
* 1 | SPI0 CSn | UART0 RX | I2C0 SCL | PWM0 B | SIO | PIO0 | PIO1 | | USB VBUS DET
* 2 | SPI0 SCK | UART0 CTS | I2C1 SDA | PWM1 A | SIO | PIO0 | PIO1 | | USB VBUS EN
* 3 | SPI0 TX | UART0 RTS | I2C1 SCL | PWM1 B | SIO | PIO0 | PIO1 | | USB OVCUR DET
* 4 | SPI0 RX | UART1 TX | I2C0 SDA | PWM2 A | SIO | PIO0 | PIO1 | | USB VBUS DET
* 5 | SPI0 CSn | UART1 RX | I2C0 SCL | PWM2 B | SIO | PIO0 | PIO1 | | USB VBUS EN
* 6 | SPI0 SCK | UART1 CTS | I2C1 SDA | PWM3 A | SIO | PIO0 | PIO1 | | USB OVCUR DET
* 7 | SPI0 TX | UART1 RTS | I2C1 SCL | PWM3 B | SIO | PIO0 | PIO1 | | USB VBUS DET
* 8 | SPI1 RX | UART1 TX | I2C0 SDA | PWM4 A | SIO | PIO0 | PIO1 | | USB VBUS EN
* 9 | SPI1 CSn | UART1 RX | I2C0 SCL | PWM4 B | SIO | PIO0 | PIO1 | | USB OVCUR DET
* 10 | SPI1 SCK | UART1 CTS | I2C1 SDA | PWM5 A | SIO | PIO0 | PIO1 | | USB VBUS DET
* 11 | SPI1 TX | UART1 RTS | I2C1 SCL | PWM5 B | SIO | PIO0 | PIO1 | | USB VBUS EN
* 12 | SPI1 RX | UART0 TX | I2C0 SDA | PWM6 A | SIO | PIO0 | PIO1 | | USB OVCUR DET
* 13 | SPI1 CSn | UART0 RX | I2C0 SCL | PWM6 B | SIO | PIO0 | PIO1 | | USB VBUS DET
* 14 | SPI1 SCK | UART0 CTS | I2C1 SDA | PWM7 A | SIO | PIO0 | PIO1 | | USB VBUS EN
* 15 | SPI1 TX | UART0 RTS | I2C1 SCL | PWM7 B | SIO | PIO0 | PIO1 | | USB OVCUR DET
* 16 | SPI0 RX | UART0 TX | I2C0 SDA | PWM0 A | SIO | PIO0 | PIO1 | | USB VBUS DET
* 17 | SPI0 CSn | UART0 RX | I2C0 SCL | PWM0 B | SIO | PIO0 | PIO1 | | USB VBUS EN
* 18 | SPI0 SCK | UART0 CTS | I2C1 SDA | PWM1 A | SIO | PIO0 | PIO1 | | USB OVCUR DET
* 19 | SPI0 TX | UART0 RTS | I2C1 SCL | PWM1 B | SIO | PIO0 | PIO1 | | USB VBUS DET
* 20 | SPI0 RX | UART1 TX | I2C0 SDA | PWM2 A | SIO | PIO0 | PIO1 | CLOCK GPIN0 | USB VBUS EN
* 21 | SPI0 CSn | UART1 RX | I2C0 SCL | PWM2 B | SIO | PIO0 | PIO1 | CLOCK GPOUT0 | USB OVCUR DET
* 22 | SPI0 SCK | UART1 CTS | I2C1 SDA | PWM3 A | SIO | PIO0 | PIO1 | CLOCK GPIN1 | USB VBUS DET
* 23 | SPI0 TX | UART1 RTS | I2C1 SCL | PWM3 B | SIO | PIO0 | PIO1 | CLOCK GPOUT1 | USB VBUS EN
* 24 | SPI1 RX | UART1 TX | I2C0 SDA | PWM4 A | SIO | PIO0 | PIO1 | CLOCK GPOUT2 | USB OVCUR DET
* 25 | SPI1 CSn | UART1 RX | I2C0 SCL | PWM4 B | SIO | PIO0 | PIO1 | CLOCK GPOUT3 | USB VBUS DET
* 26 | SPI1 SCK | UART1 CTS | I2C1 SDA | PWM5 A | SIO | PIO0 | PIO1 | | USB VBUS EN
* 27 | SPI1 TX | UART1 RTS | I2C1 SCL | PWM5 B | SIO | PIO0 | PIO1 | | USB OVCUR DET
* 28 | SPI1 RX | UART0 TX | I2C0 SDA | PWM6 A | SIO | PIO0 | PIO1 | | USB VBUS DET
* 29 | SPI1 CSn | UART0 RX | I2C0 SCL | PWM6 B | SIO | PIO0 | PIO1 | | USB VBUS EN
*/
/*! \brief GPIO function definitions for use with function select
* \ingroup hardware_gpio
* \brief GPIO function selectors
*
* Each GPIO can have one function selected at a time. Likewise, each peripheral input (e.g. UART0 RX) should only be
* selected on one GPIO at a time. If the same peripheral input is connected to multiple GPIOs, the peripheral sees the logical
* OR of these GPIO inputs.
*
* Please refer to the datsheet for more information on GPIO function selection.
*/
enum gpio_function {
GPIO_FUNC_XIP = 0,
GPIO_FUNC_SPI = 1,
GPIO_FUNC_UART = 2,
GPIO_FUNC_I2C = 3,
GPIO_FUNC_PWM = 4,
GPIO_FUNC_SIO = 5,
GPIO_FUNC_PIO0 = 6,
GPIO_FUNC_PIO1 = 7,
GPIO_FUNC_GPCK = 8,
GPIO_FUNC_USB = 9,
GPIO_FUNC_NULL = 0x1f,
};
#define GPIO_OUT 1
#define GPIO_IN 0
/*! \brief GPIO Interrupt level definitions
* \ingroup hardware_gpio
* \brief GPIO Interrupt levels
*
* An interrupt can be generated for every GPIO pin in 4 scenarios:
*
* * Level High: the GPIO pin is a logical 1
* * Level Low: the GPIO pin is a logical 0
* * Edge High: the GPIO has transitioned from a logical 0 to a logical 1
* * Edge Low: the GPIO has transitioned from a logical 1 to a logical 0
*
* The level interrupts are not latched. This means that if the pin is a logical 1 and the level high interrupt is active, it will
* become inactive as soon as the pin changes to a logical 0. The edge interrupts are stored in the INTR register and can be
* cleared by writing to the INTR register.
*/
enum gpio_irq_level {
GPIO_IRQ_LEVEL_LOW = 0x1u,
GPIO_IRQ_LEVEL_HIGH = 0x2u,
GPIO_IRQ_EDGE_FALL = 0x4u,
GPIO_IRQ_EDGE_RISE = 0x8u,
};
/*! Callback function type for GPIO events
* \ingroup hardware_gpio
*
* \param gpio Which GPIO caused this interrupt
* \param events Which events caused this interrupt. See \ref gpio_set_irq_enabled for details.
* \sa gpio_set_irq_enabled_with_callback()
*/
typedef void (*gpio_irq_callback_t)(uint gpio, uint32_t events);
enum gpio_override {
GPIO_OVERRIDE_NORMAL = 0, ///< peripheral signal selected via \ref gpio_set_function
GPIO_OVERRIDE_INVERT = 1, ///< invert peripheral signal selected via \ref gpio_set_function
GPIO_OVERRIDE_LOW = 2, ///< drive low/disable output
GPIO_OVERRIDE_HIGH = 3, ///< drive high/enable output
};
/*! \brief Slew rate limiting levels for GPIO outputs
* \ingroup hardware_gpio
*
* Slew rate limiting increases the minimum rise/fall time when a GPIO output
* is lightly loaded, which can help to reduce electromagnetic emissions.
* \sa gpio_set_slew_rate
*/
enum gpio_slew_rate {
GPIO_SLEW_RATE_SLOW = 0, ///< Slew rate limiting enabled
GPIO_SLEW_RATE_FAST = 1 ///< Slew rate limiting disabled
};
/*! \brief Drive strength levels for GPIO outputs
* \ingroup hardware_gpio
*
* Drive strength levels for GPIO outputs.
* \sa gpio_set_drive_strength
*/
enum gpio_drive_strength {
GPIO_DRIVE_STRENGTH_2MA = 0, ///< 2 mA nominal drive strength
GPIO_DRIVE_STRENGTH_4MA = 1, ///< 4 mA nominal drive strength
GPIO_DRIVE_STRENGTH_8MA = 2, ///< 8 mA nominal drive strength
GPIO_DRIVE_STRENGTH_12MA = 3 ///< 12 mA nominal drive strength
};
// ----------------------------------------------------------------------------
// Pad Controls + IO Muxing
// ----------------------------------------------------------------------------
// Declarations for gpio.c
/*! \brief Select GPIO function
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \param fn Which GPIO function select to use from list \ref gpio_function
*/
void gpio_set_function(uint gpio, enum gpio_function fn);
enum gpio_function gpio_get_function(uint gpio);
/*! \brief Select up and down pulls on specific GPIO
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \param up If true set a pull up on the GPIO
* \param down If true set a pull down on the GPIO
*
* \note On the RP2040, setting both pulls enables a "bus keep" function,
* i.e. a weak pull to whatever is current high/low state of GPIO.
*/
void gpio_set_pulls(uint gpio, bool up, bool down);
/*! \brief Set specified GPIO to be pulled up.
* \ingroup hardware_gpio
*
* \param gpio GPIO number
*/
static inline void gpio_pull_up(uint gpio) {
gpio_set_pulls(gpio, true, false);
}
/*! \brief Determine if the specified GPIO is pulled up.
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \return true if the GPIO is pulled up
*/
static inline bool gpio_is_pulled_up(uint gpio) {
return (padsbank0_hw->io[gpio] & PADS_BANK0_GPIO0_PUE_BITS) != 0;
}
/*! \brief Set specified GPIO to be pulled down.
* \ingroup hardware_gpio
*
* \param gpio GPIO number
*/
static inline void gpio_pull_down(uint gpio) {
gpio_set_pulls(gpio, false, true);
}
/*! \brief Determine if the specified GPIO is pulled down.
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \return true if the GPIO is pulled down
*/
static inline bool gpio_is_pulled_down(uint gpio) {
return (padsbank0_hw->io[gpio] & PADS_BANK0_GPIO0_PDE_BITS) != 0;
}
/*! \brief Disable pulls on specified GPIO
* \ingroup hardware_gpio
*
* \param gpio GPIO number
*/
static inline void gpio_disable_pulls(uint gpio) {
gpio_set_pulls(gpio, false, false);
}
/*! \brief Set GPIO IRQ override
* \ingroup hardware_gpio
*
* Optionally invert a GPIO IRQ signal, or drive it high or low
*
* \param gpio GPIO number
* \param value See \ref gpio_override
*/
void gpio_set_irqover(uint gpio, uint value);
/*! \brief Set GPIO output override
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \param value See \ref gpio_override
*/
void gpio_set_outover(uint gpio, uint value);
/*! \brief Select GPIO input override
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \param value See \ref gpio_override
*/
void gpio_set_inover(uint gpio, uint value);
/*! \brief Select GPIO output enable override
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \param value See \ref gpio_override
*/
void gpio_set_oeover(uint gpio, uint value);
/*! \brief Enable GPIO input
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \param enabled true to enable input on specified GPIO
*/
void gpio_set_input_enabled(uint gpio, bool enabled);
/*! \brief Enable/disable GPIO input hysteresis (Schmitt trigger)
* \ingroup hardware_gpio
*
* Enable or disable the Schmitt trigger hysteresis on a given GPIO. This is
* enabled on all GPIOs by default. Disabling input hysteresis can lead to
* inconsistent readings when the input signal has very long rise or fall
* times, but slightly reduces the GPIO's input delay.
*
* \sa gpio_is_input_hysteresis_enabled
* \param gpio GPIO number
* \param enabled true to enable input hysteresis on specified GPIO
*/
void gpio_set_input_hysteresis_enabled(uint gpio, bool enabled);
/*! \brief Determine whether input hysteresis is enabled on a specified GPIO
* \ingroup hardware_gpio
*
* \sa gpio_set_input_hysteresis_enabled
* \param gpio GPIO number
*/
bool gpio_is_input_hysteresis_enabled(uint gpio);
/*! \brief Set slew rate for a specified GPIO
* \ingroup hardware_gpio
*
* \sa gpio_get_slew_rate
* \param gpio GPIO number
* \param slew GPIO output slew rate
*/
void gpio_set_slew_rate(uint gpio, enum gpio_slew_rate slew);
/*! \brief Determine current slew rate for a specified GPIO
* \ingroup hardware_gpio
*
* \sa gpio_set_slew_rate
* \param gpio GPIO number
* \return Current slew rate of that GPIO
*/
enum gpio_slew_rate gpio_get_slew_rate(uint gpio);
/*! \brief Set drive strength for a specified GPIO
* \ingroup hardware_gpio
*
* \sa gpio_get_drive_strength
* \param gpio GPIO number
* \param drive GPIO output drive strength
*/
void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive);
/*! \brief Determine current slew rate for a specified GPIO
* \ingroup hardware_gpio
*
* \sa gpio_set_drive_strength
* \param gpio GPIO number
* \return Current drive strength of that GPIO
*/
enum gpio_drive_strength gpio_get_drive_strength(uint gpio);
/*! \brief Enable or disable interrupts for specified GPIO
* \ingroup hardware_gpio
*
* \note The IO IRQs are independent per-processor. This configures IRQs for
* the processor that calls the function.
*
* \param gpio GPIO number
* \param events Which events will cause an interrupt
* \param enabled Enable or disable flag
*
* Events is a bitmask of the following:
*
* bit | interrupt
* ----|----------
* 0 | Low level
* 1 | High level
* 2 | Edge low
* 3 | Edge high
*/
void gpio_set_irq_enabled(uint gpio, uint32_t events, bool enabled);
/*! \brief Enable interrupts for specified GPIO
* \ingroup hardware_gpio
*
* \note The IO IRQs are independent per-processor. This configures IRQs for
* the processor that calls the function.
*
* \param gpio GPIO number
* \param events Which events will cause an interrupt. See \ref gpio_set_irq_enabled for details.
* \param enabled Enable or disable flag
* \param callback user function to call on GPIO irq. Note only one of these can be set per processor.
*
* \note Currently the GPIO parameter is ignored, and this callback will be called for any enabled GPIO IRQ on any pin.
*
*/
void gpio_set_irq_enabled_with_callback(uint gpio, uint32_t events, bool enabled, gpio_irq_callback_t callback);
/*! \brief Enable dormant wake up interrupt for specified GPIO
* \ingroup hardware_gpio
*
* This configures IRQs to restart the XOSC or ROSC when they are
* disabled in dormant mode
*
* \param gpio GPIO number
* \param events Which events will cause an interrupt. See \ref gpio_set_irq_enabled for details.
* \param enabled Enable/disable flag
*/
void gpio_set_dormant_irq_enabled(uint gpio, uint32_t events, bool enabled);
/*! \brief Acknowledge a GPIO interrupt
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \param events Bitmask of events to clear. See \ref gpio_set_irq_enabled for details.
*
*/
void gpio_acknowledge_irq(uint gpio, uint32_t events);
/*! \brief Initialise a GPIO for (enabled I/O and set func to GPIO_FUNC_SIO)
* \ingroup hardware_gpio
*
* Clear the output enable (i.e. set to input)
* Clear any output value.
*
* \param gpio GPIO number
*/
void gpio_init(uint gpio);
/*! \brief Initialise multiple GPIOs (enabled I/O and set func to GPIO_FUNC_SIO)
* \ingroup hardware_gpio
*
* Clear the output enable (i.e. set to input)
* Clear any output value.
*
* \param gpio_mask Mask with 1 bit per GPIO number to initialize
*/
void gpio_init_mask(uint gpio_mask);
// ----------------------------------------------------------------------------
// Input
// ----------------------------------------------------------------------------
/*! \brief Get state of a single specified GPIO
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \return Current state of the GPIO. 0 for low, non-zero for high
*/
static inline bool gpio_get(uint gpio) {
return !!((1ul << gpio) & sio_hw->gpio_in);
}
/*! \brief Get raw value of all GPIOs
* \ingroup hardware_gpio
*
* \return Bitmask of raw GPIO values, as bits 0-29
*/
static inline uint32_t gpio_get_all(void) {
return sio_hw->gpio_in;
}
// ----------------------------------------------------------------------------
// Output
// ----------------------------------------------------------------------------
/*! \brief Drive high every GPIO appearing in mask
* \ingroup hardware_gpio
*
* \param mask Bitmask of GPIO values to set, as bits 0-29
*/
static inline void gpio_set_mask(uint32_t mask) {
sio_hw->gpio_set = mask;
}
/*! \brief Drive low every GPIO appearing in mask
* \ingroup hardware_gpio
*
* \param mask Bitmask of GPIO values to clear, as bits 0-29
*/
static inline void gpio_clr_mask(uint32_t mask) {
sio_hw->gpio_clr = mask;
}
/*! \brief Toggle every GPIO appearing in mask
* \ingroup hardware_gpio
*
* \param mask Bitmask of GPIO values to toggle, as bits 0-29
*/
static inline void gpio_xor_mask(uint32_t mask) {
sio_hw->gpio_togl = mask;
}
/*! \brief Drive GPIO high/low depending on parameters
* \ingroup hardware_gpio
*
* \param mask Bitmask of GPIO values to change, as bits 0-29
* \param value Value to set
*
* For each 1 bit in \p mask, drive that pin to the value given by
* corresponding bit in \p value, leaving other pins unchanged.
* Since this uses the TOGL alias, it is concurrency-safe with e.g. an IRQ
* bashing different pins from the same core.
*/
static inline void gpio_put_masked(uint32_t mask, uint32_t value) {
sio_hw->gpio_togl = (sio_hw->gpio_out ^ value) & mask;
}
/*! \brief Drive all pins simultaneously
* \ingroup hardware_gpio
*
* \param value Bitmask of GPIO values to change, as bits 0-29
*/
static inline void gpio_put_all(uint32_t value) {
sio_hw->gpio_out = value;
}
/*! \brief Drive a single GPIO high/low
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \param value If false clear the GPIO, otherwise set it.
*/
static inline void gpio_put(uint gpio, bool value) {
uint32_t mask = 1ul << gpio;
if (value)
gpio_set_mask(mask);
else
gpio_clr_mask(mask);
}
/*! \brief Determine whether a GPIO is currently driven high or low
* \ingroup hardware_gpio
*
* This function returns the high/low output level most recently assigned to a
* GPIO via gpio_put() or similar. This is the value that is presented outward
* to the IO muxing, *not* the input level back from the pad (which can be
* read using gpio_get()).
*
* To avoid races, this function must not be used for read-modify-write
* sequences when driving GPIOs -- instead functions like gpio_put() should be
* used to atomically update GPIOs. This accessor is intended for debug use
* only.
*
* \param gpio GPIO number
* \return true if the GPIO output level is high, false if low.
*/
static inline bool gpio_get_out_level(uint gpio) {
return !!(sio_hw->gpio_out & (1u << gpio));
}
// ----------------------------------------------------------------------------
// Direction
// ----------------------------------------------------------------------------
/*! \brief Set a number of GPIOs to output
* \ingroup hardware_gpio
*
* Switch all GPIOs in "mask" to output
*
* \param mask Bitmask of GPIO to set to output, as bits 0-29
*/
static inline void gpio_set_dir_out_masked(uint32_t mask) {
sio_hw->gpio_oe_set = mask;
}
/*! \brief Set a number of GPIOs to input
* \ingroup hardware_gpio
*
* \param mask Bitmask of GPIO to set to input, as bits 0-29
*/
static inline void gpio_set_dir_in_masked(uint32_t mask) {
sio_hw->gpio_oe_clr = mask;
}
/*! \brief Set multiple GPIO directions
* \ingroup hardware_gpio
*
* \param mask Bitmask of GPIO to set to input, as bits 0-29
* \param value Values to set
*
* For each 1 bit in "mask", switch that pin to the direction given by
* corresponding bit in "value", leaving other pins unchanged.
* E.g. gpio_set_dir_masked(0x3, 0x2); -> set pin 0 to input, pin 1 to output,
* simultaneously.
*/
static inline void gpio_set_dir_masked(uint32_t mask, uint32_t value) {
sio_hw->gpio_oe_togl = (sio_hw->gpio_oe ^ value) & mask;
}
/*! \brief Set direction of all pins simultaneously.
* \ingroup hardware_gpio
*
* \param values individual settings for each gpio; for GPIO N, bit N is 1 for out, 0 for in
*/
static inline void gpio_set_dir_all_bits(uint32_t values) {
sio_hw->gpio_oe = values;
}
/*! \brief Set a single GPIO direction
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \param out true for out, false for in
*/
static inline void gpio_set_dir(uint gpio, bool out) {
uint32_t mask = 1ul << gpio;
if (out)
gpio_set_dir_out_masked(mask);
else
gpio_set_dir_in_masked(mask);
}
/*! \brief Check if a specific GPIO direction is OUT
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \return true if the direction for the pin is OUT
*/
static inline bool gpio_is_dir_out(uint gpio) {
return !!(sio_hw->gpio_oe & (1u << (gpio)));
}
/*! \brief Get a specific GPIO direction
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \return 1 for out, 0 for in
*/
static inline uint gpio_get_dir(uint gpio) {
return gpio_is_dir_out(gpio); // note GPIO_OUT is 1/true and GPIO_IN is 0/false anyway
}
extern void gpio_debug_pins_init(void);
#ifdef __cplusplus
}
#endif
// PICO_CONFIG: PICO_DEBUG_PIN_BASE, First pin to use for debug output (if enabled), min=0, max=28, default=19, group=hardware_gpio
#ifndef PICO_DEBUG_PIN_BASE
#define PICO_DEBUG_PIN_BASE 19u
#endif
// PICO_CONFIG: PICO_DEBUG_PIN_COUNT, Number of pins to use for debug output (if enabled), min=1, max=28, default=3, group=hardware_gpio
#ifndef PICO_DEBUG_PIN_COUNT
#define PICO_DEBUG_PIN_COUNT 3u
#endif
#ifndef __cplusplus
// note these two macros may only be used once per and only apply per compilation unit (hence the CU_)
#define CU_REGISTER_DEBUG_PINS(...) enum __unused DEBUG_PIN_TYPE { _none = 0, __VA_ARGS__ }; static enum DEBUG_PIN_TYPE __selected_debug_pins;
#define CU_SELECT_DEBUG_PINS(x) static enum DEBUG_PIN_TYPE __selected_debug_pins = (x);
#define DEBUG_PINS_ENABLED(p) (__selected_debug_pins == (p))
#else
#define CU_REGISTER_DEBUG_PINS(p...) \
enum DEBUG_PIN_TYPE { _none = 0, p }; \
template <enum DEBUG_PIN_TYPE> class __debug_pin_settings { \
public: \
static inline bool enabled() { return false; } \
};
#define CU_SELECT_DEBUG_PINS(x) template<> inline bool __debug_pin_settings<x>::enabled() { return true; };
#define DEBUG_PINS_ENABLED(p) (__debug_pin_settings<p>::enabled())
#endif
#define DEBUG_PINS_SET(p, v) if (DEBUG_PINS_ENABLED(p)) gpio_set_mask((unsigned)(v)<<PICO_DEBUG_PIN_BASE)
#define DEBUG_PINS_CLR(p, v) if (DEBUG_PINS_ENABLED(p)) gpio_clr_mask((unsigned)(v)<<PICO_DEBUG_PIN_BASE)
#define DEBUG_PINS_XOR(p, v) if (DEBUG_PINS_ENABLED(p)) gpio_xor_mask((unsigned)(v)<<PICO_DEBUG_PIN_BASE)
#endif // _GPIO_H_