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/boards/include/boards/adafruit_kb2040.h b/src/boards/include/boards/adafruit_kb2040.h
new file mode 100644
index 0000000..9353082
--- /dev/null
+++ b/src/boards/include/boards/adafruit_kb2040.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+#ifndef _BOARDS_ADAFRUIT_KB2040_H
+#define _BOARDS_ADAFRUIT_KB2040_H
+
+// For board detection
+#define ADAFRUIT_KB2040
+
+// On some samples, the xosc can take longer to stabilize than is usual
+#ifndef PICO_XOSC_STARTUP_DELAY_MULTIPLIER
+#define PICO_XOSC_STARTUP_DELAY_MULTIPLIER 64
+#endif
+
+//------------- UART -------------//
+#ifndef PICO_DEFAULT_UART
+#define PICO_DEFAULT_UART 0
+#endif
+
+#ifndef PICO_DEFAULT_UART_TX_PIN
+#define PICO_DEFAULT_UART_TX_PIN 0
+#endif
+
+#ifndef PICO_DEFAULT_UART_RX_PIN
+#define PICO_DEFAULT_UART_RX_PIN 1
+#endif
+
+//------------- LED -------------//
+#ifndef PICO_DEFAULT_WS2812_PIN
+#define PICO_DEFAULT_WS2812_PIN 17
+#endif
+
+//------------- I2C -------------//
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C 0
+#endif
+
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN 12
+#endif
+
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN 13
+#endif
+
+//------------- SPI -------------//
+#ifndef PICO_DEFAULT_SPI
+#define PICO_DEFAULT_SPI 0
+#endif
+
+#ifndef PICO_DEFAULT_SPI_TX_PIN
+#define PICO_DEFAULT_SPI_TX_PIN 19
+#endif
+
+#ifndef PICO_DEFAULT_SPI_RX_PIN
+#define PICO_DEFAULT_SPI_RX_PIN 20
+#endif
+
+#ifndef PICO_DEFAULT_SPI_SCK_PIN
+#define PICO_DEFAULT_SPI_SCK_PIN 18
+#endif
+
+//------------- FLASH -------------//
+
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (8 * 1024 * 1024)
+#endif
+
+// All boards have B1 RP2040
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
+#endif
+
+#endif
diff --git a/src/boards/include/boards/adafruit_macropad_rp2040.h b/src/boards/include/boards/adafruit_macropad_rp2040.h
new file mode 100644
index 0000000..3c0c525
--- /dev/null
+++ b/src/boards/include/boards/adafruit_macropad_rp2040.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+#ifndef _BOARDS_ADAFRUIT_MACROPAD_RP2040_H
+#define _BOARDS_ADAFRUIT_MACROPAD_RP2040_H
+
+// For board detection
+#define ADAFRUIT_MACROPAD_RP2040
+
+// On some samples, the xosc can take longer to stabilize than is usual
+#ifndef PICO_XOSC_STARTUP_DELAY_MULTIPLIER
+#define PICO_XOSC_STARTUP_DELAY_MULTIPLIER 64
+#endif
+
+// --- BOARD SPECIFIC ---
+#ifndef ADAFRUIT_MACROPAD_KEY1_PIN
+#define ADAFRUIT_MACROPAD_KEY1_PIN 1
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_KEY2_PIN
+#define ADAFRUIT_MACROPAD_KEY2_PIN 2
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_KEY3_PIN
+#define ADAFRUIT_MACROPAD_KEY3_PIN 3
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_KEY4_PIN
+#define ADAFRUIT_MACROPAD_KEY4_PIN 4
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_KEY5_PIN
+#define ADAFRUIT_MACROPAD_KEY5_PIN 5
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_KEY6_PIN
+#define ADAFRUIT_MACROPAD_KEY6_PIN 6
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_KEY7_PIN
+#define ADAFRUIT_MACROPAD_KEY7_PIN 7
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_KEY8_PIN
+#define ADAFRUIT_MACROPAD_KEY8_PIN 8
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_KEY9_PIN
+#define ADAFRUIT_MACROPAD_KEY9_PIN 9
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_KEY10_PIN
+#define ADAFRUIT_MACROPAD_KEY10_PIN 10
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_KEY11_PIN
+#define ADAFRUIT_MACROPAD_KEY11_PIN 11
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_KEY12_PIN
+#define ADAFRUIT_MACROPAD_KEY12_PIN 12
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_LED_PIN
+#define ADAFRUIT_MACROPAD_LED_PIN 13
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_SPEAKER_ENABLE_PIN
+#define ADAFRUIT_MACROPAD_SPEAKER_ENABLE_PIN 14
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_SPEAKER_PIN
+#define ADAFRUIT_MACROPAD_SPEAKER_PIN 16
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_BUTTON_PIN
+#define ADAFRUIT_MACROPAD_BUTTON_PIN 0
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_ROTA_PIN
+#define ADAFRUIT_MACROPAD_ROTA_PIN 17
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_ROTB_PIN
+#define ADAFRUIT_MACROPAD_ROTB_PIN 18
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_NEOPIXEL_PIN
+#define ADAFRUIT_MACROPAD_NEOPIXEL_PIN 19
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_DISPLAY_OLED_CS_PIN
+#define ADAFRUIT_MACROPAD_DISPLAY_OLED_CS_PIN 22
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_DISPLAY_OLED_RESET_PIN
+#define ADAFRUIT_MACROPAD_DISPLAY_OLED_RESET_PIN 23
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_DISPLAY_OLED_DC_PIN
+#define ADAFRUIT_MACROPAD_DISPLAY_OLED_DC_PIN 24
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_DISPLAY_SCK_PIN
+#define ADAFRUIT_MACROPAD_DISPLAY_SCK_PIN 26
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_DISPLAY_MOSI_PIN
+#define ADAFRUIT_MACROPAD_DISPLAY_MOSI_PIN 27
+#endif
+
+#ifndef ADAFRUIT_MACROPAD_DISPLAY_MISO_PIN
+#define ADAFRUIT_MACROPAD_DISPLAY_MISO_PIN 28
+#endif
+
+// no PICO_DEFAULT_UART
+
+//------------- LED -------------//
+#ifndef PICO_DEFAULT_LED_PIN
+#define PICO_DEFAULT_LED_PIN ADAFRUIT_MACROPAD_LED_PIN
+#endif
+
+#ifndef PICO_DEFAULT_WS2812_PIN
+#define PICO_DEFAULT_WS2812_PIN ADAFRUIT_MACROPAD_NEOPIXEL_PIN
+#endif
+
+//------------- I2C -------------//
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C 0
+#endif
+
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN 20
+#endif
+
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN 21
+#endif
+
+//------------- SPI -------------//
+#ifndef PICO_DEFAULT_SPI
+#define PICO_DEFAULT_SPI 1
+#endif
+
+#ifndef PICO_DEFAULT_SPI_TX_PIN
+#define PICO_DEFAULT_SPI_TX_PIN 27
+#endif
+
+#ifndef PICO_DEFAULT_SPI_RX_PIN
+#define PICO_DEFAULT_SPI_RX_PIN 28
+#endif
+
+#ifndef PICO_DEFAULT_SPI_SCK_PIN
+#define PICO_DEFAULT_SPI_SCK_PIN 26
+#endif
+
+//------------- FLASH -------------//
+
+// Use slower generic flash access
+#define PICO_BOOT_STAGE2_CHOOSE_GENERIC_03H 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 4
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (8 * 1024 * 1024)
+#endif
+
+// All boards have B1 RP2040
+#ifndef PICO_FLOAT_SUPPORT_ROM_V1
+#define PICO_FLOAT_SUPPORT_ROM_V1 0
+#endif
+
+#ifndef PICO_DOUBLE_SUPPORT_ROM_V1
+#define PICO_DOUBLE_SUPPORT_ROM_V1 0
+#endif
+
+#endif
diff --git a/src/boards/include/boards/datanoisetv_rp2040_dsp.h b/src/boards/include/boards/datanoisetv_rp2040_dsp.h
new file mode 100644
index 0000000..49a357b
--- /dev/null
+++ b/src/boards/include/boards/datanoisetv_rp2040_dsp.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+//
+//------------------------------------------------------------------------------------------
+// Board definition for the DatanoiseTV RP2040 DSP Board
+//
+// This header may be included by other board headers as "boards/datanoisetv_rp2040_dsp.h"
+
+#ifndef _BOARDS_DATANOISETV_RP2040_DSP_H
+#define _BOARDS_DATANOISETV_RP2040_DSP_H
+
+// For board detection
+#define DATANOISETV_RP2040_DSP
+
+// --- I2C ---
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C 0
+#endif
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN 24
+#endif
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN 25
+#endif
+
+// -- FLASH --
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (16 * 1024 * 1024)
+#endif
+
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
+#endif
+
+
+// --- I2S ---
+#ifndef PICO_AUDIO_I2S_DATA_PIN
+#define PICO_AUDIO_I2S_DATA_PIN 16
+#endif
+#ifndef PICO_AUDIO_I2S_CLOCK_PIN_BASE
+#define PICO_AUDIO_I2S_CLOCK_PIN_BASE 17
+#endif
+
+#include "boards/pico.h"
+
+#endif
diff --git a/src/boards/include/boards/eetree_gamekit_rp2040.h b/src/boards/include/boards/eetree_gamekit_rp2040.h
new file mode 100644
index 0000000..f007147
--- /dev/null
+++ b/src/boards/include/boards/eetree_gamekit_rp2040.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+#ifndef _BOARDS_EETREE_GAMEKIT_RP2040_H
+#define _BOARDS_EETREE_GAMEKIT_RP2040_H
+
+// For board detection
+#define EETREE_GAMEKIT_RP2040
+
+// --- UART ---
+// no PICO_DEFAULT_UART
+// no PICO_DEFAULT_UART_TX_PIN
+// no PICO_DEFAULT_UART_RX_PIN
+
+// --- LED ---
+#ifndef PICO_DEFAULT_LED_PIN
+ #define PICO_DEFAULT_LED_PIN 4
+#endif
+// no PICO_DEFAULT_WS2812_PIN
+
+// --- I2C ---
+#ifndef PICO_DEFAULT_I2C
+ #define PICO_DEFAULT_I2C 1
+#endif
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+ #define PICO_DEFAULT_I2C_SDA_PIN 10
+#endif
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+ #define PICO_DEFAULT_I2C_SCL_PIN 11
+#endif
+
+// --- SPI ---
+// no PICO_DEFAULT_SPI
+// no PICO_DEFAULT_SPI_SCK_PIN
+// no PICO_DEFAULT_SPI_TX_PIN
+// no PICO_DEFAULT_SPI_RX_PIN
+// no PICO_DEFAULT_SPI_CSN_PIN
+
+// --- LCD ---
+#ifndef EETREE_RP2040_LCD_SPI
+ #define EETREE_RP2040_LCD_SPI 0
+#endif
+#ifndef EETREE_RP2040_LCD_DC_PIN
+ #define EETREE_RP2040_LCD_DC_PIN 1
+#endif
+#ifndef EETREE_RP2040_LCD_SCLK_PIN
+ #define EETREE_RP2040_LCD_SCLK_PIN 2
+#endif
+#ifndef EETREE_RP2040_LCD_TX_PIN
+ #define EETREE_RP2040_LCD_TX_PIN 3
+#endif
+#ifndef EETREE_RP2040_LCD_RST_PIN
+ #define EETREE_RP2040_LCD_RST_PIN 0
+#endif
+// no EETREE_RP2040_LCD_CS_PIN
+
+// --- FLASH ---
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+#ifndef PICO_FLASH_SPI_CLKDIV
+ #define PICO_FLASH_SPI_CLKDIV 2
+#endif
+#ifndef PICO_FLASH_SIZE_BYTES
+ #define PICO_FLASH_SIZE_BYTES (2 * 1024 * 1024)
+#endif
+
+// All boards have B1 RP2040
+#ifndef PICO_RP2040_B0_SUPPORTED
+ #define PICO_RP2040_B0_SUPPORTED 0
+#endif
+
+#endif // _BOARDS_EETREE_GAMEKIT_RP2040_H
diff --git a/src/boards/include/boards/pybstick26_rp2040.h b/src/boards/include/boards/garatronic_pybstick26_rp2040.h
similarity index 90%
rename from src/boards/include/boards/pybstick26_rp2040.h
rename to src/boards/include/boards/garatronic_pybstick26_rp2040.h
index 8a9ca41..d1c0298 100644
--- a/src/boards/include/boards/pybstick26_rp2040.h
+++ b/src/boards/include/boards/garatronic_pybstick26_rp2040.h
@@ -9,11 +9,11 @@
// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
// -----------------------------------------------------
-#ifndef _BOARDS_PYBSTICK26_RP2040_H
-#define _BOARDS_PYBSTICK26_RP2040_H
+#ifndef _BOARDS_GARATRONIC_PYBSTICK26_RP2040_H
+#define _BOARDS_GARATRONIC_PYBSTICK26_RP2040_H
// For board detection
-#define PYBSTICK26_RP2040
+#define GARATRONIC_PYBSTICK26_RP2040
// --- UART ---
#ifndef PICO_DEFAULT_UART
@@ -82,4 +82,4 @@
#endif
#endif
-// of #define _BOARDS_PYBSTICK26_RP2040_H
+// of #define _BOARDS_GARATRONIC_PYBSTICK26_RP2040_H
diff --git a/src/boards/include/boards/pico_w.h b/src/boards/include/boards/pico_w.h
new file mode 100644
index 0000000..b4a8bd7
--- /dev/null
+++ b/src/boards/include/boards/pico_w.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+// This header may be included by other board headers as "boards/pico.h"
+
+#ifndef _BOARDS_PICO_W_H
+#define _BOARDS_PICO_W_H
+
+// For board detection
+#define RASPBERRYPI_PICO_W
+
+// --- UART ---
+#ifndef PICO_DEFAULT_UART
+#define PICO_DEFAULT_UART 0
+#endif
+#ifndef PICO_DEFAULT_UART_TX_PIN
+#define PICO_DEFAULT_UART_TX_PIN 0
+#endif
+#ifndef PICO_DEFAULT_UART_RX_PIN
+#define PICO_DEFAULT_UART_RX_PIN 1
+#endif
+
+// --- LED ---
+// no PICO_DEFAULT_LED_PIN - LED is on Wireless chip
+// no PICO_DEFAULT_WS2812_PIN
+
+// --- I2C ---
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C 0
+#endif
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN 4
+#endif
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN 5
+#endif
+
+// --- SPI ---
+#ifndef PICO_DEFAULT_SPI
+#define PICO_DEFAULT_SPI 0
+#endif
+#ifndef PICO_DEFAULT_SPI_SCK_PIN
+#define PICO_DEFAULT_SPI_SCK_PIN 18
+#endif
+#ifndef PICO_DEFAULT_SPI_TX_PIN
+#define PICO_DEFAULT_SPI_TX_PIN 19
+#endif
+#ifndef PICO_DEFAULT_SPI_RX_PIN
+#define PICO_DEFAULT_SPI_RX_PIN 16
+#endif
+#ifndef PICO_DEFAULT_SPI_CSN_PIN
+#define PICO_DEFAULT_SPI_CSN_PIN 17
+#endif
+
+// --- FLASH ---
+
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (2 * 1024 * 1024)
+#endif
+
+// note the SMSP mode pin is on WL_GPIO1
+// #define PICO_SMPS_MODE_PIN
+
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
+#endif
+
+#ifndef PICO_RP2040_B1_SUPPORTED
+#define PICO_RP2040_B1_SUPPORTED 0
+#endif
+
+#ifndef CYW43_PIN_WL_HOST_WAKE
+#define CYW43_PIN_WL_HOST_WAKE 24
+#endif
+
+#ifndef CYW43_PIN_WL_REG_ON
+#define CYW43_PIN_WL_REG_ON 23
+#endif
+
+#ifndef CYW43_WL_GPIO_COUNT
+#define CYW43_WL_GPIO_COUNT 3
+#endif
+
+#ifndef CYW43_WL_GPIO_LED_PIN
+#define CYW43_WL_GPIO_LED_PIN 0
+#endif
+
+#endif
diff --git a/src/boards/include/boards/pimoroni_badger2040.h b/src/boards/include/boards/pimoroni_badger2040.h
new file mode 100644
index 0000000..0749450
--- /dev/null
+++ b/src/boards/include/boards/pimoroni_badger2040.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+#ifndef _BOARDS_PIMORONI_BADGER2040_H
+#define _BOARDS_PIMORONI_BADGER2040_H
+
+// For board detection
+#define PIMORONI_BADGER2040
+
+// --- BOARD SPECIFIC ---
+#define BADGER2040_UART 0
+#define BADGER2040_TX_PIN 0
+#define BADGER2040_RX_PIN 1
+
+#define BADGER2040_I2C 0
+#define BADGER2040_INT_PIN 3
+#define BADGER2040_SDA_PIN 4
+#define BADGER2040_SCL_PIN 5
+
+#define BADGER2040_3V3_EN_PIN 10
+
+#define BADGER2040_SW_DOWN_PIN 11
+#define BADGER2040_SW_A_PIN 12
+#define BADGER2040_SW_B_PIN 13
+#define BADGER2040_SW_C_PIN 14
+#define BADGER2040_SW_UP_PIN 15
+
+#define BADGER2040_INKY_SPI 0
+#define BADGER2040_INKY_MISO_PIN 16
+#define BADGER2040_INKY_CSN_PIN 17
+#define BADGER2040_INKY_SCK_PIN 18
+#define BADGER2040_INKY_MOSI_PIN 19
+#define BADGER2040_INKY_DC_PIN 20
+#define BADGER2040_INKY_RESET_PIN 21
+#define BADGER2040_INKY_BUSY_PIN 26
+
+#define BADGER2040_USER_SW_PIN 23
+#define BADGER2040_USER_LED_PIN 25
+
+#define BADGER2040_VBUS_DETECT_PIN 24
+#define BADGER2040_VREF_POWER_PIN 27
+#define BADGER2040_1V2_REF_PIN 28
+#define BADGER2040_BAT_SENSE_PIN 29
+
+// --- UART ---
+#ifndef PICO_DEFAULT_UART
+#define PICO_DEFAULT_UART BADGER2040_UART
+#endif
+
+#ifndef PICO_DEFAULT_UART_TX_PIN
+#define PICO_DEFAULT_UART_TX_PIN BADGER2040_TX_PIN
+#endif
+
+#ifndef PICO_DEFAULT_UART_RX_PIN
+#define PICO_DEFAULT_UART_RX_PIN BADGER2040_RX_PIN
+#endif
+
+// --- LED ---
+#ifndef PICO_DEFAULT_LED_PIN
+#define PICO_DEFAULT_LED_PIN BADGER2040_USER_LED_PIN
+#endif
+// no PICO_DEFAULT_WS2812_PIN
+
+// --- I2C ---
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C BADGER2040_I2C
+#endif
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN BADGER2040_SDA_PIN
+#endif
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN BADGER2040_SCL_PIN
+#endif
+
+// --- SPI ---
+#ifndef PICO_DEFAULT_SPI
+#define PICO_DEFAULT_SPI BADGER2040_INKY_SPI
+#endif
+#ifndef PICO_DEFAULT_SPI_SCK_PIN
+#define PICO_DEFAULT_SPI_SCK_PIN BADGER2040_INKY_SCK_PIN
+#endif
+#ifndef PICO_DEFAULT_SPI_TX_PIN
+#define PICO_DEFAULT_SPI_TX_PIN BADGER2040_INKY_MOSI_PIN
+#endif
+#ifndef PICO_DEFAULT_SPI_RX_PIN
+#define PICO_DEFAULT_SPI_RX_PIN BADGER2040_INKY_MISO_PIN
+#endif
+#ifndef PICO_DEFAULT_SPI_CSN_PIN
+#define PICO_DEFAULT_SPI_CSN_PIN BADGER2040_INKY_CSN_PIN
+#endif
+
+// --- FLASH ---
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (2 * 1024 * 1024)
+#endif
+
+// All boards have B1 RP2040
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
+#endif
+
+#endif
diff --git a/src/boards/include/boards/pimoroni_interstate75.h b/src/boards/include/boards/pimoroni_interstate75.h
index e2621b0..5b5bf06 100644
--- a/src/boards/include/boards/pimoroni_interstate75.h
+++ b/src/boards/include/boards/pimoroni_interstate75.h
@@ -16,117 +16,42 @@
#define PIMORONI_INTERSTATE75
// --- BOARD SPECIFIC ---
-#ifndef INTERSTATE75_R0_PIN
#define INTERSTATE75_R0_PIN 0
-#endif
-
-#ifndef INTERSTATE75_G0_PIN
#define INTERSTATE75_G0_PIN 1
-#endif
-
-#ifndef INTERSTATE75_B0_PIN
#define INTERSTATE75_B0_PIN 2
-#endif
-
-#ifndef INTERSTATE75_R1_PIN
#define INTERSTATE75_R1_PIN 3
-#endif
-
-#ifndef INTERSTATE75_G1_PIN
#define INTERSTATE75_G1_PIN 4
-#endif
-
-#ifndef INTERSTATE75_B1_PIN
#define INTERSTATE75_B1_PIN 5
-#endif
-#ifndef INTERSTATE75_ROW_A_PIN
#define INTERSTATE75_ROW_A_PIN 6
-#endif
-
-#ifndef INTERSTATE75_ROW_B_PIN
#define INTERSTATE75_ROW_B_PIN 7
-#endif
-
-#ifndef INTERSTATE75_ROW_C_PIN
#define INTERSTATE75_ROW_C_PIN 8
-#endif
-
-#ifndef INTERSTATE75_ROW_D_PIN
#define INTERSTATE75_ROW_D_PIN 9
-#endif
-
-#ifndef INTERSTATE75_ROW_E_PIN
#define INTERSTATE75_ROW_E_PIN 10
-#endif
-#ifndef INTERSTATE75_CLK_PIN
#define INTERSTATE75_CLK_PIN 11
-#endif
-
-#ifndef INTERSTATE75_LAT_PIN
#define INTERSTATE75_LAT_PIN 12
-#endif
-
-#ifndef INTERSTATE75_OE_PIN
#define INTERSTATE75_OE_PIN 13
-#endif
-#ifndef INTERSTATE75_SW_A_PIN
#define INTERSTATE75_SW_A_PIN 14
-#endif
-#ifndef INTERSTATE75_LED_R_PIN
#define INTERSTATE75_LED_R_PIN 16
-#endif
-
-#ifndef INTERSTATE75_LED_G_PIN
#define INTERSTATE75_LED_G_PIN 17
-#endif
-
-#ifndef INTERSTATE75_LED_B_PIN
#define INTERSTATE75_LED_B_PIN 18
-#endif
-#ifndef INTERSTATE75_I2C
#define INTERSTATE75_I2C 0
-#endif
-
-#ifndef INTERSTATE75_INT_PIN
#define INTERSTATE75_INT_PIN 19
-#endif
-
-#ifndef INTERSTATE75_SDA_PIN
#define INTERSTATE75_SDA_PIN 20
-#endif
-
-#ifndef INTERSTATE75_SCL_PIN
#define INTERSTATE75_SCL_PIN 21
-#endif
-#ifndef INTERSTATE75_USER_SW_PIN
#define INTERSTATE75_USER_SW_PIN 23
-#endif
-#ifndef INTERSTATE75_A0_PIN
#define INTERSTATE75_A0_PIN 26
-#endif
-
-#ifndef INTERSTATE75_A1_PIN
#define INTERSTATE75_A1_PIN 27
-#endif
-
-#ifndef INTERSTATE75_A2_PIN
#define INTERSTATE75_A2_PIN 28
-#endif
-
-#ifndef INTERSTATE75_NUM_ADC_PINS
#define INTERSTATE75_NUM_ADC_PINS 3
-#endif
-#ifndef INTERSTATE75_CURRENT_SENSE_PIN
#define INTERSTATE75_CURRENT_SENSE_PIN 29
-#endif
// --- UART ---
// no PICO_DEFAULT_UART
diff --git a/src/boards/include/boards/pimoroni_keybow2040.h b/src/boards/include/boards/pimoroni_keybow2040.h
index 43772e8..baf0c40 100644
--- a/src/boards/include/boards/pimoroni_keybow2040.h
+++ b/src/boards/include/boards/pimoroni_keybow2040.h
@@ -16,89 +16,30 @@
#define PIMORONI_KEYBOW2040
// --- BOARD SPECIFIC ---
-#ifndef KEYBOW2040_I2C_SDA_PIN
#define KEYBOW2040_I2C_SDA_PIN 4
-#endif
-
-#ifndef KEYBOW2040_I2C_SCL_PIN
#define KEYBOW2040_I2C_SCL_PIN 5
-#endif
-
-#ifndef KEYBOW2040_I2C_INT_PIN
#define KEYBOW2040_I2C_INT_PIN 3
-#endif
-#ifndef KEYBOW2040_USER_SW_PIN
#define KEYBOW2040_USER_SW_PIN 23
-#endif
-#ifndef KEYBOW2040_SW0_PIN
#define KEYBOW2040_SW0_PIN 21
-#endif
-
-#ifndef KEYBOW2040_SW1_PIN
#define KEYBOW2040_SW1_PIN 20
-#endif
-
-#ifndef KEYBOW2040_SW2_PIN
#define KEYBOW2040_SW2_PIN 19
-#endif
-
-#ifndef KEYBOW2040_SW3_PIN
#define KEYBOW2040_SW3_PIN 18
-#endif
-
-#ifndef KEYBOW2040_SW4_PIN
#define KEYBOW2040_SW4_PIN 17
-#endif
-
-#ifndef KEYBOW2040_SW5_PIN
#define KEYBOW2040_SW5_PIN 16
-#endif
-
-#ifndef KEYBOW2040_SW6_PIN
#define KEYBOW2040_SW6_PIN 15
-#endif
-
-#ifndef KEYBOW2040_SW7_PIN
#define KEYBOW2040_SW7_PIN 14
-#endif
-
-#ifndef KEYBOW2040_SW8_PIN
#define KEYBOW2040_SW8_PIN 13
-#endif
-
-#ifndef KEYBOW2040_SW9_PIN
#define KEYBOW2040_SW9_PIN 12
-#endif
-
-#ifndef KEYBOW2040_SW10_PIN
#define KEYBOW2040_SW10_PIN 11
-#endif
-
-#ifndef KEYBOW2040_SW11_PIN
#define KEYBOW2040_SW11_PIN 10
-#endif
-
-#ifndef KEYBOW2040_SW12_PIN
#define KEYBOW2040_SW12_PIN 9
-#endif
-
-#ifndef KEYBOW2040_SW13_PIN
#define KEYBOW2040_SW13_PIN 8
-#endif
-
-#ifndef KEYBOW2040_SW14_PIN
#define KEYBOW2040_SW14_PIN 7
-#endif
-
-#ifndef KEYBOW2040_SW15_PIN
#define KEYBOW2040_SW15_PIN 6
-#endif
-#ifndef KEYBOW2040_NUM_SWITCHES_PINS
#define KEYBOW2040_NUM_SWITCHES_PINS 16
-#endif
// --- UART ---
#ifndef PICO_DEFAULT_UART
diff --git a/src/boards/include/boards/pimoroni_motor2040.h b/src/boards/include/boards/pimoroni_motor2040.h
new file mode 100644
index 0000000..00fd91a
--- /dev/null
+++ b/src/boards/include/boards/pimoroni_motor2040.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+#ifndef _BOARDS_PIMORONI_MOTOR2040_H
+#define _BOARDS_PIMORONI_MOTOR2040_H
+
+// For board detection
+#define PIMORONI_MOTOR2040
+
+#ifndef MOTOR2040_USE_DISTANCE_SENSOR
+// default to 0, if not explicitly set
+#define MOTOR2040_USE_DISTANCE_SENSOR 0
+#endif
+
+// --- BOARD SPECIFIC ---
+#define MOTOR2040_MOTOR_A_P_PIN 4
+#define MOTOR2040_MOTOR_A_N_PIN 5
+#define MOTOR2040_MOTOR_B_P_PIN 6
+#define MOTOR2040_MOTOR_B_N_PIN 7
+#define MOTOR2040_MOTOR_C_P_PIN 8
+#define MOTOR2040_MOTOR_C_N_PIN 9
+#define MOTOR2040_MOTOR_D_P_PIN 10
+#define MOTOR2040_MOTOR_D_N_PIN 11
+#define MOTOR2040_NUM_MOTORS 4
+
+#define MOTOR2040_ENCODER_A_A_PIN 0
+#define MOTOR2040_ENCODER_A_B_PIN 1
+#define MOTOR2040_ENCODER_B_A_PIN 2
+#define MOTOR2040_ENCODER_B_B_PIN 3
+#define MOTOR2040_ENCODER_C_A_PIN 12
+#define MOTOR2040_ENCODER_C_B_PIN 13
+#define MOTOR2040_ENCODER_D_A_PIN 14
+#define MOTOR2040_ENCODER_D_B_PIN 15
+#define MOTOR2040_NUM_ENCODERS 4
+
+#if MOTOR2040_USE_DISTANCE_SENSOR
+#define MOTOR2040_TRIG_PIN 16
+#define MOTOR2040_ECHO_PIN 17
+#else
+#define MOTOR2040_UART 0
+#define MOTOR2040_TX_PIN 16
+#define MOTOR2040_RX_PIN 17
+#endif
+
+#define MOTOR2040_LED_DATA_PIN 18
+#define MOTOR2040_NUM_LEDS 1
+
+#define MOTOR2040_I2C 0
+#define MOTOR2040_INT_PIN 19
+#define MOTOR2040_SDA_PIN 20
+#define MOTOR2040_SCL_PIN 21
+
+#define MOTOR2040_USER_SW_PIN 23
+
+#define MOTOR2040_A0_PIN 26
+#define MOTOR2040_A1_PIN 27
+#define MOTOR2040_A2_PIN 28
+#define MOTOR2040_NUM_ADC_PINS 3
+
+#define MOTOR2040_SHARED_ADC_PIN 29
+#define MOTOR2040_ADC_ADDR_0_PIN 22
+#define MOTOR2040_ADC_ADDR_1_PIN 24
+#define MOTOR2040_ADC_ADDR_2_PIN 25
+
+#define MOTOR2040_CURRENT_SENSE_A_ADDR 0b000
+#define MOTOR2040_CURRENT_SENSE_B_ADDR 0b001
+#define MOTOR2040_CURRENT_SENSE_C_ADDR 0b010
+#define MOTOR2040_CURRENT_SENSE_D_ADDR 0b011
+#define MOTOR2040_VOLTAGE_SENSE_ADDR 0b100
+#define MOTOR2040_FAULT_SENSE_ADDR 0b101
+#define MOTOR2040_SENSOR_1_ADDR 0b110
+#define MOTOR2040_SENSOR_2_ADDR 0b111
+#define MOTOR2040_NUM_SENSORS 2
+
+// --- UART ---
+#if MOTOR2040_USE_DISTANCE_SENSOR
+// no PICO_DEFAULT_UART
+#else
+#ifndef PICO_DEFAULT_UART
+#define PICO_DEFAULT_UART MOTOR2040_UART
+#endif
+#ifndef PICO_DEFAULT_UART_TX_PIN
+#define PICO_DEFAULT_UART_TX_PIN MOTOR2040_TX_PIN
+#endif
+#ifndef PICO_DEFAULT_UART_RX_PIN
+#define PICO_DEFAULT_UART_RX_PIN MOTOR2040_RX_PIN
+#endif
+#endif
+
+// --- LED ---
+// no PICO_DEFAULT_LED_PIN
+#ifndef PICO_DEFAULT_WS2812_PIN
+#define PICO_DEFAULT_WS2812_PIN MOTOR2040_LED_DATA_PIN
+#endif
+
+// --- I2C ---
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C MOTOR2040_I2C
+#endif
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN MOTOR2040_SDA_PIN
+#endif
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN MOTOR2040_SCL_PIN
+#endif
+
+// --- SPI ---
+// no PICO_DEFAULT_SPI
+// no PICO_DEFAULT_SPI_SCK_PIN
+// no PICO_DEFAULT_SPI_TX_PIN
+// no PICO_DEFAULT_SPI_RX_PIN
+// no PICO_DEFAULT_SPI_CSN_PIN
+
+// --- FLASH ---
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (2 * 1024 * 1024)
+#endif
+
+// All boards have B1 RP2040
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
+#endif
+
+#endif
diff --git a/src/boards/include/boards/pimoroni_picolipo_16mb.h b/src/boards/include/boards/pimoroni_picolipo_16mb.h
index 338977b..dfad767 100644
--- a/src/boards/include/boards/pimoroni_picolipo_16mb.h
+++ b/src/boards/include/boards/pimoroni_picolipo_16mb.h
@@ -16,17 +16,9 @@
#define PIMORONI_PICOLIPO_16MB
// --- BOARD SPECIFIC ---
-#ifndef PICOLIPO_USER_SW_PIN
#define PICOLIPO_USER_SW_PIN 23
-#endif
-
-#ifndef PICOLIPO_VBUS_DETECT_PIN
#define PICOLIPO_VBUS_DETECT_PIN 24
-#endif
-
-#ifndef PICOLIPO_BAT_SENSE_PIN
#define PICOLIPO_BAT_SENSE_PIN 29
-#endif
// --- UART ---
#ifndef PICO_DEFAULT_UART
diff --git a/src/boards/include/boards/pimoroni_picolipo_4mb.h b/src/boards/include/boards/pimoroni_picolipo_4mb.h
index 871ed83..aea767d 100644
--- a/src/boards/include/boards/pimoroni_picolipo_4mb.h
+++ b/src/boards/include/boards/pimoroni_picolipo_4mb.h
@@ -16,17 +16,9 @@
#define PIMORONI_PICOLIPO_4MB
// --- BOARD SPECIFIC ---
-#ifndef PICOLIPO_USER_SW_PIN
#define PICOLIPO_USER_SW_PIN 23
-#endif
-
-#ifndef PICOLIPO_VBUS_DETECT_PIN
#define PICOLIPO_VBUS_DETECT_PIN 24
-#endif
-
-#ifndef PICOLIPO_BAT_SENSE_PIN
#define PICOLIPO_BAT_SENSE_PIN 29
-#endif
// --- UART ---
#ifndef PICO_DEFAULT_UART
diff --git a/src/boards/include/boards/pimoroni_picosystem.h b/src/boards/include/boards/pimoroni_picosystem.h
index 1e7c80e..0717b05 100644
--- a/src/boards/include/boards/pimoroni_picosystem.h
+++ b/src/boards/include/boards/pimoroni_picosystem.h
@@ -16,97 +16,35 @@
#define PIMORONI_PICOSYSTEM
// --- BOARD SPECIFIC ---
-#ifndef PICOSYSTEM_VBUS_DETECT_PIN
#define PICOSYSTEM_VBUS_DETECT_PIN 2
-#endif
-#ifndef PICOSYSTEM_LCD_SPI
#define PICOSYSTEM_LCD_SPI 0
-#endif
-
-#ifndef PICOSYSTEM_LCD_RESET_PIN
#define PICOSYSTEM_LCD_RESET_PIN 4
-#endif
-
-#ifndef PICOSYSTEM_LCD_CSN_PIN
#define PICOSYSTEM_LCD_CSN_PIN 5
-#endif
-
-#ifndef PICOSYSTEM_LCD_SCLK_PIN
#define PICOSYSTEM_LCD_SCLK_PIN 6
-#endif
-
-#ifndef PICOSYSTEM_LCD_MOSI_PIN
#define PICOSYSTEM_LCD_MOSI_PIN 7
-#endif
-
-#ifndef PICOSYSTEM_LCD_VSYNC_PIN
#define PICOSYSTEM_LCD_VSYNC_PIN 8
-#endif
-
-#ifndef PICOSYSTEM_LCD_DC_PIN
#define PICOSYSTEM_LCD_DC_PIN 9
-#endif
-#ifndef PICOSYSTEM_AUDIO_PIN
#define PICOSYSTEM_AUDIO_PIN 11
-#endif
-#ifndef PICOSYSTEM_BACKLIGHT_PIN
#define PICOSYSTEM_BACKLIGHT_PIN 12
-#endif
-#ifndef PICOSYSTEM_LED_G_PIN
#define PICOSYSTEM_LED_G_PIN 13
-#endif
-
-#ifndef PICOSYSTEM_LED_R_PIN
#define PICOSYSTEM_LED_R_PIN 14
-#endif
-
-#ifndef PICOSYSTEM_LED_B_PIN
#define PICOSYSTEM_LED_B_PIN 15
-#endif
-#ifndef PICOSYSTEM_SW_Y_PIN
#define PICOSYSTEM_SW_Y_PIN 16
-#endif
-
-#ifndef PICOSYSTEM_SW_X_PIN
#define PICOSYSTEM_SW_X_PIN 17
-#endif
-
-#ifndef PICOSYSTEM_SW_A_PIN
#define PICOSYSTEM_SW_A_PIN 18
-#endif
-
-#ifndef PICOSYSTEM_SW_B_PIN
#define PICOSYSTEM_SW_B_PIN 19
-#endif
-
-#ifndef PICOSYSTEM_SW_DOWN_PIN
#define PICOSYSTEM_SW_DOWN_PIN 20
-#endif
-
-#ifndef PICOSYSTEM_SW_RIGHT_PIN
#define PICOSYSTEM_SW_RIGHT_PIN 21
-#endif
-
-#ifndef PICOSYSTEM_SW_LEFT_PIN
#define PICOSYSTEM_SW_LEFT_PIN 22
-#endif
-
-#ifndef PICOSYSTEM_SW_UP_PIN
#define PICOSYSTEM_SW_UP_PIN 23
-#endif
-#ifndef PICOSYSTEM_CHARGE_STAT_PIN
#define PICOSYSTEM_CHARGE_STAT_PIN 24
-#endif
-
-#ifndef PICOSYSTEM_BAT_SENSE_PIN
#define PICOSYSTEM_BAT_SENSE_PIN 26
-#endif
// --- UART ---
#ifndef PICO_DEFAULT_UART
diff --git a/src/boards/include/boards/pimoroni_plasma2040.h b/src/boards/include/boards/pimoroni_plasma2040.h
index 226aaf5..2cdb4c5 100644
--- a/src/boards/include/boards/pimoroni_plasma2040.h
+++ b/src/boards/include/boards/pimoroni_plasma2040.h
@@ -16,73 +16,29 @@
#define PIMORONI_PLASMA2040
// --- BOARD SPECIFIC ---
-#ifndef PLASMA2040_SW_A_PIN
#define PLASMA2040_SW_A_PIN 12
-#endif
-
-#ifndef PLASMA2040_SW_B_PIN
#define PLASMA2040_SW_B_PIN 13
-#endif
-#ifndef PLASMA2040_CLK_PIN
#define PLASMA2040_CLK_PIN 14
-#endif
-
-#ifndef PLASMA2040_DATA_PIN
#define PLASMA2040_DATA_PIN 15
-#endif
-#ifndef PLASMA2040_LED_R_PIN
#define PLASMA2040_LED_R_PIN 16
-#endif
-
-#ifndef PLASMA2040_LED_G_PIN
#define PLASMA2040_LED_G_PIN 17
-#endif
-
-#ifndef PLASMA2040_LED_B_PIN
#define PLASMA2040_LED_B_PIN 18
-#endif
-#ifndef PLASMA2040_I2C
#define PLASMA2040_I2C 0
-#endif
-
-#ifndef PLASMA2040_INT_PIN
#define PLASMA2040_INT_PIN 19
-#endif
-
-#ifndef PLASMA2040_SDA_PIN
#define PLASMA2040_SDA_PIN 20
-#endif
-
-#ifndef PLASMA2040_SCL_PIN
#define PLASMA2040_SCL_PIN 21
-#endif
-#ifndef PLASMA2040_USER_SW_PIN
#define PLASMA2040_USER_SW_PIN 23
-#endif
-#ifndef PLASMA2040_A0_PIN
#define PLASMA2040_A0_PIN 26
-#endif
-
-#ifndef PLASMA2040_A1_PIN
#define PLASMA2040_A1_PIN 27
-#endif
-
-#ifndef PLASMA2040_A2_PIN
#define PLASMA2040_A2_PIN 28
-#endif
-
-#ifndef PLASMA2040_NUM_ADC_PINS
#define PLASMA2040_NUM_ADC_PINS 3
-#endif
-#ifndef PLASMA2040_CURRENT_SENSE_PIN
#define PLASMA2040_CURRENT_SENSE_PIN 29
-#endif
// --- UART ---
// no PICO_DEFAULT_UART
diff --git a/src/boards/include/boards/pimoroni_servo2040.h b/src/boards/include/boards/pimoroni_servo2040.h
new file mode 100644
index 0000000..17fd76f
--- /dev/null
+++ b/src/boards/include/boards/pimoroni_servo2040.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+#ifndef _BOARDS_PIMORONI_SERVO2040_H
+#define _BOARDS_PIMORONI_SERVO2040_H
+
+// For board detection
+#define PIMORONI_SERVO2040
+
+// --- BOARD SPECIFIC ---
+#define SERVO2040_SERVO_1_PIN 0
+#define SERVO2040_SERVO_2_PIN 1
+#define SERVO2040_SERVO_3_PIN 2
+#define SERVO2040_SERVO_4_PIN 3
+#define SERVO2040_SERVO_5_PIN 4
+#define SERVO2040_SERVO_6_PIN 5
+#define SERVO2040_SERVO_7_PIN 6
+#define SERVO2040_SERVO_8_PIN 7
+#define SERVO2040_SERVO_9_PIN 8
+#define SERVO2040_SERVO_10_PIN 9
+#define SERVO2040_SERVO_11_PIN 10
+#define SERVO2040_SERVO_12_PIN 11
+#define SERVO2040_SERVO_13_PIN 12
+#define SERVO2040_SERVO_14_PIN 13
+#define SERVO2040_SERVO_15_PIN 14
+#define SERVO2040_SERVO_16_PIN 15
+#define SERVO2040_SERVO_17_PIN 16
+#define SERVO2040_SERVO_18_PIN 17
+#define SERVO2040_NUM_SERVOS 18
+
+#define SERVO2040_LED_DATA_PIN 18
+#define SERVO2040_NUM_LEDS 6
+
+#define SERVO2040_I2C 0
+#define SERVO2040_INT_PIN 19
+#define SERVO2040_SDA_PIN 20
+#define SERVO2040_SCL_PIN 21
+
+#define SERVO2040_USER_SW_PIN 23
+
+#define SERVO2040_A0_PIN 26
+#define SERVO2040_A1_PIN 27
+#define SERVO2040_A2_PIN 28
+#define SERVO2040_NUM_ADC_PINS 3
+
+#define SERVO2040_SHARED_ADC_PIN 29
+#define SERVO2040_ADC_ADDR_0_PIN 22
+#define SERVO2040_ADC_ADDR_1_PIN 24
+#define SERVO2040_ADC_ADDR_2_PIN 25
+
+#define SERVO2040_SENSOR_1_ADDR 0b000
+#define SERVO2040_SENSOR_2_ADDR 0b001
+#define SERVO2040_SENSOR_3_ADDR 0b010
+#define SERVO2040_SENSOR_4_ADDR 0b011
+#define SERVO2040_SENSOR_5_ADDR 0b100
+#define SERVO2040_SENSOR_6_ADDR 0b101
+#define SERVO2040_VOLTAGE_SENSE_ADDR 0b110
+#define SERVO2040_CURRENT_SENSE_ADDR 0b111
+#define SERVO2040_NUM_SENSORS 6
+
+// --- UART ---
+// no PICO_DEFAULT_UART
+// no PICO_DEFAULT_UART_TX_PIN
+// no PICO_DEFAULT_UART_RX_PIN
+
+// --- LED ---
+// no PICO_DEFAULT_LED_PIN
+#ifndef PICO_DEFAULT_WS2812_PIN
+#define PICO_DEFAULT_WS2812_PIN SERVO2040_LED_DATA_PIN
+#endif
+
+// --- I2C ---
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C SERVO2040_I2C
+#endif
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN SERVO2040_SDA_PIN
+#endif
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN SERVO2040_SCL_PIN
+#endif
+
+// --- SPI ---
+// no PICO_DEFAULT_SPI
+// no PICO_DEFAULT_SPI_SCK_PIN
+// no PICO_DEFAULT_SPI_TX_PIN
+// no PICO_DEFAULT_SPI_RX_PIN
+// no PICO_DEFAULT_SPI_CSN_PIN
+
+// --- FLASH ---
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (2 * 1024 * 1024)
+#endif
+
+// All boards have B1 RP2040
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
+#endif
+
+#endif
diff --git a/src/boards/include/boards/pimoroni_tiny2040.h b/src/boards/include/boards/pimoroni_tiny2040.h
index 51d17f6..f407008 100644
--- a/src/boards/include/boards/pimoroni_tiny2040.h
+++ b/src/boards/include/boards/pimoroni_tiny2040.h
@@ -14,47 +14,22 @@
// For board detection
#define PIMORONI_TINY2040
+#define PIMORONI_TINY2040_8MB
// --- BOARD SPECIFIC ---
-#ifndef TINY2040_LED_R_PIN
#define TINY2040_LED_R_PIN 18
-#endif
-
-#ifndef TINY2040_LED_G_PIN
#define TINY2040_LED_G_PIN 19
-#endif
-
-#ifndef TINY2040_LED_B_PIN
#define TINY2040_LED_B_PIN 20
-#endif
-#ifndef TINY2040_USER_SW_PIN
#define TINY2040_USER_SW_PIN 23
-#endif
-#ifndef TINY2040_A0_PIN
#define TINY2040_A0_PIN 26
-#endif
-
-#ifndef TINY2040_A1_PIN
#define TINY2040_A1_PIN 27
-#endif
-
-#ifndef TINY2040_A2_PIN
#define TINY2040_A2_PIN 28
-#endif
-
-#ifndef TINY2040_A3_PIN
#define TINY2040_A3_PIN 29
-#endif
-#ifndef TINY2040_NUM_IO_PINS
#define TINY2040_NUM_IO_PINS 8
-#endif
-
-#ifndef TINY2040_NUM_ADC_PINS
#define TINY2040_NUM_ADC_PINS 4
-#endif
// --- UART ---
#ifndef PICO_DEFAULT_UART
diff --git a/src/boards/include/boards/pimoroni_tiny2040_2mb.h b/src/boards/include/boards/pimoroni_tiny2040_2mb.h
new file mode 100644
index 0000000..e32d370
--- /dev/null
+++ b/src/boards/include/boards/pimoroni_tiny2040_2mb.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+#ifndef _BOARDS_PIMORONI_TINY2040_2MB_H
+#define _BOARDS_PIMORONI_TINY2040_2MB_H
+
+// For board detection
+#define PIMORONI_TINY2040
+#define PIMORONI_TINY2040_2MB
+
+// --- BOARD SPECIFIC ---
+#define TINY2040_LED_R_PIN 18
+#define TINY2040_LED_G_PIN 19
+#define TINY2040_LED_B_PIN 20
+
+#define TINY2040_USER_SW_PIN 23
+
+#define TINY2040_A0_PIN 26
+#define TINY2040_A1_PIN 27
+#define TINY2040_A2_PIN 28
+#define TINY2040_A3_PIN 29
+
+#define TINY2040_NUM_IO_PINS 8
+#define TINY2040_NUM_ADC_PINS 4
+
+// --- UART ---
+#ifndef PICO_DEFAULT_UART
+#define PICO_DEFAULT_UART 0
+#endif
+
+#ifndef PICO_DEFAULT_UART_TX_PIN
+#define PICO_DEFAULT_UART_TX_PIN 0
+#endif
+
+#ifndef PICO_DEFAULT_UART_RX_PIN
+#define PICO_DEFAULT_UART_RX_PIN 1
+#endif
+
+// --- LED ---
+// Included so basic examples will work, and set it to the green LED
+#ifndef PICO_DEFAULT_LED_PIN
+#define PICO_DEFAULT_LED_PIN TINY2040_LED_G_PIN
+#endif
+// no PICO_DEFAULT_WS2812_PIN
+
+#ifndef PICO_DEFAULT_LED_PIN_INVERTED
+#define PICO_DEFAULT_LED_PIN_INVERTED 1
+#endif
+
+// --- I2C ---
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C 1
+#endif
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN 2
+#endif
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN 3
+#endif
+
+// --- SPI ---
+#ifndef PICO_DEFAULT_SPI
+#define PICO_DEFAULT_SPI 0
+#endif
+#ifndef PICO_DEFAULT_SPI_SCK_PIN
+#define PICO_DEFAULT_SPI_SCK_PIN 6
+#endif
+#ifndef PICO_DEFAULT_SPI_TX_PIN
+#define PICO_DEFAULT_SPI_TX_PIN 7
+#endif
+#ifndef PICO_DEFAULT_SPI_RX_PIN
+#define PICO_DEFAULT_SPI_RX_PIN 4
+#endif
+#ifndef PICO_DEFAULT_SPI_CSN_PIN
+#define PICO_DEFAULT_SPI_CSN_PIN 5
+#endif
+
+// --- FLASH ---
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (2 * 1024 * 1024)
+#endif
+
+// All boards have B1 RP2040
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
+#endif
+
+#endif
diff --git a/src/boards/include/boards/seeed_xiao_rp2040.h b/src/boards/include/boards/seeed_xiao_rp2040.h
new file mode 100644
index 0000000..2fd3687
--- /dev/null
+++ b/src/boards/include/boards/seeed_xiao_rp2040.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+#ifndef _BOARDS_SEEED_XIAO_RP2040_H
+#define _BOARDS_SEEED_XIAO_RP2040_H
+
+// For board detection
+#define SEEED_XIAO_RP2040
+
+// On some samples, the xosc can take longer to stabilize than is usual
+#ifndef PICO_XOSC_STARTUP_DELAY_MULTIPLIER
+#define PICO_XOSC_STARTUP_DELAY_MULTIPLIER 64
+#endif
+
+//------------- UART -------------//
+#ifndef PICO_DEFAULT_UART
+#define PICO_DEFAULT_UART 0
+#endif
+
+#ifndef PICO_DEFAULT_UART_TX_PIN
+#define PICO_DEFAULT_UART_TX_PIN 0
+#endif
+
+#ifndef PICO_DEFAULT_UART_RX_PIN
+#define PICO_DEFAULT_UART_RX_PIN 1
+#endif
+
+//------------- LED -------------//
+#ifndef PICO_DEFAULT_LED_PIN
+#define PICO_DEFAULT_LED_PIN 25
+#endif
+
+#ifndef PICO_DEFAULT_LED_PIN_INVERTED
+#define PICO_DEFAULT_LED_PIN_INVERTED 1
+#endif
+
+#ifndef PICO_DEFAULT_WS2812_PIN
+#define PICO_DEFAULT_WS2812_PIN 12
+#endif
+
+#ifndef PICO_DEFAULT_WS2812_POWER_PIN
+#define PICO_DEFAULT_WS2812_POWER_PIN 11
+#endif
+
+//------------- I2C -------------//
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C 1
+#endif
+
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN 6
+#endif
+
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN 7
+#endif
+
+//------------- SPI -------------//
+#ifndef PICO_DEFAULT_SPI
+#define PICO_DEFAULT_SPI 0
+#endif
+
+#ifndef PICO_DEFAULT_SPI_TX_PIN
+#define PICO_DEFAULT_SPI_TX_PIN 3
+#endif
+
+#ifndef PICO_DEFAULT_SPI_RX_PIN
+#define PICO_DEFAULT_SPI_RX_PIN 4
+#endif
+
+#ifndef PICO_DEFAULT_SPI_SCK_PIN
+#define PICO_DEFAULT_SPI_SCK_PIN 2
+#endif
+
+//------------- FLASH -------------//
+
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (2 * 1024 * 1024)
+#endif
+
+// All boards have B1 RP2040
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
+#endif
+
+#endif
diff --git a/src/boards/include/boards/solderparty_rp2040_stamp.h b/src/boards/include/boards/solderparty_rp2040_stamp.h
new file mode 100644
index 0000000..fb3c5b9
--- /dev/null
+++ b/src/boards/include/boards/solderparty_rp2040_stamp.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+//
+//------------------------------------------------------------------------------------------
+// Board definition for the Solder Party RP2040 Stamp
+//
+// This header may be included by other board headers as "boards/solderparty_rp2040_stamp.h"
+
+#ifndef _BOARDS_SOLDERPARTY_RP2040_STAMP_H
+#define _BOARDS_SOLDERPARTY_RP2040_STAMP_H
+
+// For board detection
+#define SOLDERPARTY_RP2040_STAMP
+
+// --- UART ---
+#ifndef PICO_DEFAULT_UART
+#define PICO_DEFAULT_UART 0
+#endif
+#ifndef PICO_DEFAULT_UART_TX_PIN
+#define PICO_DEFAULT_UART_TX_PIN 0
+#endif
+#ifndef PICO_DEFAULT_UART_RX_PIN
+#define PICO_DEFAULT_UART_RX_PIN 1
+#endif
+
+// --- Neopixel ---
+#ifndef PICO_DEFAULT_WS2812_PIN
+#define PICO_DEFAULT_WS2812_PIN 21
+#endif
+
+// --- I2C ---
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C 0
+#endif
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN 4
+#endif
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN 5
+#endif
+
+// --- SPI ---
+#ifndef PICO_DEFAULT_SPI
+#define PICO_DEFAULT_SPI 0
+#endif
+#ifndef PICO_DEFAULT_SPI_SCK_PIN
+#define PICO_DEFAULT_SPI_SCK_PIN 18
+#endif
+#ifndef PICO_DEFAULT_SPI_TX_PIN
+#define PICO_DEFAULT_SPI_TX_PIN 19
+#endif
+#ifndef PICO_DEFAULT_SPI_RX_PIN
+#define PICO_DEFAULT_SPI_RX_PIN 16
+#endif
+#ifndef PICO_DEFAULT_SPI_CSN_PIN
+#define PICO_DEFAULT_SPI_CSN_PIN 17
+#endif
+
+// --- FLASH ---
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (8 * 1024 * 1024)
+#endif
+
+// All production boards have B1 RP2040
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
+#endif
+
+#endif
diff --git a/src/boards/include/boards/solderparty_rp2040_stamp_carrier.h b/src/boards/include/boards/solderparty_rp2040_stamp_carrier.h
new file mode 100644
index 0000000..aac45f4
--- /dev/null
+++ b/src/boards/include/boards/solderparty_rp2040_stamp_carrier.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+//
+//------------------------------------------------------------------------------------------
+// Board definition for the Solder Party RP2040 Stamp Carrier
+//
+// This header may be included by other board headers as "boards/solderparty_rp2040_stamp_carrier.h"
+
+#ifndef _BOARDS_SOLDERPARTY_RP2040_STAMP_CARRIER_H
+#define _BOARDS_SOLDERPARTY_RP2040_STAMP_CARRIER_H
+
+// For board detection
+#define SOLDERPARTY_RP2040_STAMP_CARRIER
+
+#ifndef PICO_DEFAULT_LED_PIN
+#define PICO_DEFAULT_LED_PIN 20
+#endif
+
+#include "solderparty_rp2040_stamp.h"
+
+#endif
diff --git a/src/boards/include/boards/solderparty_rp2040_stamp_round_carrier.h b/src/boards/include/boards/solderparty_rp2040_stamp_round_carrier.h
new file mode 100644
index 0000000..bb9d335
--- /dev/null
+++ b/src/boards/include/boards/solderparty_rp2040_stamp_round_carrier.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+//
+//------------------------------------------------------------------------------------------
+// Board definition for the Solder Party RP2040 Stamp Round Carrier
+//
+// This header may be included by other board headers as "boards/solderparty_rp2040_stamp_round_carrier.h"
+
+#ifndef _BOARDS_SOLDERPARTY_RP2040_STAMP_ROUND_CARRIER_H
+#define _BOARDS_SOLDERPARTY_RP2040_STAMP_ROUND_CARRIER_H
+
+// For board detection
+#define SOLDERPARTY_RP2040_STAMP_ROUND_CARRIER
+
+// --- User LED ---
+#ifndef PICO_DEFAULT_LED_PIN
+#define PICO_DEFAULT_LED_PIN 25
+#endif
+
+// --- UART ---
+#ifndef PICO_DEFAULT_UART
+#define PICO_DEFAULT_UART 0
+#endif
+#ifndef PICO_DEFAULT_UART_TX_PIN
+#define PICO_DEFAULT_UART_TX_PIN 16
+#endif
+#ifndef PICO_DEFAULT_UART_RX_PIN
+#define PICO_DEFAULT_UART_RX_PIN 17
+#endif
+
+// --- Neopixel Ring ---
+#ifndef PICO_DEFAULT_WS2812_PIN
+#define PICO_DEFAULT_WS2812_PIN 24
+#endif
+
+// --- On-Stamp Neopixel ---
+#ifndef SOLDERPARTY_RP2040_STAMP_WS2812_PIN
+#define SOLDERPARTY_RP2040_STAMP_WS2812_PIN 21
+#endif
+
+// --- I2C ---
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C 0
+#endif
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN 0
+#endif
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN 1
+#endif
+
+// --- SPI ---
+#ifndef PICO_DEFAULT_SPI
+#define PICO_DEFAULT_SPI 1
+#endif
+#ifndef PICO_DEFAULT_SPI_SCK_PIN
+#define PICO_DEFAULT_SPI_SCK_PIN 10
+#endif
+#ifndef PICO_DEFAULT_SPI_TX_PIN
+#define PICO_DEFAULT_SPI_TX_PIN 11
+#endif
+#ifndef PICO_DEFAULT_SPI_RX_PIN
+#define PICO_DEFAULT_SPI_RX_PIN 8
+#endif
+#ifndef PICO_DEFAULT_SPI_CSN_PIN
+#define PICO_DEFAULT_SPI_CSN_PIN 9
+#endif
+
+#include "solderparty_rp2040_stamp.h"
+
+#endif
diff --git a/src/boards/include/boards/vgaboard.h b/src/boards/include/boards/vgaboard.h
index f0b6f0e..dd4bf6c 100644
--- a/src/boards/include/boards/vgaboard.h
+++ b/src/boards/include/boards/vgaboard.h
@@ -53,12 +53,25 @@
#define PICO_DEFAULT_UART_RX_PIN 21
#endif
+#ifndef PICO_SCANVIDEO_COLOR_PIN_BASE
#define PICO_SCANVIDEO_COLOR_PIN_BASE VGABOARD_VGA_COLOR_PIN_BASE
-#define PICO_SCANVIDEO_SYNC_PIN_BASE VGABOARD_VGA_SYNC_PIN_BASE
+#endif
+#ifndef PICO_SCANVIDEO_SYNC_PIN_BASE
+#define PICO_SCANVIDEO_SYNC_PIN_BASE VGABOARD_VGA_SYNC_PIN_BASE
+#endif
+
+#ifndef PICO_SD_CLK_PIN
#define PICO_SD_CLK_PIN VGABOARD_SD_CLK_PIN
+#endif
+
+#ifndef PICO_SD_CMD_PIN
#define PICO_SD_CMD_PIN VGABOARD_SD_CMD_PIN
+#endif
+
+#ifndef PICO_SD_DAT0_PIN
#define PICO_SD_DAT0_PIN VGABOARD_SD_DAT0_PIN
+#endif
// 1 or 4
#ifndef PICO_SD_DAT_PIN_COUNT
@@ -66,13 +79,24 @@
#endif
// 1 or -1
+#ifndef PICO_SD_DAT_PIN_INCREMENT
#define PICO_SD_DAT_PIN_INCREMENT 1
+#endif
+#ifndef PICO_AUDIO_I2S_DATA_PIN
#define PICO_AUDIO_I2S_DATA_PIN VGABOARD_I2S_DIN_PIN
+#endif
+#ifndef PICO_AUDIO_I2S_CLOCK_PIN_BASE
#define PICO_AUDIO_I2S_CLOCK_PIN_BASE VGABOARD_I2S_BCK_PIN
+#endif
+#ifndef PICO_AUDIO_PWM_L_PIN
#define PICO_AUDIO_PWM_L_PIN VGABOARD_PWM_L_PIN
+#endif
+
+#ifndef PICO_AUDIO_PWM_R_PIN
#define PICO_AUDIO_PWM_R_PIN VGABOARD_PWM_R_PIN
+#endif
#define PICO_VGA_BOARD
diff --git a/src/boards/include/boards/wiznet_w5100s_evb_pico.h b/src/boards/include/boards/wiznet_w5100s_evb_pico.h
new file mode 100644
index 0000000..585f1d1
--- /dev/null
+++ b/src/boards/include/boards/wiznet_w5100s_evb_pico.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+
+
+#ifndef _BOARDS_WIZNET_W5100S_EVB_PICO_H
+#define _BOARDS_WIZNET_W5100S_EVB_PICO_H
+
+// For board detection
+#define WIZNET_W5100S_EVB_PICO
+
+// --- BOARD SPECIFIC ---
+#ifndef W5100S_EVB_PICO_INTN_PIN
+#define W5100S_EVB_PICO_INTN_PIN 21
+#endif
+
+#ifndef W5100S_EVB_PICO_RSTN_PIN
+#define W5100S_EVB_PICO_RSTN_PIN 20
+#endif
+
+#ifndef W5100S_EVB_PICO_A0_PIN
+#define W5100S_EVB_PICO_A0_PIN 26
+#endif
+#ifndef W5100S_EVB_PICO_A1_PIN
+#define W5100S_EVB_PICO_A1_PIN 27
+#endif
+#ifndef W5100S_EVB_PICO_A2_PIN
+#define W5100S_EVB_PICO_A2_PIN 28
+#endif
+
+// --- LED ---
+#ifndef PICO_DEFAULT_LED_PIN
+#define PICO_DEFAULT_LED_PIN 25
+#endif
+
+// --- UART ---
+#ifndef PICO_DEFAULT_UART
+#define PICO_DEFAULT_UART 0
+#endif
+#ifndef PICO_DEFAULT_UART_TX_PIN
+#define PICO_DEFAULT_UART_TX_PIN 0
+#endif
+#ifndef PICO_DEFAULT_UART_RX_PIN
+#define PICO_DEFAULT_UART_RX_PIN 1
+#endif
+
+
+// --- I2C ---
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C 0
+#endif
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN 4
+#endif
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN 5
+#endif
+
+// --- SPI ---
+#ifndef PICO_DEFAULT_SPI
+#define PICO_DEFAULT_SPI 0
+#endif
+#ifndef PICO_DEFAULT_SPI_SCK_PIN
+#define PICO_DEFAULT_SPI_SCK_PIN 18
+#endif
+#ifndef PICO_DEFAULT_SPI_TX_PIN
+#define PICO_DEFAULT_SPI_TX_PIN 19
+#endif
+#ifndef PICO_DEFAULT_SPI_RX_PIN
+#define PICO_DEFAULT_SPI_RX_PIN 16
+#endif
+#ifndef PICO_DEFAULT_SPI_CSN_PIN
+#define PICO_DEFAULT_SPI_CSN_PIN 17
+#endif
+
+// --- FLASH ---
+
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (2 * 1024 * 1024)
+#endif
+
+// Drive high to force power supply into PWM mode (lower ripple on 3V3 at light loads)
+#define PICO_SMPS_MODE_PIN 23
+
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
+#endif
+
+#endif
diff --git a/src/boards/pico_w.cmake b/src/boards/pico_w.cmake
new file mode 100644
index 0000000..15b901d
--- /dev/null
+++ b/src/boards/pico_w.cmake
@@ -0,0 +1,2 @@
+set(PICO_CYW43_SUPPORTED "1" CACHE INTERNAL "Try to add support for PICO_CYW43")
+include(${CMAKE_CURRENT_LIST_DIR}/generic_board.cmake)
diff --git a/src/common/pico_base/include/pico.h b/src/common/pico_base/include/pico.h
index 1b73651..784566e 100644
--- a/src/common/pico_base/include/pico.h
+++ b/src/common/pico_base/include/pico.h
@@ -16,9 +16,18 @@
* This header may be included by assembly code
*/
+#define __PICO_STRING(x) #x
+#define __PICO_XSTRING(x) __PICO_STRING(x)
+
#include "pico/types.h"
#include "pico/version.h"
+
+// PICO_CONFIG: PICO_CONFIG_HEADER, unquoted path to header include in place of the default pico/config.h which may be desirable for build systems which can't easily generate the config_autogen header, group=pico_base
+#ifdef PICO_CONFIG_HEADER
+#include __PICO_XSTRING(PICO_CONFIG_HEADER)
+#else
#include "pico/config.h"
+#endif
#include "pico/platform.h"
#include "pico/error.h"
diff --git a/src/common/pico_base/include/pico/config.h b/src/common/pico_base/include/pico/config.h
index 8d69269..10a9c6a 100644
--- a/src/common/pico_base/include/pico/config.h
+++ b/src/common/pico_base/include/pico/config.h
@@ -18,4 +18,9 @@
#include "pico/config_autogen.h"
-#endif
\ No newline at end of file
+// PICO_CONFIG: PICO_CONFIG_RTOS_ADAPTER_HEADER, unquoted path to header include in the default pico/config.h for RTOS integration defines that must be included in all sources, group=pico_base
+#ifdef PICO_CONFIG_RTOS_ADAPTER_HEADER
+#include __PICO_XSTRING(PICO_CONFIG_RTOS_ADAPTER_HEADER)
+#endif
+
+#endif
diff --git a/src/common/pico_base/include/pico/error.h b/src/common/pico_base/include/pico/error.h
index fadb45e..a5cbc39 100644
--- a/src/common/pico_base/include/pico/error.h
+++ b/src/common/pico_base/include/pico/error.h
@@ -10,14 +10,18 @@
#ifndef __ASSEMBLER__
/*!
- * Common return codes from pico_sdk methods that return a status
+ * \brief Common return codes from pico_sdk methods that return a status
+ * \ingroup pico_base
*/
-enum {
+enum pico_error_codes {
PICO_OK = 0,
PICO_ERROR_NONE = 0,
PICO_ERROR_TIMEOUT = -1,
PICO_ERROR_GENERIC = -2,
PICO_ERROR_NO_DATA = -3,
+ PICO_ERROR_NOT_PERMITTED = -4,
+ PICO_ERROR_INVALID_ARG = -5,
+ PICO_ERROR_IO = -6,
};
#endif // !__ASSEMBLER__
diff --git a/src/common/pico_binary_info/include/pico/binary_info.h b/src/common/pico_binary_info/include/pico/binary_info.h
index 77b1c08..b5c08e7 100644
--- a/src/common/pico_binary_info/include/pico/binary_info.h
+++ b/src/common/pico_binary_info/include/pico/binary_info.h
@@ -25,7 +25,5 @@
#if !PICO_ON_DEVICE && !defined(PICO_NO_BINARY_INFO)
#define PICO_NO_BINARY_INFO 1
#endif
-#if !PICO_NO_BINARY_INFO
#include "pico/binary_info/code.h"
#endif
-#endif
diff --git a/src/common/pico_binary_info/include/pico/binary_info/code.h b/src/common/pico_binary_info/include/pico/binary_info/code.h
index e87a2cd..9478477 100644
--- a/src/common/pico_binary_info/include/pico/binary_info/code.h
+++ b/src/common/pico_binary_info/include/pico/binary_info/code.h
@@ -7,7 +7,12 @@
#ifndef _PICO_BINARY_INFO_CODE_H
#define _PICO_BINARY_INFO_CODE_H
+// pico.h is not available when PICO_NO_BINARY_INFO=1 is used for builds outside of the SDK (e.g. picotool)
+// and only needed anyway (because of macro definitions) in PICO_NO_BINARY_INFO=0 builds
+#if !PICO_NO_BINARY_INFO
#include "pico.h"
+#endif
+
#include "pico/binary_info/structure.h"
#if !PICO_NO_BINARY_INFO
@@ -131,7 +136,7 @@
#define bi_pin_range_with_func(plo, phi, func) __bi_encoded_pins_with_func(BI_PINS_ENCODING_RANGE | ((func << 3)) | ((plo) << 7) | ((phi) << 12))
#define bi_pin_mask_with_name(pmask, label) __bi_pins_with_name((pmask), (label))
-// names are sperated by | ... i.e. "name1|name2|name3"
+// names are separated by | ... i.e. "name1|name2|name3"
#define bi_pin_mask_with_names(pmask, label) __bi_pins_with_name((pmask), (label))
#define bi_1pin_with_name(p0, name) bi_pin_mask_with_name(1u << (p0), name)
#define bi_2pins_with_names(p0, name0, p1, name1) bi_pin_mask_with_names((1u << (p0)) | (1u << (p1)), name0 "|" name1)
diff --git a/src/common/pico_sync/include/pico/mutex.h b/src/common/pico_sync/include/pico/mutex.h
index e834dc5..ca93760 100644
--- a/src/common/pico_sync/include/pico/mutex.h
+++ b/src/common/pico_sync/include/pico/mutex.h
@@ -289,7 +289,7 @@
*
* But the initialization of the mutex is performed automatically during runtime initialization
*/
-#define auto_init_recursive_mutex(name) static __attribute__((section(".mutex_array"))) recursive_mutex_t name = { .core.spin_lock = (spin_lock_t *)1 /* marker for runtime_init */ }
+#define auto_init_recursive_mutex(name) static __attribute__((section(".mutex_array"))) recursive_mutex_t name = { .core = { .spin_lock = (spin_lock_t *)1 /* marker for runtime_init */ }, .owner = 0, .enter_count = 0 }
#ifdef __cplusplus
}
diff --git a/src/common/pico_sync/include/pico/sem.h b/src/common/pico_sync/include/pico/sem.h
index 6244e32..f9f724b 100644
--- a/src/common/pico_sync/include/pico/sem.h
+++ b/src/common/pico_sync/include/pico/sem.h
@@ -122,6 +122,17 @@
*/
bool sem_acquire_block_until(semaphore_t *sem, absolute_time_t until);
+/*! \brief Attempt to acquire a permit from a semaphore without blocking
+ * \ingroup sem
+ *
+ * This function will return false without blocking if no permits are
+ * available, otherwise it will acquire a permit and return true.
+ *
+ * \param sem Pointer to semaphore structure
+ * \return true if permit was acquired.
+ */
+bool sem_try_acquire(semaphore_t *sem);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/common/pico_sync/sem.c b/src/common/pico_sync/sem.c
index 06b4946..ec49fdb 100644
--- a/src/common/pico_sync/sem.c
+++ b/src/common/pico_sync/sem.c
@@ -23,7 +23,7 @@
uint32_t save = spin_lock_blocking(sem->core.spin_lock);
if (sem->permits > 0) {
sem->permits--;
- lock_internal_spin_unlock_with_notify(&sem->core, save);
+ spin_unlock(sem->core.spin_lock, save);
break;
}
lock_internal_spin_unlock_with_wait(&sem->core, save);
@@ -43,7 +43,7 @@
uint32_t save = spin_lock_blocking(sem->core.spin_lock);
if (sem->permits > 0) {
sem->permits--;
- lock_internal_spin_unlock_with_notify(&sem->core, save);
+ spin_unlock(sem->core.spin_lock, save);
return true;
}
if (lock_internal_spin_unlock_with_best_effort_wait_or_timeout(&sem->core, save, until)) {
@@ -52,6 +52,17 @@
} while (true);
}
+bool __time_critical_func(sem_try_acquire)(semaphore_t *sem) {
+ uint32_t save = spin_lock_blocking(sem->core.spin_lock);
+ if (sem->permits > 0) {
+ sem->permits--;
+ spin_unlock(sem->core.spin_lock, save);
+ return true;
+ }
+ spin_unlock(sem->core.spin_lock, save);
+ return false;
+}
+
// todo this should really have a blocking variant for when permits are maxed out
bool __time_critical_func(sem_release)(semaphore_t *sem) {
uint32_t save = spin_lock_blocking(sem->core.spin_lock);
diff --git a/src/common/pico_time/include/pico/time.h b/src/common/pico_time/include/pico/time.h
index c00b7a8..0fde00f 100644
--- a/src/common/pico_time/include/pico/time.h
+++ b/src/common/pico_time/include/pico/time.h
@@ -76,7 +76,7 @@
* \ingroup timestamp
* \brief Convert a timestamp into a number of milliseconds since boot.
* \param t an absolute_time_t value to convert
- * \return the number of microseconds since boot represented by t
+ * \return the number of milliseconds since boot represented by t
* \sa to_us_since_boot()
*/
static inline uint32_t to_ms_since_boot(absolute_time_t t) {
@@ -162,6 +162,16 @@
*/
extern const absolute_time_t at_the_end_of_time;
+/*! \brief Determine if the given timestamp is "at_the_end_of_time"
+ * \ingroup timestamp
+ * \param t the timestamp
+ * \return true if the timestamp is at_the_end_of_time
+ * \sa at_the_end_of_time
+ */
+static inline bool is_at_the_end_of_time(absolute_time_t t) {
+ return to_us_since_boot(t) == to_us_since_boot(at_the_end_of_time);
+}
+
/*! \brief The timestamp representing a null timestamp
* \ingroup timestamp
*/
diff --git a/src/common/pico_util/include/pico/util/pheap.h b/src/common/pico_util/include/pico/util/pheap.h
index 25351b4..5dc5133 100644
--- a/src/common/pico_util/include/pico/util/pheap.h
+++ b/src/common/pico_util/include/pico/util/pheap.h
@@ -24,13 +24,12 @@
* Pairing Heap Implementation
* \ingroup pico_util
*
- * pheap defines a simple pairing heap. the implementation simply tracks array indexes, it is up to
+ * pheap defines a simple pairing heap. The implementation simply tracks array indexes, it is up to
* the user to provide storage for heap entries and a comparison function.
*
- * NOTE: this class is not safe for concurrent usage. It should be externally protected. Furthermore
+ * NOTE: This class is not safe for concurrent usage. It should be externally protected. Furthermore
* if used concurrently, the caller needs to protect around their use of the returned id.
- * for example, ph_remove_and_free_head returns the id of an element that is no longer in the heap.
- *
+ * For example, ph_remove_and_free_head returns the id of an element that is no longer in the heap.
* The user can still use this to look at the data in their companion array, however obviously further operations
* on the heap may cause them to overwrite that data as the id may be reused on subsequent operations
*
diff --git a/src/common/pico_util/include/pico/util/queue.h b/src/common/pico_util/include/pico/util/queue.h
index 097578a..eb71e36 100644
--- a/src/common/pico_util/include/pico/util/queue.h
+++ b/src/common/pico_util/include/pico/util/queue.h
@@ -101,6 +101,7 @@
return level;
}
+#if PICO_QUEUE_MAX_LEVEL
/*! \brief Returns the highest level reached by the specified queue since it was created
* or since the max level was reset
* \ingroup queue
@@ -108,18 +109,17 @@
* \param q Pointer to a queue_t structure, used as a handle
* \return Maximum level of the queue
*/
-#if PICO_QUEUE_MAX_LEVEL
static inline uint queue_get_max_level(queue_t *q) {
return q->max_level;
}
#endif
+#if PICO_QUEUE_MAX_LEVEL
/*! \brief Reset the highest level reached of the specified queue.
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
*/
-#if PICO_QUEUE_MAX_LEVEL
static inline void queue_reset_max_level(queue_t *q) {
uint32_t save = spin_lock_blocking(q->core.spin_lock);
q->max_level = queue_get_level_unsafe(q);
diff --git a/src/host/hardware_sync/include/hardware/sync.h b/src/host/hardware_sync/include/hardware/sync.h
index a27ea01..58426f5 100644
--- a/src/host/hardware_sync/include/hardware/sync.h
+++ b/src/host/hardware_sync/include/hardware/sync.h
@@ -86,8 +86,6 @@
void spin_unlock(spin_lock_t *lock, uint32_t saved_irq);
-uint get_core_num();
-
spin_lock_t *spin_lock_init(uint lock_num);
void clear_spin_locks(void);
diff --git a/src/host/pico_platform/include/pico/platform.h b/src/host/pico_platform/include/pico/platform.h
index 27e5c08..b5e8137 100644
--- a/src/host/pico_platform/include/pico/platform.h
+++ b/src/host/pico_platform/include/pico/platform.h
@@ -22,7 +22,7 @@
#define __not_in_flash(group)
#define __not_in_flash_func(func) func
-#define __no_inline_not_in_flash_func(func)
+#define __no_inline_not_in_flash_func(func) func
#define __in_flash(group)
#define __scratch_x(group)
#define __scratch_y(group)
@@ -139,6 +139,9 @@
static inline void __compiler_memory_barrier(void) {
}
+
+uint get_core_num();
+
#ifdef __cplusplus
}
#endif
diff --git a/src/rp2040/hardware_regs/include/hardware/platform_defs.h b/src/rp2040/hardware_regs/include/hardware/platform_defs.h
index 08c7159..21f77ca 100644
--- a/src/rp2040/hardware_regs/include/hardware/platform_defs.h
+++ b/src/rp2040/hardware_regs/include/hardware/platform_defs.h
@@ -21,6 +21,7 @@
#define NUM_DMA_CHANNELS _u(12)
#define NUM_DMA_TIMERS _u(4)
#define NUM_IRQS _u(32)
+#define NUM_USER_IRQS _u(6)
#define NUM_PIOS _u(2)
#define NUM_PIO_STATE_MACHINES _u(4)
#define NUM_PWM_SLICES _u(8)
diff --git a/src/rp2040/hardware_regs/include/hardware/regs/dma.h b/src/rp2040/hardware_regs/include/hardware/regs/dma.h
index 042c3c1..1b69346 100644
--- a/src/rp2040/hardware_regs/include/hardware/regs/dma.h
+++ b/src/rp2040/hardware_regs/include/hardware/regs/dma.h
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -183,7 +183,6 @@
// Description : When this channel completes, it will trigger the channel
// indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this
// channel)_.
-// Reset value is equal to channel number (0).
#define DMA_CH0_CTRL_TRIG_CHAIN_TO_RESET _u(0x0)
#define DMA_CH0_CTRL_TRIG_CHAIN_TO_BITS _u(0x00007800)
#define DMA_CH0_CTRL_TRIG_CHAIN_TO_MSB _u(14)
@@ -457,7 +456,7 @@
// Description : DMA Channel 1 Control and Status
#define DMA_CH1_CTRL_TRIG_OFFSET _u(0x0000004c)
#define DMA_CH1_CTRL_TRIG_BITS _u(0xe1ffffff)
-#define DMA_CH1_CTRL_TRIG_RESET _u(0x00000800)
+#define DMA_CH1_CTRL_TRIG_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : DMA_CH1_CTRL_TRIG_AHB_ERROR
// Description : Logical OR of the READ_ERROR and WRITE_ERROR flags. The channel
@@ -572,8 +571,7 @@
// Description : When this channel completes, it will trigger the channel
// indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this
// channel)_.
-// Reset value is equal to channel number (1).
-#define DMA_CH1_CTRL_TRIG_CHAIN_TO_RESET _u(0x1)
+#define DMA_CH1_CTRL_TRIG_CHAIN_TO_RESET _u(0x0)
#define DMA_CH1_CTRL_TRIG_CHAIN_TO_BITS _u(0x00007800)
#define DMA_CH1_CTRL_TRIG_CHAIN_TO_MSB _u(14)
#define DMA_CH1_CTRL_TRIG_CHAIN_TO_LSB _u(11)
@@ -846,7 +844,7 @@
// Description : DMA Channel 2 Control and Status
#define DMA_CH2_CTRL_TRIG_OFFSET _u(0x0000008c)
#define DMA_CH2_CTRL_TRIG_BITS _u(0xe1ffffff)
-#define DMA_CH2_CTRL_TRIG_RESET _u(0x00001000)
+#define DMA_CH2_CTRL_TRIG_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : DMA_CH2_CTRL_TRIG_AHB_ERROR
// Description : Logical OR of the READ_ERROR and WRITE_ERROR flags. The channel
@@ -961,8 +959,7 @@
// Description : When this channel completes, it will trigger the channel
// indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this
// channel)_.
-// Reset value is equal to channel number (2).
-#define DMA_CH2_CTRL_TRIG_CHAIN_TO_RESET _u(0x2)
+#define DMA_CH2_CTRL_TRIG_CHAIN_TO_RESET _u(0x0)
#define DMA_CH2_CTRL_TRIG_CHAIN_TO_BITS _u(0x00007800)
#define DMA_CH2_CTRL_TRIG_CHAIN_TO_MSB _u(14)
#define DMA_CH2_CTRL_TRIG_CHAIN_TO_LSB _u(11)
@@ -1235,7 +1232,7 @@
// Description : DMA Channel 3 Control and Status
#define DMA_CH3_CTRL_TRIG_OFFSET _u(0x000000cc)
#define DMA_CH3_CTRL_TRIG_BITS _u(0xe1ffffff)
-#define DMA_CH3_CTRL_TRIG_RESET _u(0x00001800)
+#define DMA_CH3_CTRL_TRIG_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : DMA_CH3_CTRL_TRIG_AHB_ERROR
// Description : Logical OR of the READ_ERROR and WRITE_ERROR flags. The channel
@@ -1350,8 +1347,7 @@
// Description : When this channel completes, it will trigger the channel
// indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this
// channel)_.
-// Reset value is equal to channel number (3).
-#define DMA_CH3_CTRL_TRIG_CHAIN_TO_RESET _u(0x3)
+#define DMA_CH3_CTRL_TRIG_CHAIN_TO_RESET _u(0x0)
#define DMA_CH3_CTRL_TRIG_CHAIN_TO_BITS _u(0x00007800)
#define DMA_CH3_CTRL_TRIG_CHAIN_TO_MSB _u(14)
#define DMA_CH3_CTRL_TRIG_CHAIN_TO_LSB _u(11)
@@ -1624,7 +1620,7 @@
// Description : DMA Channel 4 Control and Status
#define DMA_CH4_CTRL_TRIG_OFFSET _u(0x0000010c)
#define DMA_CH4_CTRL_TRIG_BITS _u(0xe1ffffff)
-#define DMA_CH4_CTRL_TRIG_RESET _u(0x00002000)
+#define DMA_CH4_CTRL_TRIG_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : DMA_CH4_CTRL_TRIG_AHB_ERROR
// Description : Logical OR of the READ_ERROR and WRITE_ERROR flags. The channel
@@ -1739,8 +1735,7 @@
// Description : When this channel completes, it will trigger the channel
// indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this
// channel)_.
-// Reset value is equal to channel number (4).
-#define DMA_CH4_CTRL_TRIG_CHAIN_TO_RESET _u(0x4)
+#define DMA_CH4_CTRL_TRIG_CHAIN_TO_RESET _u(0x0)
#define DMA_CH4_CTRL_TRIG_CHAIN_TO_BITS _u(0x00007800)
#define DMA_CH4_CTRL_TRIG_CHAIN_TO_MSB _u(14)
#define DMA_CH4_CTRL_TRIG_CHAIN_TO_LSB _u(11)
@@ -2013,7 +2008,7 @@
// Description : DMA Channel 5 Control and Status
#define DMA_CH5_CTRL_TRIG_OFFSET _u(0x0000014c)
#define DMA_CH5_CTRL_TRIG_BITS _u(0xe1ffffff)
-#define DMA_CH5_CTRL_TRIG_RESET _u(0x00002800)
+#define DMA_CH5_CTRL_TRIG_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : DMA_CH5_CTRL_TRIG_AHB_ERROR
// Description : Logical OR of the READ_ERROR and WRITE_ERROR flags. The channel
@@ -2128,8 +2123,7 @@
// Description : When this channel completes, it will trigger the channel
// indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this
// channel)_.
-// Reset value is equal to channel number (5).
-#define DMA_CH5_CTRL_TRIG_CHAIN_TO_RESET _u(0x5)
+#define DMA_CH5_CTRL_TRIG_CHAIN_TO_RESET _u(0x0)
#define DMA_CH5_CTRL_TRIG_CHAIN_TO_BITS _u(0x00007800)
#define DMA_CH5_CTRL_TRIG_CHAIN_TO_MSB _u(14)
#define DMA_CH5_CTRL_TRIG_CHAIN_TO_LSB _u(11)
@@ -2402,7 +2396,7 @@
// Description : DMA Channel 6 Control and Status
#define DMA_CH6_CTRL_TRIG_OFFSET _u(0x0000018c)
#define DMA_CH6_CTRL_TRIG_BITS _u(0xe1ffffff)
-#define DMA_CH6_CTRL_TRIG_RESET _u(0x00003000)
+#define DMA_CH6_CTRL_TRIG_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : DMA_CH6_CTRL_TRIG_AHB_ERROR
// Description : Logical OR of the READ_ERROR and WRITE_ERROR flags. The channel
@@ -2517,8 +2511,7 @@
// Description : When this channel completes, it will trigger the channel
// indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this
// channel)_.
-// Reset value is equal to channel number (6).
-#define DMA_CH6_CTRL_TRIG_CHAIN_TO_RESET _u(0x6)
+#define DMA_CH6_CTRL_TRIG_CHAIN_TO_RESET _u(0x0)
#define DMA_CH6_CTRL_TRIG_CHAIN_TO_BITS _u(0x00007800)
#define DMA_CH6_CTRL_TRIG_CHAIN_TO_MSB _u(14)
#define DMA_CH6_CTRL_TRIG_CHAIN_TO_LSB _u(11)
@@ -2791,7 +2784,7 @@
// Description : DMA Channel 7 Control and Status
#define DMA_CH7_CTRL_TRIG_OFFSET _u(0x000001cc)
#define DMA_CH7_CTRL_TRIG_BITS _u(0xe1ffffff)
-#define DMA_CH7_CTRL_TRIG_RESET _u(0x00003800)
+#define DMA_CH7_CTRL_TRIG_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : DMA_CH7_CTRL_TRIG_AHB_ERROR
// Description : Logical OR of the READ_ERROR and WRITE_ERROR flags. The channel
@@ -2906,8 +2899,7 @@
// Description : When this channel completes, it will trigger the channel
// indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this
// channel)_.
-// Reset value is equal to channel number (7).
-#define DMA_CH7_CTRL_TRIG_CHAIN_TO_RESET _u(0x7)
+#define DMA_CH7_CTRL_TRIG_CHAIN_TO_RESET _u(0x0)
#define DMA_CH7_CTRL_TRIG_CHAIN_TO_BITS _u(0x00007800)
#define DMA_CH7_CTRL_TRIG_CHAIN_TO_MSB _u(14)
#define DMA_CH7_CTRL_TRIG_CHAIN_TO_LSB _u(11)
@@ -3180,7 +3172,7 @@
// Description : DMA Channel 8 Control and Status
#define DMA_CH8_CTRL_TRIG_OFFSET _u(0x0000020c)
#define DMA_CH8_CTRL_TRIG_BITS _u(0xe1ffffff)
-#define DMA_CH8_CTRL_TRIG_RESET _u(0x00004000)
+#define DMA_CH8_CTRL_TRIG_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : DMA_CH8_CTRL_TRIG_AHB_ERROR
// Description : Logical OR of the READ_ERROR and WRITE_ERROR flags. The channel
@@ -3295,8 +3287,7 @@
// Description : When this channel completes, it will trigger the channel
// indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this
// channel)_.
-// Reset value is equal to channel number (8).
-#define DMA_CH8_CTRL_TRIG_CHAIN_TO_RESET _u(0x8)
+#define DMA_CH8_CTRL_TRIG_CHAIN_TO_RESET _u(0x0)
#define DMA_CH8_CTRL_TRIG_CHAIN_TO_BITS _u(0x00007800)
#define DMA_CH8_CTRL_TRIG_CHAIN_TO_MSB _u(14)
#define DMA_CH8_CTRL_TRIG_CHAIN_TO_LSB _u(11)
@@ -3569,7 +3560,7 @@
// Description : DMA Channel 9 Control and Status
#define DMA_CH9_CTRL_TRIG_OFFSET _u(0x0000024c)
#define DMA_CH9_CTRL_TRIG_BITS _u(0xe1ffffff)
-#define DMA_CH9_CTRL_TRIG_RESET _u(0x00004800)
+#define DMA_CH9_CTRL_TRIG_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : DMA_CH9_CTRL_TRIG_AHB_ERROR
// Description : Logical OR of the READ_ERROR and WRITE_ERROR flags. The channel
@@ -3684,8 +3675,7 @@
// Description : When this channel completes, it will trigger the channel
// indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this
// channel)_.
-// Reset value is equal to channel number (9).
-#define DMA_CH9_CTRL_TRIG_CHAIN_TO_RESET _u(0x9)
+#define DMA_CH9_CTRL_TRIG_CHAIN_TO_RESET _u(0x0)
#define DMA_CH9_CTRL_TRIG_CHAIN_TO_BITS _u(0x00007800)
#define DMA_CH9_CTRL_TRIG_CHAIN_TO_MSB _u(14)
#define DMA_CH9_CTRL_TRIG_CHAIN_TO_LSB _u(11)
@@ -3958,7 +3948,7 @@
// Description : DMA Channel 10 Control and Status
#define DMA_CH10_CTRL_TRIG_OFFSET _u(0x0000028c)
#define DMA_CH10_CTRL_TRIG_BITS _u(0xe1ffffff)
-#define DMA_CH10_CTRL_TRIG_RESET _u(0x00005000)
+#define DMA_CH10_CTRL_TRIG_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : DMA_CH10_CTRL_TRIG_AHB_ERROR
// Description : Logical OR of the READ_ERROR and WRITE_ERROR flags. The channel
@@ -4073,8 +4063,7 @@
// Description : When this channel completes, it will trigger the channel
// indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this
// channel)_.
-// Reset value is equal to channel number (10).
-#define DMA_CH10_CTRL_TRIG_CHAIN_TO_RESET _u(0xa)
+#define DMA_CH10_CTRL_TRIG_CHAIN_TO_RESET _u(0x0)
#define DMA_CH10_CTRL_TRIG_CHAIN_TO_BITS _u(0x00007800)
#define DMA_CH10_CTRL_TRIG_CHAIN_TO_MSB _u(14)
#define DMA_CH10_CTRL_TRIG_CHAIN_TO_LSB _u(11)
@@ -4347,7 +4336,7 @@
// Description : DMA Channel 11 Control and Status
#define DMA_CH11_CTRL_TRIG_OFFSET _u(0x000002cc)
#define DMA_CH11_CTRL_TRIG_BITS _u(0xe1ffffff)
-#define DMA_CH11_CTRL_TRIG_RESET _u(0x00005800)
+#define DMA_CH11_CTRL_TRIG_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : DMA_CH11_CTRL_TRIG_AHB_ERROR
// Description : Logical OR of the READ_ERROR and WRITE_ERROR flags. The channel
@@ -4462,8 +4451,7 @@
// Description : When this channel completes, it will trigger the channel
// indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this
// channel)_.
-// Reset value is equal to channel number (11).
-#define DMA_CH11_CTRL_TRIG_CHAIN_TO_RESET _u(0xb)
+#define DMA_CH11_CTRL_TRIG_CHAIN_TO_RESET _u(0x0)
#define DMA_CH11_CTRL_TRIG_CHAIN_TO_BITS _u(0x00007800)
#define DMA_CH11_CTRL_TRIG_CHAIN_TO_MSB _u(14)
#define DMA_CH11_CTRL_TRIG_CHAIN_TO_LSB _u(11)
diff --git a/src/rp2040/hardware_regs/include/hardware/regs/pll.h b/src/rp2040/hardware_regs/include/hardware/regs/pll.h
index a0f5ad0..9dba689 100644
--- a/src/rp2040/hardware_regs/include/hardware/regs/pll.h
+++ b/src/rp2040/hardware_regs/include/hardware/regs/pll.h
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -17,7 +17,7 @@
// GENERAL CONSTRAINTS:
// Reference clock frequency min=5MHz, max=800MHz
// Feedback divider min=16, max=320
-// VCO frequency min=400MHz, max=1600MHz
+// VCO frequency min=750MHz, max=1600MHz
#define PLL_CS_OFFSET _u(0x00000000)
#define PLL_CS_BITS _u(0x8000013f)
#define PLL_CS_RESET _u(0x00000001)
diff --git a/src/rp2040/hardware_regs/include/hardware/regs/sio.h b/src/rp2040/hardware_regs/include/hardware/regs/sio.h
index f641533..8d4a4ac 100644
--- a/src/rp2040/hardware_regs/include/hardware/regs/sio.h
+++ b/src/rp2040/hardware_regs/include/hardware/regs/sio.h
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -344,7 +344,7 @@
// q`.
// Any operand write starts a new calculation. The results appear
// in QUOTIENT, REMAINDER.
-// UDIVIDEND/SDIVIDEND are aliases of the same internal register.
+// UDIVISOR/SDIVISOR are aliases of the same internal register.
// The U alias starts an
// unsigned calculation, and the S alias starts a signed
// calculation.
diff --git a/src/rp2040/hardware_regs/rp2040.svd b/src/rp2040/hardware_regs/rp2040.svd
index 52da2c0..3849776 100644
--- a/src/rp2040/hardware_regs/rp2040.svd
+++ b/src/rp2040/hardware_regs/rp2040.svd
@@ -22367,7 +22367,7 @@
GENERAL CONSTRAINTS:\n
Reference clock frequency min=5MHz, max=800MHz\n
Feedback divider min=16, max=320\n
- VCO frequency min=400MHz, max=1600MHz</description>
+ VCO frequency min=750MHz, max=1600MHz</description>
<fields>
<field>
<access>read-only</access>
@@ -29754,8 +29754,7 @@
<field>
<access>read-write</access>
<bitRange>[14:11]</bitRange>
- <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.\n
- Reset value is equal to channel number (0).</description>
+ <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.</description>
<name>CHAIN_TO</name>
</field>
<field>
@@ -30039,8 +30038,7 @@
<field>
<access>read-write</access>
<bitRange>[14:11]</bitRange>
- <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.\n
- Reset value is equal to channel number (1).</description>
+ <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.</description>
<name>CHAIN_TO</name>
</field>
<field>
@@ -30113,7 +30111,7 @@
</field>
</fields>
<name>CH1_CTRL_TRIG</name>
- <resetValue>0x00000800</resetValue>
+ <resetValue>0x00000000</resetValue>
</register>
<register>
<access>read-write</access>
@@ -30324,8 +30322,7 @@
<field>
<access>read-write</access>
<bitRange>[14:11]</bitRange>
- <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.\n
- Reset value is equal to channel number (2).</description>
+ <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.</description>
<name>CHAIN_TO</name>
</field>
<field>
@@ -30398,7 +30395,7 @@
</field>
</fields>
<name>CH2_CTRL_TRIG</name>
- <resetValue>0x00001000</resetValue>
+ <resetValue>0x00000000</resetValue>
</register>
<register>
<access>read-write</access>
@@ -30609,8 +30606,7 @@
<field>
<access>read-write</access>
<bitRange>[14:11]</bitRange>
- <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.\n
- Reset value is equal to channel number (3).</description>
+ <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.</description>
<name>CHAIN_TO</name>
</field>
<field>
@@ -30683,7 +30679,7 @@
</field>
</fields>
<name>CH3_CTRL_TRIG</name>
- <resetValue>0x00001800</resetValue>
+ <resetValue>0x00000000</resetValue>
</register>
<register>
<access>read-write</access>
@@ -30894,8 +30890,7 @@
<field>
<access>read-write</access>
<bitRange>[14:11]</bitRange>
- <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.\n
- Reset value is equal to channel number (4).</description>
+ <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.</description>
<name>CHAIN_TO</name>
</field>
<field>
@@ -30968,7 +30963,7 @@
</field>
</fields>
<name>CH4_CTRL_TRIG</name>
- <resetValue>0x00002000</resetValue>
+ <resetValue>0x00000000</resetValue>
</register>
<register>
<access>read-write</access>
@@ -31179,8 +31174,7 @@
<field>
<access>read-write</access>
<bitRange>[14:11]</bitRange>
- <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.\n
- Reset value is equal to channel number (5).</description>
+ <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.</description>
<name>CHAIN_TO</name>
</field>
<field>
@@ -31253,7 +31247,7 @@
</field>
</fields>
<name>CH5_CTRL_TRIG</name>
- <resetValue>0x00002800</resetValue>
+ <resetValue>0x00000000</resetValue>
</register>
<register>
<access>read-write</access>
@@ -31464,8 +31458,7 @@
<field>
<access>read-write</access>
<bitRange>[14:11]</bitRange>
- <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.\n
- Reset value is equal to channel number (6).</description>
+ <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.</description>
<name>CHAIN_TO</name>
</field>
<field>
@@ -31538,7 +31531,7 @@
</field>
</fields>
<name>CH6_CTRL_TRIG</name>
- <resetValue>0x00003000</resetValue>
+ <resetValue>0x00000000</resetValue>
</register>
<register>
<access>read-write</access>
@@ -31749,8 +31742,7 @@
<field>
<access>read-write</access>
<bitRange>[14:11]</bitRange>
- <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.\n
- Reset value is equal to channel number (7).</description>
+ <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.</description>
<name>CHAIN_TO</name>
</field>
<field>
@@ -31823,7 +31815,7 @@
</field>
</fields>
<name>CH7_CTRL_TRIG</name>
- <resetValue>0x00003800</resetValue>
+ <resetValue>0x00000000</resetValue>
</register>
<register>
<access>read-write</access>
@@ -32034,8 +32026,7 @@
<field>
<access>read-write</access>
<bitRange>[14:11]</bitRange>
- <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.\n
- Reset value is equal to channel number (8).</description>
+ <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.</description>
<name>CHAIN_TO</name>
</field>
<field>
@@ -32108,7 +32099,7 @@
</field>
</fields>
<name>CH8_CTRL_TRIG</name>
- <resetValue>0x00004000</resetValue>
+ <resetValue>0x00000000</resetValue>
</register>
<register>
<access>read-write</access>
@@ -32319,8 +32310,7 @@
<field>
<access>read-write</access>
<bitRange>[14:11]</bitRange>
- <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.\n
- Reset value is equal to channel number (9).</description>
+ <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.</description>
<name>CHAIN_TO</name>
</field>
<field>
@@ -32393,7 +32383,7 @@
</field>
</fields>
<name>CH9_CTRL_TRIG</name>
- <resetValue>0x00004800</resetValue>
+ <resetValue>0x00000000</resetValue>
</register>
<register>
<access>read-write</access>
@@ -32604,8 +32594,7 @@
<field>
<access>read-write</access>
<bitRange>[14:11]</bitRange>
- <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.\n
- Reset value is equal to channel number (10).</description>
+ <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.</description>
<name>CHAIN_TO</name>
</field>
<field>
@@ -32678,7 +32667,7 @@
</field>
</fields>
<name>CH10_CTRL_TRIG</name>
- <resetValue>0x00005000</resetValue>
+ <resetValue>0x00000000</resetValue>
</register>
<register>
<access>read-write</access>
@@ -32889,8 +32878,7 @@
<field>
<access>read-write</access>
<bitRange>[14:11]</bitRange>
- <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.\n
- Reset value is equal to channel number (11).</description>
+ <description>When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_.</description>
<name>CHAIN_TO</name>
</field>
<field>
@@ -32963,7 +32951,7 @@
</field>
</fields>
<name>CH11_CTRL_TRIG</name>
- <resetValue>0x00005800</resetValue>
+ <resetValue>0x00000000</resetValue>
</register>
<register>
<access>read-write</access>
@@ -44521,7 +44509,7 @@
<description>Divider unsigned divisor\n
Write to the DIVISOR operand of the divider, i.e. the q in `p / q`.\n
Any operand write starts a new calculation. The results appear in QUOTIENT, REMAINDER.\n
- UDIVIDEND/SDIVIDEND are aliases of the same internal register. The U alias starts an\n
+ UDIVISOR/SDIVISOR are aliases of the same internal register. The U alias starts an\n
unsigned calculation, and the S alias starts a signed calculation.</description>
<name>DIV_UDIVISOR</name>
<resetValue>0x00000000</resetValue>
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/adc.h b/src/rp2040/hardware_structs/include/hardware/structs/adc.h
index c47e9d4..016137c 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/adc.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/adc.h
@@ -86,6 +86,6 @@
io_ro_32 ints;
} adc_hw_t;
-#define adc_hw ((adc_hw_t *const)ADC_BASE)
+#define adc_hw ((adc_hw_t *)ADC_BASE)
#endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/bus_ctrl.h b/src/rp2040/hardware_structs/include/hardware/structs/bus_ctrl.h
index 81118a8..d4e819e 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/bus_ctrl.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/bus_ctrl.h
@@ -72,6 +72,6 @@
bus_ctrl_perf_hw_t counter[4];
} bus_ctrl_hw_t;
-#define bus_ctrl_hw ((bus_ctrl_hw_t *const)BUSCTRL_BASE)
+#define bus_ctrl_hw ((bus_ctrl_hw_t *)BUSCTRL_BASE)
#endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/clocks.h b/src/rp2040/hardware_structs/include/hardware/structs/clocks.h
index a245dbd..0d27da5 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/clocks.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/clocks.h
@@ -319,7 +319,7 @@
io_ro_32 ints;
} clocks_hw_t;
-#define clocks_hw ((clocks_hw_t *const)CLOCKS_BASE)
+#define clocks_hw ((clocks_hw_t *)CLOCKS_BASE)
static_assert( CLK_COUNT == 10, "");
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/dma.h b/src/rp2040/hardware_structs/include/hardware/structs/dma.h
index 0d20641..4281ddf 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/dma.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/dma.h
@@ -194,8 +194,8 @@
} ch[NUM_DMA_CHANNELS];
} dma_debug_hw_t;
-#define dma_hw ((dma_hw_t *const)DMA_BASE)
-#define dma_debug_hw ((dma_debug_hw_t *const)(DMA_BASE + DMA_CH0_DBG_CTDREQ_OFFSET))
+#define dma_hw ((dma_hw_t *)DMA_BASE)
+#define dma_debug_hw ((dma_debug_hw_t *)(DMA_BASE + DMA_CH0_DBG_CTDREQ_OFFSET))
static_assert( NUM_DMA_TIMERS == 4, "");
static_assert( NUM_DMA_CHANNELS == 12, "");
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/i2c.h b/src/rp2040/hardware_structs/include/hardware/structs/i2c.h
index 43d6086..397ad9a 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/i2c.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/i2c.h
@@ -327,7 +327,7 @@
io_ro_32 comp_type;
} i2c_hw_t;
-#define i2c0_hw ((i2c_hw_t *const)I2C0_BASE)
-#define i2c1_hw ((i2c_hw_t *const)I2C1_BASE)
+#define i2c0_hw ((i2c_hw_t *)I2C0_BASE)
+#define i2c1_hw ((i2c_hw_t *)I2C1_BASE)
#endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/iobank0.h b/src/rp2040/hardware_structs/include/hardware/structs/iobank0.h
index aae74b2..04b3f4d 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/iobank0.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/iobank0.h
@@ -208,7 +208,7 @@
io_irq_ctrl_hw_t dormant_wake_irq_ctrl;
} iobank0_hw_t;
-#define iobank0_hw ((iobank0_hw_t *const)IO_BANK0_BASE)
+#define iobank0_hw ((iobank0_hw_t *)IO_BANK0_BASE)
/// \end::iobank0_hw[]
static_assert( NUM_BANK0_GPIOS == 30, "");
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/ioqspi.h b/src/rp2040/hardware_structs/include/hardware/structs/ioqspi.h
index 2992bfe..70ba09e 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/ioqspi.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/ioqspi.h
@@ -167,7 +167,7 @@
io_qspi_ctrl_hw_t dormant_wake_qspi_ctrl;
} ioqspi_hw_t;
-#define ioqspi_hw ((ioqspi_hw_t *const)IO_QSPI_BASE)
+#define ioqspi_hw ((ioqspi_hw_t *)IO_QSPI_BASE)
static_assert( NUM_QSPI_GPIOS == 6, "");
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/mpu.h b/src/rp2040/hardware_structs/include/hardware/structs/mpu.h
index e647220..09fb644 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/mpu.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/mpu.h
@@ -56,6 +56,6 @@
io_rw_32 rasr;
} mpu_hw_t;
-#define mpu_hw ((mpu_hw_t *const)(PPB_BASE + M0PLUS_MPU_TYPE_OFFSET))
+#define mpu_hw ((mpu_hw_t *)(PPB_BASE + M0PLUS_MPU_TYPE_OFFSET))
#endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/pads_qspi.h b/src/rp2040/hardware_structs/include/hardware/structs/pads_qspi.h
index 8036cd9..5c9d90f 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/pads_qspi.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/pads_qspi.h
@@ -40,7 +40,7 @@
io_rw_32 io[NUM_QSPI_GPIOS]; // 6
} pads_qspi_hw_t;
-#define pads_qspi_hw ((pads_qspi_hw_t *const)PADS_QSPI_BASE)
+#define pads_qspi_hw ((pads_qspi_hw_t *)PADS_QSPI_BASE)
static_assert( NUM_QSPI_GPIOS == 6, "");
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/padsbank0.h b/src/rp2040/hardware_structs/include/hardware/structs/padsbank0.h
index 2c067fa..fbb6052 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/padsbank0.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/padsbank0.h
@@ -40,7 +40,7 @@
io_rw_32 io[NUM_BANK0_GPIOS]; // 30
} padsbank0_hw_t;
-#define padsbank0_hw ((padsbank0_hw_t *const)PADS_BANK0_BASE)
+#define padsbank0_hw ((padsbank0_hw_t *)PADS_BANK0_BASE)
static_assert( NUM_BANK0_GPIOS == 30, "");
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/pio.h b/src/rp2040/hardware_structs/include/hardware/structs/pio.h
index 515e4d1..6a3126a 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/pio.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/pio.h
@@ -275,8 +275,8 @@
io_ro_32 ints1;
} pio_hw_t;
-#define pio0_hw ((pio_hw_t *const)PIO0_BASE)
-#define pio1_hw ((pio_hw_t *const)PIO1_BASE)
+#define pio0_hw ((pio_hw_t *)PIO0_BASE)
+#define pio1_hw ((pio_hw_t *)PIO1_BASE)
static_assert( NUM_PIO_STATE_MACHINES == 4, "");
static_assert( PIO_INSTRUCTION_COUNT == 32, "");
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/pll.h b/src/rp2040/hardware_structs/include/hardware/structs/pll.h
index 5a506e3..5633ad9 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/pll.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/pll.h
@@ -49,8 +49,8 @@
io_rw_32 prim;
} pll_hw_t;
-#define pll_sys_hw ((pll_hw_t *const)PLL_SYS_BASE)
-#define pll_usb_hw ((pll_hw_t *const)PLL_USB_BASE)
+#define pll_sys_hw ((pll_hw_t *)PLL_SYS_BASE)
+#define pll_usb_hw ((pll_hw_t *)PLL_USB_BASE)
/// \end::pll_hw[]
#endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/psm.h b/src/rp2040/hardware_structs/include/hardware/structs/psm.h
index cdfb2e3..3b9e65e 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/psm.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/psm.h
@@ -106,6 +106,6 @@
io_ro_32 done;
} psm_hw_t;
-#define psm_hw ((psm_hw_t *const)PSM_BASE)
+#define psm_hw ((psm_hw_t *)PSM_BASE)
#endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/pwm.h b/src/rp2040/hardware_structs/include/hardware/structs/pwm.h
index fd9a75c..f62c6d7 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/pwm.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/pwm.h
@@ -119,7 +119,7 @@
io_ro_32 ints;
} pwm_hw_t;
-#define pwm_hw ((pwm_hw_t *const)PWM_BASE)
+#define pwm_hw ((pwm_hw_t *)PWM_BASE)
static_assert( NUM_PWM_SLICES == 8, "");
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/resets.h b/src/rp2040/hardware_structs/include/hardware/structs/resets.h
index bc1c10c..c27337c 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/resets.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/resets.h
@@ -110,7 +110,7 @@
io_ro_32 reset_done;
} resets_hw_t;
-#define resets_hw ((resets_hw_t *const)RESETS_BASE)
+#define resets_hw ((resets_hw_t *)RESETS_BASE)
/// \end::resets_hw[]
#endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/rosc.h b/src/rp2040/hardware_structs/include/hardware/structs/rosc.h
index 114c602..86fa042 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/rosc.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/rosc.h
@@ -81,6 +81,6 @@
io_rw_32 count;
} rosc_hw_t;
-#define rosc_hw ((rosc_hw_t *const)ROSC_BASE)
+#define rosc_hw ((rosc_hw_t *)ROSC_BASE)
#endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/rtc.h b/src/rp2040/hardware_structs/include/hardware/structs/rtc.h
index 794a0e0..ccdb326 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/rtc.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/rtc.h
@@ -109,6 +109,6 @@
io_ro_32 ints;
} rtc_hw_t;
-#define rtc_hw ((rtc_hw_t *const)RTC_BASE)
+#define rtc_hw ((rtc_hw_t *)RTC_BASE)
#endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/scb.h b/src/rp2040/hardware_structs/include/hardware/structs/scb.h
index 42569c7..3214414 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/scb.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/scb.h
@@ -64,6 +64,6 @@
io_rw_32 scr;
} armv6m_scb_t;
-#define scb_hw ((armv6m_scb_t *const)(PPB_BASE + M0PLUS_CPUID_OFFSET))
+#define scb_hw ((armv6m_scb_t *)(PPB_BASE + M0PLUS_CPUID_OFFSET))
#endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/sio.h b/src/rp2040/hardware_structs/include/hardware/structs/sio.h
index 00b7e7e..251dd30 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/sio.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/sio.h
@@ -171,6 +171,6 @@
interp_hw_t interp[2];
} sio_hw_t;
-#define sio_hw ((sio_hw_t *const)SIO_BASE)
+#define sio_hw ((sio_hw_t *)SIO_BASE)
#endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/spi.h b/src/rp2040/hardware_structs/include/hardware/structs/spi.h
index f7fffb8..08243c0 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/spi.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/spi.h
@@ -94,7 +94,7 @@
io_rw_32 dmacr;
} spi_hw_t;
-#define spi0_hw ((spi_hw_t *const)SPI0_BASE)
-#define spi1_hw ((spi_hw_t *const)SPI1_BASE)
+#define spi0_hw ((spi_hw_t *)SPI0_BASE)
+#define spi1_hw ((spi_hw_t *)SPI1_BASE)
#endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/ssi.h b/src/rp2040/hardware_structs/include/hardware/structs/ssi.h
index 0ab18be..639bd64 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/ssi.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/ssi.h
@@ -205,6 +205,6 @@
io_rw_32 txd_drive_edge;
} ssi_hw_t;
-#define ssi_hw ((ssi_hw_t *const)XIP_SSI_BASE)
+#define ssi_hw ((ssi_hw_t *)XIP_SSI_BASE)
#endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/syscfg.h b/src/rp2040/hardware_structs/include/hardware/structs/syscfg.h
index 52218fb..e890521 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/syscfg.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/syscfg.h
@@ -72,6 +72,6 @@
io_rw_32 mempowerdown;
} syscfg_hw_t;
-#define syscfg_hw ((syscfg_hw_t *const)SYSCFG_BASE)
+#define syscfg_hw ((syscfg_hw_t *)SYSCFG_BASE)
#endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/systick.h b/src/rp2040/hardware_structs/include/hardware/structs/systick.h
index a859fea..b57a740 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/systick.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/systick.h
@@ -47,6 +47,6 @@
io_ro_32 calib;
} systick_hw_t;
-#define systick_hw ((systick_hw_t *const)(PPB_BASE + M0PLUS_SYST_CSR_OFFSET))
+#define systick_hw ((systick_hw_t *)(PPB_BASE + M0PLUS_SYST_CSR_OFFSET))
#endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/timer.h b/src/rp2040/hardware_structs/include/hardware/structs/timer.h
index c7c7066..7622f13 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/timer.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/timer.h
@@ -100,7 +100,7 @@
io_ro_32 ints;
} timer_hw_t;
-#define timer_hw ((timer_hw_t *const)TIMER_BASE)
+#define timer_hw ((timer_hw_t *)TIMER_BASE)
static_assert( NUM_TIMERS == 4, "");
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/uart.h b/src/rp2040/hardware_structs/include/hardware/structs/uart.h
index 09af33e..4912824 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/uart.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/uart.h
@@ -171,7 +171,7 @@
io_rw_32 dmacr;
} uart_hw_t;
-#define uart0_hw ((uart_hw_t *const)UART0_BASE)
-#define uart1_hw ((uart_hw_t *const)UART1_BASE)
+#define uart0_hw ((uart_hw_t *)UART0_BASE)
+#define uart1_hw ((uart_hw_t *)UART1_BASE)
#endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/usb.h b/src/rp2040/hardware_structs/include/hardware/structs/usb.h
index c9455d0..d5d74df 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/usb.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/usb.h
@@ -568,7 +568,7 @@
io_ro_32 ints;
} usb_hw_t;
-#define usb_hw ((usb_hw_t *const)USBCTRL_REGS_BASE)
+#define usb_hw ((usb_hw_t *)USBCTRL_REGS_BASE)
#define usb_dpram ((usb_device_dpram_t *)USBCTRL_DPRAM_BASE)
#define usbh_dpram ((usb_host_dpram_t *)USBCTRL_DPRAM_BASE)
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/vreg_and_chip_reset.h b/src/rp2040/hardware_structs/include/hardware/structs/vreg_and_chip_reset.h
index 554d9e4..edfc498 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/vreg_and_chip_reset.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/vreg_and_chip_reset.h
@@ -44,6 +44,6 @@
io_rw_32 chip_reset;
} vreg_and_chip_reset_hw_t;
-#define vreg_and_chip_reset_hw ((vreg_and_chip_reset_hw_t *const)VREG_AND_CHIP_RESET_BASE)
+#define vreg_and_chip_reset_hw ((vreg_and_chip_reset_hw_t *)VREG_AND_CHIP_RESET_BASE)
#endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/watchdog.h b/src/rp2040/hardware_structs/include/hardware/structs/watchdog.h
index 9579700..5071cf5 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/watchdog.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/watchdog.h
@@ -57,6 +57,6 @@
io_rw_32 tick;
} watchdog_hw_t;
-#define watchdog_hw ((watchdog_hw_t *const)WATCHDOG_BASE)
+#define watchdog_hw ((watchdog_hw_t *)WATCHDOG_BASE)
#endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/xip_ctrl.h b/src/rp2040/hardware_structs/include/hardware/structs/xip_ctrl.h
index 21885e8..84e92b4 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/xip_ctrl.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/xip_ctrl.h
@@ -63,7 +63,7 @@
io_ro_32 stream_fifo;
} xip_ctrl_hw_t;
-#define xip_ctrl_hw ((xip_ctrl_hw_t *const)XIP_CTRL_BASE)
+#define xip_ctrl_hw ((xip_ctrl_hw_t *)XIP_CTRL_BASE)
#define XIP_STAT_FIFO_FULL XIP_STAT_FIFO_FULL_BITS
#define XIP_STAT_FIFO_EMPTY XIP_STAT_FIFO_EMPTY_BITS
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/xosc.h b/src/rp2040/hardware_structs/include/hardware/structs/xosc.h
index 0ff4db4..d327aa9 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/xosc.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/xosc.h
@@ -54,7 +54,7 @@
io_rw_32 count;
} xosc_hw_t;
-#define xosc_hw ((xosc_hw_t *const)XOSC_BASE)
+#define xosc_hw ((xosc_hw_t *)XOSC_BASE)
/// \end::xosc_hw[]
#endif
diff --git a/src/rp2_common/CMakeLists.txt b/src/rp2_common/CMakeLists.txt
index 4ca55be..0d0f9b9 100644
--- a/src/rp2_common/CMakeLists.txt
+++ b/src/rp2_common/CMakeLists.txt
@@ -58,6 +58,10 @@
pico_add_subdirectory(tinyusb)
pico_add_subdirectory(pico_stdio_usb)
+ pico_add_subdirectory(cyw43_driver)
+ pico_add_subdirectory(pico_lwip)
+ pico_add_subdirectory(pico_cyw43_arch)
+
pico_add_subdirectory(pico_stdlib)
pico_add_subdirectory(pico_cxx_options)
diff --git a/src/rp2_common/boot_stage2/pad_checksum b/src/rp2_common/boot_stage2/pad_checksum
index 356227d..d301756 100755
--- a/src/rp2_common/boot_stage2/pad_checksum
+++ b/src/rp2_common/boot_stage2/pad_checksum
@@ -31,7 +31,7 @@
except:
sys.exit("Could not open input file '{}'".format(args.ifile))
-if len(idata) >= args.pad - 4:
+if len(idata) > args.pad - 4:
sys.exit("Input file size ({} bytes) too large for final size ({} bytes)".format(len(idata), args.pad))
idata_padded = idata + bytes(args.pad - 4 - len(idata))
diff --git a/src/rp2_common/cyw43_driver/CMakeLists.txt b/src/rp2_common/cyw43_driver/CMakeLists.txt
new file mode 100644
index 0000000..8951df4
--- /dev/null
+++ b/src/rp2_common/cyw43_driver/CMakeLists.txt
@@ -0,0 +1,81 @@
+if (DEFINED ENV{PICO_CYW43_DRIVER_PATH} AND (NOT PICO_CYW43_DRIVER_PATH))
+ set(PICO_CYW43_DRIVER_PATH $ENV{PICO_CYW43_DRIVER_PATH})
+ message("Using PICO_CYW43_DRIVER_PATH from environment ('${PICO_CYW43_DRIVER_PATH}')")
+endif()
+
+set(CYW43_DRIVER_TEST_FILE "src/cyw43.h")
+
+if (NOT PICO_CYW43_DRIVER_PATH)
+ set(PICO_CYW43_DRIVER_PATH ${PICO_SDK_PATH}/lib/cyw43-driver)
+ if (PICO_CYW43_SUPPORTED AND NOT EXISTS ${PICO_CYW43_DRIVER_PATH}/${CYW43_DRIVER_TEST_FILE})
+ message(WARNING "cyw43-driver submodule has not been initialized; Pico W wireless support will be unavailable
+hint: try 'git submodule update --init' from your SDK directory (${PICO_SDK_PATH}).")
+ endif()
+elseif (NOT EXISTS ${PICO_CYW43_DRIVER_PATH}/${CYW43_DRIVER_TEST_FILE})
+ message(WARNING "PICO_CYW43_DRIVER_PATH specified but content not present.")
+endif()
+
+if (EXISTS ${PICO_CYW43_DRIVER_PATH}/${CYW43_DRIVER_TEST_FILE})
+ message("cyw43-driver available at ${PICO_CYW43_DRIVER_PATH}")
+
+ pico_register_common_scope_var(PICO_CYW43_DRIVER_PATH)
+
+ # base driver without our bus
+ add_library(cyw43_driver_base INTERFACE)
+ target_sources(cyw43_driver_base INTERFACE
+ ${PICO_CYW43_DRIVER_PATH}/src/cyw43_ll.c
+ ${PICO_CYW43_DRIVER_PATH}/src/cyw43_stats.c
+ ${PICO_CYW43_DRIVER_PATH}/src/cyw43_lwip.c
+ ${PICO_CYW43_DRIVER_PATH}/src/cyw43_ctrl.c
+ )
+ target_include_directories(cyw43_driver_base INTERFACE
+ ${PICO_CYW43_DRIVER_PATH}/src
+ ${PICO_CYW43_DRIVER_PATH}/firmware
+ )
+
+ # Build the driver for cyw43 for pico w
+
+ # Firmware stuff
+ set(CYW43_FIRMWARE_BIN 43439A0-7.95.49.00.combined)
+ string(REGEX REPLACE [\\\.\-] _ CYW43_FIRMWARE_BIN_ ${CYW43_FIRMWARE_BIN})
+ string(REGEX MATCH [^_]+_?[^_]*_?[^_]*_?[^_]*_?[^_]* CYW43_FIRMWARE_PRETTY ${CYW43_FIRMWARE_BIN_})
+ set(CYW43_FIRMWARE_PRETTY fw_${CYW43_FIRMWARE_PRETTY})
+ set(RESOURCE_SECNAME .big_const)
+ set(RESOURCE_SECFLAGS contents,alloc,load,readonly,data)
+ set(CYW43_FIRMWARE_OBJ ${CMAKE_CURRENT_BINARY_DIR}/cyw43_resource.o)
+
+ add_custom_target(cyw43_firmware_package DEPENDS ${CYW43_FIRMWARE_OBJ})
+
+ # cyw43_resource.o contains the WiFi and BT firmware as a binary blob
+ add_custom_command(
+ OUTPUT ${CYW43_FIRMWARE_OBJ}
+ DEPENDS ${PICO_CYW43_DRIVER_PATH}/firmware/${CYW43_FIRMWARE_BIN}
+ WORKING_DIRECTORY ${PICO_CYW43_DRIVER_PATH}/firmware
+ COMMAND ${CMAKE_OBJCOPY} -I binary -O elf32-littlearm -B arm
+ --readonly-text
+ --rename-section .data=${RESOURCE_SECNAME},${RESOURCE_SECFLAGS}
+ --redefine-sym _binary_${CYW43_FIRMWARE_BIN_}_start=${CYW43_FIRMWARE_PRETTY}_start
+ --redefine-sym _binary_${CYW43_FIRMWARE_BIN_}_end=${CYW43_FIRMWARE_PRETTY}_end
+ --redefine-sym _binary_${CYW43_FIRMWARE_BIN_}_size=${CYW43_FIRMWARE_PRETTY}_size
+ ${CYW43_FIRMWARE_BIN} ${CYW43_FIRMWARE_OBJ}
+ )
+
+ add_library(cyw43_driver_picow INTERFACE)
+ target_sources(cyw43_driver_picow INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/cyw43_bus_pio_spi.c
+ )
+ pico_generate_pio_header(cyw43_driver_picow ${CMAKE_CURRENT_LIST_DIR}/cyw43_bus_pio_spi.pio)
+ add_dependencies(cyw43_driver_picow INTERFACE cyw43_firmware_package)
+ target_link_libraries(cyw43_driver_picow INTERFACE
+ ${CYW43_FIRMWARE_OBJ}
+ )
+ target_link_libraries(cyw43_driver_picow INTERFACE
+ cyw43_driver_base
+ pico_stdlib
+ hardware_pio
+ hardware_dma
+ hardware_exception
+ )
+
+ pico_promote_common_scope_vars()
+endif()
diff --git a/src/rp2_common/cyw43_driver/cyw43_bus_pio_spi.c b/src/rp2_common/cyw43_driver/cyw43_bus_pio_spi.c
new file mode 100644
index 0000000..0fd17f4
--- /dev/null
+++ b/src/rp2_common/cyw43_driver/cyw43_bus_pio_spi.c
@@ -0,0 +1,545 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "pico/stdlib.h"
+#include "hardware/gpio.h"
+#include "hardware/pio.h"
+#include "hardware/clocks.h"
+#include "hardware/structs/iobank0.h"
+#include "hardware/sync.h"
+#include "hardware/dma.h"
+#include "cyw43_bus_pio_spi.pio.h"
+#include "cyw43.h"
+#include "cyw43_internal.h"
+#include "cyw43_spi.h"
+#include "cyw43_debug_pins.h"
+
+#if CYW43_SPI_PIO
+#define WL_REG_ON 23
+#define DATA_OUT_PIN 24u
+#define DATA_IN_PIN 24u
+#define IRQ_PIN 24u
+// #define MONITOR_PIN 3u
+#define CLOCK_PIN 29u
+#define CS_PIN 25u
+#define IRQ_SAMPLE_DELAY_NS 100
+
+#define SPI_PROGRAM_NAME spi_gap01_sample0
+#define SPI_PROGRAM_FUNC __CONCAT(SPI_PROGRAM_NAME, _program)
+#define SPI_PROGRAM_GET_DEFAULT_CONFIG_FUNC __CONCAT(SPI_PROGRAM_NAME, _program_get_default_config)
+#define SPI_OFFSET_END __CONCAT(SPI_PROGRAM_NAME, _offset_end)
+#define SPI_OFFSET_LP1_END __CONCAT(SPI_PROGRAM_NAME, _offset_lp1_end)
+
+#define CLOCK_DIV 2
+#define CLOCK_DIV_MINOR 0
+#define PADS_DRIVE_STRENGTH PADS_BANK0_GPIO0_DRIVE_VALUE_12MA
+
+#if !CYW43_USE_SPI
+#error CYW43_USE_SPI should be true
+#endif
+
+#ifndef NDEBUG
+//#define ENABLE_SPI_DUMPING 1
+#endif
+
+// Set to 1 to enable
+#if ENABLE_SPI_DUMPING //NDEBUG
+#if 0
+#define DUMP_SPI_TRANSACTIONS(A) A
+#else
+static bool enable_spi_packet_dumping; // set to true to dump
+#define DUMP_SPI_TRANSACTIONS(A) if (enable_spi_packet_dumping) {A}
+#endif
+
+static uint32_t counter = 0;
+#else
+#define DUMP_SPI_TRANSACTIONS(A)
+#endif
+
+//#define SWAP32(A) ((((A) & 0xff000000U) >> 8) | (((A) & 0xff0000U) << 8) | (((A) & 0xff00U) >> 8) | (((A) & 0xffU) << 8))
+__force_inline static uint32_t __swap16x2(uint32_t a) {
+ __asm ("rev16 %0, %0" : "+l" (a) : : );
+ return a;
+}
+#define SWAP32(a) __swap16x2(a)
+
+#ifndef CYW43_SPI_PIO_PREFERRED_PIO
+#define CYW43_SPI_PIO_PREFERRED_PIO 1
+#endif
+static_assert(CYW43_SPI_PIO_PREFERRED_PIO >=0 && CYW43_SPI_PIO_PREFERRED_PIO < NUM_PIOS, "");
+
+typedef struct {
+ pio_hw_t *pio;
+ uint8_t pio_func_sel;
+ int8_t pio_offset;
+ int8_t pio_sm;
+ int8_t dma_out;
+ int8_t dma_in;
+} bus_data_t;
+
+static bus_data_t bus_data_instance;
+
+int cyw43_spi_init(cyw43_int_t *self) {
+ // Only does something if CYW43_LOGIC_DEBUG=1
+ logic_debug_init();
+
+ static_assert(NUM_PIOS == 2, "");
+
+ pio_hw_t *pios[2] = {pio0, pio1};
+ uint pio_index = CYW43_SPI_PIO_PREFERRED_PIO;
+ // Check we can add the program
+ if (!pio_can_add_program(pios[pio_index], &SPI_PROGRAM_FUNC)) {
+ pio_index ^= 1;
+ if (!pio_can_add_program(pios[pio_index], &SPI_PROGRAM_FUNC)) {
+ return CYW43_FAIL_FAST_CHECK(-CYW43_EIO);
+ }
+ }
+ assert(!self->bus_data);
+ self->bus_data = &bus_data_instance;
+ bus_data_t *bus_data = (bus_data_t *)self->bus_data;
+ bus_data->pio = pios[pio_index];
+ bus_data->dma_in = -1;
+ bus_data->dma_out = -1;
+
+ static_assert(GPIO_FUNC_PIO1 == GPIO_FUNC_PIO0 + 1, "");
+ bus_data->pio_func_sel = GPIO_FUNC_PIO0 + pio_index;
+ bus_data->pio_sm = (int8_t)pio_claim_unused_sm(bus_data->pio, false);
+ if (bus_data->pio_sm < 0) {
+ cyw43_spi_deinit(self);
+ return CYW43_FAIL_FAST_CHECK(-CYW43_EIO);
+ }
+
+ bus_data->pio_offset = pio_add_program(bus_data->pio, &SPI_PROGRAM_FUNC);
+ pio_sm_config config = SPI_PROGRAM_GET_DEFAULT_CONFIG_FUNC(bus_data->pio_offset);
+
+ sm_config_set_clkdiv_int_frac(&config, CLOCK_DIV, CLOCK_DIV_MINOR);
+ hw_write_masked(&padsbank0_hw->io[CLOCK_PIN],
+ (uint)PADS_DRIVE_STRENGTH << PADS_BANK0_GPIO0_DRIVE_LSB,
+ PADS_BANK0_GPIO0_DRIVE_BITS
+ );
+ hw_write_masked(&padsbank0_hw->io[CLOCK_PIN],
+ (uint)1 << PADS_BANK0_GPIO0_SLEWFAST_LSB,
+ PADS_BANK0_GPIO0_SLEWFAST_BITS
+ );
+
+ sm_config_set_out_pins(&config, DATA_OUT_PIN, 1);
+ sm_config_set_in_pins(&config, DATA_IN_PIN);
+ sm_config_set_set_pins(&config, DATA_OUT_PIN, 1);
+ sm_config_set_sideset(&config, 1, false, false);
+ sm_config_set_sideset_pins(&config, CLOCK_PIN);
+ sm_config_set_in_shift(&config, false, true, 32);
+ sm_config_set_out_shift(&config, false, true, 32);
+ hw_set_bits(&bus_data->pio->input_sync_bypass, 1u << DATA_IN_PIN);
+ pio_sm_set_config(bus_data->pio, bus_data->pio_sm, &config);
+ pio_sm_set_consecutive_pindirs(bus_data->pio, bus_data->pio_sm, CLOCK_PIN, 1, true);
+ gpio_set_function(DATA_OUT_PIN, bus_data->pio_func_sel);
+ gpio_set_function(CLOCK_PIN, bus_data->pio_func_sel);
+
+ // Set data pin to pull down and schmitt
+ gpio_set_pulls(DATA_IN_PIN, false, true);
+ gpio_set_input_hysteresis_enabled(DATA_IN_PIN, true);
+
+ pio_sm_exec(bus_data->pio, bus_data->pio_sm, pio_encode_set(pio_pins, 1));
+
+ bus_data->dma_out = (int8_t) dma_claim_unused_channel(false);
+ bus_data->dma_in = (int8_t) dma_claim_unused_channel(false);
+ if (bus_data->dma_out < 0 || bus_data->dma_in < 0) {
+ cyw43_spi_deinit(self);
+ return CYW43_FAIL_FAST_CHECK(-CYW43_EIO);
+ }
+ return 0;
+}
+
+void cyw43_spi_deinit(cyw43_int_t *self) {
+ if (self->bus_data) {
+ bus_data_t *bus_data = (bus_data_t *)self->bus_data;
+ if (bus_data->pio_sm >= 0) {
+ if (bus_data->pio_offset != -1)
+ pio_remove_program(bus_data->pio, &SPI_PROGRAM_FUNC, bus_data->pio_offset);
+ pio_sm_unclaim(bus_data->pio, bus_data->pio_sm);
+ }
+ if (bus_data->dma_out >= 0) {
+ dma_channel_unclaim(bus_data->dma_out);
+ bus_data->dma_out = -1;
+ }
+ if (bus_data->dma_in >= 0) {
+ dma_channel_unclaim(bus_data->dma_in);
+ bus_data->dma_in = -1;
+ }
+ self->bus_data = NULL;
+ }
+}
+
+static void cs_set(bool value) {
+ gpio_put(CS_PIN, value);
+}
+
+static __noinline void ns_delay(uint32_t ns) {
+ // cycles = ns * clk_sys_hz / 1,000,000,000
+ uint32_t cycles = ns * (clock_get_hz(clk_sys) >> 16u) / (1000000000u >> 16u);
+ busy_wait_at_least_cycles(cycles);
+}
+
+static void start_spi_comms(cyw43_int_t *self) {
+ bus_data_t *bus_data = (bus_data_t *)self->bus_data;
+ // Pull CS low
+ cs_set(false);
+ gpio_set_function(DATA_OUT_PIN, bus_data->pio_func_sel);
+}
+
+// we need to atomically de-assert CS and enable IRQ
+static void stop_spi_comms(void) {
+ // from this point a positive edge will cause an IRQ to be pending
+ cs_set(true);
+
+ // we need to wait a bit in case the irq line is incorrectly high
+ ns_delay(IRQ_SAMPLE_DELAY_NS);
+}
+
+#if ENABLE_SPI_DUMPING
+static void dump_bytes(const uint8_t *bptr, uint32_t len) {
+ unsigned int i = 0;
+
+ for (i = 0; i < len;) {
+ if ((i & 0x0f) == 0) {
+ printf("\n");
+ } else if ((i & 0x07) == 0) {
+ printf(" ");
+ }
+ printf("%02x ", bptr[i++]);
+ }
+ printf("\n");
+}
+#endif
+
+int cyw43_spi_transfer(cyw43_int_t *self, const uint8_t *tx, size_t tx_length, uint8_t *rx,
+ size_t rx_length) {
+
+ if ((tx == NULL) && (rx == NULL)) {
+ return CYW43_FAIL_FAST_CHECK(-CYW43_EINVAL);
+ }
+
+ bus_data_t *bus_data = (bus_data_t *)self->bus_data;
+ start_spi_comms(self);
+ if (rx != NULL) {
+ if (tx == NULL) {
+ tx = rx;
+ assert(tx_length && tx_length < rx_length);
+ }
+ DUMP_SPI_TRANSACTIONS(
+ printf("[%lu] bus TX/RX %u bytes rx %u:", counter++, tx_length, rx_length);
+ dump_bytes(tx, tx_length);
+ )
+ assert(!(tx_length & 3));
+ assert(!(((uintptr_t)tx) & 3));
+ assert(!(((uintptr_t)rx) & 3));
+ assert(!(rx_length & 3));
+
+ pio_sm_set_enabled(bus_data->pio, bus_data->pio_sm, false);
+ pio_sm_set_wrap(bus_data->pio, bus_data->pio_sm, bus_data->pio_offset, bus_data->pio_offset + SPI_OFFSET_END - 1);
+ pio_sm_clear_fifos(bus_data->pio, bus_data->pio_sm);
+ pio_sm_set_pindirs_with_mask(bus_data->pio, bus_data->pio_sm, 1u << DATA_OUT_PIN, 1u << DATA_OUT_PIN);
+ pio_sm_restart(bus_data->pio, bus_data->pio_sm);
+ pio_sm_clkdiv_restart(bus_data->pio, bus_data->pio_sm);
+ pio_sm_put(bus_data->pio, bus_data->pio_sm, tx_length * 8 - 1);
+ pio_sm_exec(bus_data->pio, bus_data->pio_sm, pio_encode_out(pio_x, 32));
+ pio_sm_put(bus_data->pio, bus_data->pio_sm, (rx_length - tx_length) * 8 - 1);
+ pio_sm_exec(bus_data->pio, bus_data->pio_sm, pio_encode_out(pio_y, 32));
+ pio_sm_exec(bus_data->pio, bus_data->pio_sm, pio_encode_jmp(bus_data->pio_offset));
+ dma_channel_abort(bus_data->dma_out);
+ dma_channel_abort(bus_data->dma_in);
+
+ dma_channel_config out_config = dma_channel_get_default_config(bus_data->dma_out);
+ channel_config_set_bswap(&out_config, true);
+ channel_config_set_dreq(&out_config, pio_get_dreq(bus_data->pio, 0, true));
+
+ dma_channel_configure(bus_data->dma_out, &out_config, &bus_data->pio->txf[0], tx, tx_length / 4, true);
+
+ dma_channel_config in_config = dma_channel_get_default_config(bus_data->dma_in);
+ channel_config_set_bswap(&in_config, true);
+ channel_config_set_dreq(&in_config, pio_get_dreq(bus_data->pio, 0, false));
+ channel_config_set_write_increment(&in_config, true);
+ channel_config_set_read_increment(&in_config, false);
+ dma_channel_configure(bus_data->dma_in, &in_config, rx + tx_length, &bus_data->pio->rxf[0], rx_length / 4 - tx_length / 4, true);
+
+ pio_sm_set_enabled(bus_data->pio, bus_data->pio_sm, true);
+ __compiler_memory_barrier();
+
+ dma_channel_wait_for_finish_blocking(bus_data->dma_out);
+ dma_channel_wait_for_finish_blocking(bus_data->dma_in);
+
+ __compiler_memory_barrier();
+ memset(rx, 0, tx_length); // make sure we don't have garbage in what would have been returned data if using real SPI
+ } else if (tx != NULL) {
+ DUMP_SPI_TRANSACTIONS(
+ printf("[%lu] bus TX only %u bytes:", counter++, tx_length);
+ dump_bytes(tx, tx_length);
+ )
+ assert(!(((uintptr_t)tx) & 3));
+ assert(!(tx_length & 3));
+ pio_sm_set_enabled(bus_data->pio, bus_data->pio_sm, false);
+ pio_sm_set_wrap(bus_data->pio, bus_data->pio_sm, bus_data->pio_offset, bus_data->pio_offset + SPI_OFFSET_LP1_END - 1);
+ pio_sm_clear_fifos(bus_data->pio, bus_data->pio_sm);
+ pio_sm_set_pindirs_with_mask(bus_data->pio, bus_data->pio_sm, 1u << DATA_OUT_PIN, 1u << DATA_OUT_PIN);
+ pio_sm_restart(bus_data->pio, bus_data->pio_sm);
+ pio_sm_clkdiv_restart(bus_data->pio, bus_data->pio_sm);
+ pio_sm_put(bus_data->pio, bus_data->pio_sm, tx_length * 8 - 1);
+ pio_sm_exec(bus_data->pio, bus_data->pio_sm, pio_encode_out(pio_x, 32));
+ pio_sm_put(bus_data->pio, bus_data->pio_sm, 0);
+ pio_sm_exec(bus_data->pio, bus_data->pio_sm, pio_encode_out(pio_y, 32));
+ pio_sm_exec(bus_data->pio, bus_data->pio_sm, pio_encode_jmp(bus_data->pio_offset));
+ dma_channel_abort(bus_data->dma_out);
+
+ dma_channel_config out_config = dma_channel_get_default_config(bus_data->dma_out);
+ channel_config_set_bswap(&out_config, true);
+ channel_config_set_dreq(&out_config, pio_get_dreq(bus_data->pio, 0, true));
+
+ dma_channel_configure(bus_data->dma_out, &out_config, &bus_data->pio->txf[0], tx, tx_length / 4, true);
+
+ bus_data->pio->fdebug = 1u << PIO_FDEBUG_TXSTALL_LSB;
+ pio_sm_set_enabled(bus_data->pio, 0, true);
+ while (!(bus_data->pio->fdebug & (1u << PIO_FDEBUG_TXSTALL_LSB))) {
+ tight_loop_contents(); // todo timeout
+ }
+ __compiler_memory_barrier();
+ pio_sm_set_enabled(bus_data->pio, bus_data->pio_sm, false);
+ pio_sm_set_consecutive_pindirs(bus_data->pio, bus_data->pio_sm, DATA_IN_PIN, 1, false);
+ } else if (rx != NULL) { /* currently do one at a time */
+ DUMP_SPI_TRANSACTIONS(
+ printf("[%lu] bus TX %u bytes:", counter++, rx_length);
+ dump_bytes(rx, rx_length);
+ )
+ panic_unsupported();
+ }
+ pio_sm_exec(bus_data->pio, bus_data->pio_sm, pio_encode_mov(pio_pins, pio_null)); // for next time we turn output on
+
+ stop_spi_comms();
+ DUMP_SPI_TRANSACTIONS(
+ printf("RXed:");
+ dump_bytes(rx, rx_length);
+ printf("\n");
+ )
+
+ return 0;
+}
+
+// Initialise our gpios
+void cyw43_spi_gpio_setup(void) {
+ // Setup WL_REG_ON (23)
+ gpio_init(WL_REG_ON);
+ gpio_set_dir(WL_REG_ON, GPIO_OUT);
+ gpio_pull_up(WL_REG_ON);
+
+ // Setup DO, DI and IRQ (24)
+ gpio_init(DATA_OUT_PIN);
+ gpio_set_dir(DATA_OUT_PIN, GPIO_OUT);
+ gpio_put(DATA_OUT_PIN, false);
+
+ // Setup CS (25)
+ gpio_init(CS_PIN);
+ gpio_set_dir(CS_PIN, GPIO_OUT);
+ gpio_put(CS_PIN, true);
+}
+
+// Reset wifi chip
+void cyw43_spi_reset(void) {
+ gpio_put(WL_REG_ON, false); // off
+ sleep_ms(20);
+ gpio_put(WL_REG_ON, true); // on
+ sleep_ms(250);
+
+ // Setup IRQ (24) - also used for DO, DI
+ gpio_init(IRQ_PIN);
+ gpio_set_dir(IRQ_PIN, GPIO_IN);
+}
+
+static inline uint32_t make_cmd(bool write, bool inc, uint32_t fn, uint32_t addr, uint32_t sz) {
+ return write << 31 | inc << 30 | fn << 28 | (addr & 0x1ffff) << 11 | sz;
+}
+
+#if CYW43_VERBOSE_DEBUG
+static const char *func_name(int fn) {
+ switch (fn)
+ {
+ case BUS_FUNCTION:
+ return "BUS_FUNCTION";
+ case BACKPLANE_FUNCTION:
+ return "BACKPLANE_FUNCTION";
+ case WLAN_FUNCTION:
+ return "WLAN_FUNCTION";
+ default:
+ return "UNKNOWN";
+ }
+}
+#endif
+
+uint32_t read_reg_u32_swap(cyw43_int_t *self, uint32_t fn, uint32_t reg) {
+ uint32_t buf[2] = {0};
+ assert(fn != BACKPLANE_FUNCTION);
+ buf[0] = SWAP32(make_cmd(false, true, fn, reg, 4));
+ int ret = cyw43_spi_transfer(self, NULL, 4, (uint8_t *)buf, 8);
+ if (ret != 0) {
+ return ret;
+ }
+ return SWAP32(buf[1]);
+}
+
+static inline uint32_t _cyw43_read_reg(cyw43_int_t *self, uint32_t fn, uint32_t reg, uint size) {
+ // Padding plus max read size of 32 bits + another 4?
+ static_assert(WHD_BUS_SPI_BACKPLANE_READ_PADD_SIZE % 4 == 0, "");
+ uint32_t buf32[WHD_BUS_SPI_BACKPLANE_READ_PADD_SIZE/4 + 1 + 1];
+ uint8_t *buf = (uint8_t *)buf32;
+ const uint32_t padding = (fn == BACKPLANE_FUNCTION) ? WHD_BUS_SPI_BACKPLANE_READ_PADD_SIZE : 0; // Add response delay
+ buf32[0] = make_cmd(false, true, fn, reg, size + padding);
+
+ if (fn == BACKPLANE_FUNCTION) {
+ logic_debug_set(pin_BACKPLANE_READ, 1);
+ }
+ int ret = cyw43_spi_transfer(self, NULL, 4, buf, 8 + padding);
+ if (fn == BACKPLANE_FUNCTION) {
+ logic_debug_set(pin_BACKPLANE_READ, 0);
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+ uint32_t result = buf32[padding > 0 ? 2 : 1];
+ CYW43_VDEBUG("cyw43_read_reg_u%d %s 0x%lx=0x%lx\n", size * 8, func_name(fn), reg, result);
+ return result;
+}
+
+uint32_t cyw43_read_reg_u32(cyw43_int_t *self, uint32_t fn, uint32_t reg) {
+ return _cyw43_read_reg(self, fn, reg, 4);
+}
+
+int cyw43_read_reg_u16(cyw43_int_t *self, uint32_t fn, uint32_t reg) {
+ return _cyw43_read_reg(self, fn, reg, 2);
+}
+
+int cyw43_read_reg_u8(cyw43_int_t *self, uint32_t fn, uint32_t reg) {
+ return _cyw43_read_reg(self, fn, reg, 1);
+}
+
+// This is only used to switch the word order on boot
+int write_reg_u32_swap(cyw43_int_t *self, uint32_t fn, uint32_t reg, uint32_t val) {
+ uint32_t buf[2];
+ // Boots up in little endian so command needs swapping too
+ buf[0] = SWAP32(make_cmd(true, true, fn, reg, 4));
+ buf[1] = SWAP32(val);
+ int ret = cyw43_spi_transfer(self, (uint8_t *)buf, 8, NULL, 0);
+ CYW43_VDEBUG("write_reg_u32_swap %s 0x%lx=0x%lx\n", func_name(fn), reg, val);
+ return ret;
+}
+
+static inline int _cyw43_write_reg(cyw43_int_t *self, uint32_t fn, uint32_t reg, uint32_t val, uint size) {
+ uint32_t buf[2];
+ buf[0] = make_cmd(true, true, fn, reg, size);
+ buf[1] = val;
+ if (fn == BACKPLANE_FUNCTION) {
+ // In case of f1 overflow
+ self->last_size = 8;
+ self->last_header[0] = buf[0];
+ self->last_header[1] = buf[1];
+ self->last_backplane_window = self->cur_backplane_window;
+ }
+
+ if (fn == BACKPLANE_FUNCTION) {
+ logic_debug_set(pin_BACKPLANE_WRITE, 1);
+ }
+
+ int ret = cyw43_spi_transfer(self, (uint8_t *)buf, 8, NULL, 0);
+
+ if (fn == BACKPLANE_FUNCTION) {
+ logic_debug_set(pin_BACKPLANE_WRITE, 0);
+ }
+
+ CYW43_VDEBUG("cyw43_write_reg_u%d %s 0x%lx=0x%lx\n", size * 8, func_name(fn), reg, val);
+ return ret;
+}
+
+int cyw43_write_reg_u32(cyw43_int_t *self, uint32_t fn, uint32_t reg, uint32_t val) {
+ return _cyw43_write_reg(self, fn, reg, val, 4);
+}
+
+int cyw43_write_reg_u16(cyw43_int_t *self, uint32_t fn, uint32_t reg, uint16_t val) {
+ return _cyw43_write_reg(self, fn, reg, val, 2);
+}
+
+int cyw43_write_reg_u8(cyw43_int_t *self, uint32_t fn, uint32_t reg, uint32_t val) {
+ return _cyw43_write_reg(self, fn, reg, val, 1);
+}
+
+#if MAX_BLOCK_SIZE > 0x7f8
+#error Block size is wrong for SPI
+#endif
+
+// Assumes we're reading into spid_buf
+int cyw43_read_bytes(cyw43_int_t *self, uint32_t fn, uint32_t addr, size_t len, uint8_t *buf) {
+ assert(fn != BACKPLANE_FUNCTION || (len <= 64 && (addr + len) <= 0x8000));
+ const uint32_t padding = (fn == BACKPLANE_FUNCTION) ? 4 : 0; // Add response delay
+ size_t aligned_len = (len + 3) & ~3;
+ assert(aligned_len > 0 && aligned_len <= 0x7f8);
+ self->spi_header[padding > 0 ? 0 : 1] = make_cmd(false, true, fn, addr, len + padding);
+ if (fn == WLAN_FUNCTION) {
+ logic_debug_set(pin_WIFI_RX, 1);
+ }
+ int ret = cyw43_spi_transfer(self, NULL, 4, (uint8_t *)&self->spi_header[padding > 0 ? 0 : 1], aligned_len + 4 + padding);
+ if (fn == WLAN_FUNCTION) {
+ logic_debug_set(pin_WIFI_RX, 0);
+ }
+ if (ret != 0) {
+ printf("cyw43_read_bytes error %d", ret);
+ return ret;
+ }
+ if (buf != self->spid_buf) { // avoid a copy in the usual case just to add the header
+ memcpy(buf, self->spid_buf, len);
+ }
+ return 0;
+}
+
+// See whd_bus_spi_transfer_bytes
+// Note, uses spid_buf if src isn't using it already
+// Apart from firmware download this appears to only be used for wlan functions?
+int cyw43_write_bytes(cyw43_int_t *self, uint32_t fn, uint32_t addr, size_t len, const uint8_t *src) {
+ assert(fn != BACKPLANE_FUNCTION || (len <= 64 && (addr + len) <= 0x8000));
+ size_t aligned_len = (len + 3) & ~3u;
+ assert(aligned_len > 0 && aligned_len <= 0x7f8);
+ if (fn == WLAN_FUNCTION) {
+ // Wait for FIFO to be ready to accept data
+ int f2_ready_attempts = 1000;
+ while (f2_ready_attempts-- > 0) {
+ uint32_t bus_status = cyw43_read_reg_u32(self, BUS_FUNCTION, SPI_STATUS_REGISTER);
+ if (bus_status & STATUS_F2_RX_READY) {
+ logic_debug_set(pin_F2_RX_READY_WAIT, 0);
+ break;
+ } else {
+ logic_debug_set(pin_F2_RX_READY_WAIT, 1);
+ }
+ }
+ if (f2_ready_attempts <= 0) {
+ printf("F2 not ready\n");
+ return CYW43_FAIL_FAST_CHECK(-CYW43_EIO);
+ }
+ }
+ if (src == self->spid_buf) { // avoid a copy in the usual case just to add the header
+ self->spi_header[1] = make_cmd(true, true, fn, addr, len);
+ logic_debug_set(pin_WIFI_TX, 1);
+ int res = cyw43_spi_transfer(self, (uint8_t *)&self->spi_header[1], aligned_len + 4, NULL, 0);
+ logic_debug_set(pin_WIFI_TX, 0);
+ return res;
+ } else {
+ // todo: would be nice to get rid of this. Only used for firmware download?
+ assert(src < self->spid_buf || src >= (self->spid_buf + sizeof(self->spid_buf)));
+ self->spi_header[1] = make_cmd(true, true, fn, addr, len);
+ memcpy(self->spid_buf, src, len);
+ return cyw43_spi_transfer(self, (uint8_t *)&self->spi_header[1], aligned_len + 4, NULL, 0);
+ }
+}
+#endif
diff --git a/src/rp2_common/cyw43_driver/cyw43_bus_pio_spi.pio b/src/rp2_common/cyw43_driver/cyw43_bus_pio_spi.pio
new file mode 100644
index 0000000..ea0d195
--- /dev/null
+++ b/src/rp2_common/cyw43_driver/cyw43_bus_pio_spi.pio
@@ -0,0 +1,61 @@
+;
+; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+;
+; SPDX-License-Identifier: BSD-3-Clause
+;
+
+.program spi_gap0_sample1
+.side_set 1
+
+; always transmit multiple of 32 bytes
+lp: out pins, 1 side 0
+ jmp x-- lp side 1
+public lp1_end:
+ set pindirs, 0 side 0
+lp2:
+ in pins, 1 side 1
+ jmp y-- lp2 side 0
+public end:
+
+.program spi_gap01_sample0
+.side_set 1
+
+; always transmit multiple of 32 bytes
+lp: out pins, 1 side 0
+ jmp x-- lp side 1
+public lp1_end:
+ set pindirs, 0 side 0
+ nop side 1
+lp2:
+ in pins, 1 side 0
+ jmp y-- lp2 side 1
+public end:
+
+.program spi_gap010_sample1
+.side_set 1
+
+; always transmit multiple of 32 bytes
+lp: out pins, 1 side 0
+ jmp x-- lp side 1
+public lp1_end:
+ set pindirs, 0 side 0
+ nop side 1
+ nop side 0
+lp2:
+ in pins, 1 side 1
+ jmp y-- lp2 side 0
+public end:
+
+.program spi_gap0_sample1_regular
+.side_set 1
+
+; always transmit multiple of 32 bytes
+lp: out pins, 1 side 0
+ jmp x-- lp side 1
+public lp1_end:
+ set pindirs, 0 side 0
+lp2:
+ in pins, 1 side 1
+ jmp y-- lp2 side 0
+public end:
+
diff --git a/src/rp2_common/hardware_adc/include/hardware/adc.h b/src/rp2_common/hardware_adc/include/hardware/adc.h
index be82025..b8987ee 100644
--- a/src/rp2_common/hardware_adc/include/hardware/adc.h
+++ b/src/rp2_common/hardware_adc/include/hardware/adc.h
@@ -106,7 +106,7 @@
* \param input_mask A bit pattern indicating which of the 5 inputs are to be sampled. Write a value of 0 to disable round robin sampling.
*/
static inline void adc_set_round_robin(uint input_mask) {
- invalid_params_if(ADC, input_mask & ~ADC_CS_RROBIN_BITS);
+ valid_params_if(ADC, input_mask < (1 << NUM_ADC_CHANNELS));
hw_write_masked(&adc_hw->cs, input_mask << ADC_CS_RROBIN_LSB, ADC_CS_RROBIN_BITS);
}
diff --git a/src/rp2_common/hardware_clocks/clocks.c b/src/rp2_common/hardware_clocks/clocks.c
index f51331a..9ba51f0 100644
--- a/src/rp2_common/hardware_clocks/clocks.c
+++ b/src/rp2_common/hardware_clocks/clocks.c
@@ -148,13 +148,13 @@
/// \tag::pll_settings[]
// Configure PLLs
// REF FBDIV VCO POSTDIV
- // PLL SYS: 12 / 1 = 12MHz * 125 = 1500MHZ / 6 / 2 = 125MHz
- // PLL USB: 12 / 1 = 12MHz * 40 = 480 MHz / 5 / 2 = 48MHz
+ // PLL SYS: 12 / 1 = 12MHz * 125 = 1500MHz / 6 / 2 = 125MHz
+ // PLL USB: 12 / 1 = 12MHz * 100 = 1200MHz / 5 / 5 = 48MHz
/// \end::pll_settings[]
/// \tag::pll_init[]
pll_init(pll_sys, 1, 1500 * MHZ, 6, 2);
- pll_init(pll_usb, 1, 480 * MHZ, 5, 2);
+ pll_init(pll_usb, 1, 1200 * MHZ, 5, 5);
/// \end::pll_init[]
// Configure clocks
diff --git a/src/rp2_common/hardware_clocks/scripts/vcocalc.py b/src/rp2_common/hardware_clocks/scripts/vcocalc.py
index 4d90146..5d143b3 100755
--- a/src/rp2_common/hardware_clocks/scripts/vcocalc.py
+++ b/src/rp2_common/hardware_clocks/scripts/vcocalc.py
@@ -5,7 +5,7 @@
parser = argparse.ArgumentParser(description="PLL parameter calculator")
parser.add_argument("--input", "-i", default=12, help="Input (reference) frequency. Default 12 MHz", type=float)
parser.add_argument("--vco-max", default=1600, help="Override maximum VCO frequency. Default 1600 MHz", type=float)
-parser.add_argument("--vco-min", default=400, help="Override minimum VCO frequency. Default 400 MHz", type=float)
+parser.add_argument("--vco-min", default=750, help="Override minimum VCO frequency. Default 750 MHz", type=float)
parser.add_argument("--low-vco", "-l", action="store_true", help="Use a lower VCO frequency when possible. This reduces power consumption, at the cost of increased jitter")
parser.add_argument("output", help="Output frequency in MHz.", type=float)
args = parser.parse_args()
diff --git a/src/rp2_common/hardware_dma/dma.c b/src/rp2_common/hardware_dma/dma.c
index 90fde06..f142b53 100644
--- a/src/rp2_common/hardware_dma/dma.c
+++ b/src/rp2_common/hardware_dma/dma.c
@@ -36,6 +36,12 @@
hw_claim_clear((uint8_t *) &_claimed, channel);
}
+void dma_unclaim_mask(uint32_t mask) {
+ for(uint i = 0; mask; i++, mask >>= 1u) {
+ if (mask & 1u) dma_channel_unclaim(i);
+ }
+}
+
int dma_claim_unused_channel(bool required) {
return hw_claim_unused_from_range((uint8_t*)&_claimed, required, 0, NUM_DMA_CHANNELS-1, "No DMA channels are available");
}
diff --git a/src/rp2_common/hardware_dma/include/hardware/dma.h b/src/rp2_common/hardware_dma/include/hardware/dma.h
index 7c9406f..ec73564 100644
--- a/src/rp2_common/hardware_dma/include/hardware/dma.h
+++ b/src/rp2_common/hardware_dma/include/hardware/dma.h
@@ -88,12 +88,17 @@
/*! \brief Mark a dma channel as no longer used
* \ingroup hardware_dma
*
- * Method for cooperative claiming of hardware.
- *
* \param channel the dma channel to release
*/
void dma_channel_unclaim(uint channel);
+/*! \brief Mark multiple dma channels as no longer used
+ * \ingroup hardware_dma
+ *
+ * \param channel_mask Bitfield of all channels to unclaim (bit 0 == channel 0, bit 1 == channel 1 etc)
+ */
+void dma_unclaim_mask(uint32_t channel_mask);
+
/*! \brief Claim a free dma channel
* \ingroup hardware_dma
*
@@ -118,7 +123,6 @@
*
* A DMA channel needs to be configured, these functions provide handy helpers to set up configuration
* structures. See \ref dma_channel_config
- *
*/
/*! \brief Enumeration of available DMA channel transfer sizes.
@@ -136,10 +140,10 @@
uint32_t ctrl;
} dma_channel_config;
-/*! \brief Set DMA channel read increment
+/*! \brief Set DMA channel read increment in a channel configuration object
* \ingroup channel_config
*
- * \param c Pointer to channel configuration data
+ * \param c Pointer to channel configuration object
* \param incr True to enable read address increments, if false, each read will be from the same address
* Usually disabled for peripheral to memory transfers
*/
@@ -147,10 +151,10 @@
c->ctrl = incr ? (c->ctrl | DMA_CH0_CTRL_TRIG_INCR_READ_BITS) : (c->ctrl & ~DMA_CH0_CTRL_TRIG_INCR_READ_BITS);
}
-/*! \brief Set DMA channel write increment
+/*! \brief Set DMA channel write increment in a channel configuration object
* \ingroup channel_config
*
- * \param c Pointer to channel configuration data
+ * \param c Pointer to channel configuration object
* \param incr True to enable write address increments, if false, each write will be to the same address
* Usually disabled for memory to peripheral transfers
* Usually disabled for memory to peripheral transfers
@@ -159,7 +163,7 @@
c->ctrl = incr ? (c->ctrl | DMA_CH0_CTRL_TRIG_INCR_WRITE_BITS) : (c->ctrl & ~DMA_CH0_CTRL_TRIG_INCR_WRITE_BITS);
}
-/*! \brief Select a transfer request signal
+/*! \brief Select a transfer request signal in a channel configuration object
* \ingroup channel_config
*
* The channel uses the transfer request signal to pace its data transfer rate.
@@ -179,13 +183,13 @@
c->ctrl = (c->ctrl & ~DMA_CH0_CTRL_TRIG_TREQ_SEL_BITS) | (dreq << DMA_CH0_CTRL_TRIG_TREQ_SEL_LSB);
}
-/*! \brief Set DMA channel completion channel
+/*! \brief Set DMA channel chain_to channel in a channel configuration object
* \ingroup channel_config
*
* When this channel completes, it will trigger the channel indicated by chain_to. Disable by
* setting chain_to to itself (the same channel)
*
- * \param c Pointer to channel configuration data
+ * \param c Pointer to channel configuration object
* \param chain_to Channel to trigger when this channel completes.
*/
static inline void channel_config_set_chain_to(dma_channel_config *c, uint chain_to) {
@@ -193,13 +197,13 @@
c->ctrl = (c->ctrl & ~DMA_CH0_CTRL_TRIG_CHAIN_TO_BITS) | (chain_to << DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB);
}
-/*! \brief Set the size of each DMA bus transfer
+/*! \brief Set the size of each DMA bus transfer in a channel configuration object
* \ingroup channel_config
*
* Set the size of each bus transfer (byte/halfword/word). The read and write addresses
* advance by the specific amount (1/2/4 bytes) with each transfer.
*
- * \param c Pointer to channel configuration data
+ * \param c Pointer to channel configuration object
* \param size See enum for possible values.
*/
static inline void channel_config_set_transfer_data_size(dma_channel_config *c, enum dma_channel_transfer_size size) {
@@ -207,7 +211,7 @@
c->ctrl = (c->ctrl & ~DMA_CH0_CTRL_TRIG_DATA_SIZE_BITS) | (((uint)size) << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB);
}
-/*! \brief Set address wrapping parameters
+/*! \brief Set address wrapping parameters in a channel configuration object
* \ingroup channel_config
*
* Size of address wrap region. If 0, don’t wrap. For values n > 0, only the lower n bits of the address
@@ -217,7 +221,7 @@
*
* 0x0 -> No wrapping.
*
- * \param c Pointer to channel configuration data
+ * \param c Pointer to channel configuration object
* \param write True to apply to write addresses, false to apply to read addresses
* \param size_bits 0 to disable wrapping. Otherwise the size in bits of the changing part of the address.
* Effectively wraps the address on a (1 << size_bits) byte boundary.
@@ -229,27 +233,27 @@
(write ? DMA_CH0_CTRL_TRIG_RING_SEL_BITS : 0);
}
-/*! \brief Set DMA byte swapping
+/*! \brief Set DMA byte swapping config in a channel configuration object
* \ingroup channel_config
*
* No effect for byte data, for halfword data, the two bytes of each halfword are
* swapped. For word data, the four bytes of each word are swapped to reverse their order.
*
- * \param c Pointer to channel configuration data
+ * \param c Pointer to channel configuration object
* \param bswap True to enable byte swapping
*/
static inline void channel_config_set_bswap(dma_channel_config *c, bool bswap) {
c->ctrl = bswap ? (c->ctrl | DMA_CH0_CTRL_TRIG_BSWAP_BITS) : (c->ctrl & ~DMA_CH0_CTRL_TRIG_BSWAP_BITS);
}
-/*! \brief Set IRQ quiet mode
+/*! \brief Set IRQ quiet mode in a channel configuration object
* \ingroup channel_config
*
* In QUIET mode, the channel does not generate IRQs at the end of every transfer block. Instead,
* an IRQ is raised when NULL is written to a trigger register, indicating the end of a control
* block chain.
*
- * \param c Pointer to channel configuration data
+ * \param c Pointer to channel configuration object
* \param irq_quiet True to enable quiet mode, false to disable.
*/
static inline void channel_config_set_irq_quiet(dma_channel_config *c, bool irq_quiet) {
@@ -257,13 +261,31 @@
}
/*!
- * \brief Enable/Disable the DMA channel
+ * \brief Set the channel priority in a channel configuration object
+ * \ingroup channel_config
+ *
+ * When true, gives a channel preferential treatment in issue scheduling: in each scheduling round,
+ * all high priority channels are considered first, and then only a single low
+ * priority channel, before returning to the high priority channels.
+ *
+ * This only affects the order in which the DMA schedules channels. The DMA's bus priority is not changed.
+ * If the DMA is not saturated then a low priority channel will see no loss of throughput.
+ *
+ * \param c Pointer to channel configuration object
+ * \param high_priority True to enable high priority
+ */
+static inline void channel_config_set_high_priority(dma_channel_config *c, bool high_priority) {
+ c->ctrl = high_priority ? (c->ctrl | DMA_CH0_CTRL_TRIG_HIGH_PRIORITY_BITS) : (c->ctrl & ~DMA_CH0_CTRL_TRIG_HIGH_PRIORITY_BITS);
+}
+
+/*!
+ * \brief Enable/Disable the DMA channel in a channel configuration object
* \ingroup channel_config
*
* When false, the channel will ignore triggers, stop issuing transfers, and pause the current transfer sequence (i.e. BUSY will
* remain high if already high)
*
- * \param c Pointer to channel configuration data
+ * \param c Pointer to channel configuration object
* \param enable True to enable the DMA channel. When enabled, the channel will respond to triggering events, and start transferring data.
*
*/
@@ -271,12 +293,12 @@
c->ctrl = enable ? (c->ctrl | DMA_CH0_CTRL_TRIG_EN_BITS) : (c->ctrl & ~DMA_CH0_CTRL_TRIG_EN_BITS);
}
-/*! \brief Enable access to channel by sniff hardware.
+/*! \brief Enable access to channel by sniff hardware in a channel configuration object
* \ingroup channel_config
*
* Sniff HW must be enabled and have this channel selected.
*
- * \param c Pointer to channel configuration data
+ * \param c Pointer to channel configuration object
* \param sniff_enable True to enable the Sniff HW access to this DMA channel.
*/
static inline void channel_config_set_sniff_enable(dma_channel_config *c, bool sniff_enable) {
@@ -297,6 +319,7 @@
* Ring | write=false, size=0 (i.e. off)
* Byte Swap | false
* Quiet IRQs | false
+ * High Priority | false
* Channel Enable | true
* Sniff Enable | false
*
@@ -315,6 +338,7 @@
channel_config_set_irq_quiet(&c, false);
channel_config_set_enable(&c, true);
channel_config_set_sniff_enable(&c, false);
+ channel_config_set_high_priority( &c, false);
return c;
}
@@ -473,6 +497,32 @@
*
* Function will only return once the DMA has stopped.
*
+ * Note that due to errata RP2040-E13, aborting a channel which has transfers
+ * in-flight (i.e. an individual read has taken place but the corresponding write has not), the ABORT
+ * status bit will clear prematurely, and subsequently the in-flight
+ * transfers will trigger a completion interrupt once they complete.
+ *
+ * The effect of this is that you \em may see a spurious completion interrupt
+ * on the channel as a result of calling this method.
+ *
+ * The calling code should be sure to ignore a completion IRQ as a result of this method. This may
+ * not require any additional work, as aborting a channel which may be about to complete, when you have a completion
+ * IRQ handler registered, is inherently race-prone, and so code is likely needed to disambiguate the two occurrences.
+ *
+ * If that is not the case, but you do have a channel completion IRQ handler registered, you can simply
+ * disable/re-enable the IRQ around the call to this method as shown by this code fragment (using DMA IRQ0).
+ *
+ * \code
+ * // disable the channel on IRQ0
+ * dma_channel_set_irq0_enabled(channel, false);
+ * // abort the channel
+ * dma_channel_abort(channel);
+ * // clear the spurious IRQ (if there was one)
+ * dma_channel_acknowledge_irq0(channel);
+ * // re-enable the channel on IRQ0
+ * dma_channel_set_irq0_enabled(channel, true);
+ *\endcode
+ *
* \param channel DMA channel
*/
static inline void dma_channel_abort(uint channel) {
@@ -480,7 +530,7 @@
dma_hw->abort = 1u << channel;
// Bit will go 0 once channel has reached safe state
// (i.e. any in-flight transfers have retired)
- while (dma_hw->abort & (1ul << channel)) tight_loop_contents();
+ while (dma_hw->ch[channel].ctrl_trig & DMA_CH0_CTRL_TRIG_BUSY_BITS) tight_loop_contents();
}
/*! \brief Enable single DMA channel's interrupt via DMA_IRQ_0
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
*
diff --git a/src/rp2_common/hardware_i2c/include/hardware/i2c.h b/src/rp2_common/hardware_i2c/include/hardware/i2c.h
index 23ff8f1..202ec02 100644
--- a/src/rp2_common/hardware_i2c/include/hardware/i2c.h
+++ b/src/rp2_common/hardware_i2c/include/hardware/i2c.h
@@ -89,7 +89,7 @@
* master.
*
* The I2C bus frequency is set as close as possible to requested, and
- * the return actual rate set is returned
+ * the actual rate set is returned
*
* \param i2c Either \ref i2c0 or \ref i2c1
* \param baudrate Baudrate in Hz (e.g. 100kHz is 100000)
diff --git a/src/rp2_common/hardware_irq/include/hardware/irq.h b/src/rp2_common/hardware_irq/include/hardware/irq.h
index 424a497..66679fe 100644
--- a/src/rp2_common/hardware_irq/include/hardware/irq.h
+++ b/src/rp2_common/hardware_irq/include/hardware/irq.h
@@ -103,6 +103,9 @@
#define PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY 0x80
#endif
+#define PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY 0xff
+#define PICO_SHARED_IRQ_HANDLER_LOWEST_ORDER_PRIORITY 0x00
+
// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_IRQ, Enable/disable assertions in the IRQ module, type=bool, default=0, group=hardware_irq
#ifndef PARAM_ASSERTIONS_ENABLED_IRQ
#define PARAM_ASSERTIONS_ENABLED_IRQ 0
@@ -126,7 +129,7 @@
/*! \brief Set specified interrupt's priority
* \ingroup hardware_irq
*
- * \param num Interrupt number
+ * \param num Interrupt number \ref interrupt_nums
* \param hardware_priority Priority to set.
* Numerically-lower values indicate a higher priority. Hardware priorities
* range from 0 (highest priority) to 255 (lowest priority) though only the
@@ -147,7 +150,7 @@
* initialized to PICO_DEFAULT_IRQ_PRIORITY by the SDK runtime at startup.
* PICO_DEFAULT_IRQ_PRIORITY defaults to 0x80
*
- * \param num Interrupt number
+ * \param num Interrupt number \ref interrupt_nums
* \return the IRQ priority
*/
uint irq_get_priority(uint num);
@@ -171,7 +174,7 @@
/*! \brief Enable/disable multiple interrupts on the executing core
* \ingroup hardware_irq
*
- * \param mask 32-bit mask with one bits set for the interrupts to enable/disable
+ * \param mask 32-bit mask with one bits set for the interrupts to enable/disable \ref interrupt_nums
* \param enabled true to enable the interrupts, false to disable them.
*/
void irq_set_mask_enabled(uint32_t mask, bool enabled);
@@ -216,7 +219,7 @@
* the (total across all IRQs on both cores) maximum (configurable via PICO_MAX_SHARED_IRQ_HANDLERS) number of shared handlers
* would be exceeded.
*
- * \param num Interrupt number
+ * \param num Interrupt number \ref interrupt_nums
* \param handler The handler to set. See \ref irq_handler_t
* \param order_priority The order priority controls the order that handlers for the same IRQ number on the core are called.
* The shared irq handlers for an interrupt are all called when an IRQ fires, however the order of the calls is based
@@ -224,6 +227,9 @@
* rule of thumb is to use PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY if you don't much care, as it is in the middle of
* the priority range by default.
*
+ * \note The order_priority uses \em higher values for higher priorities which is the \em opposite of the CPU interrupt priorities passed
+ * to irq_set_priority() which use lower values for higher priorities.
+ *
* \see irq_set_exclusive_handler()
*/
void irq_add_shared_handler(uint num, irq_handler_t handler, uint8_t order_priority);
@@ -246,6 +252,14 @@
*/
void irq_remove_handler(uint num, irq_handler_t handler);
+/*! \brief Determine if the current handler for the given number is shared
+ * \ingroup hardware_irq
+ *
+ * \param num Interrupt number \ref interrupt_nums
+ * \param return true if the specified IRQ has a shared handler
+ */
+bool irq_has_shared_handler(uint num);
+
/*! \brief Get the current IRQ handler for the specified IRQ from the currently installed hardware vector table (VTOR)
* of the execution core
* \ingroup hardware_irq
@@ -258,6 +272,10 @@
/*! \brief Clear a specific interrupt on the executing core
* \ingroup hardware_irq
*
+ * This method is only useful for "software" IRQs that are not connected to hardware (i.e. IRQs 26-31)
+ * as the the NVIC always reflects the current state of the IRQ state of the hardware for hardware IRQs, and clearing
+ * of the IRQ state of the hardware is performed via the hardware's registers instead.
+ *
* \param int_num Interrupt number \ref interrupt_nums
*/
static inline void irq_clear(uint int_num) {
@@ -279,6 +297,69 @@
* \note This is an internal method and user should generally not call it.
*/
void irq_init_priorities(void);
+
+/*! \brief Claim ownership of a user IRQ on the calling core
+ * \ingroup hardware_irq
+ *
+ * User IRQs are numbered 26-31 and are not connected to any hardware, but can be triggered by \ref irq_set_pending.
+ *
+ * \note User IRQs are a core local feature; they cannot be used to communicate between cores. Therfore all functions
+ * dealing with Uer IRQs affect only the calling core
+ *
+ * This method explicitly claims ownership of a user IRQ, so other code can know it is being used.
+ *
+ * \param irq_num the user IRQ to claim
+ */
+void user_irq_claim(uint irq_num);
+
+/*! \brief Mark a user IRQ as no longer used on the calling core
+ * \ingroup hardware_irq
+ *
+ * User IRQs are numbered 26-31 and are not connected to any hardware, but can be triggered by \ref irq_set_pending.
+ *
+ * \note User IRQs are a core local feature; they cannot be used to communicate between cores. Therfore all functions
+ * dealing with Uer IRQs affect only the calling core
+ *
+ * This method explicitly releases ownership of a user IRQ, so other code can know it is free to use.
+ *
+ * \note it is customary to have disabled the irq and removed the handler prior to calling this method.
+ *
+ * \param irq_num the irq irq_num to unclaim
+ */
+void user_irq_unclaim(uint irq_num);
+
+/*! \brief Claim ownership of a free user IRQ on the calling core
+ * \ingroup hardware_irq
+ *
+ * User IRQs are numbered 26-31 and are not connected to any hardware, but can be triggered by \ref irq_set_pending.
+ *
+ * \note User IRQs are a core local feature; they cannot be used to communicate between cores. Therfore all functions
+ * dealing with Uer IRQs affect only the calling core
+ *
+ * This method explicitly claims ownership of an unused user IRQ if there is one, so other code can know it is being used.
+ *
+ * \param required if true the function will panic if none are available
+ * \return the user IRQ number or -1 if required was false, and none were free
+ */
+int user_irq_claim_unused(bool required);
+
+/*
+*! \brief Check if a user IRQ is in use on the calling core
+ * \ingroup hardware_irq
+ *
+ * User IRQs are numbered 26-31 and are not connected to any hardware, but can be triggered by \ref irq_set_pending.
+ *
+ * \note User IRQs are a core local feature; they cannot be used to communicate between cores. Therfore all functions
+ * dealing with Uer IRQs affect only the calling core
+ *
+ * \param irq_num the irq irq_num
+ * \return true if the irq_num is claimed, false otherwise
+ * \sa user_irq_claim
+ * \sa user_irq_unclaim
+ * \sa user_irq_claim_unused
+ */
+bool user_irq_is_claimed(uint irq_num);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/rp2_common/hardware_irq/irq.c b/src/rp2_common/hardware_irq/irq.c
index 211f6d0..251cdf7 100644
--- a/src/rp2_common/hardware_irq/irq.c
+++ b/src/rp2_common/hardware_irq/irq.c
@@ -8,12 +8,15 @@
#include "hardware/regs/m0plus.h"
#include "hardware/platform_defs.h"
#include "hardware/structs/scb.h"
+#include "hardware/claim.h"
#include "pico/mutex.h"
#include "pico/assert.h"
extern void __unhandled_user_irq(void);
+static uint8_t user_irq_claimed[NUM_CORES];
+
static inline irq_handler_t *get_vtable(void) {
return (irq_handler_t *) scb_hw->vtor;
}
@@ -92,10 +95,21 @@
static inline bool is_shared_irq_raw_handler(irq_handler_t raw_handler) {
return (uintptr_t)raw_handler - (uintptr_t)irq_handler_chain_slots < sizeof(irq_handler_chain_slots);
}
+
+bool irq_has_shared_handler(uint irq_num) {
+ check_irq_param(irq_num);
+ irq_handler_t handler = irq_get_vtable_handler(irq_num);
+ return handler && is_shared_irq_raw_handler(handler);
+}
+
#else
#define is_shared_irq_raw_handler(h) false
+bool irq_has_shared_handler(uint irq_num) {
+ return false;
+}
#endif
+
irq_handler_t irq_get_vtable_handler(uint num) {
check_irq_param(num);
return get_vtable()[16 + num];
@@ -135,9 +149,9 @@
static uint16_t make_branch(uint16_t *from, void *to) {
uint32_t ui_from = (uint32_t)from;
uint32_t ui_to = (uint32_t)to;
- uint32_t delta = (ui_to - ui_from - 4) / 2;
- assert(!(delta >> 11u));
- return (uint16_t)(0xe000 | (delta & 0x7ff));
+ int32_t delta = (int32_t)(ui_to - ui_from - 4);
+ assert(delta >= -2048 && delta <= 2046 && !(delta & 1));
+ return (uint16_t)(0xe000 | ((delta >> 1) & 0x7ff));
}
static void insert_branch_and_link(uint16_t *from, void *to) {
@@ -287,7 +301,6 @@
struct irq_handler_chain_slot *prev_slot = NULL;
struct irq_handler_chain_slot *existing_vtable_slot = remove_thumb_bit(vtable_handler);
struct irq_handler_chain_slot *to_free_slot = existing_vtable_slot;
- int8_t to_free_slot_index = get_slot_index(to_free_slot);
while (to_free_slot->handler != handler) {
prev_slot = to_free_slot;
if (to_free_slot->link < 0) break;
@@ -325,7 +338,7 @@
}
// add slot back to free list
to_free_slot->link = irq_hander_chain_free_slot_head;
- irq_hander_chain_free_slot_head = to_free_slot_index;
+ irq_hander_chain_free_slot_head = get_slot_index(to_free_slot);
} else {
// since we are the last slot we know that our inst3 hasn't executed yet, so we change
// it to bl to irq_handler_chain_remove_tail which will remove the slot.
@@ -411,3 +424,31 @@
}
#endif
}
+
+#define FIRST_USER_IRQ (NUM_IRQS - NUM_USER_IRQS)
+
+static uint get_user_irq_claim_index(uint irq_num) {
+ invalid_params_if(IRQ, irq_num < FIRST_USER_IRQ || irq_num >= NUM_IRQS);
+ // we count backwards from the last, to match the existing hard coded uses of user IRQs in the SDK which were previously using 31
+ static_assert(NUM_IRQS - FIRST_USER_IRQ <= 8, ""); // we only use a single byte's worth of claim bits today.
+ return NUM_IRQS - irq_num - 1u;
+}
+
+void user_irq_claim(uint irq_num) {
+ hw_claim_or_assert(&user_irq_claimed[get_core_num()], get_user_irq_claim_index(irq_num), "User IRQ is already claimed");
+}
+
+void user_irq_unclaim(uint irq_num) {
+ hw_claim_clear(&user_irq_claimed[get_core_num()], get_user_irq_claim_index(irq_num));
+}
+
+int user_irq_claim_unused(bool required) {
+ int bit = hw_claim_unused_from_range(&user_irq_claimed[get_core_num()], required, 0, NUM_USER_IRQS - 1, "No user IRQs are available");
+ if (bit >= 0) bit = (int)NUM_IRQS - bit - 1;
+ return bit;
+}
+
+bool user_irq_is_claimed(uint irq_num) {
+ return hw_is_claimed(&user_irq_claimed[get_core_num()], get_user_irq_claim_index(irq_num));
+}
+
diff --git a/src/rp2_common/hardware_irq/irq_handler_chain.S b/src/rp2_common/hardware_irq/irq_handler_chain.S
index 7d7be7d..ca15292 100644
--- a/src/rp2_common/hardware_irq/irq_handler_chain.S
+++ b/src/rp2_common/hardware_irq/irq_handler_chain.S
@@ -54,17 +54,18 @@
.endr
irq_handler_chain_first_slot:
- push {lr}
- ldr r0, [r1, #4]
- adds r1, #1
- mov lr, r1
- bx r0
+ push {lr} // Save EXC_RETURN token, so `pop {pc}` will return from interrupt
+ ldr r0, [r1, #4] // Get `handler` field of irq_handler_chain_slot
+ adds r1, #1 // r1 points to `inst3` field of slot struct. Set Thumb bit on r1,
+ mov lr, r1 // and copy to lr, so `inst3` is executed on return from handler
+ bx r0 // Enter handler
+
irq_handler_chain_remove_tail:
- mov r0, lr
- subs r0, #9
+ mov r0, lr // Get start of struct. This function was called by a bl at offset +4,
+ subs r0, #9 // so lr points to offset +8. Note also lr has its Thumb bit set!
ldr r1, =irq_add_tail_to_free_list
blx r1
- pop {pc}
+ pop {pc} // Top of stack is EXC_RETURN
#endif
diff --git a/src/rp2_common/hardware_pio/include/hardware/pio.h b/src/rp2_common/hardware_pio/include/hardware/pio.h
index d2377ac..e42c60f 100644
--- a/src/rp2_common/hardware_pio/include/hardware/pio.h
+++ b/src/rp2_common/hardware_pio/include/hardware/pio.h
@@ -73,20 +73,16 @@
* e.g. pio_gpio_init(pio0, 5)
*
* \ingroup hardware_pio
- * @{
*/
#define pio0 pio0_hw
-/** @} */
/** Identifier for the second (PIO 1) hardware PIO instance (for use in PIO functions).
*
* e.g. pio_gpio_init(pio1, 5)
*
* \ingroup hardware_pio
- * @{
*/
#define pio1 pio1_hw
-/** @} */
/** \brief PIO state machine configuration
* \defgroup sm_config sm_config
@@ -99,6 +95,9 @@
/** \brief PIO Configuration structure
* \ingroup sm_config
+ *
+ * This structure is an in-memory representation of the configuration that can be applied to a PIO
+ * state machine later using pio_sm_set_config() or pio_sm_init().
*/
typedef struct {
uint32_t clkdiv;
@@ -157,7 +156,7 @@
/*! \brief Set the 'in' pins in a state machine configuration
* \ingroup sm_config
*
- * Can overlap with the 'out', ''set' and 'sideset' pins
+ * Can overlap with the 'out', 'set' and 'sideset' pins
*
* \param c Pointer to the configuration structure to modify
* \param in_base 0-31 First pin to use as input
@@ -215,6 +214,7 @@
* \sa sm_config_set_clkdiv()
*/
static inline void sm_config_set_clkdiv_int_frac(pio_sm_config *c, uint16_t div_int, uint8_t div_frac) {
+ invalid_params_if(PIO, div_int == 0 && div_frac != 0);
c->clkdiv =
(((uint)div_frac) << PIO_SM0_CLKDIV_FRAC_LSB) |
(((uint)div_int) << PIO_SM0_CLKDIV_INT_LSB);
@@ -374,8 +374,8 @@
* Side Set Pins (base) | 0
* Side Set | disabled
* Wrap | wrap=31, wrap_to=0
- * In Shift | shift_direction=right, autopush=false, push_thrshold=32
- * Out Shift | shift_direction=right, autopull=false, pull_thrshold=32
+ * In Shift | shift_direction=right, autopush=false, push_threshold=32
+ * Out Shift | shift_direction=right, autopull=false, pull_threshold=32
* Jmp Pin | 0
* Out Special | sticky=false, has_enable_pin=false, enable_pin_index=0
* Mov Status | status_sel=STATUS_TX_LESSTHAN, n=0
@@ -790,9 +790,9 @@
static inline void pio_set_irqn_source_mask_enabled(PIO pio, uint irq_index, uint32_t source_mask, bool enabled) {
invalid_params_if(PIO, irq_index > 1);
if (irq_index) {
- pio_set_irq0_source_mask_enabled(pio, source_mask, enabled);
- } else {
pio_set_irq1_source_mask_enabled(pio, source_mask, enabled);
+ } else {
+ pio_set_irq0_source_mask_enabled(pio, source_mask, enabled);
}
}
@@ -905,7 +905,7 @@
}
/*! \brief Set the current 'out' pins for a state machine
- * \ingroup sm_config
+ * \ingroup hardware_pio
*
* Can overlap with the 'in', 'set' and 'sideset' pins
*
@@ -926,7 +926,7 @@
/*! \brief Set the current 'set' pins for a state machine
- * \ingroup sm_config
+ * \ingroup hardware_pio
*
* Can overlap with the 'in', 'out' and 'sideset' pins
*
@@ -946,9 +946,9 @@
}
/*! \brief Set the current 'in' pins for a state machine
- * \ingroup sm_config
+ * \ingroup hardware_pio
*
- * Can overlap with the 'out', ''set' and 'sideset' pins
+ * Can overlap with the 'out', 'set' and 'sideset' pins
*
* \param pio The PIO instance; either \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
@@ -963,7 +963,7 @@
}
/*! \brief Set the current 'sideset' pins for a state machine
- * \ingroup sm_config
+ * \ingroup hardware_pio
*
* Can overlap with the 'in', 'out' and 'set' pins
*
@@ -1155,6 +1155,7 @@
static inline void pio_sm_set_clkdiv_int_frac(PIO pio, uint sm, uint16_t div_int, uint8_t div_frac) {
check_pio_param(pio);
check_sm_param(sm);
+ invalid_params_if(PIO, div_int == 0 && div_frac != 0);
pio->sm[sm].clkdiv =
(((uint)div_frac) << PIO_SM0_CLKDIV_FRAC_LSB) |
(((uint)div_int) << PIO_SM0_CLKDIV_INT_LSB);
diff --git a/src/rp2_common/hardware_pll/include/hardware/pll.h b/src/rp2_common/hardware_pll/include/hardware/pll.h
index ee0c3ae..0466504 100644
--- a/src/rp2_common/hardware_pll/include/hardware/pll.h
+++ b/src/rp2_common/hardware_pll/include/hardware/pll.h
@@ -31,6 +31,14 @@
#define pll_sys pll_sys_hw
#define pll_usb pll_usb_hw
+#ifndef PICO_PLL_VCO_MIN_FREQ_MHZ
+#define PICO_PLL_VCO_MIN_FREQ_MHZ 750
+#endif
+
+#ifndef PICO_PLL_VCO_MAX_FREQ_MHZ
+#define PICO_PLL_VCO_MAX_FREQ_MHZ 1600
+#endif
+
/*! \brief Initialise specified PLL.
* \ingroup hardware_pll
* \param pll pll_sys or pll_usb
diff --git a/src/rp2_common/hardware_pll/pll.c b/src/rp2_common/hardware_pll/pll.c
index 6cc6184..e152b84 100644
--- a/src/rp2_common/hardware_pll/pll.c
+++ b/src/rp2_common/hardware_pll/pll.c
@@ -13,6 +13,9 @@
void pll_init(PLL pll, uint refdiv, uint vco_freq, uint post_div1, uint post_div2) {
uint32_t ref_mhz = XOSC_MHZ / refdiv;
+ // Check vco freq is in an acceptable range
+ assert(vco_freq >= (PICO_PLL_VCO_MIN_FREQ_MHZ * MHZ) && vco_freq <= (PICO_PLL_VCO_MAX_FREQ_MHZ * MHZ));
+
// What are we multiplying the reference clock by to get the vco freq
// (The regs are called div, because you divide the vco output and compare it to the refclk)
uint32_t fbdiv = vco_freq / (ref_mhz * MHZ);
@@ -41,7 +44,7 @@
if ((pll->cs & PLL_CS_LOCK_BITS) &&
(refdiv == (pll->cs & PLL_CS_REFDIV_BITS)) &&
(fbdiv == (pll->fbdiv_int & PLL_FBDIV_INT_BITS)) &&
- (pdiv == (pll->prim & (PLL_PRIM_POSTDIV1_BITS & PLL_PRIM_POSTDIV2_BITS)))) {
+ (pdiv == (pll->prim & (PLL_PRIM_POSTDIV1_BITS | PLL_PRIM_POSTDIV2_BITS)))) {
// do not disrupt PLL that is already correctly configured and operating
return;
}
diff --git a/src/rp2_common/hardware_pwm/include/hardware/pwm.h b/src/rp2_common/hardware_pwm/include/hardware/pwm.h
index 634375e..839b8f0 100644
--- a/src/rp2_common/hardware_pwm/include/hardware/pwm.h
+++ b/src/rp2_common/hardware_pwm/include/hardware/pwm.h
@@ -106,7 +106,7 @@
| (bool_to_bit(phase_correct) << PWM_CH0_CSR_PH_CORRECT_LSB);
}
-/** \brief Set clock divider in a PWM configuration
+/** \brief Set PWM clock divider in a PWM configuration
* \ingroup hardware_pwm
*
* \param c PWM configuration struct to modify
@@ -117,9 +117,27 @@
* before passing them on to the PWM counter.
*/
static inline void pwm_config_set_clkdiv(pwm_config *c, float div) {
+ valid_params_if(PWM, div >= 1.f && div < 256.f);
c->div = (uint32_t)(div * (float)(1u << PWM_CH0_DIV_INT_LSB));
}
+/** \brief Set PWM clock divider in a PWM configuration using an 8:4 fractional value
+ * \ingroup hardware_pwm
+ *
+ * \param c PWM configuration struct to modify
+ * \param integer 8 bit integer part of the clock divider. Must be greater than or equal to 1.
+ * \param fract 4 bit fractional part of the clock divider
+ *
+ * If the divide mode is free-running, the PWM counter runs at clk_sys / div.
+ * Otherwise, the divider reduces the rate of events seen on the B pin input (level or edge)
+ * before passing them on to the PWM counter.
+ */
+static inline void pwm_config_set_clkdiv_int_frac(pwm_config *c, uint8_t integer, uint8_t fract) {
+ valid_params_if(PWM, integer >= 1);
+ valid_params_if(PWM, fract < 16);
+ c->div = (((uint)integer) << PWM_CH0_DIV_INT_LSB) | (((uint)fract) << PWM_CH0_DIV_FRAC_LSB);
+}
+
/** \brief Set PWM clock divider in a PWM configuration
* \ingroup hardware_pwm
*
@@ -131,7 +149,8 @@
* before passing them on to the PWM counter.
*/
static inline void pwm_config_set_clkdiv_int(pwm_config *c, uint div) {
- c->div = div << PWM_CH0_DIV_INT_LSB;
+ valid_params_if(PWM, div >= 1 && div < 256);
+ pwm_config_set_clkdiv_int_frac(c, (uint8_t)div, 0);
}
/** \brief Set PWM counting mode in a PWM configuration
@@ -376,6 +395,7 @@
*/
static inline void pwm_set_clkdiv_int_frac(uint slice_num, uint8_t integer, uint8_t fract) {
check_slice_num_param(slice_num);
+ valid_params_if(PWM, integer >= 1);
valid_params_if(PWM, fract < 16);
pwm_hw->slice[slice_num].div = (((uint)integer) << PWM_CH0_DIV_INT_LSB) | (((uint)fract) << PWM_CH0_DIV_FRAC_LSB);
}
diff --git a/src/rp2_common/hardware_rtc/include/hardware/rtc.h b/src/rp2_common/hardware_rtc/include/hardware/rtc.h
index 8757e36..2a72a8e 100644
--- a/src/rp2_common/hardware_rtc/include/hardware/rtc.h
+++ b/src/rp2_common/hardware_rtc/include/hardware/rtc.h
@@ -47,6 +47,10 @@
/*! \brief Set the RTC to the specified time
* \ingroup hardware_rtc
*
+ * \note Note that after setting the RTC date and time, a subsequent read of the values (e.g. via rtc_get_datetime()) may not
+ * reflect the new setting until up to three cycles of the potentially-much-slower RTC clock domain have passed. This represents a period
+ * of 64 microseconds with the default RTC clock configuration.
+ *
* \param t Pointer to a \ref datetime_t structure contains time to set
* \return true if set, false if the passed in datetime was invalid.
*/
diff --git a/src/rp2_common/hardware_rtc/rtc.c b/src/rp2_common/hardware_rtc/rtc.c
index 5429acd..be9250f 100644
--- a/src/rp2_common/hardware_rtc/rtc.c
+++ b/src/rp2_common/hardware_rtc/rtc.c
@@ -65,13 +65,13 @@
}
// Write to setup registers
- rtc_hw->setup_0 = (((uint)t->year) << RTC_SETUP_0_YEAR_LSB ) |
- (((uint)t->month) << RTC_SETUP_0_MONTH_LSB) |
- (((uint)t->day) << RTC_SETUP_0_DAY_LSB);
- rtc_hw->setup_1 = (((uint)t->dotw) << RTC_SETUP_1_DOTW_LSB) |
- (((uint)t->hour) << RTC_SETUP_1_HOUR_LSB) |
- (((uint)t->min) << RTC_SETUP_1_MIN_LSB) |
- (((uint)t->sec) << RTC_SETUP_1_SEC_LSB);
+ rtc_hw->setup_0 = (((uint32_t)t->year) << RTC_SETUP_0_YEAR_LSB ) |
+ (((uint32_t)t->month) << RTC_SETUP_0_MONTH_LSB) |
+ (((uint32_t)t->day) << RTC_SETUP_0_DAY_LSB);
+ rtc_hw->setup_1 = (((uint32_t)t->dotw) << RTC_SETUP_1_DOTW_LSB) |
+ (((uint32_t)t->hour) << RTC_SETUP_1_HOUR_LSB) |
+ (((uint32_t)t->min) << RTC_SETUP_1_MIN_LSB) |
+ (((uint32_t)t->sec) << RTC_SETUP_1_SEC_LSB);
// Load setup values into rtc clock domain
rtc_hw->ctrl = RTC_CTRL_LOAD_BITS;
@@ -95,13 +95,13 @@
uint32_t rtc_0 = rtc_hw->rtc_0;
uint32_t rtc_1 = rtc_hw->rtc_1;
- t->dotw = (rtc_0 & RTC_RTC_0_DOTW_BITS ) >> RTC_RTC_0_DOTW_LSB;
- t->hour = (rtc_0 & RTC_RTC_0_HOUR_BITS ) >> RTC_RTC_0_HOUR_LSB;
- t->min = (rtc_0 & RTC_RTC_0_MIN_BITS ) >> RTC_RTC_0_MIN_LSB;
- t->sec = (rtc_0 & RTC_RTC_0_SEC_BITS ) >> RTC_RTC_0_SEC_LSB;
- t->year = (rtc_1 & RTC_RTC_1_YEAR_BITS ) >> RTC_RTC_1_YEAR_LSB;
- t->month = (rtc_1 & RTC_RTC_1_MONTH_BITS) >> RTC_RTC_1_MONTH_LSB;
- t->day = (rtc_1 & RTC_RTC_1_DAY_BITS ) >> RTC_RTC_1_DAY_LSB;
+ t->dotw = (int8_t) ((rtc_0 & RTC_RTC_0_DOTW_BITS ) >> RTC_RTC_0_DOTW_LSB);
+ t->hour = (int8_t) ((rtc_0 & RTC_RTC_0_HOUR_BITS ) >> RTC_RTC_0_HOUR_LSB);
+ t->min = (int8_t) ((rtc_0 & RTC_RTC_0_MIN_BITS ) >> RTC_RTC_0_MIN_LSB);
+ t->sec = (int8_t) ((rtc_0 & RTC_RTC_0_SEC_BITS ) >> RTC_RTC_0_SEC_LSB);
+ t->year = (int16_t) ((rtc_1 & RTC_RTC_1_YEAR_BITS ) >> RTC_RTC_1_YEAR_LSB);
+ t->month = (int8_t) ((rtc_1 & RTC_RTC_1_MONTH_BITS) >> RTC_RTC_1_MONTH_LSB);
+ t->day = (int8_t) ((rtc_1 & RTC_RTC_1_DAY_BITS ) >> RTC_RTC_1_DAY_LSB);
return true;
}
@@ -148,13 +148,13 @@
rtc_disable_alarm();
// Only add to setup if it isn't -1
- rtc_hw->irq_setup_0 = ((t->year < 0) ? 0 : (((uint)t->year) << RTC_IRQ_SETUP_0_YEAR_LSB )) |
- ((t->month < 0) ? 0 : (((uint)t->month) << RTC_IRQ_SETUP_0_MONTH_LSB)) |
- ((t->day < 0) ? 0 : (((uint)t->day) << RTC_IRQ_SETUP_0_DAY_LSB ));
- rtc_hw->irq_setup_1 = ((t->dotw < 0) ? 0 : (((uint)t->dotw) << RTC_IRQ_SETUP_1_DOTW_LSB)) |
- ((t->hour < 0) ? 0 : (((uint)t->hour) << RTC_IRQ_SETUP_1_HOUR_LSB)) |
- ((t->min < 0) ? 0 : (((uint)t->min) << RTC_IRQ_SETUP_1_MIN_LSB )) |
- ((t->sec < 0) ? 0 : (((uint)t->sec) << RTC_IRQ_SETUP_1_SEC_LSB ));
+ rtc_hw->irq_setup_0 = ((t->year < 0) ? 0 : (((uint32_t)t->year) << RTC_IRQ_SETUP_0_YEAR_LSB )) |
+ ((t->month < 0) ? 0 : (((uint32_t)t->month) << RTC_IRQ_SETUP_0_MONTH_LSB)) |
+ ((t->day < 0) ? 0 : (((uint32_t)t->day) << RTC_IRQ_SETUP_0_DAY_LSB ));
+ rtc_hw->irq_setup_1 = ((t->dotw < 0) ? 0 : (((uint32_t)t->dotw) << RTC_IRQ_SETUP_1_DOTW_LSB)) |
+ ((t->hour < 0) ? 0 : (((uint32_t)t->hour) << RTC_IRQ_SETUP_1_HOUR_LSB)) |
+ ((t->min < 0) ? 0 : (((uint32_t)t->min) << RTC_IRQ_SETUP_1_MIN_LSB )) |
+ ((t->sec < 0) ? 0 : (((uint32_t)t->sec) << RTC_IRQ_SETUP_1_SEC_LSB ));
// Set the match enable bits for things we care about
if (t->year >= 0) hw_set_bits(&rtc_hw->irq_setup_0, RTC_IRQ_SETUP_0_YEAR_ENA_BITS);
diff --git a/src/rp2_common/hardware_spi/include/hardware/spi.h b/src/rp2_common/hardware_spi/include/hardware/spi.h
index e8dc952..8e27533 100644
--- a/src/rp2_common/hardware_spi/include/hardware/spi.h
+++ b/src/rp2_common/hardware_spi/include/hardware/spi.h
@@ -53,7 +53,7 @@
*
* \ingroup hardware_spi
*/
-#define spi0 ((spi_inst_t * const)spi0_hw)
+#define spi0 ((spi_inst_t *)spi0_hw)
/** Identifier for the second (SPI 1) hardware SPI instance (for use in SPI functions).
*
@@ -61,7 +61,7 @@
*
* \ingroup hardware_spi
*/
-#define spi1 ((spi_inst_t * const)spi1_hw)
+#define spi1 ((spi_inst_t *)spi1_hw)
#if !defined(PICO_DEFAULT_SPI_INSTANCE) && defined(PICO_DEFAULT_SPI)
#define PICO_DEFAULT_SPI_INSTANCE (__CONCAT(spi,PICO_DEFAULT_SPI))
diff --git a/src/rp2_common/hardware_sync/include/hardware/sync.h b/src/rp2_common/hardware_sync/include/hardware/sync.h
index 8f91d55..eee675e 100644
--- a/src/rp2_common/hardware_sync/include/hardware/sync.h
+++ b/src/rp2_common/hardware_sync/include/hardware/sync.h
@@ -304,15 +304,6 @@
restore_interrupts(saved_irq);
}
-/*! \brief Get the current core number
- * \ingroup hardware_sync
- *
- * \return The core number the call was made from
- */
-__force_inline static uint get_core_num(void) {
- return (*(uint32_t *) (SIO_BASE + SIO_CPUID_OFFSET));
-}
-
/*! \brief Initialise a spin lock
* \ingroup hardware_sync
*
diff --git a/src/rp2_common/hardware_uart/include/hardware/uart.h b/src/rp2_common/hardware_uart/include/hardware/uart.h
index bce0d2f..0309e59 100644
--- a/src/rp2_common/hardware_uart/include/hardware/uart.h
+++ b/src/rp2_common/hardware_uart/include/hardware/uart.h
@@ -78,8 +78,8 @@
* \ingroup hardware_uart
* @{
*/
-#define uart0 ((uart_inst_t * const)uart0_hw) ///< Identifier for UART instance 0
-#define uart1 ((uart_inst_t * const)uart1_hw) ///< Identifier for UART instance 1
+#define uart0 ((uart_inst_t *)uart0_hw) ///< Identifier for UART instance 0
+#define uart1 ((uart_inst_t *)uart1_hw) ///< Identifier for UART instance 1
/** @} */
diff --git a/src/rp2_common/hardware_watchdog/include/hardware/watchdog.h b/src/rp2_common/hardware_watchdog/include/hardware/watchdog.h
index 747838b..7ce89ff 100644
--- a/src/rp2_common/hardware_watchdog/include/hardware/watchdog.h
+++ b/src/rp2_common/hardware_watchdog/include/hardware/watchdog.h
@@ -97,7 +97,7 @@
* This would not be present if a watchdog reset is initiated by \ref watchdog_reboot or by the RP2040 bootrom
* (e.g. dragging a UF2 onto the RPI-RP2 drive).
*
- * @return true If the watchdog timer or a watchdog force caused (see \reg watchdog_caused_reboot) the last reboot
+ * @return true If the watchdog timer or a watchdog force caused (see \ref watchdog_caused_reboot) the last reboot
* and the watchdog reboot happened after \ref watchdog_enable was called
* @return false If there has been no watchdog reboot since the last power on reset, or the watchdog reboot was not caused
* by a watchdog timeout after \ref watchdog_enable was called.
diff --git a/src/rp2_common/pico_bit_ops/bit_ops_aeabi.S b/src/rp2_common/pico_bit_ops/bit_ops_aeabi.S
index eba839e..7b83edb 100644
--- a/src/rp2_common/pico_bit_ops/bit_ops_aeabi.S
+++ b/src/rp2_common/pico_bit_ops/bit_ops_aeabi.S
@@ -85,7 +85,7 @@
ldr r3, =aeabi_bits_funcs
ldr r3, [r3, #CTZ32]
cmp r0, #0
- bne 1f
+ beq 1f
bx r3
1:
push {lr}
diff --git a/src/rp2_common/pico_bootrom/bootrom.c b/src/rp2_common/pico_bootrom/bootrom.c
index af7d091..5def61a 100644
--- a/src/rp2_common/pico_bootrom/bootrom.c
+++ b/src/rp2_common/pico_bootrom/bootrom.c
@@ -12,9 +12,6 @@
// Returns the 32 bit pointer into the ROM if found or NULL otherwise.
typedef void *(*rom_table_lookup_fn)(uint16_t *table, uint32_t code);
-// Convert a 16 bit pointer stored at the given rom address into a 32 bit pointer
-#define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
-
void *rom_func_lookup(uint32_t code) {
return rom_func_lookup_inline(code);
}
diff --git a/src/rp2_common/pico_bootrom/include/pico/bootrom.h b/src/rp2_common/pico_bootrom/include/pico/bootrom.h
index e557893..4484568 100644
--- a/src/rp2_common/pico_bootrom/include/pico/bootrom.h
+++ b/src/rp2_common/pico_bootrom/include/pico/bootrom.h
@@ -116,8 +116,18 @@
// Returns the 32 bit pointer into the ROM if found or NULL otherwise.
typedef void *(*rom_table_lookup_fn)(uint16_t *table, uint32_t code);
+#if defined(__GNUC__) && (__GNUC__ >= 12)
// Convert a 16 bit pointer stored at the given rom address into a 32 bit pointer
-#define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
+static inline void *rom_hword_as_ptr(uint16_t rom_address) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+ return (void *)(uintptr_t)*(uint16_t *)(uintptr_t)rom_address;
+#pragma GCC diagnostic pop
+}
+#else
+// Convert a 16 bit pointer stored at the given rom address into a 32 bit pointer
+#define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)(uintptr_t)(rom_address))
+#endif
/*!
* \brief Lookup a bootrom function by code. This method is forceably inlined into the caller for FLASH/RAM sensitive code usage
diff --git a/src/rp2_common/pico_cyw43_arch/CMakeLists.txt b/src/rp2_common/pico_cyw43_arch/CMakeLists.txt
new file mode 100644
index 0000000..ede03f1
--- /dev/null
+++ b/src/rp2_common/pico_cyw43_arch/CMakeLists.txt
@@ -0,0 +1,66 @@
+if (PICO_CYW43_SUPPORTED) # set by BOARD=pico-w
+ if (TARGET cyw43_driver_picow)
+ message("Enabling build support for Pico W wireless.")
+
+ pico_add_impl_library(pico_cyw43_arch)
+ target_sources(pico_cyw43_arch INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/cyw43_arch.c
+ ${CMAKE_CURRENT_LIST_DIR}/cyw43_arch_poll.c
+ ${CMAKE_CURRENT_LIST_DIR}/cyw43_arch_threadsafe_background.c
+ ${CMAKE_CURRENT_LIST_DIR}/cyw43_arch_freertos.c
+ )
+
+ target_include_directories(pico_cyw43_arch INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/include)
+
+ target_link_libraries(pico_cyw43_arch INTERFACE
+ pico_unique_id
+ cyw43_driver_picow)
+
+ if (NOT TARGET pico_lwip)
+ message(WARNING "lwIP is not available; Full Pico W wireless support will be unavailable too")
+ else()
+ add_library(pico_cyw43_arch_lwip_poll INTERFACE)
+ target_link_libraries(pico_cyw43_arch_lwip_poll INTERFACE
+ pico_cyw43_arch
+ pico_lwip
+ pico_lwip_nosys)
+ target_compile_definitions(pico_cyw43_arch_lwip_poll INTERFACE
+ CYW43_LWIP=1
+ PICO_CYW43_ARCH_POLL=1
+ )
+
+ add_library(pico_cyw43_arch_lwip_threadsafe_background INTERFACE)
+ target_link_libraries(pico_cyw43_arch_lwip_threadsafe_background INTERFACE
+ pico_cyw43_arch
+ pico_lwip
+ pico_lwip_nosys)
+ target_compile_definitions(pico_cyw43_arch_lwip_threadsafe_background INTERFACE
+ CYW43_LWIP=1
+ PICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1
+ )
+
+ add_library(pico_cyw43_arch_lwip_sys_freertos INTERFACE)
+ target_link_libraries(pico_cyw43_arch_lwip_sys_freertos INTERFACE
+ pico_cyw43_arch
+ pico_lwip
+ pico_lwip_contrib_freertos)
+ target_compile_definitions(pico_cyw43_arch_lwip_sys_freertos INTERFACE
+ CYW43_LWIP=1
+ LWIP_PROVIDE_ERRNO=1
+ PICO_CYW43_ARCH_FREERTOS=1
+ )
+ endif()
+
+ add_library(pico_cyw43_arch_none INTERFACE)
+ target_link_libraries(pico_cyw43_arch_none INTERFACE pico_cyw43_arch)
+ target_compile_definitions(pico_cyw43_arch_none INTERFACE
+ CYW43_LWIP=0
+ PICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 # none still uses threadsafe_background to make gpio use easy
+ )
+ endif()
+endif()
+
+if (PICO_CYW43_DRIVER_PATH AND EXISTS "${PICO_CYW43_DRIVER_PATH}")
+ pico_add_doxygen(${PICO_CYW43_DRIVER_PATH}/src)
+endif()
\ No newline at end of file
diff --git a/src/rp2_common/pico_cyw43_arch/cyw43_arch.c b/src/rp2_common/pico_cyw43_arch/cyw43_arch.c
new file mode 100644
index 0000000..c328d6e
--- /dev/null
+++ b/src/rp2_common/pico_cyw43_arch/cyw43_arch.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "pico/unique_id.h"
+#include "cyw43.h"
+#include "pico/cyw43_arch.h"
+#include "cyw43_ll.h"
+#include "cyw43_stats.h"
+
+#if CYW43_ARCH_DEBUG_ENABLED
+#define CYW43_ARCH_DEBUG(...) printf(__VA_ARGS__)
+#else
+#define CYW43_ARCH_DEBUG(...) ((void)0)
+#endif
+
+static uint32_t country_code = PICO_CYW43_ARCH_DEFAULT_COUNTRY_CODE;
+
+void cyw43_arch_enable_sta_mode() {
+ assert(cyw43_is_initialized(&cyw43_state));
+ cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_STA, true, cyw43_arch_get_country_code());
+}
+
+void cyw43_arch_enable_ap_mode(const char *ssid, const char *password, uint32_t auth) {
+ assert(cyw43_is_initialized(&cyw43_state));
+ cyw43_wifi_ap_set_ssid(&cyw43_state, strlen(ssid), (const uint8_t *) ssid);
+ if (password) {
+ cyw43_wifi_ap_set_password(&cyw43_state, strlen(password), (const uint8_t *) password);
+ cyw43_wifi_ap_set_auth(&cyw43_state, auth);
+ } else {
+ cyw43_wifi_ap_set_auth(&cyw43_state, CYW43_AUTH_OPEN);
+ }
+ cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_AP, true, cyw43_arch_get_country_code());
+}
+
+#if CYW43_ARCH_DEBUG_ENABLED
+// Return a string for the wireless state
+static const char* status_name(int status)
+{
+ switch (status) {
+ case CYW43_LINK_DOWN:
+ return "link down";
+ case CYW43_LINK_JOIN:
+ return "joining";
+ case CYW43_LINK_NOIP:
+ return "no ip";
+ case CYW43_LINK_UP:
+ return "link up";
+ case CYW43_LINK_FAIL:
+ return "link fail";
+ case CYW43_LINK_NONET:
+ return "network fail";
+ case CYW43_LINK_BADAUTH:
+ return "bad auth";
+ }
+ return "unknown";
+}
+#endif
+
+int cyw43_arch_wifi_connect_async(const char *ssid, const char *pw, uint32_t auth) {
+ if (!pw) auth = CYW43_AUTH_OPEN;
+ // Connect to wireless
+ return cyw43_wifi_join(&cyw43_state, strlen(ssid), (const uint8_t *)ssid, pw ? strlen(pw) : 0, (const uint8_t *)pw, auth, NULL, CYW43_ITF_STA);
+}
+
+// Connect to wireless, return with success when an IP address has been assigned
+int cyw43_arch_wifi_connect_until(const char *ssid, const char *pw, uint32_t auth, absolute_time_t until) {
+ int err = cyw43_arch_wifi_connect_async(ssid, pw, auth);
+ if (err) return err;
+
+ int status = CYW43_LINK_UP + 1;
+ while(status >= 0 && status != CYW43_LINK_UP) {
+ int new_status = cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA);
+ if (new_status != status) {
+ status = new_status;
+ CYW43_ARCH_DEBUG("connect status: %s\n", status_name(status));
+ }
+ // in case polling is required
+ cyw43_arch_poll();
+ best_effort_wfe_or_timeout(until);
+ if (time_reached(until)) {
+ return PICO_ERROR_TIMEOUT;
+ }
+ }
+ return status == CYW43_LINK_UP ? 0 : status;
+}
+
+int cyw43_arch_wifi_connect_blocking(const char *ssid, const char *pw, uint32_t auth) {
+ return cyw43_arch_wifi_connect_until(ssid, pw, auth, at_the_end_of_time);
+}
+
+int cyw43_arch_wifi_connect_timeout_ms(const char *ssid, const char *pw, uint32_t auth, uint32_t timeout_ms) {
+ return cyw43_arch_wifi_connect_until(ssid, pw, auth, make_timeout_time_ms(timeout_ms));
+}
+
+// todo maybe add an #ifdef in cyw43_driver
+uint32_t storage_read_blocks(__unused uint8_t *dest, __unused uint32_t block_num, __unused uint32_t num_blocks) {
+ // shouldn't be used
+ panic_unsupported();
+}
+
+// Generate a mac address if one is not set in otp
+void cyw43_hal_generate_laa_mac(__unused int idx, uint8_t buf[6]) {
+ CYW43_DEBUG("Warning. No mac in otp. Generating mac from board id\n");
+ pico_unique_board_id_t board_id;
+ pico_get_unique_board_id(&board_id);
+ memcpy(buf, &board_id.id[2], 6);
+ buf[0] &= (uint8_t)~0x1; // unicast
+ buf[0] |= 0x2; // locally administered
+}
+
+// Return mac address
+void cyw43_hal_get_mac(__unused int idx, uint8_t buf[6]) {
+ // The mac should come from cyw43 otp.
+ // This is loaded into the state after the driver is initialised
+ // cyw43_hal_generate_laa_mac is called by the driver to generate a mac if otp is not set
+ memcpy(buf, cyw43_state.mac, 6);
+}
+
+uint32_t cyw43_arch_get_country_code(void) {
+ return country_code;
+}
+
+int cyw43_arch_init_with_country(uint32_t country) {
+ country_code = country;
+ return cyw43_arch_init();
+}
+
+void cyw43_arch_gpio_put(uint wl_gpio, bool value) {
+ invalid_params_if(CYW43_ARCH, wl_gpio >= CYW43_WL_GPIO_COUNT);
+ cyw43_gpio_set(&cyw43_state, (int)wl_gpio, value);
+}
+
+bool cyw43_arch_gpio_get(uint wl_gpio) {
+ invalid_params_if(CYW43_ARCH, wl_gpio >= CYW43_WL_GPIO_COUNT);
+ bool value = false;
+ cyw43_gpio_get(&cyw43_state, (int)wl_gpio, &value);
+ return value;
+}
diff --git a/src/rp2_common/pico_cyw43_arch/cyw43_arch_freertos.c b/src/rp2_common/pico_cyw43_arch/cyw43_arch_freertos.c
new file mode 100644
index 0000000..88dde6e
--- /dev/null
+++ b/src/rp2_common/pico_cyw43_arch/cyw43_arch_freertos.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+
+#include "pico/cyw43_arch.h"
+
+#include "hardware/gpio.h"
+#include "hardware/irq.h"
+#include "hardware/sync.h"
+
+#include "cyw43_stats.h"
+
+#if CYW43_LWIP
+#include <lwip/tcpip.h>
+#endif
+
+#if PICO_CYW43_ARCH_FREERTOS
+
+// FreeRTOS includes
+#include "FreeRTOS.h"
+#include "timers.h"
+#include "semphr.h"
+
+#if NO_SYS
+#error example_cyw43_arch_frertos_sys requires NO_SYS=0
+#endif
+
+#ifndef CYW43_TASK_PRIORITY
+#define CYW43_TASK_PRIORITY ( tskIDLE_PRIORITY + 4)
+#endif
+
+#ifndef CYW43_SLEEP_CHECK_MS
+#define CYW43_SLEEP_CHECK_MS 50 // How often to run lwip callback
+#endif
+
+#define CYW43_GPIO_IRQ_HANDLER_PRIORITY 0x40
+
+static void signal_cyw43_task(void);
+
+#if !LWIP_TCPIP_CORE_LOCKING_INPUT
+static SemaphoreHandle_t cyw43_mutex;
+#endif
+static TimerHandle_t timer_handle;
+static TaskHandle_t cyw43_task_handle;
+static volatile bool cyw43_task_should_exit;
+static SemaphoreHandle_t cyw43_worker_ran_sem;
+static uint8_t cyw43_core_num;
+
+// Called in low priority pendsv interrupt only to do lwip processing and check cyw43 sleep
+static void periodic_worker(__unused TimerHandle_t handle)
+{
+#if CYW43_USE_STATS
+ static uint32_t counter;
+ if (counter++ % (30000 / LWIP_SYS_CHECK_MS) == 0) {
+ cyw43_dump_stats();
+ }
+#endif
+
+ CYW43_STAT_INC(LWIP_RUN_COUNT);
+ if (cyw43_poll) {
+ if (cyw43_sleep > 0) {
+ if (--cyw43_sleep == 0) {
+ signal_cyw43_task();
+ }
+ }
+ }
+}
+
+void cyw43_await_background_or_timeout_us(uint32_t timeout_us) {
+ // if we are called from within an IRQ, then don't wait (we are only ever called in a polling loop)
+ assert(!portCHECK_IF_IN_ISR());
+ xSemaphoreTake(cyw43_worker_ran_sem, pdMS_TO_TICKS(timeout_us / 1000));
+}
+
+// GPIO interrupt handler to tell us there's cyw43 has work to do
+static void gpio_irq_handler(void)
+{
+ uint32_t events = gpio_get_irq_event_mask(CYW43_PIN_WL_HOST_WAKE);
+ if (events & GPIO_IRQ_LEVEL_HIGH) {
+ // As we use a high level interrupt, it will go off forever until it's serviced
+ // So disable the interrupt until this is done. It's re-enabled again by CYW43_POST_POLL_HOOK
+ // which is called at the end of cyw43_poll_func
+ gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, false);
+ signal_cyw43_task();
+ CYW43_STAT_INC(IRQ_COUNT);
+ }
+}
+
+// Low priority interrupt handler to perform background processing
+static void cyw43_task(__unused void *param) {
+ do {
+ ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
+ if (cyw43_task_should_exit) break;
+ cyw43_thread_enter();
+ if (cyw43_poll) cyw43_poll();
+ cyw43_thread_exit();
+ xSemaphoreGive(cyw43_worker_ran_sem);
+ __sev(); // it is possible regular code is waiting on a WFE on the other core
+ } while (true);
+}
+
+static void tcpip_init_done(void *param) {
+ xSemaphoreGive((SemaphoreHandle_t)param);
+}
+
+int cyw43_arch_init(void) {
+ cyw43_core_num = get_core_num();
+#if configUSE_CORE_AFFINITY && configNUM_CORES > 1
+ TaskHandle_t task_handle = xTaskGetCurrentTaskHandle();
+ UBaseType_t affinity = vTaskCoreAffinityGet(task_handle);
+ // we must bind the main task to one core during init
+ vTaskCoreAffinitySet(task_handle, 1 << portGET_CORE_ID());
+#endif
+#if !LWIP_TCPIP_CORE_LOCKING_INPUT
+ cyw43_mutex = xSemaphoreCreateRecursiveMutex();
+#endif
+ cyw43_init(&cyw43_state);
+ cyw43_worker_ran_sem = xSemaphoreCreateBinary();
+
+#if CYW43_LWIP
+ SemaphoreHandle_t init_sem = xSemaphoreCreateBinary();
+ tcpip_init(tcpip_init_done, init_sem);
+ xSemaphoreTake(init_sem, portMAX_DELAY);
+#endif
+
+ timer_handle = xTimerCreate( "cyw43_sleep_timer", // Just a text name, not used by the kernel.
+ pdMS_TO_TICKS(CYW43_SLEEP_CHECK_MS),
+ pdTRUE, // The timers will auto-reload themselves when they expire.
+ NULL,
+ periodic_worker);
+
+ if (!timer_handle) {
+ return PICO_ERROR_GENERIC;
+ }
+
+ gpio_add_raw_irq_handler_with_order_priority(IO_IRQ_BANK0, gpio_irq_handler, CYW43_GPIO_IRQ_HANDLER_PRIORITY);
+ gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true);
+ irq_set_enabled(IO_IRQ_BANK0, true);
+
+ cyw43_task_should_exit = false;
+ xTaskCreate(cyw43_task, "CYW43 Worker", configMINIMAL_STACK_SIZE, NULL, CYW43_TASK_PRIORITY, &cyw43_task_handle);
+#if configUSE_CORE_AFFINITY && configNUM_CORES > 1
+ // the cyw43 task mus tbe on the same core so it can restore IRQs
+ vTaskCoreAffinitySet(cyw43_task_handle, 1 << portGET_CORE_ID());
+#endif
+
+#if configUSE_CORE_AFFINITY && configNUM_CORES > 1
+ vTaskCoreAffinitySet(task_handle, affinity);
+#endif
+
+ return PICO_OK;
+}
+
+void cyw43_arch_deinit(void) {
+ assert(cyw43_core_num == get_core_num());
+ if (timer_handle) {
+ xTimerDelete(timer_handle, 0);
+ timer_handle = 0;
+ }
+ if (cyw43_task_handle) {
+ cyw43_task_should_exit = true;
+ signal_cyw43_task();
+ }
+ gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, false);
+ gpio_remove_raw_irq_handler(IO_IRQ_BANK0, gpio_irq_handler);
+}
+
+void cyw43_post_poll_hook(void) {
+ assert(cyw43_core_num == get_core_num());
+ gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true);
+}
+
+// This is called in the gpio and low_prio_irq interrupts and on either core
+static void signal_cyw43_task(void) {
+ if (cyw43_task_handle) {
+ if (portCHECK_IF_IN_ISR()) {
+ vTaskNotifyGiveFromISR(cyw43_task_handle, NULL);
+ } else {
+ xTaskNotifyGive(cyw43_task_handle);
+ }
+ }
+}
+
+void cyw43_schedule_internal_poll_dispatch(void (*func)(void)) {
+ assert(func == cyw43_poll);
+ signal_cyw43_task();
+}
+
+static int nesting;
+// Prevent background processing in pensv and access by the other core
+// These methods are called in pensv context and on either core
+// They can be called recursively
+void cyw43_thread_enter(void) {
+ // Lock the other core and stop low_prio_irq running
+ assert(!portCHECK_IF_IN_ISR());
+#if LWIP_TCPIP_CORE_LOCKING_INPUT
+ // we must share their mutex otherwise we can get deadlocks with two different recursive mutexes
+ LOCK_TCPIP_CORE();
+#else
+ xSemaphoreTakeRecursive(cyw43_mutex, portMAX_DELAY);
+#endif
+ nesting++;
+}
+
+#ifndef NDEBUG
+void cyw43_thread_lock_check(void) {
+ // Lock the other core and stop low_prio_irq running
+#if LWIP_TCPIP_CORE_LOCKING_INPUT
+ assert(xSemaphoreGetMutexHolder(lock_tcpip_core.mut) == xTaskGetCurrentTaskHandle());
+#else
+ assert(xSemaphoreGetMutexHolder(cyw43_mutex) == xTaskGetCurrentTaskHandle());
+#endif
+}
+#endif
+
+// Re-enable background processing
+void cyw43_thread_exit(void) {
+ // Run low_prio_irq if needed
+ --nesting;
+#if LWIP_TCPIP_CORE_LOCKING_INPUT
+ // we must share their mutex otherwise we can get deadlocks with two different recursive mutexes
+ UNLOCK_TCPIP_CORE();
+#else
+ xSemaphoreGiveRecursive(cyw43_mutex);
+#endif
+
+ if (!nesting && cyw43_task_handle != xTaskGetCurrentTaskHandle())
+ signal_cyw43_task();
+}
+
+void cyw43_delay_ms(uint32_t ms) {
+ assert(!portCHECK_IF_IN_ISR());
+ vTaskDelay(pdMS_TO_TICKS(ms));
+}
+
+void cyw43_delay_us(uint32_t us) {
+ if (us >= 1000) {
+ cyw43_delay_ms(us / 1000);
+ } else {
+ vTaskDelay(1);
+ }
+}
+
+void cyw43_arch_poll() {
+}
+
+#endif
\ No newline at end of file
diff --git a/src/rp2_common/pico_cyw43_arch/cyw43_arch_poll.c b/src/rp2_common/pico_cyw43_arch/cyw43_arch_poll.c
new file mode 100644
index 0000000..e71f86a
--- /dev/null
+++ b/src/rp2_common/pico_cyw43_arch/cyw43_arch_poll.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+#include "hardware/gpio.h"
+#include "hardware/irq.h"
+#include "pico/sem.h"
+#include "pico/cyw43_arch.h"
+#include "cyw43_stats.h"
+
+#if PICO_CYW43_ARCH_POLL
+#include <lwip/init.h>
+#include "lwip/timeouts.h"
+
+#if CYW43_LWIP && !NO_SYS
+#error PICO_CYW43_ARCH_POLL requires lwIP NO_SYS=1
+#endif
+
+#define CYW43_GPIO_IRQ_HANDLER_PRIORITY 0x40
+
+#ifndef NDEBUG
+uint8_t cyw43_core_num;
+#endif
+
+bool cyw43_poll_required;
+
+// GPIO interrupt handler to tell us there's cyw43 has work to do
+static void gpio_irq_handler(void)
+{
+ uint32_t events = gpio_get_irq_event_mask(CYW43_PIN_WL_HOST_WAKE);
+ if (events & GPIO_IRQ_LEVEL_HIGH) {
+ // As we use a high level interrupt, it will go off forever until it's serviced
+ // So disable the interrupt until this is done. It's re-enabled again by CYW43_POST_POLL_HOOK
+ // which is called at the end of cyw43_poll_func
+ gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, false);
+ // also clear the force bit which we use to programmatically cause this handler to fire (on the right core)
+ io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ?
+ &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
+ hw_clear_bits(&irq_ctrl_base->intf[CYW43_PIN_WL_HOST_WAKE/8], GPIO_IRQ_LEVEL_HIGH << (4 * (CYW43_PIN_WL_HOST_WAKE & 7)));
+ cyw43_schedule_internal_poll_dispatch(cyw43_poll);
+ CYW43_STAT_INC(IRQ_COUNT);
+ }
+}
+
+void cyw43_post_poll_hook(void) {
+ gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true);
+}
+
+int cyw43_arch_init(void) {
+#ifndef NDEBUG
+ cyw43_core_num = (uint8_t)get_core_num();
+#endif
+ cyw43_init(&cyw43_state);
+ static bool done_lwip_init;
+ if (!done_lwip_init) {
+ lwip_init();
+ done_lwip_init = true;
+ }
+ gpio_add_raw_irq_handler_with_order_priority(IO_IRQ_BANK0, gpio_irq_handler, CYW43_GPIO_IRQ_HANDLER_PRIORITY);
+ gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true);
+ irq_set_enabled(IO_IRQ_BANK0, true);
+ return 0;
+}
+
+void cyw43_arch_deinit(void) {
+ gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, false);
+ gpio_remove_raw_irq_handler(IO_IRQ_BANK0, gpio_irq_handler);
+ cyw43_deinit(&cyw43_state);
+}
+
+
+void cyw43_schedule_internal_poll_dispatch(__unused void (*func)(void)) {
+ cyw43_poll_required = true;
+}
+
+void cyw43_arch_poll(void)
+{
+ CYW43_STAT_INC(LWIP_RUN_COUNT);
+ sys_check_timeouts();
+ if (cyw43_poll) {
+ if (cyw43_sleep > 0) {
+ // todo check this; but we don't want to advance too quickly
+ static absolute_time_t last_poll_time;
+ absolute_time_t current = get_absolute_time();
+ if (absolute_time_diff_us(last_poll_time, current) > 1000) {
+ if (--cyw43_sleep == 0) {
+ cyw43_poll_required = 1;
+ }
+ last_poll_time = current;
+ }
+ }
+ // todo graham i removed this because otherwise polling can do nothing during connect.
+ // in the polling only case, the caller is responsible for throttling how often they call anyway.
+ // The alternative would be to have the call to this function from the init set the poll_required flag first
+// if (cyw43_poll_required) {
+ cyw43_poll();
+// cyw43_poll_required = false;
+// }
+ }
+}
+
+#ifndef NDEBUG
+void cyw43_thread_check() {
+ if (__get_current_exception() || get_core_num() != cyw43_core_num) {
+ panic("cyw43_thread_lock_check failed");
+ }
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/src/rp2_common/pico_cyw43_arch/cyw43_arch_threadsafe_background.c b/src/rp2_common/pico_cyw43_arch/cyw43_arch_threadsafe_background.c
new file mode 100644
index 0000000..a3dde74
--- /dev/null
+++ b/src/rp2_common/pico_cyw43_arch/cyw43_arch_threadsafe_background.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+
+#include "pico/cyw43_arch.h"
+#include "pico/mutex.h"
+#include "pico/sem.h"
+
+#include "hardware/gpio.h"
+#include "hardware/irq.h"
+
+#include "cyw43_stats.h"
+
+#if CYW43_LWIP
+#include <lwip/init.h>
+#include "lwip/timeouts.h"
+#endif
+
+// note same code
+#if PICO_CYW43_ARCH_THREADSAFE_BACKGROUND
+
+#if PICO_CYW43_ARCH_THREADSAFE_BACKGROUND && CYW43_LWIP && !NO_SYS
+#error PICO_CYW43_ARCH_THREADSAFE_BACKGROUND requires lwIP NO_SYS=1
+#endif
+#if PICO_CYW43_ARCH_THREADSAFE_BACKGROUND && CYW43_LWIP && MEM_LIBC_MALLOC
+#error MEM_LIBC_MALLOC is incompatible with PICO_CYW43_ARCH_THREADSAFE_BACKGROUND
+#endif
+// todo right now we are now always doing a cyw43_dispatch along with a lwip one when hopping cores in low_prio_irq_schedule_dispatch
+
+#ifndef CYW43_SLEEP_CHECK_MS
+#define CYW43_SLEEP_CHECK_MS 50 // How often to run lwip callback
+#endif
+static alarm_id_t periodic_alarm = -1;
+
+static inline uint recursive_mutex_enter_count(recursive_mutex_t *mutex) {
+ return mutex->enter_count;
+}
+
+static inline lock_owner_id_t recursive_mutex_owner(recursive_mutex_t *mutex) {
+ return mutex->owner;
+}
+
+#define CYW43_GPIO_IRQ_HANDLER_PRIORITY 0x40
+
+enum {
+ CYW43_DISPATCH_SLOT_CYW43 = 0,
+ CYW43_DISPATCH_SLOT_ADAPTER,
+ CYW43_DISPATCH_SLOT_ENUM_COUNT
+};
+#ifndef CYW43_DISPATCH_SLOT_COUNT
+#define CYW43_DISPATCH_SLOT_COUNT CYW43_DISPATCH_SLOT_ENUM_COUNT
+#endif
+
+typedef void (*low_prio_irq_dispatch_t)(void);
+static void low_prio_irq_schedule_dispatch(size_t slot, low_prio_irq_dispatch_t f);
+
+static uint8_t cyw43_core_num;
+#ifndef NDEBUG
+static bool in_low_priority_irq;
+#endif
+static uint8_t low_priority_irq_num;
+static bool low_priority_irq_missed;
+static low_prio_irq_dispatch_t low_priority_irq_dispatch_slots[CYW43_DISPATCH_SLOT_COUNT];
+static recursive_mutex_t cyw43_mutex;
+semaphore_t cyw43_irq_sem;
+
+// Called in low priority pendsv interrupt only to do lwip processing and check cyw43 sleep
+static void periodic_worker(void)
+{
+#if CYW43_USE_STATS
+ static uint32_t counter;
+ if (counter++ % (30000 / LWIP_SYS_CHECK_MS) == 0) {
+ cyw43_dump_stats();
+ }
+#endif
+
+ CYW43_STAT_INC(LWIP_RUN_COUNT);
+#if CYW43_LWIP
+ sys_check_timeouts();
+#endif
+ if (cyw43_poll) {
+ if (cyw43_sleep > 0) {
+ if (--cyw43_sleep == 0) {
+ low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
+ }
+ }
+ }
+}
+
+// Regular callback to get lwip to check for timeouts
+static int64_t periodic_alarm_handler(__unused alarm_id_t id, __unused void *user_data)
+{
+ // Do lwip processing in low priority pendsv interrupt
+ low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_ADAPTER, periodic_worker);
+ return CYW43_SLEEP_CHECK_MS * 1000;
+}
+
+void cyw43_await_background_or_timeout_us(uint32_t timeout_us) {
+ // if we are called from within an IRQ, then don't wait (we are only ever called in a polling loop)
+ if (!__get_current_exception()) {
+ sem_acquire_timeout_us(&cyw43_irq_sem, timeout_us);
+ }
+}
+
+// GPIO interrupt handler to tell us there's cyw43 has work to do
+static void gpio_irq_handler(void)
+{
+ uint32_t events = gpio_get_irq_event_mask(CYW43_PIN_WL_HOST_WAKE);
+ if (events & GPIO_IRQ_LEVEL_HIGH) {
+ // As we use a high level interrupt, it will go off forever until it's serviced
+ // So disable the interrupt until this is done. It's re-enabled again by CYW43_POST_POLL_HOOK
+ // which is called at the end of cyw43_poll_func
+ gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, false);
+ // also clear the force bit which we use to progratically cause this handler to fire (on the right core)
+ io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ?
+ &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
+ hw_clear_bits(&irq_ctrl_base->intf[CYW43_PIN_WL_HOST_WAKE/8], GPIO_IRQ_LEVEL_HIGH << (4 * (CYW43_PIN_WL_HOST_WAKE & 7)));
+ low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
+ CYW43_STAT_INC(IRQ_COUNT);
+ }
+}
+
+// Low priority interrupt handler to perform background processing
+static void low_priority_irq_handler(void) {
+ assert(cyw43_core_num == get_core_num());
+ if (recursive_mutex_try_enter(&cyw43_mutex, NULL)) {
+ if (recursive_mutex_enter_count(&cyw43_mutex) != 1) {
+ low_priority_irq_missed = true;
+ CYW43_STAT_INC(PENDSV_DISABLED_COUNT);
+ } else {
+ CYW43_STAT_INC(PENDSV_RUN_COUNT);
+#ifndef NDEBUG
+ in_low_priority_irq = true;
+#endif
+ for (size_t i = 0; i < count_of(low_priority_irq_dispatch_slots); i++) {
+ if (low_priority_irq_dispatch_slots[i] != NULL) {
+ low_prio_irq_dispatch_t f = low_priority_irq_dispatch_slots[i];
+ low_priority_irq_dispatch_slots[i] = NULL;
+ f();
+ }
+ }
+#ifndef NDEBUG
+ in_low_priority_irq = false;
+#endif
+ }
+ recursive_mutex_exit(&cyw43_mutex);
+ } else {
+ CYW43_STAT_INC(PENDSV_DISABLED_COUNT);
+ low_priority_irq_missed = true;
+ }
+ sem_release(&cyw43_irq_sem);
+}
+
+static bool low_prio_irq_init(uint8_t priority) {
+ assert(get_core_num() == cyw43_core_num);
+ int irq = user_irq_claim_unused(false);
+ if (irq < 0) return false;
+ low_priority_irq_num = (uint8_t) irq;
+ irq_set_exclusive_handler(low_priority_irq_num, low_priority_irq_handler);
+ irq_set_enabled(low_priority_irq_num, true);
+ irq_set_priority(low_priority_irq_num, priority);
+ return true;
+}
+
+static void low_prio_irq_deinit(void) {
+ if (low_priority_irq_num > 0) {
+ irq_set_enabled(low_priority_irq_num, false);
+ irq_remove_handler(low_priority_irq_num, low_priority_irq_handler);
+ user_irq_unclaim(low_priority_irq_num);
+ low_priority_irq_num = 0;
+ }
+}
+
+int cyw43_arch_init(void) {
+ cyw43_core_num = get_core_num();
+ recursive_mutex_init(&cyw43_mutex);
+ cyw43_init(&cyw43_state);
+ sem_init(&cyw43_irq_sem, 0, 1);
+
+ // Start regular lwip callback to handle timeouts
+ periodic_alarm = add_alarm_in_us(CYW43_SLEEP_CHECK_MS * 1000, periodic_alarm_handler, NULL, true);
+ if (periodic_alarm < 0) {
+ return PICO_ERROR_GENERIC;
+ }
+
+ gpio_add_raw_irq_handler_with_order_priority(IO_IRQ_BANK0, gpio_irq_handler, CYW43_GPIO_IRQ_HANDLER_PRIORITY);
+ gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true);
+ irq_set_enabled(IO_IRQ_BANK0, true);
+
+#if CYW43_LWIP
+ lwip_init();
+#endif
+ // start low priority handler (no background work is done before this)
+ bool ok = low_prio_irq_init(PICO_LOWEST_IRQ_PRIORITY);
+ if (!ok) {
+ cyw43_arch_deinit();
+ return PICO_ERROR_GENERIC;
+ }
+ return PICO_OK;
+}
+
+void cyw43_arch_deinit(void) {
+ if (periodic_alarm >= 0) {
+ cancel_alarm(periodic_alarm);
+ periodic_alarm = -1;
+ }
+ gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, false);
+ gpio_remove_raw_irq_handler(IO_IRQ_BANK0, gpio_irq_handler);
+ low_prio_irq_deinit();
+}
+
+void cyw43_post_poll_hook(void) {
+ gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true);
+}
+
+// This is called in the gpio and low_prio_irq interrupts and on either core
+static void low_prio_irq_schedule_dispatch(size_t slot, low_prio_irq_dispatch_t f) {
+ assert(slot < count_of(low_priority_irq_dispatch_slots));
+ low_priority_irq_dispatch_slots[slot] = f;
+ if (cyw43_core_num == get_core_num()) {
+ //on same core, can dispatch directly
+ irq_set_pending(low_priority_irq_num);
+ } else {
+ // on wrong core, so force via GPIO IRQ which itself calls this method for the CYW43 slot.
+ // since the CYW43 slot always uses the same function, this is fine with the addition of an
+ // extra (but harmless) CYW43 slot call when another SLOT is invoked.
+ // We could do better, but would have to track why the IRQ was called.
+ io_irq_ctrl_hw_t *irq_ctrl_base = cyw43_core_num ?
+ &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
+ hw_set_bits(&irq_ctrl_base->intf[CYW43_PIN_WL_HOST_WAKE/8], GPIO_IRQ_LEVEL_HIGH << (4 * (CYW43_PIN_WL_HOST_WAKE & 7)));
+ }
+}
+
+void cyw43_schedule_internal_poll_dispatch(void (*func)(void)) {
+ low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, func);
+}
+
+// Prevent background processing in pensv and access by the other core
+// These methods are called in pensv context and on either core
+// They can be called recursively
+void cyw43_thread_enter(void) {
+ // Lock the other core and stop low_prio_irq running
+ recursive_mutex_enter_blocking(&cyw43_mutex);
+}
+
+#ifndef NDEBUG
+void cyw43_thread_lock_check(void) {
+ // Lock the other core and stop low_prio_irq running
+ if (recursive_mutex_enter_count(&cyw43_mutex) < 1 || recursive_mutex_owner(&cyw43_mutex) != lock_get_caller_owner_id()) {
+ panic("cyw43_thread_lock_check failed");
+ }
+}
+#endif
+
+// Re-enable background processing
+void cyw43_thread_exit(void) {
+ // Run low_prio_irq if needed
+ if (1 == recursive_mutex_enter_count(&cyw43_mutex)) {
+ // note the outer release of the mutex is not via cyw43_exit in the low_priority_irq case (it is a direct mutex exit)
+ assert(!in_low_priority_irq);
+// if (low_priority_irq_missed) {
+// low_priority_irq_missed = false;
+ if (low_priority_irq_dispatch_slots[CYW43_DISPATCH_SLOT_CYW43]) {
+ low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
+ }
+// }
+ }
+ recursive_mutex_exit(&cyw43_mutex);
+}
+
+
+static void cyw43_delay_until(absolute_time_t until) {
+ // sleep can be called in IRQs, so there's not much we can do there
+ if (__get_current_exception()) {
+ busy_wait_until(until);
+ } else {
+ sleep_until(until);
+ }
+}
+
+void cyw43_delay_ms(uint32_t ms) {
+ cyw43_delay_until(make_timeout_time_ms(ms));
+}
+
+void cyw43_delay_us(uint32_t us) {
+ cyw43_delay_until(make_timeout_time_us(us));
+}
+
+void cyw43_arch_poll() {
+ // should not be necessary
+// if (cyw43_poll) {
+// low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
+// }
+}
+
+#if !CYW43_LWIP
+static void no_lwip_fail() {
+ panic("You cannot use IP with pico_cyw43_arch_none");
+}
+void cyw43_cb_tcpip_init(cyw43_t *self, int itf) {
+}
+void cyw43_cb_tcpip_deinit(cyw43_t *self, int itf) {
+}
+void cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf) {
+ no_lwip_fail();
+}
+void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {
+ no_lwip_fail();
+}
+void cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf) {
+ no_lwip_fail();
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/src/rp2_common/pico_cyw43_arch/include/cyw43_configport.h b/src/rp2_common/pico_cyw43_arch/include/cyw43_configport.h
new file mode 100644
index 0000000..7827c81
--- /dev/null
+++ b/src/rp2_common/pico_cyw43_arch/include/cyw43_configport.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// This header is included by cyw43_driver to setup its environment
+
+#ifndef _CYW43_CONFIGPORT_H
+#define _CYW43_CONFIGPORT_H
+
+#include "pico.h"
+
+#ifdef PICO_CYW43_ARCH_HEADER
+#include __XSTRING(PICO_CYW43_ARCH_HEADER)
+#else
+#if PICO_CYW43_ARCH_POLL
+#include "pico/cyw43_arch/arch_poll.h"
+#elif PICO_CYW43_ARCH_THREADSAFE_BACKGROUND
+#include "pico/cyw43_arch/arch_threadsafe_background.h"
+#elif PICO_CYW43_ARCH_FREERTOS
+#include "pico/cyw43_arch/arch_freertos.h"
+#else
+#error must specify support pico_cyw43_arch architecture type or set PICO_CYW43_ARCH_HEADER
+#endif
+#endif
+
+#ifndef CYW43_HOST_NAME
+#define CYW43_HOST_NAME "PicoW"
+#endif
+
+#ifndef CYW43_GPIO
+#define CYW43_GPIO 1
+#endif
+
+#ifndef CYW43_LOGIC_DEBUG
+#define CYW43_LOGIC_DEBUG 0
+#endif
+
+#ifndef CYW43_USE_OTP_MAC
+#define CYW43_USE_OTP_MAC 1
+#endif
+
+#ifndef CYW43_NO_NETUTILS
+#define CYW43_NO_NETUTILS 1
+#endif
+
+#ifndef CYW43_IOCTL_TIMEOUT_US
+#define CYW43_IOCTL_TIMEOUT_US 1000000
+#endif
+
+#ifndef CYW43_USE_STATS
+#define CYW43_USE_STATS 0
+#endif
+
+// todo should this be user settable?
+#ifndef CYW43_HAL_MAC_WLAN0
+#define CYW43_HAL_MAC_WLAN0 0
+#endif
+
+#ifndef STATIC
+#define STATIC static
+#endif
+
+#ifndef CYW43_USE_SPI
+#define CYW43_USE_SPI 1
+#endif
+
+#ifndef CYW43_SPI_PIO
+#define CYW43_SPI_PIO 1
+#endif
+
+#endif
\ No newline at end of file
diff --git a/src/rp2_common/pico_cyw43_arch/include/pico/cyw43_arch.h b/src/rp2_common/pico_cyw43_arch/include/pico/cyw43_arch.h
new file mode 100644
index 0000000..8d6a628
--- /dev/null
+++ b/src/rp2_common/pico_cyw43_arch/include/pico/cyw43_arch.h
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_CYW43_ARCH_H
+#define _PICO_CYW43_ARCH_H
+
+#include "pico.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "cyw43.h"
+#include "cyw43_country.h"
+
+/**
+ * \defgroup cyw43_driver cyw43_driver
+ * \ingroup pico_cyw43_arch
+ * \brief Driver used for Pico W wireless
+*/
+
+/**
+ * \defgroup cyw43_ll cyw43_ll
+ * \ingroup cyw43_driver
+ * \brief Low Level CYW43 driver interface
+*/
+
+/** \file pico/cyw43_arch.h
+ * \defgroup pico_cyw43_arch pico_cyw43_arch
+ *
+ * Architecture for integrating the CYW43 driver (for the wireless on Pico W) and lwIP (for TCP/IP stack) into the SDK. It is also necessary for accessing the on-board LED on Pico W
+ *
+ * Both the low level \c cyw43_driver and the lwIP stack require periodic servicing, and have limitations
+ * on whether they can be called from multiple cores/threads.
+ *
+ * \c pico_cyw43_arch attempts to abstract these complications into several behavioral groups:
+ *
+ * * \em 'poll' - This not multi-core/IRQ safe, and requires the user to call \ref cyw43_arch_poll periodically from their main loop
+ * * \em 'thread_safe_background' - This is multi-core/thread/task safe, and maintenance of the driver and TCP/IP stack is handled automatically in the background
+ *
+ * As of right now, lwIP is the only supported TCP/IP stack, however the use of \c pico_cyw43_arch is intended to be independent of
+ * the particular TCP/IP stack used (and possibly Bluetooth stack used) in the future. For this reason, the integration of lwIP
+ * is handled in the base (\c pico_cyw43_arch) library based on the #define \ref CYW43_LWIP used by the \c cyw43_driver.
+ *
+ * Whilst you can use the \c pico_cyw43_arch library directly and specify \ref CYW$#_LWIP (and other defines) yourself, several
+ * other libraries are made available to the build which aggregate the defines and other dependencies for you:
+ *
+ * * \b pico_cyw43_arch_lwip_poll - For using the RAW lwIP API (in `NO_SYS=1` mode) without any background processing or multi-core/thread safety.
+ *
+ * The user must call \ref pico_cyw43_poll periodically from their main loop.
+ *
+ * This wrapper library:
+ * - Sets \c CYW43_LWIP=1 to enable lwIP support in \c pico_cyw43_arch and \c cyw43_driver.
+ * - Sets \c PICO_CYW43_ARCH_POLL=1 to select the polling behavior.
+ * - Adds the \c pico_lwip as a dependency to pull in lwIP.
+ *
+ * * \b pico_cyw43_arch_lwip_threadsafe_background - For using the RAW lwIP API (in `NO_SYS=1` mode) with multi-core/thread safety, and automatic servicing of the \c cyw43_driver and
+ * lwIP in background.
+ *
+ * Calls into the \c cyw43_driver high level API (cyw43.h) may be made from either core or from lwIP callbacks, however calls into lwIP (which
+ * is not thread-safe) other than those made from lwIP callbacks, must be bracketed with \ref cyw43_arch_lwip_begin and \ref cyw43_arch_lwip_end. It is fine to bracket
+ * calls made from within lwIP callbacks too; you just don't have to.
+ *
+ * \note lwIP callbacks happen in a (low priority) IRQ context (similar to an alarm callback), so care should be taken when interacting
+ * with other code.
+ *
+ * This wrapper library:
+ * - Sets \c CYW43_LWIP=1 to enable lwIP support in \c pico_cyw43_arch and \c cyw43_driver
+ * - Sets \c PICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 to select the thread-safe/non-polling behavior.
+ * - Adds the pico_lwip as a dependency to pull in lwIP.
+ *
+ *
+ * This library \em can also be used under the RP2040 port of FreeRTOS with lwIP in `NO_SYS=1` mode (allowing you to call \c cyw43_driver APIs
+ * from any task, and to call lwIP from lwIP callbacks, or from any task if you bracket the calls with \ref cyw43_arch_lwip_begin and \ref cyw43_arch_lwip_end. Again, you should be
+ * careful about what you do in lwIP callbacks, as you cannot call most FreeRTOS APIs from within an IRQ context. Unless you have good reason, you should probably
+ * use the full FreeRTOS integration (with `NO_SYS=0`) provided by \c pico_cyw43_arch_lwip_sys_freertos.
+ *
+ * * \b pico_cyw43_arch_lwip_sys_freertos - For using the full lwIP API including blocking sockets in OS (`NO_SYS=0`) mode, along with with multi-core/task/thread safety, and automatic servicing of the \c cyw43_driver and
+ * the lwIP stack.
+ *
+ * This wrapper library:
+ * - Sets \c CYW43_LWIP=1 to enable lwIP support in \c pico_cyw43_arch and \c cyw43_driver.
+ * - Sets \c PICO_CYW43_ARCH_FREERTOS=1 to select the NO_SYS=0 lwip/FreeRTOS integration
+ * - Sets \c LWIP_PROVIDE_ERRNO=1 to provide error numbers needed for compilation without an OS
+ * - Adds the \c pico_lwip as a dependency to pull in lwIP.
+ * - Adds the lwIP/FreeRTOS code from lwip-contrib (in the contrib directory of lwIP)
+ *
+ * Calls into the \c cyw43_driver high level API (cyw43.h) may be made from any task or from lwIP callbacks, but not from IRQs. Calls into the lwIP RAW API (which is not thread safe)
+ * must be bracketed with \ref cyw43_arch_lwip_begin and \ref cyw43_arch_lwip_end. It is fine to bracket calls made from within lwIP callbacks too; you just don't have to.
+ *
+ * \note this wrapper library requires you to link FreeRTOS functionality with your application yourself.
+ *
+ * * \b pico_cyw43_arch_none - If you do not need the TCP/IP stack but wish to use the on-board LED.
+ *
+ * This wrapper library:
+ * - Sets \c CYW43_LWIP=0 to disable lwIP support in \c pico_cyw43_arch and \c cyw43_driver
+ */
+
+// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_CYW43_ARCH, Enable/disable assertions in the pico_cyw43_arch module, type=bool, default=0, group=pico_cyw43_arch
+#ifndef PARAM_ASSERTIONS_ENABLED_CYW43_ARCH
+#define PARAM_ASSERTIONS_ENABLED_CYW43_ARCH 0
+#endif
+
+// PICO_CONFIG: CYW43_ARCH_DEBUG_ENABLED, Enable/disable some debugging output in the pico_cyw43_arch module, type=bool, default=1 in debug builds, group=pico_cyw43_arch
+#ifndef CYW43_ARCH_DEBUG_ENABLED
+#ifndef NDEBUG
+#define CYW43_ARCH_DEBUG_ENABLED 1
+#else
+#define CYW43_ARCH_DEBUG_ENABLED 0
+#endif
+#endif
+
+// PICO_CONFIG: PICO_CYW43_ARCH_DEFAULT_COUNTRY_CODE, Default country code for the cyw43 wireless driver, default=CYW43_COUNTRY_WORLDWIDE, group=pico_cyw43_arch
+#ifndef PICO_CYW43_ARCH_DEFAULT_COUNTRY_CODE
+#define PICO_CYW43_ARCH_DEFAULT_COUNTRY_CODE CYW43_COUNTRY_WORLDWIDE
+#endif
+
+/*!
+ * \brief Initialize the CYW43 architecture
+ * \ingroup pico_cyw43_arch
+ *
+ * This method initializes the `cyw43_driver` code and initializes the lwIP stack (if it
+ * was enabled at build time). This method must be called prior to using any other \c pico_cyw43_arch,
+ * \cyw43_driver or lwIP functions.
+ *
+ * \note this method initializes wireless with a country code of \c PICO_CYW43_ARCH_DEFAULT_COUNTRY_CODE
+ * which defaults to \c CYW43_COUNTRY_WORLDWIDE. Worldwide settings may not give the best performance; consider
+ * setting PICO_CYW43_ARCH_DEFAULT_COUNTRY_CODE to a different value or calling \ref cyw43_arch_init_with_country
+ * \return 0 if the initialization is successful, an error code otherwise \see pico_error_codes
+ */
+int cyw43_arch_init(void);
+
+/*!
+ * \brief Initialize the CYW43 architecture for use in a specific country
+ * \ingroup pico_cyw43_arch
+ *
+ * This method initializes the `cyw43_driver` code and initializes the lwIP stack (if it
+ * was enabled at build time). This method must be called prior to using any other \c pico_cyw43_arch,
+ * \cyw43_driver or lwIP functions.
+ *
+ * \param country the country code to use (see \ref CYW43_COUNTRY_)
+ * \return 0 if the initialization is successful, an error code otherwise \see pico_error_codes
+ */
+int cyw43_arch_init_with_country(uint32_t country);
+
+/*!
+ * \brief Enables Wi-Fi STA (Station) mode.
+ * \ingroup pico_cyw43_arch
+ *
+ * This enables the Wi-Fi in \emStation mode such that connections can be made to other Wi-Fi Access Points
+ */
+void cyw43_arch_enable_sta_mode(void);
+
+/*!
+ * \brief Enables Wi-Fi AP (Access point) mode.
+ * \ingroup pico_cyw43_arch
+ *
+ * This enables the Wi-Fi in \em Access \em Point mode such that connections can be made to the device by other Wi-Fi clients
+ * \param ssid the name for the access point
+ * \param password the password to use or NULL for no password.
+ * \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
+ * \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
+ */
+void cyw43_arch_enable_ap_mode(const char *ssid, const char *password, uint32_t auth);
+
+/*!
+ * \brief De-initialize the CYW43 architecture
+ * \ingroup pico_cyw43_arch
+ *
+ * This method de-initializes the `cyw43_driver` code and de-initializes the lwIP stack (if it
+ * was enabled at build time). Note this method should always be called from the same core (or RTOS
+ * task, depending on the environment) as \ref cyw43_arch_init.
+ */
+void cyw43_arch_deinit(void);
+
+/*!
+ * \brief Attempt to connect to a wireless access point, blocking until the network is joined or a failure is detected.
+ * \ingroup pico_cyw43_arch
+ *
+ * \param ssid the network name to connect to
+ * \param password the network password or NULL if there is no password required
+ * \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
+ * \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
+ *
+ * \return 0 if the initialization is successful, an error code otherwise \see pico_error_codes
+ */
+int cyw43_arch_wifi_connect_blocking(const char *ssid, const char *pw, uint32_t auth);
+
+/*!
+ * \brief Attempt to connect to a wireless access point, blocking until the network is joined, a failure is detected or a timeout occurs
+ * \ingroup pico_cyw43_arch
+ *
+ * \param ssid the network name to connect to
+ * \param password the network password or NULL if there is no password required
+ * \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
+ * \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
+ *
+ * \return 0 if the initialization is successful, an error code otherwise \see pico_error_codes
+ */
+int cyw43_arch_wifi_connect_timeout_ms(const char *ssid, const char *pw, uint32_t auth, uint32_t timeout);
+
+/*!
+ * \brief Start attempting to connect to a wireless access point
+ * \ingroup pico_cyw43_arch
+ *
+ * This method tells the CYW43 driver to start connecting to an access point. You should subsequently check the
+ * status by calling \ref cyw43_wifi_link_status.
+ *
+ * \param ssid the network name to connect to
+ * \param password the network password or NULL if there is no password required
+ * \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
+ * \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
+ *
+ * \return 0 if the scan was started successfully, an error code otherwise \see pico_error_codes
+ */
+int cyw43_arch_wifi_connect_async(const char *ssid, const char *pw, uint32_t auth);
+
+/*!
+ * \brief Return the country code used to initialize cyw43_arch
+ * \ingroup pico_cyw43_arch
+ *
+ * \return the country code (see \ref CYW43_COUNTRY_)
+ */
+uint32_t cyw43_arch_get_country_code(void);
+
+/*!
+ * \brief Set a GPIO pin on the wireless chip to a given value
+ * \ingroup pico_cyw43_arch
+ * \note this method does not check for errors setting the GPIO. You can use the lower level \ref cyw43_gpio_set instead if you wish
+ * to check for errors.
+ *
+ * \param wl_gpio the GPIO number on the wireless chip
+ * \param value true to set the GPIO, false to clear it.
+ */
+void cyw43_arch_gpio_put(uint wl_gpio, bool value);
+
+/*!
+ * \brief Read the value of a GPIO pin on the wireless chip
+ * \ingroup pico_cyw43_arch
+ * \note this method does not check for errors setting the GPIO. You can use the lower level \ref cyw43_gpio_get instead if you wish
+ * to check for errors.
+ *
+ * \param wl_gpio the GPIO number on the wireless chip
+ * \return true if the GPIO is high, false otherwise
+ */
+bool cyw43_arch_gpio_get(uint wl_gpio);
+
+/*!
+ * \brief Perform any processing required by the \c cyw43_driver or the TCP/IP stack
+ * \ingroup pico_cyw43_arch
+ *
+ * This method must be called periodically from the main loop when using a
+ * \em polling style \c pico_cyw43_arch (e.g. \c pico_cyw43_arch_lwip_poll ). It
+ * may be called in other styles, but it is unnecessary to do so.
+ */
+void cyw43_arch_poll(void);
+
+/*!
+ * \fn cyw43_arch_lwip_begin
+ * \brief Acquire any locks required to call into lwIP
+ * \ingroup pico_cyw43_arch
+ *
+ * The lwIP API is not thread safe. You should surround calls into the lwIP API
+ * with calls to this method and \ref cyw43_arch_lwip_end. Note these calls are not
+ * necessary (but harmless) when you are calling back into the lwIP API from an lwIP callback.
+ * If you are using single-core polling only (pico_cyw43_arch_poll) then these calls are no-ops
+ * anyway it is good practice to call them anyway where they are necessary.
+ *
+ * \sa cyw43_arch_lwip_end
+ * \sa cyw43_arch_lwip_protect
+ */
+
+/*!
+ * \fn void cyw43_arch_lwip_end(void)
+ * \brief Release any locks required for calling into lwIP
+ * \ingroup pico_cyw43_arch
+ *
+ * The lwIP API is not thread safe. You should surround calls into the lwIP API
+ * with calls to \ref cyw43_arch_lwip_begin and this method. Note these calls are not
+ * necessary (but harmless) when you are calling back into the lwIP API from an lwIP callback.
+ * If you are using single-core polling only (pico_cyw43_arch_poll) then these calls are no-ops
+ * anyway it is good practice to call them anyway where they are necessary.
+ *
+ * \sa cyw43_arch_lwip_begin
+ * \sa cyw43_arch_lwip_protect
+ */
+
+/*!
+ * \fn int cyw43_arch_lwip_protect(int (*func)(void *param), void *param)
+ * \brief sad Release any locks required for calling into lwIP
+ * \ingroup pico_cyw43_arch
+ *
+ * The lwIP API is not thread safe. You can use this method to wrap a function
+ * with any locking required to call into the lwIP API. If you are using
+ * single-core polling only (pico_cyw43_arch_poll) then there are no
+ * locks to required, but it is still good practice to use this function.
+ *
+ * \param func the function ta call with any required locks held
+ * \param param parameter to pass to \c func
+ * \return the return value from \c func
+ * \sa cyw43_arch_lwip_begin
+ * \sa cyw43_arch_lwip_end
+ */
+
+/*!
+ * \fn void cyw43_arch_lwip_check(void)
+ * \brief Checks the caller has any locks required for calling into lwIP
+ * \ingroup pico_cyw43_arch
+ *
+ * The lwIP API is not thread safe. You should surround calls into the lwIP API
+ * with calls to \ref cyw43_arch_lwip_begin and this method. Note these calls are not
+ * necessary (but harmless) when you are calling back into the lwIP API from an lwIP callback.
+ *
+ * This method will assert in debug mode, if the above conditions are not met (i.e. it is not safe to
+ * call into the lwIP API)
+ *
+ * \sa cyw43_arch_lwip_begin
+ * \sa cyw43_arch_lwip_protect
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/rp2_common/pico_cyw43_arch/include/pico/cyw43_arch/arch_common.h b/src/rp2_common/pico_cyw43_arch/include/pico/cyw43_arch/arch_common.h
new file mode 100644
index 0000000..3cd5aa9
--- /dev/null
+++ b/src/rp2_common/pico_cyw43_arch/include/pico/cyw43_arch/arch_common.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_CYW43_ARCH_ARCH_COMMON_H
+#define _PICO_CYW43_ARCH_ARCH_COMMON_H
+
+#include "pico.h"
+#include "pico/time.h"
+#include "hardware/gpio.h"
+#include "pico/error.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Note, these are negated, because cyw43_driver negates them before returning!
+#define CYW43_EPERM (-PICO_ERROR_NOT_PERMITTED) // Operation not permitted
+#define CYW43_EIO (-PICO_ERROR_IO) // I/O error
+#define CYW43_EINVAL (-PICO_ERROR_INVALID_ARG) // Invalid argument
+#define CYW43_ETIMEDOUT (-PICO_ERROR_TIMEOUT) // Connection timed out
+
+#define CYW43_NUM_GPIOS CYW43_WL_GPIO_COUNT
+
+#define cyw43_hal_pin_obj_t uint
+
+// get the number of elements in a fixed-size array
+#define CYW43_ARRAY_SIZE(a) count_of(a)
+
+static inline uint32_t cyw43_hal_ticks_us(void) {
+ return time_us_32();
+}
+
+static inline uint32_t cyw43_hal_ticks_ms(void) {
+ return to_ms_since_boot(get_absolute_time());
+}
+
+static inline int cyw43_hal_pin_read(cyw43_hal_pin_obj_t pin) {
+ return gpio_get(pin);
+}
+
+static inline void cyw43_hal_pin_low(cyw43_hal_pin_obj_t pin) {
+ gpio_clr_mask(1 << pin);
+}
+
+static inline void cyw43_hal_pin_high(cyw43_hal_pin_obj_t pin) {
+ gpio_set_mask(1 << pin);
+}
+
+#define CYW43_HAL_PIN_MODE_INPUT (GPIO_IN)
+#define CYW43_HAL_PIN_MODE_OUTPUT (GPIO_OUT)
+
+#define CYW43_HAL_PIN_PULL_NONE (0)
+#define CYW43_HAL_PIN_PULL_UP (1)
+#define CYW43_HAL_PIN_PULL_DOWN (2)
+
+static inline void cyw43_hal_pin_config(cyw43_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, __unused uint32_t alt) {
+ assert((mode == CYW43_HAL_PIN_MODE_INPUT || mode == CYW43_HAL_PIN_MODE_OUTPUT) && alt == 0);
+ gpio_set_dir(pin, mode);
+ gpio_set_pulls(pin, pull == CYW43_HAL_PIN_PULL_UP, pull == CYW43_HAL_PIN_PULL_DOWN);
+}
+
+void cyw43_hal_get_mac(int idx, uint8_t buf[6]);
+
+void cyw43_hal_generate_laa_mac(int idx, uint8_t buf[6]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/rp2_common/pico_cyw43_arch/include/pico/cyw43_arch/arch_freertos.h b/src/rp2_common/pico_cyw43_arch/include/pico/cyw43_arch/arch_freertos.h
new file mode 100644
index 0000000..342a85c
--- /dev/null
+++ b/src/rp2_common/pico_cyw43_arch/include/pico/cyw43_arch/arch_freertos.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _EXAMPLE_CYW43_ARCH_ARCH_FREERTOS_SYS_H
+#define _EXAMPLE_CYW43_ARCH_ARCH_FREERTOS_SYS_H
+
+#include "pico/cyw43_arch/arch_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void cyw43_thread_enter(void);
+void cyw43_thread_exit(void);
+
+#define CYW43_THREAD_ENTER cyw43_thread_enter();
+#define CYW43_THREAD_EXIT cyw43_thread_exit();
+#ifndef NDEBUG
+void cyw43_thread_lock_check(void);
+#define cyw43_arch_lwip_check() cyw43_thread_lock_check()
+#define CYW43_THREAD_LOCK_CHECK cyw43_arch_lwip_check();
+#else
+#define cyw43_arch_lwip_check() ((void)0)
+#define CYW43_THREAD_LOCK_CHECK
+#endif
+
+void cyw43_await_background_or_timeout_us(uint32_t timeout_us);
+// todo not 100% sure about the timeouts here; MP uses __WFI which will always wakeup periodically
+#define CYW43_SDPCM_SEND_COMMON_WAIT cyw43_await_background_or_timeout_us(1000);
+#define CYW43_DO_IOCTL_WAIT cyw43_await_background_or_timeout_us(1000);
+
+void cyw43_delay_ms(uint32_t ms);
+void cyw43_delay_us(uint32_t us);
+
+void cyw43_schedule_internal_poll_dispatch(void (*func)(void));
+
+void cyw43_post_poll_hook(void);
+#define CYW43_POST_POLL_HOOK cyw43_post_poll_hook();
+
+static inline void cyw43_arch_lwip_begin(void) {
+ cyw43_thread_enter();
+}
+static inline void cyw43_arch_lwip_end(void) {
+ cyw43_thread_exit();
+}
+
+static inline int cyw43_arch_lwip_protect(int (*func)(void *param), void *param) {
+ cyw43_arch_lwip_begin();
+ int rc = func(param);
+ cyw43_arch_lwip_end();
+ return rc;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/src/rp2_common/pico_cyw43_arch/include/pico/cyw43_arch/arch_poll.h b/src/rp2_common/pico_cyw43_arch/include/pico/cyw43_arch/arch_poll.h
new file mode 100644
index 0000000..bfaea7f
--- /dev/null
+++ b/src/rp2_common/pico_cyw43_arch/include/pico/cyw43_arch/arch_poll.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_CYW43_ARCH_ARCH_POLL_H
+#define _PICO_CYW43_ARCH_ARCH_POLL_H
+
+#include "pico/cyw43_arch/arch_common.h"
+
+#include <assert.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CYW43_THREAD_ENTER
+#define CYW43_THREAD_EXIT
+#ifndef NDEBUG
+
+void cyw43_thread_check(void);
+
+#define cyw43_arch_lwip_check() cyw43_thread_check()
+#define CYW43_THREAD_LOCK_CHECK cyw43_arch_lwip_check();
+#else
+#define cyw43_arch_lwip_check() ((void)0)
+#define CYW43_THREAD_LOCK_CHECK
+#endif
+
+#define CYW43_SDPCM_SEND_COMMON_WAIT cyw43_poll_required = true;
+#define CYW43_DO_IOCTL_WAIT cyw43_poll_required = true;
+
+#define cyw43_delay_ms sleep_ms
+#define cyw43_delay_us sleep_us
+
+void cyw43_schedule_internal_poll_dispatch(void (*func)(void));
+
+void cyw43_post_poll_hook(void);
+
+extern bool cyw43_poll_required;
+
+#define CYW43_POST_POLL_HOOK cyw43_post_poll_hook();
+#endif
+
+#ifndef DOXYGEN_GENERATION // multiple definitions in separate headers seems to confused doxygen
+#define cyw43_arch_lwip_begin() ((void)0)
+#define cyw43_arch_lwip_end() ((void)0)
+
+static inline int cyw43_arch_lwip_protect(int (*func)(void *param), void *param) {
+ return func(param);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/rp2_common/pico_cyw43_arch/include/pico/cyw43_arch/arch_threadsafe_background.h b/src/rp2_common/pico_cyw43_arch/include/pico/cyw43_arch/arch_threadsafe_background.h
new file mode 100644
index 0000000..713fcc1
--- /dev/null
+++ b/src/rp2_common/pico_cyw43_arch/include/pico/cyw43_arch/arch_threadsafe_background.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_CYW43_ARCH_ARCH_THREADSAFE_BACKGROUND_H
+#define _PICO_CYW43_ARCH_ARCH_THREADSAFE_BACKGROUND_H
+
+#include "pico/cyw43_arch/arch_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void cyw43_thread_enter(void);
+
+void cyw43_thread_exit(void);
+
+#define CYW43_THREAD_ENTER cyw43_thread_enter();
+#define CYW43_THREAD_EXIT cyw43_thread_exit();
+#ifndef NDEBUG
+
+void cyw43_thread_lock_check(void);
+
+#define cyw43_arch_lwip_check() cyw43_thread_lock_check()
+#define CYW43_THREAD_LOCK_CHECK cyw43_arch_lwip_check();
+#else
+#define cyw43_arch_lwip_check() ((void)0)
+#define CYW43_THREAD_LOCK_CHECK
+#endif
+
+void cyw43_await_background_or_timeout_us(uint32_t timeout_us);
+// todo not 100% sure about the timeouts here; MP uses __WFI which will always wakeup periodically
+#define CYW43_SDPCM_SEND_COMMON_WAIT cyw43_await_background_or_timeout_us(1000);
+#define CYW43_DO_IOCTL_WAIT cyw43_await_background_or_timeout_us(1000);
+
+void cyw43_delay_ms(uint32_t ms);
+
+void cyw43_delay_us(uint32_t us);
+
+void cyw43_schedule_internal_poll_dispatch(void (*func)(void));
+
+void cyw43_post_poll_hook(void);
+
+#define CYW43_POST_POLL_HOOK cyw43_post_poll_hook();
+
+static inline void cyw43_arch_lwip_begin(void) {
+ cyw43_thread_enter();
+}
+
+static inline void cyw43_arch_lwip_end(void) {
+ cyw43_thread_exit();
+}
+
+static inline int cyw43_arch_lwip_protect(int (*func)(void *param), void *param) {
+ cyw43_arch_lwip_begin();
+ int rc = func(param);
+ cyw43_arch_lwip_end();
+ return rc;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/src/rp2_common/pico_divider/divider.S b/src/rp2_common/pico_divider/divider.S
index 234c1a4..ba42662 100644
--- a/src/rp2_common/pico_divider/divider.S
+++ b/src/rp2_common/pico_divider/divider.S
@@ -103,7 +103,7 @@
regular_func divmod_s32s32
#if !PICO_DIVIDER_DISABLE_INTERRUPTS
// to support IRQ usage (or context switch) we must save/restore divider state around call if state is dirty
- ldr r2, =(SIO_BASE)
+ ldr r2, =SIO_BASE
ldr r3, [r2, #SIO_DIV_CSR_OFFSET]
lsrs r3, #SIO_DIV_CSR_DIRTY_SHIFT_FOR_CARRY
bcs divmod_s32s32_savestate
@@ -114,7 +114,7 @@
// are the hardware_divider functions that can be used instead anyway
regular_func divmod_s32s32_unsafe
// to avoid worrying about IRQs (or context switches), simply disable interrupts around call
- ldr r2, =(SIO_BASE)
+ ldr r2, =SIO_BASE
mrs r3, PRIMASK
cpsid i
#endif /* !PICO_DIVIDER_DISABLE_INTERRUPTS */
@@ -167,7 +167,7 @@
wrapper_func __aeabi_uidivmod
#if !PICO_DIVIDER_DISABLE_INTERRUPTS
// to support IRQ usage (or context switch) we must save/restore divider state around call if state is dirty
- ldr r2, =(SIO_BASE)
+ ldr r2, =SIO_BASE
ldr r3, [r2, #SIO_DIV_CSR_OFFSET]
lsrs r3, #SIO_DIV_CSR_DIRTY_SHIFT_FOR_CARRY
bcs divmod_u32u32_savestate
@@ -178,7 +178,7 @@
// are the hardware_divider functions that can be used instead anyway
regular_func divmod_u32u32_unsafe
// to avoid worrying about IRQs (or context switches), simply disable interrupts around call
- ldr r2, =(SIO_BASE)
+ ldr r2, =SIO_BASE
mrs r3, PRIMASK
cpsid i
#endif /* !PICO_DIVIDER_DISABLE_INTERRUPTS */
@@ -227,7 +227,7 @@
#if !PICO_DIVIDER_DISABLE_INTERRUPTS
// to support IRQ usage (or context switch) we must save/restore divider state around call if state is dirty
mov ip, r2
- ldr r2, =(SIO_BASE)
+ ldr r2, =SIO_BASE
ldr r2, [r2, #SIO_DIV_CSR_OFFSET]
lsrs r2, #SIO_DIV_CSR_DIRTY_SHIFT_FOR_CARRY
mov r2, ip
@@ -255,7 +255,7 @@
#if !PICO_DIVIDER_DISABLE_INTERRUPTS
// to support IRQ usage (or context switch) we must save/restore divider state around call if state is dirty
mov ip, r2
- ldr r2, =(SIO_BASE)
+ ldr r2, =SIO_BASE
ldr r2, [r2, #SIO_DIV_CSR_OFFSET]
lsrs r2, #SIO_DIV_CSR_DIRTY_SHIFT_FOR_CARRY
mov r2, ip
@@ -278,7 +278,7 @@
.macro dneg lo,hi
mvns \hi,\hi
- rsbs \lo,#0
+ negs \lo,\lo
bne l\@_1
adds \hi,#1
l\@_1:
@@ -352,7 +352,7 @@
cmp r2,#0
beq 2f @ x==0?
mov r12,r7
- ldr r7,=#SIO_BASE
+ ldr r7,=SIO_BASE
str r0,[r7,#SIO_DIV_UDIVIDEND_OFFSET]
str r2,[r7,#SIO_DIV_UDIVISOR_OFFSET]
movs r1,#0
@@ -367,7 +367,7 @@
cmp r0,#0 @ y==0?
beq 3f @ then pass 0 to __aeabi_ldiv0
udiv0:
- ldr r0,=#0xffffffff
+ ldr r0,=0xffffffff
movs r1,r0 @ pass 2^64-1 to __aeabi_ldiv0
3:
push {r14}
@@ -402,7 +402,7 @@
cmp r2,#0
beq udiv0 @ x==0? exit as with y!=0 case above
push {r7}
- ldr r7,=#SIO_BASE
+ ldr r7,=SIO_BASE
str r1,[r7,#SIO_DIV_UDIVIDEND_OFFSET]
str r2,[r7,#SIO_DIV_UDIVISOR_OFFSET]
wait_div 4
@@ -464,9 +464,9 @@
lsrs r4,r2,#15
adds r4,#1 @ x1=(x0>>15)+1; 2^16<x1<=2^17
- ldr r7,=#SIO_BASE
+ ldr r7,=SIO_BASE
str r4,[r7,#SIO_DIV_UDIVISOR_OFFSET]
- ldr r4,=#0xffffffff
+ ldr r4,=0xffffffff
str r4,[r7,#SIO_DIV_UDIVIDEND_OFFSET]
lsrs r6,r1,#16
uxth r3,r2 @ x0l
@@ -687,9 +687,9 @@
adcs r4,r4
adds r4,#1 @ x1=(ui32)(x0>>31)+1; // 2^16<x1<=2^17
- ldr r7,=#SIO_BASE
+ ldr r7,=SIO_BASE
str r4,[r7,#SIO_DIV_UDIVISOR_OFFSET]
- ldr r4,=#0xffffffff
+ ldr r4,=0xffffffff
str r4,[r7,#SIO_DIV_UDIVIDEND_OFFSET]
lsrs r6,r1,#16
wait_div 1
@@ -821,7 +821,7 @@
adds r5,r3,#1
beq 1f
- ldr r7,=#SIO_BASE
+ ldr r7,=SIO_BASE
str r5,[r7,#SIO_DIV_UDIVISOR_OFFSET]
str r1,[r7,#SIO_DIV_UDIVIDEND_OFFSET]
wait_div 0
diff --git a/src/rp2_common/pico_double/double_aeabi.S b/src/rp2_common/pico_double/double_aeabi.S
index 0c59738..04cf22c 100644
--- a/src/rp2_common/pico_double/double_aeabi.S
+++ b/src/rp2_common/pico_double/double_aeabi.S
@@ -290,7 +290,7 @@
wrapper_func __aeabi_cdcmpeq
push {r0-r7,r14}
__aeabi_dfcmple_guts:
- ldr r7,=#0x7ff @ flush NaNs and denormals
+ ldr r7,=0x7ff @ flush NaNs and denormals
lsls r4,r1,#1
lsrs r4,#21
beq 1f
@@ -450,7 +450,7 @@
lsls r2, r4
lsls r0, r2, #20
lsrs r2, #12
- ldr r1,=#1055
+ ldr r1,=1055
subs r1, r4
lsls r1, #20
orrs r1, r3
@@ -552,7 +552,7 @@
cmp r1, #0
bmi 1f
movs r2, #0
- rsbs r0, #0
+ negs r0, r0
sbcs r2, r1
mov r1, r2
pop {pc}
diff --git a/src/rp2_common/pico_double/double_v1_rom_shim.S b/src/rp2_common/pico_double/double_v1_rom_shim.S
index 7a14ca4..6dac28a 100644
--- a/src/rp2_common/pico_double/double_v1_rom_shim.S
+++ b/src/rp2_common/pico_double/double_v1_rom_shim.S
@@ -144,7 +144,7 @@
lsls \re,#21
bcc l\@_1 @ skip on positive
mvns \rb,\rb @ negate mantissa
- rsbs \ra,#0
+ negs \ra,\ra
bcc l\@_1
adds \rb,#1
l\@_1:
@@ -218,7 +218,7 @@
mvns r1,r1 @ negate mantissa
mvns r0,r0
movs r2,#0
- rsbs r4,#0
+ negs r4,r4
adcs r0,r2
adcs r1,r2
1:
@@ -263,7 +263,7 @@
da_7:
@ here exponent overflow: return signed infinity
lsls r1,r3,#31
- ldr r3,=#0x7ff00000
+ ldr r3,=0x7ff00000
orrs r1,r3
b 1f
da_6:
@@ -524,7 +524,7 @@
adcs r1,r1
subs r3,#1 @ correct exponent
1:
- ldr r6,=#0x3ff
+ ldr r6,=0x3ff
subs r3,r6 @ correct for exponent bias
lsls r6,#1 @ 0x7fe
cmp r3,r6
@@ -811,7 +811,7 @@
muls r3,r0 @ zL*xH Q73
subs r4,r3
mul32_32_64 r2,r0, r2,r3, r5,r6,r7,r2,r3 @ xL*zL
- rsbs r2,#0 @ borrow from low half?
+ negs r2,r2 @ borrow from low half?
sbcs r4,r3 @ y-xz Q73 (remainder bits 52..73)
cmp r4,#0
@@ -830,9 +830,9 @@
mov r2,r12
lsls r7,r2,#31 @ result sign
asrs r2,#2 @ result exponent
- ldr r3,=#0x3fd
+ ldr r3,=0x3fd
adds r2,r3
- ldr r3,=#0x7fe
+ ldr r3,=0x7fe
cmp r2,r3
bhs dd_3 @ over- or underflow?
lsls r2,#20
@@ -936,7 +936,7 @@
b dq_4
dq_3:
- ldr r1,=#0x7ff
+ ldr r1,=0x7ff
lsls r1,#20 @ return +Inf
dq_4:
movs r0,#0
@@ -949,7 +949,7 @@
bcs dq_0 @ negative?
lsrs r2,#21 @ extract exponent
subs r2,#1
- ldr r3,=#0x7fe
+ ldr r3,=0x7fe
cmp r2,r3
bhs dq_2 @ catches 0 and +Inf
push {r4-r7,r14}
@@ -968,8 +968,8 @@
@ here
@ r0:r1 y mantissa Q52 [1,4)
@ r12 result exponent
-
- adr r4,drsqrtapp-8 @ first eight table entries are never accessed because of the mantissa's leading 1
+.equ drsqrtapp_minus_8, (drsqrtapp-8)
+ adr r4,drsqrtapp_minus_8 @ first eight table entries are never accessed because of the mantissa's leading 1
lsrs r2,r1,#17 @ y Q3
ldrb r2,[r4,r2] @ initial approximation to reciprocal square root a0 Q8
lsrs r3,r1,#4 @ first Newton-Raphson iteration
@@ -1100,7 +1100,7 @@
adds r2,r3 @ r1:r2 a5^2 Q106
lsls r0,#22 @ y Q84
- rsbs r1,#0
+ negs r1,r1
sbcs r0,r2 @ remainder y-a5^2
bmi 1f @ y<a5^2: no need to increment a5
movs r3,#0
@@ -1290,7 +1290,8 @@
bx r14
.weak d2fix_a // weak because it exists in float code too
-regular_func d2fix_a
+.thumb_func
+d2fix_a:
@ here
@ r0:r1 two's complement mantissa
@ r2 unbaised exponent
@@ -1304,7 +1305,7 @@
movs r4,r0
lsls r1,r2
lsls r0,r2
- rsbs r2,#0
+ negs r2,r2
adds r2,#32 @ complementary shift
lsrs r4,r2
orrs r1,r4
@@ -1319,7 +1320,7 @@
bmi 1f @ long shift?
mov r4,r1
lsls r4,r2
- rsbs r2,#0
+ negs r2,r2
adds r2,#32 @ complementary shift
asrs r1,r2
lsrs r0,r2
@@ -1331,7 +1332,7 @@
asrs r1,#31 @ shift down 32 places
adds r2,#32
bmi 1f @ very long shift?
- rsbs r2,#0
+ negs r2,r2
adds r2,#32
asrs r0,r2
pop {r4,r15}
@@ -1344,7 +1345,7 @@
regular_func double2float_shim
lsls r2,r1,#1
lsrs r2,#21 @ exponent
- ldr r3,=#0x3ff-0x7f
+ ldr r3,=0x3ff-0x7f
subs r2,r3 @ fix exponent bias
ble 1f @ underflow or zero
cmp r2,#0xff
@@ -1432,7 +1433,7 @@
sbcs r1,r3
uf2d:
push {r4,r5,r14}
- ldr r4,=#0x432
+ ldr r4,=0x432
subs r2,r4,r2 @ form biased exponent
@ here
@ r0:r1 unnormalised mantissa
@@ -1455,7 +1456,7 @@
lsrs r4,r1,#21
bcc 5b
4:
- ldr r4,=#0x7fe
+ ldr r4,=0x7fe
cmp r2,r4
bhs 6f @ over/underflow? return signed zero/infinity
7:
@@ -1506,7 +1507,7 @@
double_section dunpacks
regular_func dunpacks
mdunpacks r0,r1,r2,r3,r4
- ldr r3,=#0x3ff
+ ldr r3,=0x3ff
subs r2,r3 @ exponent without offset
bx r14
@@ -1572,7 +1573,7 @@
lsrs r3,r0,#24
orrs r1,r3
lsls r0,#8 @ r0:r1 Q60, to be shifted down -r2 places
- rsbs r3,r2,#0
+ negs r3,r2
adds r2,#32 @ shift down in r3, complementary shift in r2
bmi 1f @ long shift?
2:
@@ -1663,13 +1664,13 @@
bl dreduce
movs r4,#0
- ldr r5,=#0x9df04dbb @ this value compensates for the non-unity scaling of the CORDIC rotations
- ldr r6,=#0x36f656c5
+ ldr r5,=0x9df04dbb @ this value compensates for the non-unity scaling of the CORDIC rotations
+ ldr r6,=0x36f656c5
lsls r2,#31
bcc 1f
@ quadrant 2 or 3
mvns r6,r6
- rsbs r5,r5,#0
+ negs r5,r5
adcs r6,r4
1:
lsls r2,#1
@@ -1757,7 +1758,7 @@
@ r2:r3 x
push {r4-r7,r14}
bl push_r8_r11
- ldr r5,=#0x7ff00000
+ ldr r5,=0x7ff00000
movs r4,r1
ands r4,r5 @ y==0?
beq 1f
@@ -1786,7 +1787,7 @@
eors r3,r5
eors r1,r5
bmi 1f @ quadrant offset=+2 if y was positive
- rsbs r6,#0 @ quadrant offset=-2 if y was negative
+ negs r6,r6 @ quadrant offset=-2 if y was negative
1:
@ now in quadrant 0 or 3
adds r7,r1,r5 @ r7=-r1
@@ -1895,8 +1896,8 @@
cmp r6,#0
beq 1f
- ldr r4,=#0x885A308D @ π/2 Q61
- ldr r5,=#0x3243F6A8
+ ldr r4,=0x885A308D @ π/2 Q61
+ ldr r5,=0x3243F6A8
bpl 2f
mvns r4,r4 @ negative quadrant offset
mvns r5,r5
@@ -1959,8 +1960,8 @@
bl dreduce
cmp r1,#0
bge 1f
- ldr r4,=#0xF473DE6B
- ldr r5,=#0x2C5C85FD @ ln2 Q62
+ ldr r4,=0xF473DE6B
+ ldr r5,=0x2C5C85FD @ ln2 Q62
adds r0,r4
adcs r1,r5
subs r2,#1
@@ -1979,7 +1980,7 @@
sbcs r1,r5
bmi 1f
- rsbs r6,r7,#0
+ negs r6,r7
adds r6,#32 @ complementary shift
movs r5,r3
asrs r5,r7
@@ -2015,7 +2016,7 @@
adcs r1,r3
pop {r2}
- rsbs r2,#0
+ negs r2,r2
adds r2,#62
bl fix642double_shim @ in principle we can pack faster than this because we know the exponent
pop {r4-r7,r15}
@@ -2046,7 +2047,7 @@
movs r3,#0 @ y=0 Q62
3:
- rsbs r6,r7,#0
+ negs r6,r7
adds r6,#32 @ complementary shift
movs r5,r1
asrs r5,r7
@@ -2086,8 +2087,8 @@
@ here:
@ r2:r3 ln m/2 = ln m - ln2 Q62
@ r7 unbiased exponent
-
- adr r4,dreddata1+4
+.equ dreddata1_plus_4, (dreddata1+4)
+ adr r4,dreddata1_plus_4
ldmia r4,{r0,r1,r4}
adds r7,#1
muls r0,r7 @ Q62
@@ -2128,12 +2129,12 @@
pop {r4-r7,r15}
5:
- ldr r1,=#0xfff00000
+ ldr r1,=0xfff00000
movs r0,#0
pop {r4-r7,r15}
6:
- ldr r1,=#0x7ff00000
+ ldr r1,=0x7ff00000
movs r0,#0
pop {r4-r7,r15}
diff --git a/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c b/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c
index e1073ca..503cd12 100644
--- a/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c
+++ b/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c
@@ -17,12 +17,12 @@
#define LS_K 0b10
#define LS_SE1 0b11
+#if PICO_RP2040_B0_SUPPORTED || PICO_RP2040_B1_SUPPORTED
static void hw_enumeration_fix_wait_se0(void);
static void hw_enumeration_fix_force_ls_j(void);
static void hw_enumeration_fix_finish(void);
void rp2040_usb_device_enumeration_fix(void) {
-#if PICO_RP2040_B0_SUPPORTED || PICO_RP2040_B1_SUPPORTED
// Actually check for B0/B1 h/w
if (rp2040_chip_version() == 1) {
// After coming out of reset, the hardware expects 800us of LS_J (linestate J) time
@@ -36,7 +36,6 @@
// Wait SE0 phase will call force ls_j phase which will call finish phase
hw_enumeration_fix_wait_se0();
}
-#endif
}
static inline uint8_t hw_line_state(void) {
@@ -90,9 +89,7 @@
// DM must be 0 for this to work. This is true if it is selected
// to any other function. fn 8 on this pin is only for debug so shouldn't
// be selected
- if (gpio_get_function(dm) == 8) {
- panic("Not expecting DM to be function 8");
- }
+ hard_assert(gpio_get_function(dm) != 8);
// Before changing any pin state, take a copy of the current gpio control register
gpio_ctrl_prev = iobank0_hw->io[dp].ctrl;
@@ -148,3 +145,9 @@
// Restore the pad ctrl value
padsbank0_hw->io[dp] = pad_ctrl_prev;
}
+
+#else
+void rp2040_usb_device_enumeration_fix(void) {
+ // nothing to do
+}
+#endif
\ No newline at end of file
diff --git a/src/rp2_common/pico_float/float_aeabi.S b/src/rp2_common/pico_float/float_aeabi.S
index db393df..cb6f95f 100644
--- a/src/rp2_common/pico_float/float_aeabi.S
+++ b/src/rp2_common/pico_float/float_aeabi.S
@@ -378,7 +378,7 @@
lsrs r1, r0, #31
lsls r1, #31
bpl 1f
- rsbs r0, #0
+ negs r0, r0
1:
cmp r0, #0
beq 7f
@@ -392,7 +392,7 @@
pop {r1, r2}
lsls r1, r0
subs r0, #158
- rsbs r0, #0
+ negs r0, r0
adds r1,#0x80 @ rounding
bcs 5f @ tripped carry? then have leading 1 in C as required (and result is even so can ignore sticky bits)
@@ -459,7 +459,7 @@
bl __aeabi_f2uiz
cmp r0, #0
bmi 1f
- rsbs r0, #0
+ negs r0, r0
pop {pc}
1:
movs r0, #128
@@ -534,7 +534,7 @@
cmp r1, #0
bmi 1f
movs r2, #0
- rsbs r0, #0
+ negs r0, r0
sbcs r2, r1
mov r1, r2
pop {pc}
diff --git a/src/rp2_common/pico_float/float_v1_rom_shim.S b/src/rp2_common/pico_float/float_v1_rom_shim.S
index d7541a4..50df612 100644
--- a/src/rp2_common/pico_float/float_v1_rom_shim.S
+++ b/src/rp2_common/pico_float/float_v1_rom_shim.S
@@ -100,7 +100,7 @@
movs r5,r0
movs r0,r1
4:
- rsbs r2,#0
+ negs r2,r2
adds r2,#32+29
// bl packx
@@ -132,7 +132,7 @@
bmi 2f @ force y to 0 proper, so result will be zero
subs r4,r2,r3 @ calculate shift
bge 1f @ ex>=ey?
- rsbs r4,#0 @ make shift positive
+ negs r4,r4 @ make shift positive
asrs r0,r4
cmp r4,#28
blo 3f
@@ -159,8 +159,8 @@
ldr r3, =0x2cfc @ &pi_q29, circular coefficients
cmp r0,#0 @ x negative
bge 5f
- rsbs r0,#0 @ rotate to 1st/4th quadrants
- rsbs r1,#0
+ negs r0,r0 @ rotate to 1st/4th quadrants
+ negs r1,r1
ldr r2,[r3] @ pi Q29
5:
movs r4,#1 @ m=1
@@ -272,7 +272,7 @@
movs r4,r0
lsls r1,r2
lsls r0,r2
- rsbs r2,#0
+ negs r2,r2
adds r2,#32 @ complementary shift
lsrs r4,r2
orrs r1,r4
@@ -287,7 +287,7 @@
bmi 1f @ long shift?
mov r4,r1
lsls r4,r2
- rsbs r2,#0
+ negs r2,r2
adds r2,#32 @ complementary shift
asrs r1,r2
lsrs r0,r2
@@ -299,7 +299,7 @@
asrs r1,#31 @ shift down 32 places
adds r2,#32
bmi 1f @ very long shift?
- rsbs r2,#0
+ negs r2,r2
adds r2,#32
asrs r0,r2
pop {r4,r15}
@@ -329,7 +329,7 @@
cmp r2,#0xff @ Inf?
beq 2f
lsrs r1,#4 @ exponent and top 20 bits of mantissa
- ldr r2,=#(0x3ff-0x7f)<<20 @ difference in exponent offsets
+ ldr r2,=(0x3ff-0x7f)<<20 @ difference in exponent offsets
adds r1,r2
orrs r1,r3
lsls r0,#29 @ bottom 3 bits of mantissa
@@ -340,7 +340,7 @@
movs r0,#0
bx r14
2:
- ldr r1,=#0x7ff00000 @ return signed infinity
+ ldr r1,=0x7ff00000 @ return signed infinity
adds r1,r3
b 3b
diff --git a/src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S b/src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S
index 0dbc67c..114a1aa 100644
--- a/src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S
+++ b/src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S
@@ -10,11 +10,16 @@
#include "pico/asm_helper.S"
+.macro int64_section name
#if PICO_INT64_OPS_IN_RAM
-.section RAM_SECTION_NAME(__aeabi_lmul)
+.section RAM_SECTION_NAME(\name), "ax"
#else
-.section SECTION_NAME(__aeabi_lmul)
+.section SECTION_NAME(\name), "ax"
#endif
+.endm
+
+int64_section __aeabi_lmul
+
wrapper_func __aeabi_lmul
muls r1, r2
muls r3, r0
@@ -41,4 +46,3 @@
adcs r1, r2
add r1, r12
bx lr
-
diff --git a/src/rp2_common/pico_lwip/CMakeLists.txt b/src/rp2_common/pico_lwip/CMakeLists.txt
new file mode 100644
index 0000000..7b1a8a7
--- /dev/null
+++ b/src/rp2_common/pico_lwip/CMakeLists.txt
@@ -0,0 +1,278 @@
+if (DEFINED ENV{PICO_LWIP_PATH} AND (NOT PICO_LWIP_PATH))
+ set(PICO_LWIP_PATH $ENV{PICO_LWIP_PATH})
+ message("Using PICO_LWIP_PATH from environment ('${PICO_LWIP_PATH}')")
+endif ()
+
+set(LWIP_TEST_PATH "src/Filelists.cmake")
+if (NOT PICO_LWIP_PATH)
+ set(PICO_LWIP_PATH ${PROJECT_SOURCE_DIR}/lib/lwip)
+# if (NOT EXISTS ${PICO_LWIP_PATH}/${LWIP_TEST_PATH})
+# message(WARNING "LWIP submodule has not been initialized; Pico W wireless support will be unavailable
+#hint: try 'git submodule update --init' from your SDK directory (${PICO_SDK_PATH}).")
+# endif()
+elseif (NOT EXISTS ${PICO_LWIP_PATH}/${LWIP_TEST_PATH})
+ message(WARNING "PICO_LWIP_PATH specified but content not present.")
+endif()
+
+if (EXISTS ${PICO_LWIP_PATH}/${LWIP_TEST_PATH})
+ message("lwIP available at ${PICO_LWIP_PATH}")
+
+ # argh... wanted to use this, but they dump stuff into the source tree, which breaks parallel builds
+ #set(LWIP_DIR ${PICO_LWIP_PATH})
+ #include(${PICO_LWIP_PATH}/src/Filelists.cmake)
+
+ pico_register_common_scope_var(PICO_LWIP_PATH)
+
+ # The minimum set of files needed for lwIP.
+ add_library(pico_lwip_core INTERFACE)
+ target_sources(pico_lwip_core INTERFACE
+ ${PICO_LWIP_PATH}/src/core/init.c
+ ${PICO_LWIP_PATH}/src/core/def.c
+ ${PICO_LWIP_PATH}/src/core/dns.c
+ ${PICO_LWIP_PATH}/src/core/inet_chksum.c
+ ${PICO_LWIP_PATH}/src/core/ip.c
+ ${PICO_LWIP_PATH}/src/core/mem.c
+ ${PICO_LWIP_PATH}/src/core/memp.c
+ ${PICO_LWIP_PATH}/src/core/netif.c
+ ${PICO_LWIP_PATH}/src/core/pbuf.c
+ ${PICO_LWIP_PATH}/src/core/raw.c
+ ${PICO_LWIP_PATH}/src/core/stats.c
+ ${PICO_LWIP_PATH}/src/core/sys.c
+ ${PICO_LWIP_PATH}/src/core/altcp.c
+ ${PICO_LWIP_PATH}/src/core/altcp_alloc.c
+ ${PICO_LWIP_PATH}/src/core/altcp_tcp.c
+ ${PICO_LWIP_PATH}/src/core/tcp.c
+ ${PICO_LWIP_PATH}/src/core/tcp_in.c
+ ${PICO_LWIP_PATH}/src/core/tcp_out.c
+ ${PICO_LWIP_PATH}/src/core/timeouts.c
+ ${PICO_LWIP_PATH}/src/core/udp.c
+ ${CMAKE_CURRENT_LIST_DIR}/random.c
+ )
+ target_include_directories(pico_lwip_core INTERFACE
+ ${PICO_LWIP_PATH}/src/include)
+
+ add_library(pico_lwip_core4 INTERFACE)
+ target_sources(pico_lwip_core4 INTERFACE
+ ${PICO_LWIP_PATH}/src/core/ipv4/acd.c
+ ${PICO_LWIP_PATH}/src/core/ipv4/autoip.c
+ ${PICO_LWIP_PATH}/src/core/ipv4/dhcp.c
+ ${PICO_LWIP_PATH}/src/core/ipv4/etharp.c
+ ${PICO_LWIP_PATH}/src/core/ipv4/icmp.c
+ ${PICO_LWIP_PATH}/src/core/ipv4/igmp.c
+ ${PICO_LWIP_PATH}/src/core/ipv4/ip4_frag.c
+ ${PICO_LWIP_PATH}/src/core/ipv4/ip4.c
+ ${PICO_LWIP_PATH}/src/core/ipv4/ip4_addr.c
+ )
+
+ add_library(pico_lwip_core6 INTERFACE)
+ target_sources(pico_lwip_core6 INTERFACE
+ ${PICO_LWIP_PATH}/src/core/ipv6/dhcp6.c
+ ${PICO_LWIP_PATH}/src/core/ipv6/ethip6.c
+ ${PICO_LWIP_PATH}/src/core/ipv6/icmp6.c
+ ${PICO_LWIP_PATH}/src/core/ipv6/inet6.c
+ ${PICO_LWIP_PATH}/src/core/ipv6/ip6.c
+ ${PICO_LWIP_PATH}/src/core/ipv6/ip6_addr.c
+ ${PICO_LWIP_PATH}/src/core/ipv6/ip6_frag.c
+ ${PICO_LWIP_PATH}/src/core/ipv6/mld6.c
+ ${PICO_LWIP_PATH}/src/core/ipv6/nd6.c
+ )
+
+ # APIFILES: The files which implement the sequential and socket APIs.
+ add_library(pico_lwip_api INTERFACE)
+ target_sources(pico_lwip_api INTERFACE
+ ${PICO_LWIP_PATH}/src/api/api_lib.c
+ ${PICO_LWIP_PATH}/src/api/api_msg.c
+ ${PICO_LWIP_PATH}/src/api/err.c
+ ${PICO_LWIP_PATH}/src/api/if_api.c
+ ${PICO_LWIP_PATH}/src/api/netbuf.c
+ ${PICO_LWIP_PATH}/src/api/netdb.c
+ ${PICO_LWIP_PATH}/src/api/netifapi.c
+ ${PICO_LWIP_PATH}/src/api/sockets.c
+ ${PICO_LWIP_PATH}/src/api/tcpip.c
+ )
+
+ # Files implementing various generic network interface functions
+ add_library(pico_lwip_netif INTERFACE)
+ target_sources(pico_lwip_netif INTERFACE
+ ${PICO_LWIP_PATH}/src/netif/ethernet.c
+ ${PICO_LWIP_PATH}/src/netif/bridgeif.c
+ ${PICO_LWIP_PATH}/src/netif/bridgeif_fdb.c
+ ${PICO_LWIP_PATH}/src/netif/slipif.c
+ )
+
+ # 6LoWPAN
+ add_library(pico_lwip_sixlowpan INTERFACE)
+ target_sources(pico_lwip_sixlowpan INTERFACE
+ ${PICO_LWIP_PATH}/src/netif/lowpan6_common.c
+ ${PICO_LWIP_PATH}/src/netif/lowpan6.c
+ ${PICO_LWIP_PATH}/src/netif/lowpan6_ble.c
+ ${PICO_LWIP_PATH}/src/netif/zepif.c
+ )
+
+ # PPP
+ add_library(pico_lwip_ppp INTERFACE)
+ target_sources(pico_lwip_ppp INTERFACE
+ ${PICO_LWIP_PATH}/src/netif/ppp/auth.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/ccp.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/chap-md5.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/chap_ms.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/chap-new.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/demand.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/eap.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/ecp.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/eui64.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/fsm.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/ipcp.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/ipv6cp.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/lcp.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/magic.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/mppe.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/multilink.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/ppp.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/pppapi.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/pppcrypt.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/pppoe.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/pppol2tp.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/pppos.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/upap.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/utils.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/vj.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/polarssl/arc4.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/polarssl/des.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/polarssl/md4.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/polarssl/md5.c
+ ${PICO_LWIP_PATH}/src/netif/ppp/polarssl/sha1.c
+ )
+
+ # SNMPv3 agent
+ add_library(pico_lwip_snmp INTERFACE)
+ target_sources(pico_lwip_snmp INTERFACE
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_asn1.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_core.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_mib2.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_mib2_icmp.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_mib2_interfaces.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_mib2_ip.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_mib2_snmp.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_mib2_system.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_mib2_tcp.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_mib2_udp.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_snmpv2_framework.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_snmpv2_usm.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_msg.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmpv3.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_netconn.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_pbuf_stream.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_raw.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_scalar.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_table.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_threadsync.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmp_traps.c
+ )
+
+ # HTTP server + client
+ add_library(pico_lwip_http INTERFACE)
+ target_sources(pico_lwip_http INTERFACE
+ ${PICO_LWIP_PATH}/src/apps/http/altcp_proxyconnect.c
+ ${PICO_LWIP_PATH}/src/apps/http/fs.c
+ ${PICO_LWIP_PATH}/src/apps/http/http_client.c
+ ${PICO_LWIP_PATH}/src/apps/http/httpd.c
+ )
+
+ # MAKEFSDATA HTTP server host utility
+ add_library(pico_lwip_makefsdata INTERFACE)
+ target_sources(pico_lwip_makefsdata INTERFACE
+ ${PICO_LWIP_PATH}/src/apps/http/makefsdata/makefsdata.c
+ )
+
+ # iperf
+ add_library(pico_lwip_iperf INTERFACE)
+ target_sources(pico_lwip_iperf INTERFACE
+ ${PICO_LWIP_PATH}/src/apps/lwiperf/lwiperf.c
+ )
+
+ # SMTP client
+ add_library(pico_lwip_smtp INTERFACE)
+ target_sources(pico_lwip_smtp INTERFACE
+ ${PICO_LWIP_PATH}/src/apps/smtp/smtp.c
+ )
+
+ # SNTP client
+ add_library(pico_lwip_sntp INTERFACE)
+ target_sources(pico_lwip_sntp INTERFACE
+ ${PICO_LWIP_PATH}/src/apps/sntp/sntp.c
+ )
+
+ # MDNS responder
+ add_library(pico_lwip_mdns INTERFACE)
+ target_sources(pico_lwip_mdns INTERFACE
+ ${PICO_LWIP_PATH}/src/apps/mdns/mdns.c
+ ${PICO_LWIP_PATH}/src/apps/mdns/mdns_out.c
+ ${PICO_LWIP_PATH}/src/apps/mdns/mdns_domain.c
+ )
+
+ # NetBIOS name server
+ add_library(pico_lwip_netbios INTERFACE)
+ target_sources(pico_lwip_netbios INTERFACE
+ ${PICO_LWIP_PATH}/src/apps/netbiosns/netbiosns.c
+ )
+
+ # TFTP server files
+ add_library(pico_lwip_tftp INTERFACE)
+ target_sources(pico_lwip_tftp INTERFACE
+ ${PICO_LWIP_PATH}/src/apps/tftp/tftp.c
+ )
+
+ # MQTT client files
+ add_library(pico_lwip_mbedtls INTERFACE)
+ target_sources(pico_lwip_mbedtls INTERFACE
+ ${PICO_LWIP_PATH}/src/apps/altcp_tls/altcp_tls_mbedtls.c
+ ${PICO_LWIP_PATH}/src/apps/altcp_tls/altcp_tls_mbedtls_mem.c
+ ${PICO_LWIP_PATH}/src/apps/snmp/snmpv3_mbedtls.c
+ )
+
+
+ # All LWIP files without apps
+ add_library(pico_lwip INTERFACE)
+ target_link_libraries(pico_lwip INTERFACE
+ pico_lwip_core
+ pico_lwip_core4
+ pico_lwip_core6
+ pico_lwip_api
+ pico_lwip_netif
+ pico_lwip_sixlowpan
+ pico_lwip_ppp
+ )
+
+ # our arch/cc.h
+ add_library(pico_lwip_arch INTERFACE)
+ target_include_directories(pico_lwip_arch INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/include)
+
+ # our nosys impl
+ add_library(pico_lwip_nosys INTERFACE)
+ target_sources(pico_lwip_nosys INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/nosys.c
+ )
+ target_link_libraries(pico_lwip_nosys INTERFACE
+ pico_lwip_arch)
+
+
+ if (NOT PICO_LWIP_CONTRIB_PATH)
+ set(PICO_LWIP_CONTRIB_PATH ${PICO_LWIP_PATH}/contrib)
+ endif()
+ pico_register_common_scope_var(PICO_LWIP_CONTRIB_PATH)
+
+ # Make lwip_contrib_freertos library, with the FreeRTOS/lwIP code from lwip-contrib
+ add_library(pico_lwip_contrib_freertos INTERFACE)
+ target_sources(pico_lwip_contrib_freertos INTERFACE
+ ${PICO_LWIP_CONTRIB_PATH}/ports/freertos/sys_arch.c
+ )
+ target_include_directories(pico_lwip_contrib_freertos INTERFACE
+ ${PICO_LWIP_CONTRIB_PATH}/ports/freertos/include
+ )
+ target_link_libraries(pico_lwip_contrib_freertos INTERFACE
+ pico_lwip_arch)
+
+ pico_promote_common_scope_vars()
+endif()
diff --git a/src/rp2_common/pico_lwip/doc.h b/src/rp2_common/pico_lwip/doc.h
new file mode 100644
index 0000000..ede60b6
--- /dev/null
+++ b/src/rp2_common/pico_lwip/doc.h
@@ -0,0 +1,44 @@
+/**
+ * \defgroup pico_lwip pico_lwip
+ * \brief Wrapper libraries for <a href="https://savannah.nongnu.org/projects/lwip/lwIP">lwIP</a>
+ *
+ * The following libraries are provided that contain the equivalent lwIP functionality groups:
+ *
+ * * \c \b pico_lwip_core -
+ * * \c \b pico_lwip_core4 -
+ * * \c \b pico_lwip_core6 -
+ * * \c \b pico_lwip_netif -
+ * * \c \b pico_lwip_sixlowpan -
+ * * \c \b pico_lwip_ppp -
+ * * \c \b pico_lwip_api -
+ *
+ * The following libraries are provided that contain the equivalent lwIP application support:
+ *
+ * * \c \b pico_lwip_snmp -
+ * * \c \b pico_lwip_http -
+ * * \c \b pico_lwip_makefsdata -
+ * * \c \b pico_lwip_iperf -
+ * * \c \b pico_lwip_smtp -
+ * * \c \b pico_lwip_sntp -
+ * * \c \b pico_lwip_mdns -
+ * * \c \b pico_lwip_netbios -
+ * * \c \b pico_lwip_tftp -
+ * * \c \b pico_lwip_mbedtls -
+ *
+ * The SDK Provides a common set of functionality in \c \p pico_lwip which aggregates:
+ *
+ * * \c \b pico_lwip_core -
+ * * \c \b pico_lwip_core4 -
+ * * \c \b pico_lwip_core6 -
+ * * \c \b pico_lwip_netif -
+ * * \c \b pico_lwip_sixlowpan -
+ * * \c \b pico_lwip_ppp -
+ *
+ * The following additional libraries are provided:
+ *
+ * * \c \b pico_lwip - Aggregates the lwIP RAW API: \c \b pico_lwip_core, \c \b pico_lwip_core4, \c \b pico_lwip_core6, \c \b pico_lwip_api, \c \b pico_lwip_netif, \c \b pico_lwip_sixlowpan and \c \b pico_lwip_ppp. It does
+ * not include \c \b pico_lwip_api, which requires NO_SYS=0. You should include the latter separately if you want it.
+ *
+ * * \c \b pico_lwip_arch - lwIP required compiler adapters. This is not included in \c \b pico_lwip in case you wish to replace them.
+ * * \c \b pico_lwip_nosys - basic stub functions for NO_SYS mode.
+ */
diff --git a/src/rp2_common/pico_lwip/include/arch/cc.h b/src/rp2_common/pico_lwip/include/arch/cc.h
new file mode 100644
index 0000000..447e4d2
--- /dev/null
+++ b/src/rp2_common/pico_lwip/include/arch/cc.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+#ifndef __CC_H__
+#define __CC_H__
+
+#if NO_SYS
+// todo really we should just not allow SYS_LIGHTWEIGHT_PROT for nosys mode (it doesn't do anything anyway)
+typedef int sys_prot_t;
+#endif
+
+/* define compiler specific symbols */
+#if defined (__ICCARM__)
+
+#define PACK_STRUCT_BEGIN
+#define PACK_STRUCT_STRUCT
+#define PACK_STRUCT_END
+#define PACK_STRUCT_FIELD(x) x
+#define PACK_STRUCT_USE_INCLUDES
+
+#elif defined (__CC_ARM)
+
+#define PACK_STRUCT_BEGIN __packed
+#define PACK_STRUCT_STRUCT
+#define PACK_STRUCT_END
+#define PACK_STRUCT_FIELD(x) x
+
+#elif defined (__GNUC__)
+
+#define PACK_STRUCT_BEGIN
+#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
+#define PACK_STRUCT_END
+#define PACK_STRUCT_FIELD(x) x
+
+#elif defined (__TASKING__)
+
+#define PACK_STRUCT_BEGIN
+#define PACK_STRUCT_STRUCT
+#define PACK_STRUCT_END
+#define PACK_STRUCT_FIELD(x) x
+
+#endif
+
+#define LWIP_PLATFORM_ASSERT(x) do { if(!(x)) while(1); } while(0)
+
+unsigned int pico_lwip_rand(void);
+#ifndef LWIP_RAND
+// Use ROSC based random number generation, more for the fact that rand() may not be seeded, than anything else
+#define LWIP_RAND pico_lwip_rand
+#endif
+#endif /* __CC_H__ */
diff --git a/src/rp2_common/pico_lwip/nosys.c b/src/rp2_common/pico_lwip/nosys.c
new file mode 100644
index 0000000..4e7605d
--- /dev/null
+++ b/src/rp2_common/pico_lwip/nosys.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "lwip/init.h"
+#include "pico/time.h"
+
+#if NO_SYS
+/* lwip has provision for using a mutex, when applicable */
+sys_prot_t sys_arch_protect(void) {
+ return 0;
+}
+
+void sys_arch_unprotect(sys_prot_t pval) {
+ (void) pval;
+}
+
+/* lwip needs a millisecond time source, and the TinyUSB board support code has one available */
+uint32_t sys_now(void) {
+ return to_ms_since_boot(get_absolute_time());
+}
+
+#endif
+
diff --git a/src/rp2_common/pico_lwip/random.c b/src/rp2_common/pico_lwip/random.c
new file mode 100644
index 0000000..2c4cdf8
--- /dev/null
+++ b/src/rp2_common/pico_lwip/random.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "pico.h"
+#include "hardware/structs/rosc.h"
+
+static uint8_t pico_lwip_random_byte(int cycles) {
+ static uint8_t byte;
+ assert(cycles >= 8);
+ assert(rosc_hw->status & ROSC_STATUS_ENABLED_BITS);
+ for(int i=0;i<cycles;i++) {
+ // picked a fairly arbitrary polynomial of 0x35u - this doesn't have to be crazily uniform.
+ byte = ((byte << 1) | rosc_hw->randombit) ^ (byte & 0x80u ? 0x35u : 0);
+ // delay a little because the random bit is a little slow
+ busy_wait_at_least_cycles(30);
+ }
+ return byte;
+}
+
+unsigned int pico_lwip_rand(void) {
+ uint32_t value = 0;
+ for (int i = 0; i < 4; i++) {
+ value = (value << 8u) | pico_lwip_random_byte(32);
+ }
+ return value;
+}
\ No newline at end of file
diff --git a/src/rp2_common/pico_malloc/CMakeLists.txt b/src/rp2_common/pico_malloc/CMakeLists.txt
index deeb30f..57ac267 100644
--- a/src/rp2_common/pico_malloc/CMakeLists.txt
+++ b/src/rp2_common/pico_malloc/CMakeLists.txt
@@ -10,6 +10,7 @@
pico_wrap_function(pico_malloc malloc)
pico_wrap_function(pico_malloc calloc)
+ pico_wrap_function(pico_malloc realloc)
pico_wrap_function(pico_malloc free)
target_link_libraries(pico_malloc INTERFACE pico_sync)
diff --git a/src/rp2_common/pico_malloc/pico_malloc.c b/src/rp2_common/pico_malloc/pico_malloc.c
index 4928a8e..a053986 100644
--- a/src/rp2_common/pico_malloc/pico_malloc.c
+++ b/src/rp2_common/pico_malloc/pico_malloc.c
@@ -16,6 +16,7 @@
extern void *__real_malloc(size_t size);
extern void *__real_calloc(size_t count, size_t size);
+extern void *__real_realloc(void *mem, size_t size);
extern void __real_free(void *mem);
extern char __StackLimit; /* Set by linker. */
@@ -62,6 +63,23 @@
return rc;
}
+void *__wrap_realloc(void *mem, size_t size) {
+#if PICO_USE_MALLOC_MUTEX
+ mutex_enter_blocking(&malloc_mutex);
+#endif
+ void *rc = __real_realloc(mem, size);
+#if PICO_USE_MALLOC_MUTEX
+ mutex_exit(&malloc_mutex);
+#endif
+#if PICO_DEBUG_MALLOC
+ if (!rc || ((uint8_t *)rc) + size > (uint8_t*)PICO_DEBUG_MALLOC_LOW_WATER) {
+ printf("realloc %p %d->%p\n", mem, (uint) size, rc);
+ }
+#endif
+ check_alloc(rc, size);
+ return rc;
+}
+
void __wrap_free(void *mem) {
#if PICO_USE_MALLOC_MUTEX
mutex_enter_blocking(&malloc_mutex);
diff --git a/src/rp2_common/pico_platform/include/pico/platform.h b/src/rp2_common/pico_platform/include/pico/platform.h
index ee1d360..1d9e1bc 100644
--- a/src/rp2_common/pico_platform/include/pico/platform.h
+++ b/src/rp2_common/pico_platform/include/pico/platform.h
@@ -17,6 +17,8 @@
*/
#include "hardware/platform_defs.h"
+#include "hardware/regs/addressmap.h"
+#include "hardware/regs/sio.h"
// Marker for builds targeting the RP2040
#define PICO_RP2040 1
@@ -233,7 +235,7 @@
* int __force_inline my_function(int x) {
*
*/
-#if defined(__GNUC__) && __GNUC__ <= 7
+#if defined(__GNUC__) && (__GNUC__ <= 6 || (__GNUC__ == 7 && (__GNUC_MINOR__ < 3 || !defined(__cplusplus))))
#define __force_inline inline __always_inline
#else
#define __force_inline __always_inline
@@ -334,13 +336,16 @@
* @return the RP2040 rom version number (1 for RP2040-B0, 2 for RP2040-B1, 3 for RP2040-B2)
*/
static inline uint8_t rp2040_rom_version(void) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
return *(uint8_t*)0x13;
+#pragma GCC diagnostic pop
}
/*! \brief No-op function for the body of tight loops
* \ingroup pico_platform
*
- * Np-op function intended to be called by any tight hardware polling loop. Using this ubiquitously
+ * No-op function intended to be called by any tight hardware polling loop. Using this ubiquitously
* makes it much easier to find tight loops, but also in the future \#ifdef-ed support for lockup
* debugging might be added
*/
@@ -400,6 +405,38 @@
}
#endif
+/*! \brief Helper method to busy-wait for at least the given number of cycles
+ * \ingroup pico_platform
+ *
+ * This method is useful for introducing very short delays.
+ *
+ * This method busy-waits in a tight loop for the given number of system clock cycles. The total wait time is only accurate to within 2 cycles,
+ * and this method uses a loop counter rather than a hardware timer, so the method will always take longer than expected if an
+ * interrupt is handled on the calling core during the busy-wait; you can of course disable interrupts to prevent this.
+ *
+ * You can use \ref clock_get_hz(clk_sys) to determine the number of clock cycles per second if you want to convert an actual
+ * time duration to a number of cycles.
+ *
+ * \param minimum_cycles the minimum number of system clock cycles to delay for
+ */
+static inline void busy_wait_at_least_cycles(uint32_t minimum_cycles) {
+ __asm volatile (
+ ".syntax unified\n"
+ "1: subs %0, #3\n"
+ "bcs 1b\n"
+ : "+r" (minimum_cycles) : : "memory"
+ );
+}
+
+/*! \brief Get the current core number
+ * \ingroup pico_platform
+ *
+ * \return The core number the call was made from
+ */
+__force_inline static uint get_core_num(void) {
+ return (*(uint32_t *) (SIO_BASE + SIO_CPUID_OFFSET));
+}
+
#else // __ASSEMBLER__
#define WRAPPER_FUNC_NAME(x) __wrap_##x
diff --git a/src/rp2_common/pico_runtime/runtime.c b/src/rp2_common/pico_runtime/runtime.c
index 575e23e..70dd3bb 100644
--- a/src/rp2_common/pico_runtime/runtime.c
+++ b/src/rp2_common/pico_runtime/runtime.c
@@ -175,7 +175,7 @@
}
-void _exit(__unused int status) {
+void __attribute__((noreturn)) _exit(__unused int status) {
#if PICO_ENTER_USB_BOOT_ON_EXIT
reset_usb_boot(0,0);
#else
diff --git a/src/rp2_common/pico_standard_link/crt0.S b/src/rp2_common/pico_standard_link/crt0.S
index f57ddfd..b2992f6 100644
--- a/src/rp2_common/pico_standard_link/crt0.S
+++ b/src/rp2_common/pico_standard_link/crt0.S
@@ -225,6 +225,9 @@
cmp r0, #0
bne hold_non_core0_in_bootrom
+ // In a NO_FLASH binary, don't perform .data copy, since it's loaded
+ // in-place by the SRAM load. Still need to clear .bss
+#if !PICO_NO_FLASH
adr r4, data_cpy_table
// assume there is at least one entry
@@ -235,6 +238,7 @@
bl data_cpy
b 1b
2:
+#endif
// Zero out the BSS
ldr r1, =__bss_start__
@@ -266,6 +270,7 @@
bkpt #0
b 1b
+#if !PICO_NO_FLASH
data_cpy_loop:
ldm r1!, {r0}
stm r2!, {r0}
@@ -273,6 +278,10 @@
cmp r2, r3
blo data_cpy_loop
bx lr
+#endif
+
+// Note the data copy table is still included for NO_FLASH builds, even though
+// we skip the copy, because it is listed in binary info
.align 2
data_cpy_table:
diff --git a/src/rp2_common/pico_stdio/stdio.c b/src/rp2_common/pico_stdio/stdio.c
index b457b8a..52a1c0c 100644
--- a/src/rp2_common/pico_stdio/stdio.c
+++ b/src/rp2_common/pico_stdio/stdio.c
@@ -29,6 +29,10 @@
#include "pico/stdio_semihosting.h"
#endif
+#define STDIO_HANDLE_STDIN 0
+#define STDIO_HANDLE_STDOUT 1
+#define STDIO_HANDLE_STDERR 2
+
static stdio_driver_t *drivers;
static stdio_driver_t *filter;
@@ -131,11 +135,13 @@
}
}
}
+ if (time_reached(until)) {
+ return PICO_ERROR_TIMEOUT;
+ }
// we sleep here in case the in_chars methods acquire mutexes or disable IRQs and
// potentially starve out what they are waiting on (have seen this with USB)
busy_wait_us(1);
- } while (!time_reached(until));
- return PICO_ERROR_TIMEOUT;
+ } while (true);
}
int WRAPPER_FUNC(putchar)(int c) {
@@ -165,14 +171,14 @@
}
int _read(int handle, char *buffer, int length) {
- if (handle == 0) {
+ if (handle == STDIO_HANDLE_STDIN) {
return stdio_get_until(buffer, length, at_the_end_of_time);
}
return -1;
}
int _write(int handle, char *buffer, int length) {
- if (handle == 1) {
+ if (handle == STDIO_HANDLE_STDOUT || handle == STDIO_HANDLE_STDERR) {
stdio_put_string(buffer, length, false, false);
return length;
}
@@ -180,20 +186,19 @@
}
void stdio_set_driver_enabled(stdio_driver_t *driver, bool enable) {
- stdio_driver_t *prev = drivers;
- for (stdio_driver_t *d = drivers; d; d = d->next) {
- if (d == driver) {
+ stdio_driver_t **prev = &drivers;
+ while (*prev) {
+ if (*prev == driver) {
if (!enable) {
- prev->next = d->next;
+ *prev = driver->next;
driver->next = NULL;
}
return;
}
- prev = d;
+ prev = &(*prev)->next;
}
if (enable) {
- if (prev) prev->next = driver;
- else drivers = driver;
+ *prev = driver;
}
}
diff --git a/src/rp2_common/pico_stdio_semihosting/include/pico/stdio_semihosting.h b/src/rp2_common/pico_stdio_semihosting/include/pico/stdio_semihosting.h
index 3304368..ca66417 100644
--- a/src/rp2_common/pico_stdio_semihosting/include/pico/stdio_semihosting.h
+++ b/src/rp2_common/pico_stdio_semihosting/include/pico/stdio_semihosting.h
@@ -13,7 +13,7 @@
* \defgroup pico_stdio_semihosting pico_stdio_semihosting
* \ingroup pico_stdio
*
- * Linking this library or calling `pico_enable_stdio_semihosting(TARGET)` in the CMake (which
+ * Linking this library or calling `pico_enable_stdio_semihosting(TARGET ENABLED)` in the CMake (which
* achieves the same thing) will add semihosting to the drivers used for standard output
*/
diff --git a/src/rp2_common/pico_stdio_uart/include/pico/stdio_uart.h b/src/rp2_common/pico_stdio_uart/include/pico/stdio_uart.h
index 5afe910..9e5ac53 100644
--- a/src/rp2_common/pico_stdio_uart/include/pico/stdio_uart.h
+++ b/src/rp2_common/pico_stdio_uart/include/pico/stdio_uart.h
@@ -14,8 +14,8 @@
* \defgroup pico_stdio_uart pico_stdio_uart
* \ingroup pico_stdio
*
- * Linking this library or calling `pico_enable_stdio_uart(TARGET)` in the CMake (which
- * achieves the same thing) will add UART to the drivers used for standard output
+ * Linking this library or calling `pico_enable_stdio_uart(TARGET ENABLED)` in the CMake (which
+ * achieves the same thing) will add UART to the drivers used for standard input/output
*/
// PICO_CONFIG: PICO_STDIO_UART_DEFAULT_CRLF, Default state of CR/LF translation for UART output, type=bool, default=PICO_STDIO_DEFAULT_CRLF, group=pico_stdio_uart
diff --git a/src/rp2_common/pico_stdio_usb/include/pico/stdio_usb.h b/src/rp2_common/pico_stdio_usb/include/pico/stdio_usb.h
index 2aeb647..8ac8244 100644
--- a/src/rp2_common/pico_stdio_usb/include/pico/stdio_usb.h
+++ b/src/rp2_common/pico_stdio_usb/include/pico/stdio_usb.h
@@ -13,8 +13,8 @@
* \defgroup pico_stdio_usb pico_stdio_usb
* \ingroup pico_stdio
*
- * Linking this library or calling `pico_enable_stdio_usb(TARGET)` in the CMake (which
- * achieves the same thing) will add USB CDC to the drivers used for standard output
+ * Linking this library or calling `pico_enable_stdio_usb(TARGET ENABLED)` in the CMake (which
+ * achieves the same thing) will add USB CDC to the drivers used for standard input/output
*
* Note this library is a developer convenience. It is not applicable in all cases; for one it takes full control of the USB device precluding your
* use of the USB in device or host mode. For this reason, this library will automatically disengage if you try to using it alongside \ref tinyusb_device or
@@ -39,9 +39,9 @@
#define PICO_STDIO_USB_TASK_INTERVAL_US 1000
#endif
-// PICO_CONFIG: PICO_STDIO_USB_LOW_PRIORITY_IRQ, low priority (non hardware) IRQ number to claim for tud_task() background execution, default=31, advanced=true, group=pico_stdio_usb
+// PICO_CONFIG: PICO_STDIO_USB_LOW_PRIORITY_IRQ, Explicit User IRQ number to claim for tud_task() background execution instead of letting the implementation pick a free one dynamically (deprecated), advanced=true, group=pico_stdio_usb
#ifndef PICO_STDIO_USB_LOW_PRIORITY_IRQ
-#define PICO_STDIO_USB_LOW_PRIORITY_IRQ 31
+// this variable is no longer set by default (one is claimed dynamically), but will be respected if specified
#endif
// PICO_CONFIG: PICO_STDIO_USB_ENABLE_RESET_VIA_BAUD_RATE, Enable/disable resetting into BOOTSEL mode if the host sets the baud rate to a magic value (PICO_STDIO_USB_RESET_MAGIC_BAUD_RATE), type=bool, default=1, group=pico_stdio_usb
diff --git a/src/rp2_common/pico_stdio_usb/include/tusb_config.h b/src/rp2_common/pico_stdio_usb/include/tusb_config.h
index c0a2843..c0d2ed3 100644
--- a/src/rp2_common/pico_stdio_usb/include/tusb_config.h
+++ b/src/rp2_common/pico_stdio_usb/include/tusb_config.h
@@ -29,6 +29,7 @@
#include "pico/stdio_usb.h"
+#if !defined(LIB_TINYUSB_HOST) && !defined(LIB_TINYUSB_DEVICE)
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE)
#define CFG_TUD_CDC (1)
@@ -38,3 +39,5 @@
// We use a vendor specific interface but with our own driver
#define CFG_TUD_VENDOR (0)
#endif
+
+#endif
diff --git a/src/rp2_common/pico_stdio_usb/reset_interface.c b/src/rp2_common/pico_stdio_usb/reset_interface.c
index 06dce86..cc25177 100644
--- a/src/rp2_common/pico_stdio_usb/reset_interface.c
+++ b/src/rp2_common/pico_stdio_usb/reset_interface.c
@@ -7,6 +7,8 @@
#include "pico/bootrom.h"
+#if !defined(LIB_TINYUSB_HOST) && !defined(LIB_TINYUSB_DEVICE)
+
#if PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE && !(PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL || PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT)
#warning PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE has been selected but neither PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL nor PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT have been selected.
#endif
@@ -110,3 +112,4 @@
}
#endif
+#endif
\ No newline at end of file
diff --git a/src/rp2_common/pico_stdio_usb/stdio_usb.c b/src/rp2_common/pico_stdio_usb/stdio_usb.c
index 913d606..cd2e2c9 100644
--- a/src/rp2_common/pico_stdio_usb/stdio_usb.c
+++ b/src/rp2_common/pico_stdio_usb/stdio_usb.c
@@ -4,17 +4,33 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
-#if !defined(LIB_TINYUSB_HOST) && !defined(LIB_TINYUSB_DEVICE)
+#ifndef LIB_TINYUSB_HOST
#include "tusb.h"
+#include "pico/stdio_usb.h"
+// these may not be set if the user is providing tud support (i.e. LIB_TINYUSB_DEVICE is 1 because
+// the user linked in tinyusb_device) but they haven't selected CDC
+#if (CFG_TUD_ENABLED | TUSB_OPT_DEVICE_ENABLED) && CFG_TUD_CDC
+
+#include "pico/binary_info.h"
#include "pico/time.h"
#include "pico/stdio/driver.h"
-#include "pico/binary_info.h"
#include "pico/mutex.h"
#include "hardware/irq.h"
-static_assert(PICO_STDIO_USB_LOW_PRIORITY_IRQ > RTC_IRQ, ""); // note RTC_IRQ is currently the last one
static mutex_t stdio_usb_mutex;
+#ifndef NDEBUG
+static uint8_t stdio_usb_core_num;
+#endif
+
+// when tinyusb_device is explicitly linked we do no background tud processing
+#if !LIB_TINYUSB_DEVICE
+#ifdef PICO_STDIO_USB_LOW_PRIORITY_IRQ
+static_assert(PICO_STDIO_USB_LOW_PRIORITY_IRQ >= NUM_IRQS - NUM_USER_IRQS, "");
+#define low_priority_irq_num PICO_STDIO_USB_LOW_PRIORITY_IRQ
+#else
+static uint8_t low_priority_irq_num;
+#endif
static void low_priority_worker_irq(void) {
// if the mutex is already owned, then we are in user code
@@ -26,10 +42,16 @@
}
}
+static void usb_irq(void) {
+ irq_set_pending(low_priority_irq_num);
+}
+
static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) {
- irq_set_pending(PICO_STDIO_USB_LOW_PRIORITY_IRQ);
+ assert(stdio_usb_core_num == get_core_num()); // if this fails, you have initialized stdio_usb on the wrong core
+ irq_set_pending(low_priority_irq_num);
return PICO_STDIO_USB_TASK_INTERVAL_US;
}
+#endif
static void stdio_usb_out_chars(const char *buf, int length) {
static uint64_t last_avail_time;
@@ -89,18 +111,38 @@
};
bool stdio_usb_init(void) {
+#ifndef NDEBUG
+ stdio_usb_core_num = (uint8_t)get_core_num();
+#endif
#if !PICO_NO_BI_STDIO_USB
bi_decl_if_func_used(bi_program_feature("USB stdin / stdout"));
#endif
- // initialize TinyUSB
+#if !defined(LIB_TINYUSB_DEVICE)
+ // initialize TinyUSB, as user hasn't explicitly linked it
tusb_init();
-
- irq_set_exclusive_handler(PICO_STDIO_USB_LOW_PRIORITY_IRQ, low_priority_worker_irq);
- irq_set_enabled(PICO_STDIO_USB_LOW_PRIORITY_IRQ, true);
+#else
+ assert(tud_inited()); // we expect the caller to have initialized if they are using TinyUSB
+#endif
mutex_init(&stdio_usb_mutex);
- bool rc = add_alarm_in_us(PICO_STDIO_USB_TASK_INTERVAL_US, timer_task, NULL, true);
+ bool rc = true;
+#if !LIB_TINYUSB_DEVICE
+#ifdef PICO_STDIO_USB_LOW_PRIORITY_IRQ
+ user_irq_claim(PICO_STDIO_USB_LOW_PRIORITY_IRQ);
+#else
+ low_priority_irq_num = (uint8_t) user_irq_claim_unused(true);
+#endif
+ irq_set_exclusive_handler(low_priority_irq_num, low_priority_worker_irq);
+ irq_set_enabled(low_priority_irq_num, true);
+
+ if (irq_has_shared_handler(USBCTRL_IRQ)) {
+ // we can use a shared handler to notice when there may be work to do
+ irq_add_shared_handler(USBCTRL_IRQ, usb_irq, PICO_SHARED_IRQ_HANDLER_LOWEST_ORDER_PRIORITY);
+ } else {
+ rc = add_alarm_in_us(PICO_STDIO_USB_TASK_INTERVAL_US, timer_task, NULL, true);
+ }
+#endif
if (rc) {
stdio_set_driver_enabled(&stdio_usb, true);
#if PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS
@@ -127,9 +169,15 @@
return tud_cdc_connected();
}
#else
-#include "pico/stdio_usb.h"
-#warning stdio USB was configured, but is being disabled as TinyUSB is explicitly linked
+#warning stdio USB was configured along with user use of TinyUSB device mode, but CDC is not enabled
bool stdio_usb_init(void) {
return false;
}
-#endif
+#endif // CFG_TUD_ENABLED && CFG_TUD_CDC
+#else
+#warning stdio USB was configured, but is being disabled as TinyUSB host is explicitly linked
+bool stdio_usb_init(void) {
+ return false;
+}
+#endif // !LIB_TINYUSB_HOST
+
diff --git a/src/rp2_common/pico_stdlib/stdlib.c b/src/rp2_common/pico_stdlib/stdlib.c
index 7c9854e..159095c 100644
--- a/src/rp2_common/pico_stdlib/stdlib.c
+++ b/src/rp2_common/pico_stdlib/stdlib.c
@@ -73,7 +73,7 @@
uint crystal_freq_khz = clock_get_hz(clk_ref) / 1000;
for (uint fbdiv = 320; fbdiv >= 16; fbdiv--) {
uint vco = fbdiv * crystal_freq_khz;
- if (vco < 400000 || vco > 1600000) continue;
+ if (vco < PICO_PLL_VCO_MIN_FREQ_MHZ * 1000 || vco > PICO_PLL_VCO_MAX_FREQ_MHZ * 1000) continue;
for (uint postdiv1 = 7; postdiv1 >= 1; postdiv1--) {
for (uint postdiv2 = postdiv1; postdiv2 >= 1; postdiv2--) {
uint out = vco / (postdiv1 * postdiv2);
diff --git a/src/rp2_common/tinyusb/CMakeLists.txt b/src/rp2_common/tinyusb/CMakeLists.txt
index 80a6e78..8978788 100644
--- a/src/rp2_common/tinyusb/CMakeLists.txt
+++ b/src/rp2_common/tinyusb/CMakeLists.txt
@@ -45,5 +45,14 @@
pico_add_impl_library(tinyusb_board)
target_link_libraries(tinyusb_board INTERFACE tinyusb_bsp)
+ # Override suppress_tinyusb_warnings to add suppression of (falsely) reported GCC 11.2 warnings
+ function(suppress_tinyusb_warnings)
+ _suppress_tinyusb_warnings()
+ set_source_files_properties(
+ ${PICO_TINYUSB_PATH}/src/portable/raspberrypi/rp2040/rp2040_usb.c
+ PROPERTIES
+ COMPILE_FLAGS "-Wno-stringop-overflow -Wno-array-bounds")
+ endfunction()
+
pico_promote_common_scope_vars()
endif()