Squashed 'third_party/pico-sdk/' changes from 2062372d20..2e6142b15b
2e6142b15b SDK 1.4.0 release
5e9a5e827b Add Pico W and lwIP support
77c04e458c revert TinyUSB update (#889)
bc5d1b8485 Add channel_config_set_high_priority (#888)
85dbbfdf4d Update TinyUSB to commit 39069cf4b to pick up recent RP2040 fixes (#886)
e7267f99fe Fix GPIO # callback parameter (#880)
4c49427bf3 Fix auto_init_recursive_mutex definition for C++ (#875)
33818dd0bd Increase PLL min VCO from 400MHz to 750MHz for improved stability across operating conditions (#869)
8f09099757 sem_acquire has no reason to do a notify! (#857)
9644399993 Suppress new GCC 12 warning (#842)
b3c56e7169 Add stderr support and remove 1us timeout for timeouts of 0us (#858)
7858601a58 stdio_usb improvements (#871)
0bdd463898 Add DatanoiseTV DSP Board. (#866)
7daa20ce4c Add board definition for the RP2040 Stamp Round Carrier (#837)
705b5cedcd Wrap realloc() call with malloc_mutex in multicore (#864)
bdd9746635 Don't copy .data for NO_FLASH binaries, as it's loaded in-place (#859)
babc4a1794 Remove 'default=none' from PICO_CONFIG lines (#865)
6c19d20aa5 Fix up filename displayed by extract_config.py when an invalid attribute is found (#853)
672e48e9e9 Add sem_try_acquire(). Fixes #846 (#856)
ef47dfeeaf Add new GPIO APIs for adding shared GPIO handlers, and improve docs (#850)
6389927cf9 Add some optional header includes, to make per-target changes to config easier (#851)
d3dcbb8292 Add new user_irq claim APIs to make it easier for independent code using them to interoperate (#854)
f3c446ae14 move get_core_num() into platform.h (#852)
4e4cf11d9b Start SDK 1.3.2 development
426e46126b SDK 1.3.1 release
ebc601f71f Re-merge SDK1.3.0 history back into SDK1.3.1
1e6c122fc9 gate inclusion of pico.h in binary info, so as not to break picotool builds (#836)
7880405292 Doxygen typo (#835)
530204ec0c Small tweak to busy_wait_at_least_cycles doxygen (#834)
ea79d29cd6 Merge non-squashed history of 1.3.0 release back in to master
b2ad632c24 Minor additions to PIO documentation (#831)
658a21b946 Update rtc_set_datetime docs to point out that the written value may not be immediately visible (#832)
e44d2c0010 Add busy_wait_at_least_cycles method (#830)
43a5593e8f Pass PIOASM_EXTRA_SOURCE_FILES to Pioasm sub-cmake and add OUTPUT_FORMAT option (fixes #827) (#828)
792813926d Make pioasm accept windows CRLF input (#829)
159d552150 Fix bug in irq_remove_shared_handler and add test #823 (#825)
3a3d5fe6c4 Small IRQ doxygen tweaks (#824)
5e22c09660 convert unlikely panic to hard_assert to not waste space for string (#826)
4e62c26a2c Add documentation to dma_channel_abort regarding errata RP2040-E13 (#816)
5a927792ef Suppress false GCC 11 warning on TinyUSB (#819)
60a6fea534 Fix list management in stdio_set_driver_enabled so drivers can be freely added and removed (#822)
04c68c554b cleanup pico_stdlib_test. add actual check for __builtin bitops (#821)
0d2591e1f1 Pad all but last sector in flash binary to write whole of sector (#800)
81bdcb6681 print build type during CMake config; remove spurious call to pico_is_toplevel_project() (#818)
9c616da1e5 fix bug in pico_float_test (#817)
f260477802 Adapt assembler syntax to eliminate Clang errors. (LLVM 14.0.0) (#798)
e1c5fd34e4 PLL setup check bug (#796) (#806)
5d422deed1 Add extra info about address_range defined values (#652)
0c501c246a Add wiznet_w5100s_evb_pico support (#666)
259da19660 Include structs/iobank0.h from hardware/gpio.h (#733) (#807)
5325008956 Added board definition for upcoming Pimoroni motor driver (#795)
510ca47c92 Additional PWM validation and small tidy-up (#801)
d5121dc880 Removed unnecessary ifdefs from Pimoroni boards (#802)
3c450011da Additional param-validation for PIO (#805)
6149b9e4ec Add board definition for Seeed Xiao RP2040 (#691)
8554fc4ea1 Add is_at_the_end_of_time() method (#784)
01290c4cb3 Added int_frac function for configuring PWM (#768)
8d43364cfb Small typos (#776)
1c9f72ba1c Small edits to the Doxygen mainpage and update the RPi logo (#778)
76c1830aeb Add gpio_deinit (#793)
c66a2c1c3b Remove implicit grouping for PIO defines (#779)
e4a2aa7262 Fix typo in binary_info description (#788)
fc86203f49 comment typo (#794)
6619a2d329 Typo (#799)
5a427fbf1f irq_add_shared_handler assertion fix #724 (#747)
bb5a2a3906 Added definition for Badger RP2040 board (#735)
8291f1013a add #ifdef guards to vgaboard.h to allow user overrides (#746)
e90f831756 add board definition of eetree gamekit rp2040 (#732)
541f93541c improve comment (#658)
17d53af105 Allow 252-byte binaries to be checksummed (#764)
1896b1491b fix __ctzdi2 for values with non-zero low 32 bits (fixes #765) (#766)
3d45276423 Added board definition for upcoming Pimoroni servo driver (#769)
d35083b3f7 Fix typo in SIO register description (#770)
38b26b5d65 pico_sdk_import: don't recurse git submodules (#772)
d54104a1e5 fix when PICO_NO_BINARY_INFO is set (#693)
bc3484e793 Mark __aeabi_lmul section as allocatable and executable (#722)
b7e82b638a Fix function-names reported by hardware_pwm_test (#736)
bf9848eaf9 Updated DMA CTRL_TRIG.CHAIN_TO reset values (#743)
ae7ef546a6 Fix typo in Doxygen comment (#731)
b3cf3e8f6f Correct comment in time.h (#715)
25a3b36793 Fix assert in adc_set_round_robin() (#698)
96afce8ece Add board definition for Adafruit Macropad (#684)
5bcf4ed83a Clarify header-comments about pico_enable_stdio_ CMake-functions (#705)
e379f6764b Add board definition for RP2040 Stamp and Carrier (#696)
91462e430a Add `__attribute__((noreturn))` to `_exit` (#707)
d831eff5a2 fix pioasm python output (#694) (#695)
215f77b836 Moves the #if guards to before the comments (#690)
0f67a6c00c Add board definition for Adafruit KB2040 (#676)
add120e4f6 add missing change to dma.h from __force_inline fix (#680)
386e2a7bc6 Added Tiny2040 2MB (#672)
0562089fab fixup __forceinline for cpp code and add kitchen_sink cpp test (#670)
269332dc21 rename pybstick26_rp2040.h to garatronic_pybstick26_rp2040.h (#675)
a8fa19a74d pio_set_irqn_source_mask_enabled() sets wrong irq (#655)
699838d153 Start SDK 1.3.1 development (#648)
60c5a929cc Remove <b> from mutex doxygen due to PDF generation bug
d0af70bd77 fix __packed attribute for MSVC (#646)
da476610e2 allow override of XOSC_MHZ (#644)
d7358e4ed8 update generated struct headers to fix collision (#641)
ccccff8450 Add pybstick26_rp2040 support (#636)
d0c7642369 Update ADC ENOB comment to match (measured) value in RP2040 datasheet (#643)
cc1e2e8758 Small typo in kitchen_sink (#642)
e4d6ff9ecd Small PICO_PLATFORM=host fixes (#639)
97eec951b1 Another .org -> .com fix (#638)
fba9c8ce4d change SDK version to 1.3.0 (#628)
da7c39bc23 Fix some of the (simpler) errors reported by the doxygen command (#617)
b04a09110f revert additional assertion check which breaks used of hw_alias macro outside of functions (#635)
5641cd0a4a __aeabi_memset* were switching the wrong arguments (#634)
68555c9751 Added some waveshare boards definition (#619)
e5110dfce1 add docs for pio_instructions.h (#624)
3604a6fa13 add CONTRIBUTING.md (#626)
e850214938 Platform updates (#611)
723dfd04ff add more/better documentation to pico/multicore (#620)
05418b4e71 fix minor bug in add_repeating_timer_us, and add some comments (#621)
83cd1da1ef fix build if TinyUSB not present (#631)
0ccd0db163 Update to TinyUSB 0.12.0 (#622)
22b0d5d2ed Update links in Doxygen pages from .org to .com (#625)
3c72e753b6 Split recursive mutex into their own functions (was Reduce performance hit of recursive mutex) (#495)
9320d192c3 add watchdog_enable_caused_reboot (minor compatibility issue) (#594)
68571ad33e Hardware struct regeneration (#613)
a0450d0133 Updated reg_headers and SVD (#612)
3c94bc8137 Change _watchdog_enable to trigger immediate reboot when no delay set (#561)
f808b5f2dc Add DREQ methods for PWM/SPI/UART/I2C (#603)
2f2e62968d Use auto-generated hardware/structs/ headers (based off SVD) SVD errors fixed.
a793222331 add template PR - very polite (#596)
ec4036181f tweak info message for TinyUSB support (#590)
db47fba48d respect OUTPUT_NAME target property when generating supplemental files (#592)
a0d4bdf731 fix pico_set_printf_implementation(TARGET compiler) (#593)
d50e743e0e make type punning of floating point/int in float_math and double_math use union to avoid warnings (#600)
30673fb6d0 move inline assembly constant out into C code so it doesn't get out of range in a large function (#602)
e76d5a9008 add dma_timer related methods (#604)
9f1c37318b add irq_get_priority method - improve efficiency of irq_init_priorities (#609)
4c9ba3e8ad USB: Fix description of Length 0 in dpram_regs. Fixes #541 (#608)
ace97f3387 More accurate register access-types and reset-values (#601)
0fa58ed219 Adding/propage macros/signature typedefs for ROM functions. Make rom_func_lookup non-flash safe for flash functions (#586)
0a32023aac fix arg parsing segfault (#595)
13be546dc3 pico_stdio improvements (#598)
12017a07ab SPINLOCK regs are RW. (#599)
9319ab11d9 Add xip window alias macros (#566) (#585)
62854f5eff shrink max-page-size for linker to more sensible 4096 by default (#587)
13ed99df0d split out usb_reset_interface header into its own library for consumption by picotool or others (#589)
0fdf543126 Missing extern C in datetime.h #581 (#584)
3c53029c24 Fix some typos (#517)
ce0db40223 adafruit_feather_rp2040: Fix default I2C instance (#526)
a119b5bd9f Fix semihosting_putc (#530)
eb42ecfaa5 Added definitions for some upcoming Pimoroni LED driver boards (#535)
cd4e53a202 Use W25Q080 second stage loader for Nano RP2040 Connect (#537)
f63a14e9ee Change PWM_CH1_DIV_INT_LSB to PWM_CH0_DIV_INT_LSB (#560)
2214468b51 Add Adafruit Trinkey QT2040 board (#525)
e12713d70b pio_assembler: typo fix (#538)
e6b8c7b64e bugfix: "WO" registers should be listed in the SVD as write-only, not read-write (#544)
1d0dcc8177 pico_time: Fix alarm_pool_dump_key format string (#557)
46d8597d35 Add hardware_divider to pico_divider dependencies (#571)
d7feac1495 Fix syntax error in cmake when using custom stage2 (#580)
ca232e9404 Add Melopero Shake RP2040 Board header file (#565)
c08136b696 Move ret_dzero to the same section as it get used (#513)
672d18a6f0 Fix default PICO_BOARD value (#536)
2622e9bc29 Enable UART RX timeout IRQ, as well as RX IRQ, so that individual characters can be received.
9a586371db Add doxygen clarifying PWM behaviour when enabled/disabled, and advice for controlling the pin state when disabled (#521)
a6a436b1fe use PUBLIC for pio headers on any target except INTERFACE library
7e90980118 Add explanatory note on 7-bit I2C addresses (#520)
ae6e574f53 Improve wording of comments in irq.h (#509)
ccc0ba5649 elf2uf2: correctly parse ELF files where the program header is not directly following the file header
5e05469373 bug in sleep_until on host mode for macOS (#502)
dc4342f0f6 Update usb regs to fix https://github.com/raspberrypi/pico-feedback/issues/172
35b4965054 make sure PICO_DEFAULT_BOOT_STAGE2_FILE is defined in parent CMake file (#491)
e02c6b327d Allow one of float/double to have 'none' impl but not the other - previously caused a link error
f4ab723eb5 compile failure with PICO_STDOUT_MUTEX=0
529d7087eb fix operatore precedence of */ vs +- in pioasm
cefe5c5b2a Better support for PICO_DISABLE_SHARED_IRQ_HANDLERS (#496)
edcb65c916 Enable I2C FIFO full hold in slave mode (stretch clock when RX full), fixes #456 (#494)
f16ccfa1ff Small comment typos
44feae4caf set DIVISOR for each use of h/w divider
61b7cbdc54 Using ' inline __always_inline' also for GNUC 7. (#484)
21bbaf3ca6 remove -Winline (#481)
4328b2c75f fix pioasm python output (#479)
1f1c6162cd Header info string updates for PIO DBG_PADx and XOSC STARTUP (#478)
979045dc12 removed CMSIS from SDK doxygen
d42e6a9d10 include pico.h so that uint is defined (#475)
654b66693f start 1.3.0 development
git-subtree-dir: third_party/pico-sdk
git-subtree-split: 2e6142b15b8a75c1227dd3edbe839193b2bf9041
Signed-off-by: Ravago Jones <ravagojones@gmail.com>
Change-Id: I7d5ab3e7e797e8e956d3a651b600448157ab0608
diff --git a/src/rp2_common/hardware_gpio/CMakeLists.txt b/src/rp2_common/hardware_gpio/CMakeLists.txt
index 1bfb078..97a9355 100644
--- a/src/rp2_common/hardware_gpio/CMakeLists.txt
+++ b/src/rp2_common/hardware_gpio/CMakeLists.txt
@@ -1 +1,2 @@
-pico_simple_hardware_target(gpio)
\ No newline at end of file
+pico_simple_hardware_target(gpio)
+target_link_libraries(hardware_gpio INTERFACE hardware_irq)
\ No newline at end of file
diff --git a/src/rp2_common/hardware_gpio/gpio.c b/src/rp2_common/hardware_gpio/gpio.c
index 2816b97..6e4261f 100644
--- a/src/rp2_common/hardware_gpio/gpio.c
+++ b/src/rp2_common/hardware_gpio/gpio.c
@@ -14,11 +14,13 @@
#include "pico/binary_info.h"
#endif
-static gpio_irq_callback_t _callbacks[NUM_CORES];
+static gpio_irq_callback_t callbacks[NUM_CORES];
+// a 1 bit means the IRQ is handled by a raw IRQ handler
+static uint32_t raw_irq_mask[NUM_CORES];
// Get the raw value from the pin, bypassing any muxing or overrides.
int gpio_get_pad(uint gpio) {
- invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
+ check_gpio_param(gpio);
hw_set_bits(&padsbank0_hw->io[gpio], PADS_BANK0_GPIO0_IE_BITS);
return (iobank0_hw->io[gpio].status & IO_BANK0_GPIO0_STATUS_INFROMPAD_BITS)
>> IO_BANK0_GPIO0_STATUS_INFROMPAD_LSB;
@@ -28,7 +30,7 @@
// Select function for this GPIO, and ensure input/output are enabled at the pad.
// This also clears the input/output/irq override bits.
void gpio_set_function(uint gpio, enum gpio_function fn) {
- invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
+ check_gpio_param(gpio);
invalid_params_if(GPIO, ((uint32_t)fn << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB) & ~IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS);
// Set input enable on, output disable off
hw_write_masked(&padsbank0_hw->io[gpio],
@@ -42,14 +44,14 @@
/// \end::gpio_set_function[]
enum gpio_function gpio_get_function(uint gpio) {
- invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
+ check_gpio_param(gpio);
return (enum gpio_function) ((iobank0_hw->io[gpio].ctrl & IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS) >> IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB);
}
// Note that, on RP2040, setting both pulls enables a "bus keep" function,
// i.e. weak pull to whatever is current high/low state of GPIO.
void gpio_set_pulls(uint gpio, bool up, bool down) {
- invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
+ check_gpio_param(gpio);
hw_write_masked(
&padsbank0_hw->io[gpio],
(bool_to_bit(up) << PADS_BANK0_GPIO0_PUE_LSB) | (bool_to_bit(down) << PADS_BANK0_GPIO0_PDE_LSB),
@@ -59,7 +61,7 @@
// Direct override for per-GPIO IRQ signal
void gpio_set_irqover(uint gpio, uint value) {
- invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
+ check_gpio_param(gpio);
hw_write_masked(&iobank0_hw->io[gpio].ctrl,
value << IO_BANK0_GPIO0_CTRL_IRQOVER_LSB,
IO_BANK0_GPIO0_CTRL_IRQOVER_BITS
@@ -68,7 +70,7 @@
// Direct overrides for pad controls
void gpio_set_inover(uint gpio, uint value) {
- invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
+ check_gpio_param(gpio);
hw_write_masked(&iobank0_hw->io[gpio].ctrl,
value << IO_BANK0_GPIO0_CTRL_INOVER_LSB,
IO_BANK0_GPIO0_CTRL_INOVER_BITS
@@ -76,7 +78,7 @@
}
void gpio_set_outover(uint gpio, uint value) {
- invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
+ check_gpio_param(gpio);
hw_write_masked(&iobank0_hw->io[gpio].ctrl,
value << IO_BANK0_GPIO0_CTRL_OUTOVER_LSB,
IO_BANK0_GPIO0_CTRL_OUTOVER_BITS
@@ -84,7 +86,7 @@
}
void gpio_set_oeover(uint gpio, uint value) {
- invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
+ check_gpio_param(gpio);
hw_write_masked(&iobank0_hw->io[gpio].ctrl,
value << IO_BANK0_GPIO0_CTRL_OEOVER_LSB,
IO_BANK0_GPIO0_CTRL_OEOVER_BITS
@@ -92,7 +94,7 @@
}
void gpio_set_input_hysteresis_enabled(uint gpio, bool enabled) {
- invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
+ check_gpio_param(gpio);
if (enabled)
hw_set_bits(&padsbank0_hw->io[gpio], PADS_BANK0_GPIO0_SCHMITT_BITS);
else
@@ -101,12 +103,12 @@
bool gpio_is_input_hysteresis_enabled(uint gpio) {
- invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
+ check_gpio_param(gpio);
return (padsbank0_hw->io[gpio] & PADS_BANK0_GPIO0_SCHMITT_BITS) != 0;
}
void gpio_set_slew_rate(uint gpio, enum gpio_slew_rate slew) {
- invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
+ check_gpio_param(gpio);
hw_write_masked(&padsbank0_hw->io[gpio],
(uint)slew << PADS_BANK0_GPIO0_SLEWFAST_LSB,
PADS_BANK0_GPIO0_SLEWFAST_BITS
@@ -114,7 +116,7 @@
}
enum gpio_slew_rate gpio_get_slew_rate(uint gpio) {
- invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
+ check_gpio_param(gpio);
return (enum gpio_slew_rate)((padsbank0_hw->io[gpio]
& PADS_BANK0_GPIO0_SLEWFAST_BITS)
>> PADS_BANK0_GPIO0_SLEWFAST_LSB);
@@ -124,7 +126,7 @@
// Enum encoding should match hardware encoding on RP2040
static_assert(PADS_BANK0_GPIO0_DRIVE_VALUE_8MA == GPIO_DRIVE_STRENGTH_8MA, "");
void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive) {
- invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
+ check_gpio_param(gpio);
hw_write_masked(&padsbank0_hw->io[gpio],
(uint)drive << PADS_BANK0_GPIO0_DRIVE_LSB,
PADS_BANK0_GPIO0_DRIVE_BITS
@@ -132,25 +134,28 @@
}
enum gpio_drive_strength gpio_get_drive_strength(uint gpio) {
- invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
+ check_gpio_param(gpio);
return (enum gpio_drive_strength)((padsbank0_hw->io[gpio]
& PADS_BANK0_GPIO0_DRIVE_BITS)
>> PADS_BANK0_GPIO0_DRIVE_LSB);
}
-static void gpio_irq_handler(void) {
- io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ?
- &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
- for (uint gpio = 0; gpio < NUM_BANK0_GPIOS; gpio++) {
- io_ro_32 *status_reg = &irq_ctrl_base->ints[gpio / 8];
- uint events = (*status_reg >> 4 * (gpio % 8)) & 0xf;
- if (events) {
- // TODO: If both cores care about this event then the second core won't get the irq?
- gpio_acknowledge_irq(gpio, events);
- gpio_irq_callback_t callback = _callbacks[get_core_num()];
- if (callback) {
- callback(gpio, events);
+static void gpio_default_irq_handler(void) {
+ uint core = get_core_num();
+ gpio_irq_callback_t callback = callbacks[core];
+ io_irq_ctrl_hw_t *irq_ctrl_base = core ? &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
+ for (uint gpio = 0; gpio < NUM_BANK0_GPIOS; gpio+=8) {
+ uint32_t events8 = irq_ctrl_base->ints[gpio >> 3u];
+ // note we assume events8 is 0 for non-existent GPIO
+ for(uint i=gpio;events8 && i<gpio+8;i++) {
+ uint32_t events = events8 & 0xfu;
+ if (events && !(raw_irq_mask[core] & (1u << i))) {
+ gpio_acknowledge_irq(i, events);
+ if (callback) {
+ callback(i, events);
+ }
}
+ events8 >>= 4;
}
}
}
@@ -178,21 +183,48 @@
void gpio_set_irq_enabled_with_callback(uint gpio, uint32_t events, bool enabled, gpio_irq_callback_t callback) {
gpio_set_irq_enabled(gpio, events, enabled);
+ gpio_set_irq_callback(callback);
+ if (enabled) irq_set_enabled(IO_IRQ_BANK0, true);
+}
- // TODO: Do we want to support a callback per GPIO pin?
- // Install IRQ handler
- _callbacks[get_core_num()] = callback;
- irq_set_exclusive_handler(IO_IRQ_BANK0, gpio_irq_handler);
- irq_set_enabled(IO_IRQ_BANK0, true);
+void gpio_set_irq_callback(gpio_irq_callback_t callback) {
+ uint core = get_core_num();
+ if (callbacks[core]) {
+ if (!callback) {
+ irq_remove_handler(IO_IRQ_BANK0, gpio_default_irq_handler);
+ }
+ callbacks[core] = callback;
+ } else if (callback) {
+ callbacks[core] = callback;
+ irq_add_shared_handler(IO_IRQ_BANK0, gpio_default_irq_handler, GPIO_IRQ_CALLBACK_ORDER_PRIORITY);
+ }
+}
+
+void gpio_add_raw_irq_handler_with_order_priority_masked(uint gpio_mask, irq_handler_t handler, uint8_t order_priority) {
+ hard_assert(!(raw_irq_mask[get_core_num()] & gpio_mask)); // should not add multiple handlers for the same event
+ raw_irq_mask[get_core_num()] |= gpio_mask;
+ irq_add_shared_handler(IO_IRQ_BANK0, handler, order_priority);
+}
+
+void gpio_add_raw_irq_handler_masked(uint gpio_mask, irq_handler_t handler) {
+ gpio_add_raw_irq_handler_with_order_priority_masked(gpio_mask, handler, GPIO_RAW_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
+}
+
+void gpio_remove_raw_irq_handler_masked(uint gpio_mask, irq_handler_t handler) {
+ assert(raw_irq_mask[get_core_num()] & gpio_mask); // should not remove handlers that are not added
+ irq_remove_handler(IO_IRQ_BANK0, handler);
+ raw_irq_mask[get_core_num()] &= ~gpio_mask;
}
void gpio_set_dormant_irq_enabled(uint gpio, uint32_t events, bool enabled) {
+ check_gpio_param(gpio);
io_irq_ctrl_hw_t *irq_ctrl_base = &iobank0_hw->dormant_wake_irq_ctrl;
_gpio_set_irq_enabled(gpio, events, enabled, irq_ctrl_base);
}
void gpio_acknowledge_irq(uint gpio, uint32_t events) {
- iobank0_hw->intr[gpio / 8] = events << 4 * (gpio % 8);
+ check_gpio_param(gpio);
+ iobank0_hw->intr[gpio / 8] = events << (4 * (gpio % 8));
}
#define DEBUG_PIN_MASK (((1u << PICO_DEBUG_PIN_COUNT)-1) << PICO_DEBUG_PIN_BASE)
@@ -217,8 +249,12 @@
gpio_set_function(gpio, GPIO_FUNC_SIO);
}
+void gpio_deinit(uint gpio) {
+ gpio_set_function(gpio, GPIO_FUNC_NULL);
+}
+
void gpio_init_mask(uint gpio_mask) {
- for(uint i=0;i<32;i++) {
+ for(uint i=0;i<NUM_BANK0_GPIOS;i++) {
if (gpio_mask & 1) {
gpio_init(i);
}
diff --git a/src/rp2_common/hardware_gpio/include/hardware/gpio.h b/src/rp2_common/hardware_gpio/include/hardware/gpio.h
index 7037e85..09a9b96 100644
--- a/src/rp2_common/hardware_gpio/include/hardware/gpio.h
+++ b/src/rp2_common/hardware_gpio/include/hardware/gpio.h
@@ -10,6 +10,8 @@
#include "pico.h"
#include "hardware/structs/sio.h"
#include "hardware/structs/padsbank0.h"
+#include "hardware/structs/iobank0.h"
+#include "hardware/irq.h"
#ifdef __cplusplus
extern "C" {
@@ -102,7 +104,7 @@
#define GPIO_OUT 1
#define GPIO_IN 0
-/*! \brief GPIO Interrupt level definitions
+/*! \brief GPIO Interrupt level definitions (GPIO events)
* \ingroup hardware_gpio
* \brief GPIO Interrupt levels
*
@@ -128,10 +130,11 @@
* \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.
+ * \param event_mask Which events caused this interrupt. See \ref gpio_irq_level for details.
* \sa gpio_set_irq_enabled_with_callback()
+ * \sa gpio_set_irq_callback()
*/
-typedef void (*gpio_irq_callback_t)(uint gpio, uint32_t events);
+typedef void (*gpio_irq_callback_t)(uint gpio, uint32_t event_mask);
enum gpio_override {
GPIO_OVERRIDE_NORMAL = 0, ///< peripheral signal selected via \ref gpio_set_function
@@ -165,6 +168,10 @@
GPIO_DRIVE_STRENGTH_12MA = 3 ///< 12 mA nominal drive strength
};
+static inline void check_gpio_param(__unused uint gpio) {
+ invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
+}
+
// ----------------------------------------------------------------------------
// Pad Controls + IO Muxing
// ----------------------------------------------------------------------------
@@ -346,63 +353,288 @@
*/
enum gpio_drive_strength gpio_get_drive_strength(uint gpio);
-/*! \brief Enable or disable interrupts for specified GPIO
+/*! \brief Enable or disable specific interrupt events for specified GPIO
* \ingroup hardware_gpio
*
- * \note The IO IRQs are independent per-processor. This configures IRQs for
+ * This function sets which GPIO events cause a GPIO interrupt on the calling core. See
+ * \ref gpio_set_irq_callback, \ref gpio_set_irq_enabled_with_callback and
+ * \ref gpio_add_raw_irq_handler to set up a GPIO interrupt handler to handle the events.
+ *
+ * \note The IO IRQs are independent per-processor. This configures the interrupt events for
* the processor that calls the function.
*
* \param gpio GPIO number
- * \param events Which events will cause an interrupt
+ * \param event_mask Which events will cause an interrupt
* \param enabled Enable or disable flag
*
- * Events is a bitmask of the following:
+ * Events is a bitmask of the following \ref gpio_irq_level values:
*
- * bit | interrupt
- * ----|----------
- * 0 | Low level
- * 1 | High level
- * 2 | Edge low
- * 3 | Edge high
+ * bit | constant | interrupt
+ * ----|----------------------------------------------------------
+ * 0 | GPIO_IRQ_LEVEL_LOW | Continuously while level is low
+ * 1 | GPIO_IRQ_LEVEL_HIGH | Continuously while level is high
+ * 2 | GPIO_IRQ_EDGE_FALL | On each transition from high to low
+ * 3 | GPIO_IRQ_EDGE_RISE | On each transition from low to high
+ *
+ * which are specified in \ref gpio_irq_level
*/
-void gpio_set_irq_enabled(uint gpio, uint32_t events, bool enabled);
+void gpio_set_irq_enabled(uint gpio, uint32_t event_mask, bool enabled);
-/*! \brief Enable interrupts for specified GPIO
+// PICO_CONFIG: GPIO_IRQ_CALLBACK_ORDER_PRIORITY, the irq priority order of the default IRQ callback, min=0, max=255, default=PICO_SHARED_IRQ_HANDLER_LOWEST_ORDER_PRIORITY, group=hardware_gpio
+#ifndef GPIO_IRQ_CALLBACK_ORDER_PRIORITY
+#define GPIO_IRQ_CALLBACK_ORDER_PRIORITY PICO_SHARED_IRQ_HANDLER_LOWEST_ORDER_PRIORITY
+#endif
+
+// PICO_CONFIG: GPIO_RAW_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY, the irq priority order of raw IRQ handlers if the priortiy is not specified, min=0, max=255, default=PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY, group=hardware_gpio
+#ifndef GPIO_RAW_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY
+#define GPIO_RAW_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY
+#endif
+
+/*! \brief Set the generic callback used for GPIO IRQ events for the current core
* \ingroup hardware_gpio
*
- * \note The IO IRQs are independent per-processor. This configures IRQs for
+ * This function sets the callback used for all GPIO IRQs on the current core that are not explicitly
+ * hooked via \ref gpio_add_raw_irq_handler or other gpio_add_raw_irq_handler_ functions.
+ *
+ * This function is called with the GPIO number and event mask for each of the (not explicitly hooked)
+ * GPIOs that have events enabled and that are pending (see \ref gpio_get_irq_event_mask).
+ *
+ * \note The IO IRQs are independent per-processor. This function affects
* 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.
- *
+ * \param callback default user function to call on GPIO irq. Note only one of these can be set per processor.
*/
-void gpio_set_irq_enabled_with_callback(uint gpio, uint32_t events, bool enabled, gpio_irq_callback_t callback);
+void gpio_set_irq_callback(gpio_irq_callback_t callback);
-/*! \brief Enable dormant wake up interrupt for specified GPIO
+/*! \brief Convenience function which performs multiple GPIO IRQ related initializations
+ * \ingroup hardware_gpio
+ *
+ * This method is a slightly eclectic mix of initialization, that:
+ *
+ * \li Updates whether the specified events for the specified GPIO causes an interrupt on the calling core based
+ * on the enable flag.
+ *
+ * \li Sets the callback handler for the calling core to callback (or clears the handler if the callback is NULL).
+ *
+ * \li Enables GPIO IRQs on the current core if enabled is true.
+ *
+ * This method is commonly used to perform a one time setup, and following that any additional IRQs/events are enabled
+ * via \ref gpio_set_irq_enabled. All GPIOs/events added in this way on the same core share the same callback; for multiple
+ * independent handlers for different GPIOs you should use \ref gpio_add_raw_irq_handler and related functions.
+ *
+ * This method is equivalent to:
+ *
+ * \code{.c}
+ * gpio_set_irq_enabled(gpio, event_mask, enabled);
+ * gpio_set_irq_callback(callback);
+ * if (enabled) irq_set_enabled(IO_IRQ_BANK0, true);
+ * \endcode
+ *
+ * \note The IO IRQs are independent per-processor. This method affects only the processor that calls the function.
+ *
+ * \param gpio GPIO number
+ * \param event_mask Which events will cause an interrupt. See \ref gpio_irq_level for details.
+ * \param enabled Enable or disable flag
+ * \param callback user function to call on GPIO irq. if NULL, the callback is removed
+ */
+void gpio_set_irq_enabled_with_callback(uint gpio, uint32_t event_mask, bool enabled, gpio_irq_callback_t callback);
+
+/*! \brief Enable dormant wake up interrupt for specified GPIO and events
* \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 event_mask Which events will cause an interrupt. See \ref gpio_irq_level for details.
* \param enabled Enable/disable flag
*/
-void gpio_set_dormant_irq_enabled(uint gpio, uint32_t events, bool enabled);
+void gpio_set_dormant_irq_enabled(uint gpio, uint32_t event_mask, bool enabled);
-/*! \brief Acknowledge a GPIO interrupt
+/*! \brief Return the current interrupt status (pending events) for the given GPIO
* \ingroup hardware_gpio
*
* \param gpio GPIO number
- * \param events Bitmask of events to clear. See \ref gpio_set_irq_enabled for details.
- *
+ * \return Bitmask of events that are currently pending for the GPIO. See \ref gpio_irq_level for details.
+ * \sa gpio_acknowledge_irq
*/
-void gpio_acknowledge_irq(uint gpio, uint32_t events);
+static inline uint32_t gpio_get_irq_event_mask(uint gpio) {
+ check_gpio_param(gpio);
+ io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ?
+ &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
+ io_ro_32 *status_reg = &irq_ctrl_base->ints[gpio >> 3u];
+ return (*status_reg >> (4 * (gpio & 7u))) & 0xfu;
+}
+
+/*! \brief Acknowledge a GPIO interrupt for the specified events on the calling core
+ * \ingroup hardware_gpio
+ *
+ * \note This may be called with a mask of any of valid bits specified in \ref gpio_irq_level, however
+ * it has no effect on \a level sensitive interrupts which remain pending while the GPIO is at the specified
+ * level. When handling \a level sensitive interrupts, you should generally disable the interrupt (see
+ * \ref gpio_set_irq_enabled) and then set it up again later once the GPIO level has changed (or to catch
+ * the opposite level).
+ *
+ * \param gpio GPIO number
+ * \param events Bitmask of events to clear. See \ref gpio_set_irq_enabled for details.
+ *
+ * \note For callbacks set with \ref gpio_set_irq_enabled_with_callback, or \ref gpio_set_irq_callback,this function is called automatically.
+ * \param event_mask Bitmask of events to clear. See \ref gpio_irq_level for details.
+ */
+void gpio_acknowledge_irq(uint gpio, uint32_t event_mask);
+
+/*! \brief Adds a raw GPIO IRQ handler for the specified GPIOs on the current core
+ * \ingroup hardware_gpio
+ *
+ * In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback),
+ * it is possible to add explicit GPIO IRQ handlers which are called independent of the default callback. The order
+ * relative to the default callback can be controlled via the order_priority parameter (the default callback has the priority
+ * \ref GPIO_IRQ_CALLBACK_ORDER_PRIORITY which defaults to the lowest priority with the intention of it running last).
+ *
+ * This method adds such an explicit GPIO IRQ handler, and disables the "default" callback for the specified GPIOs.
+ *
+ * \note Multiple raw handlers should not be added for the same GPIOs, and this method will assert if you attempt to.
+ *
+ * A raw handler should check for whichever GPIOs and events it handles, and acknowledge them itself; it might look something like:
+ *
+ * \code{.c}
+ * void my_irq_handler(void) {
+ * if (gpio_get_irq_event_mask(my_gpio_num) & my_gpio_event_mask) {
+ * gpio_acknowledge_irq(my_gpio_num, my_gpio_event_mask);
+ * // handle the IRQ
+ * }
+ * if (gpio_get_irq_event_mask(my_gpio_num2) & my_gpio_event_mask2) {
+ * gpio_acknowledge_irq(my_gpio_num2, my_gpio_event_mask2);
+ * // handle the IRQ
+ * }
+ * }
+ * \endcode
+ *
+ * @param gpio_mask a bit mask of the GPIO numbers that will no longer be passed to the default callback for this core
+ * @param handler the handler to add to the list of GPIO IRQ handlers for this core
+ * @param order_priority the priority order to determine the relative position of the handler in the list of GPIO IRQ handlers for this core.
+ */
+void gpio_add_raw_irq_handler_with_order_priority_masked(uint gpio_mask, irq_handler_t handler, uint8_t order_priority);
+
+/*! \brief Adds a raw GPIO IRQ handler for a specific GPIO on the current core
+ * \ingroup hardware_gpio
+ *
+ * In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback),
+ * it is possible to add explicit GPIO IRQ handlers which are called independent of the default callback. The order
+ * relative to the default callback can be controlled via the order_priority parameter(the default callback has the priority
+ * \ref GPIO_IRQ_CALLBACK_ORDER_PRIORITY which defaults to the lowest priority with the intention of it running last).
+ *
+ * This method adds such a callback, and disables the "default" callback for the specified GPIO.
+ *
+ * \note Multiple raw handlers should not be added for the same GPIO, and this method will assert if you attempt to.
+ *
+ * A raw handler should check for whichever GPIOs and events it handles, and acknowledge them itself; it might look something like:
+ *
+ * \code{.c}
+ * void my_irq_handler(void) {
+ * if (gpio_get_irq_event_mask(my_gpio_num) & my_gpio_event_mask) {
+ * gpio_acknowledge_irq(my_gpio_num, my_gpio_event_mask);
+ * // handle the IRQ
+ * }
+ * }
+ * \endcode
+ *
+ * @param gpio the GPIO number that will no longer be passed to the default callback for this core
+ * @param handler the handler to add to the list of GPIO IRQ handlers for this core
+ * @param order_priority the priority order to determine the relative position of the handler in the list of GPIO IRQ handlers for this core.
+ */
+static inline void gpio_add_raw_irq_handler_with_order_priority(uint gpio, irq_handler_t handler, uint8_t order_priority) {
+ check_gpio_param(gpio);
+ gpio_add_raw_irq_handler_with_order_priority_masked(1u << gpio, handler, order_priority);
+}
+
+/*! \brief Adds a raw GPIO IRQ handler for the specified GPIOs on the current core
+ * \ingroup hardware_gpio
+ *
+ * In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback),
+ * it is possible to add explicit GPIO IRQ handlers which are called independent of the default event callback.
+ *
+ * This method adds such a callback, and disables the "default" callback for the specified GPIOs.
+ *
+ * \note Multiple raw handlers should not be added for the same GPIOs, and this method will assert if you attempt to.
+ *
+ * A raw handler should check for whichever GPIOs and events it handles, and acknowledge them itself; it might look something like:
+ *
+ * \code{.c}
+ * void my_irq_handler(void) {
+ * if (gpio_get_irq_event_mask(my_gpio_num) & my_gpio_event_mask) {
+ * gpio_acknowledge_irq(my_gpio_num, my_gpio_event_mask);
+ * // handle the IRQ
+ * }
+ * if (gpio_get_irq_event_mask(my_gpio_num2) & my_gpio_event_mask2) {
+ * gpio_acknowledge_irq(my_gpio_num2, my_gpio_event_mask2);
+ * // handle the IRQ
+ * }
+ * }
+ * \endcode
+ *
+ * @param gpio_mask a bit mask of the GPIO numbers that will no longer be passed to the default callback for this core
+ * @param handler the handler to add to the list of GPIO IRQ handlers for this core
+ */
+void gpio_add_raw_irq_handler_masked(uint gpio_mask, irq_handler_t handler);
+
+/*! \brief Adds a raw GPIO IRQ handler for a specific GPIO on the current core
+ * \ingroup hardware_gpio
+ *
+ * In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback),
+ * it is possible to add explicit GPIO IRQ handlers which are called independent of the default event callback.
+ *
+ * This method adds such a callback, and disables the "default" callback for the specified GPIO.
+ *
+ * \note Multiple raw handlers should not be added for the same GPIO, and this method will assert if you attempt to.
+ *
+ * A raw handler should check for whichever GPIOs and events it handles, and acknowledge them itself; it might look something like:
+ *
+ * \code{.c}
+ * void my_irq_handler(void) {
+ * if (gpio_get_irq_event_mask(my_gpio_num) & my_gpio_event_mask) {
+ * gpio_acknowledge_irq(my_gpio_num, my_gpio_event_mask);
+ * // handle the IRQ
+ * }
+ * }
+ * \endcode
+ *
+ * @param gpio the GPIO number that will no longer be passed to the default callback for this core
+ * @param handler the handler to add to the list of GPIO IRQ handlers for this core
+ */
+static inline void gpio_add_raw_irq_handler(uint gpio, irq_handler_t handler) {
+ check_gpio_param(gpio);
+ gpio_add_raw_irq_handler_masked(1u << gpio, handler);
+}
+
+/*! \brief Removes a raw GPIO IRQ handler for the specified GPIOs on the current core
+ * \ingroup hardware_gpio
+ *
+ * In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback),
+ * it is possible to add explicit GPIO IRQ handlers which are called independent of the default event callback.
+ *
+ * This method removes such a callback, and enables the "default" callback for the specified GPIOs.
+ *
+ * @param gpio_mask a bit mask of the GPIO numbers that will now be passed to the default callback for this core
+ * @param handler the handler to remove from the list of GPIO IRQ handlers for this core
+ */
+void gpio_remove_raw_irq_handler_masked(uint gpio_mask, irq_handler_t handler);
+
+/*! \brief Removes a raw GPIO IRQ handler for the specified GPIO on the current core
+ * \ingroup hardware_gpio
+ *
+ * In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback),
+ * it is possible to add explicit GPIO IRQ handlers which are called independent of the default event callback.
+ *
+ * This method removes such a callback, and enables the "default" callback for the specified GPIO.
+ *
+ * @param gpio the GPIO number that will now be passed to the default callback for this core
+ * @param handler the handler to remove from the list of GPIO IRQ handlers for this core
+ */
+static inline void gpio_remove_raw_irq_handler(uint gpio, irq_handler_t handler) {
+ check_gpio_param(gpio);
+ gpio_remove_raw_irq_handler_masked(1u << gpio, handler);
+}
/*! \brief Initialise a GPIO for (enabled I/O and set func to GPIO_FUNC_SIO)
* \ingroup hardware_gpio
@@ -414,6 +646,13 @@
*/
void gpio_init(uint gpio);
+/*! \brief Resets a GPIO back to the NULL function, i.e. disables it.
+ * \ingroup hardware_gpio
+ *
+ * \param gpio GPIO number
+ */
+void gpio_deinit(uint gpio);
+
/*! \brief Initialise multiple GPIOs (enabled I/O and set func to GPIO_FUNC_SIO)
* \ingroup hardware_gpio
*