Skip to content

Commit 4cf55b4

Browse files
committed
Add new GPIO APIs for adding shared GPIO handlers, and improve docs
1 parent f3c446a commit 4cf55b4

File tree

3 files changed

+292
-51
lines changed

3 files changed

+292
-51
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
pico_simple_hardware_target(gpio)
1+
pico_simple_hardware_target(gpio)
2+
target_link_libraries(hardware_gpio INTERFACE hardware_irq)

src/rp2_common/hardware_gpio/gpio.c

Lines changed: 67 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
#include "pico/binary_info.h"
1515
#endif
1616

17-
static gpio_irq_callback_t _callbacks[NUM_CORES];
17+
static gpio_irq_callback_t callbacks[NUM_CORES];
18+
// a 1 bit means the IRQ is handled by a raw IRQ handler
19+
static uint32_t raw_irq_mask[NUM_CORES];
1820

1921
// Get the raw value from the pin, bypassing any muxing or overrides.
2022
int gpio_get_pad(uint gpio) {
21-
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
23+
check_gpio_param(gpio);
2224
hw_set_bits(&padsbank0_hw->io[gpio], PADS_BANK0_GPIO0_IE_BITS);
2325
return (iobank0_hw->io[gpio].status & IO_BANK0_GPIO0_STATUS_INFROMPAD_BITS)
2426
>> IO_BANK0_GPIO0_STATUS_INFROMPAD_LSB;
@@ -28,7 +30,7 @@ int gpio_get_pad(uint gpio) {
2830
// Select function for this GPIO, and ensure input/output are enabled at the pad.
2931
// This also clears the input/output/irq override bits.
3032
void gpio_set_function(uint gpio, enum gpio_function fn) {
31-
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
33+
check_gpio_param(gpio);
3234
invalid_params_if(GPIO, ((uint32_t)fn << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB) & ~IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS);
3335
// Set input enable on, output disable off
3436
hw_write_masked(&padsbank0_hw->io[gpio],
@@ -42,14 +44,14 @@ void gpio_set_function(uint gpio, enum gpio_function fn) {
4244
/// \end::gpio_set_function[]
4345

4446
enum gpio_function gpio_get_function(uint gpio) {
45-
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
47+
check_gpio_param(gpio);
4648
return (enum gpio_function) ((iobank0_hw->io[gpio].ctrl & IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS) >> IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB);
4749
}
4850

4951
// Note that, on RP2040, setting both pulls enables a "bus keep" function,
5052
// i.e. weak pull to whatever is current high/low state of GPIO.
5153
void gpio_set_pulls(uint gpio, bool up, bool down) {
52-
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
54+
check_gpio_param(gpio);
5355
hw_write_masked(
5456
&padsbank0_hw->io[gpio],
5557
(bool_to_bit(up) << PADS_BANK0_GPIO0_PUE_LSB) | (bool_to_bit(down) << PADS_BANK0_GPIO0_PDE_LSB),
@@ -59,7 +61,7 @@ void gpio_set_pulls(uint gpio, bool up, bool down) {
5961

6062
// Direct override for per-GPIO IRQ signal
6163
void gpio_set_irqover(uint gpio, uint value) {
62-
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
64+
check_gpio_param(gpio);
6365
hw_write_masked(&iobank0_hw->io[gpio].ctrl,
6466
value << IO_BANK0_GPIO0_CTRL_IRQOVER_LSB,
6567
IO_BANK0_GPIO0_CTRL_IRQOVER_BITS
@@ -68,31 +70,31 @@ void gpio_set_irqover(uint gpio, uint value) {
6870

6971
// Direct overrides for pad controls
7072
void gpio_set_inover(uint gpio, uint value) {
71-
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
73+
check_gpio_param(gpio);
7274
hw_write_masked(&iobank0_hw->io[gpio].ctrl,
7375
value << IO_BANK0_GPIO0_CTRL_INOVER_LSB,
7476
IO_BANK0_GPIO0_CTRL_INOVER_BITS
7577
);
7678
}
7779

7880
void gpio_set_outover(uint gpio, uint value) {
79-
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
81+
check_gpio_param(gpio);
8082
hw_write_masked(&iobank0_hw->io[gpio].ctrl,
8183
value << IO_BANK0_GPIO0_CTRL_OUTOVER_LSB,
8284
IO_BANK0_GPIO0_CTRL_OUTOVER_BITS
8385
);
8486
}
8587

8688
void gpio_set_oeover(uint gpio, uint value) {
87-
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
89+
check_gpio_param(gpio);
8890
hw_write_masked(&iobank0_hw->io[gpio].ctrl,
8991
value << IO_BANK0_GPIO0_CTRL_OEOVER_LSB,
9092
IO_BANK0_GPIO0_CTRL_OEOVER_BITS
9193
);
9294
}
9395

9496
void gpio_set_input_hysteresis_enabled(uint gpio, bool enabled) {
95-
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
97+
check_gpio_param(gpio);
9698
if (enabled)
9799
hw_set_bits(&padsbank0_hw->io[gpio], PADS_BANK0_GPIO0_SCHMITT_BITS);
98100
else
@@ -101,20 +103,20 @@ void gpio_set_input_hysteresis_enabled(uint gpio, bool enabled) {
101103

102104

103105
bool gpio_is_input_hysteresis_enabled(uint gpio) {
104-
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
106+
check_gpio_param(gpio);
105107
return (padsbank0_hw->io[gpio] & PADS_BANK0_GPIO0_SCHMITT_BITS) != 0;
106108
}
107109

108110
void gpio_set_slew_rate(uint gpio, enum gpio_slew_rate slew) {
109-
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
111+
check_gpio_param(gpio);
110112
hw_write_masked(&padsbank0_hw->io[gpio],
111113
(uint)slew << PADS_BANK0_GPIO0_SLEWFAST_LSB,
112114
PADS_BANK0_GPIO0_SLEWFAST_BITS
113115
);
114116
}
115117

116118
enum gpio_slew_rate gpio_get_slew_rate(uint gpio) {
117-
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
119+
check_gpio_param(gpio);
118120
return (enum gpio_slew_rate)((padsbank0_hw->io[gpio]
119121
& PADS_BANK0_GPIO0_SLEWFAST_BITS)
120122
>> PADS_BANK0_GPIO0_SLEWFAST_LSB);
@@ -124,32 +126,35 @@ enum gpio_slew_rate gpio_get_slew_rate(uint gpio) {
124126
// Enum encoding should match hardware encoding on RP2040
125127
static_assert(PADS_BANK0_GPIO0_DRIVE_VALUE_8MA == GPIO_DRIVE_STRENGTH_8MA, "");
126128
void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive) {
127-
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
129+
check_gpio_param(gpio);
128130
hw_write_masked(&padsbank0_hw->io[gpio],
129131
(uint)drive << PADS_BANK0_GPIO0_DRIVE_LSB,
130132
PADS_BANK0_GPIO0_DRIVE_BITS
131133
);
132134
}
133135

134136
enum gpio_drive_strength gpio_get_drive_strength(uint gpio) {
135-
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
137+
check_gpio_param(gpio);
136138
return (enum gpio_drive_strength)((padsbank0_hw->io[gpio]
137139
& PADS_BANK0_GPIO0_DRIVE_BITS)
138140
>> PADS_BANK0_GPIO0_DRIVE_LSB);
139141
}
140142

141-
static void gpio_irq_handler(void) {
142-
io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ?
143-
&iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
144-
for (uint gpio = 0; gpio < NUM_BANK0_GPIOS; gpio++) {
145-
io_ro_32 *status_reg = &irq_ctrl_base->ints[gpio / 8];
146-
uint events = (*status_reg >> 4 * (gpio % 8)) & 0xf;
147-
if (events) {
148-
// TODO: If both cores care about this event then the second core won't get the irq?
149-
gpio_acknowledge_irq(gpio, events);
150-
gpio_irq_callback_t callback = _callbacks[get_core_num()];
151-
if (callback) {
152-
callback(gpio, events);
143+
static void gpio_default_irq_handler(void) {
144+
uint core = get_core_num();
145+
gpio_irq_callback_t callback = callbacks[core];
146+
io_irq_ctrl_hw_t *irq_ctrl_base = core ? &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
147+
for (uint gpio = 0; gpio < NUM_BANK0_GPIOS; gpio+=8) {
148+
uint32_t events8 = irq_ctrl_base->ints[gpio >> 3u];
149+
// note we assume events8 is 0 for non-existent GPIO
150+
for(uint i=gpio;events8 && i<gpio+8;i++) {
151+
events8 >>= 4;
152+
uint32_t events = events8 & 0xfu;
153+
if (events && !(raw_irq_mask[core] & (1u << i))) {
154+
gpio_acknowledge_irq(i, events);
155+
if (callback) {
156+
callback(gpio, events);
157+
}
153158
}
154159
}
155160
}
@@ -177,22 +182,50 @@ void gpio_set_irq_enabled(uint gpio, uint32_t events, bool enabled) {
177182
}
178183

179184
void gpio_set_irq_enabled_with_callback(uint gpio, uint32_t events, bool enabled, gpio_irq_callback_t callback) {
185+
// this is the original behavior
180186
gpio_set_irq_enabled(gpio, events, enabled);
187+
gpio_set_irq_callback(callback);
188+
if (enabled) irq_set_enabled(IO_IRQ_BANK0, true);
189+
}
190+
191+
void gpio_set_irq_callback(gpio_irq_callback_t callback) {
192+
uint core = get_core_num();
193+
if (callbacks[core]) {
194+
if (!callback) {
195+
irq_remove_handler(IO_IRQ_BANK0, gpio_default_irq_handler);
196+
}
197+
callbacks[core] = callback;
198+
} else if (callback) {
199+
callbacks[core] = callback;
200+
// todo - remove comment; note we could have added a #define to resort to the old exclusive handler, but since the
201+
// new handler is likely faster anyway, i don't think there is much point (it's only a few cycles for a shared one)
202+
irq_add_shared_handler(IO_IRQ_BANK0, gpio_default_irq_handler, GPIO_CALLBACK_IRQ_ORDER_PRIORITY);
203+
}
204+
}
205+
206+
void gpio_add_raw_irq_handler_with_order_priority_masked(uint gpio_mask, irq_handler_t handler, uint8_t order_priority) {
207+
raw_irq_mask[get_core_num()] |= gpio_mask;
208+
irq_add_shared_handler(IO_IRQ_BANK0, handler, order_priority);
209+
}
210+
211+
void gpio_add_raw_irq_handler_masked(uint gpio_mask, irq_handler_t handler) {
212+
gpio_add_raw_irq_handler_with_order_priority_masked(gpio_mask, handler, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
213+
}
181214

182-
// TODO: Do we want to support a callback per GPIO pin?
183-
// Install IRQ handler
184-
_callbacks[get_core_num()] = callback;
185-
irq_set_exclusive_handler(IO_IRQ_BANK0, gpio_irq_handler);
186-
irq_set_enabled(IO_IRQ_BANK0, true);
215+
void gpio_remove_raw_irq_handler_masked(uint gpio_mask, irq_handler_t handler) {
216+
irq_remove_handler(IO_IRQ_BANK0, handler);
217+
raw_irq_mask[get_core_num()] &= ~gpio_mask;
187218
}
188219

189220
void gpio_set_dormant_irq_enabled(uint gpio, uint32_t events, bool enabled) {
221+
check_gpio_param(gpio);
190222
io_irq_ctrl_hw_t *irq_ctrl_base = &iobank0_hw->dormant_wake_irq_ctrl;
191223
_gpio_set_irq_enabled(gpio, events, enabled, irq_ctrl_base);
192224
}
193225

194226
void gpio_acknowledge_irq(uint gpio, uint32_t events) {
195-
iobank0_hw->intr[gpio / 8] = events << 4 * (gpio % 8);
227+
check_gpio_param(gpio);
228+
iobank0_hw->intr[gpio / 8] = events << (4 * (gpio % 8));
196229
}
197230

198231
#define DEBUG_PIN_MASK (((1u << PICO_DEBUG_PIN_COUNT)-1) << PICO_DEBUG_PIN_BASE)
@@ -222,7 +255,7 @@ void gpio_deinit(uint gpio) {
222255
}
223256

224257
void gpio_init_mask(uint gpio_mask) {
225-
for(uint i=0;i<32;i++) {
258+
for(uint i=0;i<NUM_BANK0_GPIOS;i++) {
226259
if (gpio_mask & 1) {
227260
gpio_init(i);
228261
}

0 commit comments

Comments
 (0)