14
14
#include "pico/binary_info.h"
15
15
#endif
16
16
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 ];
18
20
19
21
// Get the raw value from the pin, bypassing any muxing or overrides.
20
22
int gpio_get_pad (uint gpio ) {
21
- invalid_params_if ( GPIO , gpio >= NUM_BANK0_GPIOS );
23
+ check_gpio_param ( gpio );
22
24
hw_set_bits (& padsbank0_hw -> io [gpio ], PADS_BANK0_GPIO0_IE_BITS );
23
25
return (iobank0_hw -> io [gpio ].status & IO_BANK0_GPIO0_STATUS_INFROMPAD_BITS )
24
26
>> IO_BANK0_GPIO0_STATUS_INFROMPAD_LSB ;
@@ -28,7 +30,7 @@ int gpio_get_pad(uint gpio) {
28
30
// Select function for this GPIO, and ensure input/output are enabled at the pad.
29
31
// This also clears the input/output/irq override bits.
30
32
void gpio_set_function (uint gpio , enum gpio_function fn ) {
31
- invalid_params_if ( GPIO , gpio >= NUM_BANK0_GPIOS );
33
+ check_gpio_param ( gpio );
32
34
invalid_params_if (GPIO , ((uint32_t )fn << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB ) & ~IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS );
33
35
// Set input enable on, output disable off
34
36
hw_write_masked (& padsbank0_hw -> io [gpio ],
@@ -42,14 +44,14 @@ void gpio_set_function(uint gpio, enum gpio_function fn) {
42
44
/// \end::gpio_set_function[]
43
45
44
46
enum gpio_function gpio_get_function (uint gpio ) {
45
- invalid_params_if ( GPIO , gpio >= NUM_BANK0_GPIOS );
47
+ check_gpio_param ( gpio );
46
48
return (enum gpio_function ) ((iobank0_hw -> io [gpio ].ctrl & IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS ) >> IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB );
47
49
}
48
50
49
51
// Note that, on RP2040, setting both pulls enables a "bus keep" function,
50
52
// i.e. weak pull to whatever is current high/low state of GPIO.
51
53
void gpio_set_pulls (uint gpio , bool up , bool down ) {
52
- invalid_params_if ( GPIO , gpio >= NUM_BANK0_GPIOS );
54
+ check_gpio_param ( gpio );
53
55
hw_write_masked (
54
56
& padsbank0_hw -> io [gpio ],
55
57
(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) {
59
61
60
62
// Direct override for per-GPIO IRQ signal
61
63
void gpio_set_irqover (uint gpio , uint value ) {
62
- invalid_params_if ( GPIO , gpio >= NUM_BANK0_GPIOS );
64
+ check_gpio_param ( gpio );
63
65
hw_write_masked (& iobank0_hw -> io [gpio ].ctrl ,
64
66
value << IO_BANK0_GPIO0_CTRL_IRQOVER_LSB ,
65
67
IO_BANK0_GPIO0_CTRL_IRQOVER_BITS
@@ -68,31 +70,31 @@ void gpio_set_irqover(uint gpio, uint value) {
68
70
69
71
// Direct overrides for pad controls
70
72
void gpio_set_inover (uint gpio , uint value ) {
71
- invalid_params_if ( GPIO , gpio >= NUM_BANK0_GPIOS );
73
+ check_gpio_param ( gpio );
72
74
hw_write_masked (& iobank0_hw -> io [gpio ].ctrl ,
73
75
value << IO_BANK0_GPIO0_CTRL_INOVER_LSB ,
74
76
IO_BANK0_GPIO0_CTRL_INOVER_BITS
75
77
);
76
78
}
77
79
78
80
void gpio_set_outover (uint gpio , uint value ) {
79
- invalid_params_if ( GPIO , gpio >= NUM_BANK0_GPIOS );
81
+ check_gpio_param ( gpio );
80
82
hw_write_masked (& iobank0_hw -> io [gpio ].ctrl ,
81
83
value << IO_BANK0_GPIO0_CTRL_OUTOVER_LSB ,
82
84
IO_BANK0_GPIO0_CTRL_OUTOVER_BITS
83
85
);
84
86
}
85
87
86
88
void gpio_set_oeover (uint gpio , uint value ) {
87
- invalid_params_if ( GPIO , gpio >= NUM_BANK0_GPIOS );
89
+ check_gpio_param ( gpio );
88
90
hw_write_masked (& iobank0_hw -> io [gpio ].ctrl ,
89
91
value << IO_BANK0_GPIO0_CTRL_OEOVER_LSB ,
90
92
IO_BANK0_GPIO0_CTRL_OEOVER_BITS
91
93
);
92
94
}
93
95
94
96
void gpio_set_input_hysteresis_enabled (uint gpio , bool enabled ) {
95
- invalid_params_if ( GPIO , gpio >= NUM_BANK0_GPIOS );
97
+ check_gpio_param ( gpio );
96
98
if (enabled )
97
99
hw_set_bits (& padsbank0_hw -> io [gpio ], PADS_BANK0_GPIO0_SCHMITT_BITS );
98
100
else
@@ -101,20 +103,20 @@ void gpio_set_input_hysteresis_enabled(uint gpio, bool enabled) {
101
103
102
104
103
105
bool gpio_is_input_hysteresis_enabled (uint gpio ) {
104
- invalid_params_if ( GPIO , gpio >= NUM_BANK0_GPIOS );
106
+ check_gpio_param ( gpio );
105
107
return (padsbank0_hw -> io [gpio ] & PADS_BANK0_GPIO0_SCHMITT_BITS ) != 0 ;
106
108
}
107
109
108
110
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 );
110
112
hw_write_masked (& padsbank0_hw -> io [gpio ],
111
113
(uint )slew << PADS_BANK0_GPIO0_SLEWFAST_LSB ,
112
114
PADS_BANK0_GPIO0_SLEWFAST_BITS
113
115
);
114
116
}
115
117
116
118
enum gpio_slew_rate gpio_get_slew_rate (uint gpio ) {
117
- invalid_params_if ( GPIO , gpio >= NUM_BANK0_GPIOS );
119
+ check_gpio_param ( gpio );
118
120
return (enum gpio_slew_rate )((padsbank0_hw -> io [gpio ]
119
121
& PADS_BANK0_GPIO0_SLEWFAST_BITS )
120
122
>> PADS_BANK0_GPIO0_SLEWFAST_LSB );
@@ -124,32 +126,35 @@ enum gpio_slew_rate gpio_get_slew_rate(uint gpio) {
124
126
// Enum encoding should match hardware encoding on RP2040
125
127
static_assert (PADS_BANK0_GPIO0_DRIVE_VALUE_8MA == GPIO_DRIVE_STRENGTH_8MA , "" );
126
128
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 );
128
130
hw_write_masked (& padsbank0_hw -> io [gpio ],
129
131
(uint )drive << PADS_BANK0_GPIO0_DRIVE_LSB ,
130
132
PADS_BANK0_GPIO0_DRIVE_BITS
131
133
);
132
134
}
133
135
134
136
enum gpio_drive_strength gpio_get_drive_strength (uint gpio ) {
135
- invalid_params_if ( GPIO , gpio >= NUM_BANK0_GPIOS );
137
+ check_gpio_param ( gpio );
136
138
return (enum gpio_drive_strength )((padsbank0_hw -> io [gpio ]
137
139
& PADS_BANK0_GPIO0_DRIVE_BITS )
138
140
>> PADS_BANK0_GPIO0_DRIVE_LSB );
139
141
}
140
142
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
+ }
153
158
}
154
159
}
155
160
}
@@ -177,22 +182,50 @@ void gpio_set_irq_enabled(uint gpio, uint32_t events, bool enabled) {
177
182
}
178
183
179
184
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
180
186
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
+ }
181
214
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 ;
187
218
}
188
219
189
220
void gpio_set_dormant_irq_enabled (uint gpio , uint32_t events , bool enabled ) {
221
+ check_gpio_param (gpio );
190
222
io_irq_ctrl_hw_t * irq_ctrl_base = & iobank0_hw -> dormant_wake_irq_ctrl ;
191
223
_gpio_set_irq_enabled (gpio , events , enabled , irq_ctrl_base );
192
224
}
193
225
194
226
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 ));
196
229
}
197
230
198
231
#define DEBUG_PIN_MASK (((1u << PICO_DEBUG_PIN_COUNT)-1) << PICO_DEBUG_PIN_BASE)
@@ -222,7 +255,7 @@ void gpio_deinit(uint gpio) {
222
255
}
223
256
224
257
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 ++ ) {
226
259
if (gpio_mask & 1 ) {
227
260
gpio_init (i );
228
261
}
0 commit comments