From 94c594b76475d9cb6e9510e1229d19e787c61b1d Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Tue, 1 Oct 2024 15:35:43 +0100 Subject: [PATCH 01/30] rp2: Fix USB sleep on 2350. Signed-off-by: Peter Harper --- ports/rp2/modmachine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c index cd73552dd9874..3229aed277b35 100644 --- a/ports/rp2/modmachine.c +++ b/ports/rp2/modmachine.c @@ -228,7 +228,7 @@ static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) { #if PICO_RP2040 clocks_hw->sleep_en1 |= CLOCKS_SLEEP_EN1_CLK_USB_USBCTRL_BITS; #elif PICO_RP2350 - clocks_hw->sleep_en1 |= CLOCKS_SLEEP_EN1_CLK_SYS_USBCTRL_BITS; + clocks_hw->sleep_en1 |= CLOCKS_SLEEP_EN1_CLK_USB_BITS; #else #error Unknown processor #endif From 3fd5bbeb57670f95c9a6cfa57ca9ca26f92ef9da Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 25 Sep 2024 09:58:07 +0100 Subject: [PATCH 02/30] rp2: CMakeLists: Add components required by bootrom.h. Signed-off-by: Peter Harper --- ports/rp2/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 4baaf7debf6c5..4c85b83440ebe 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -196,6 +196,7 @@ set(MICROPY_SOURCE_QSTR ) set(PICO_SDK_COMPONENTS + boot_bootrom_headers hardware_adc hardware_base hardware_boot_lock @@ -222,6 +223,7 @@ set(PICO_SDK_COMPONENTS pico_base_headers pico_binary_info pico_bootrom + pico_flash pico_multicore pico_platform pico_platform_compiler From ff20a5043b8e3dc844b71935d44c15670a43160f Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Mon, 30 Sep 2024 13:05:22 +0100 Subject: [PATCH 03/30] rp2: Sleep changes. Stop using soft timer for mp_wfe_or_timeout. Now uses the alarm pool again as issues with this code have been fixed. This resolves the "sev" issue that stops the rp2 port going idle. Change the sleep code to use the hardware timer library and alarm 2 as alarm 3 is used by the alarm pool Signed-off-by: Peter Harper --- ports/rp2/main.c | 1 - ports/rp2/modmachine.c | 34 +++++++++++++++++++--------------- ports/rp2/mphalport.c | 12 +----------- 3 files changed, 20 insertions(+), 27 deletions(-) diff --git a/ports/rp2/main.c b/ports/rp2/main.c index d6bf448267152..9a82def6ff079 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -85,7 +85,6 @@ int main(int argc, char **argv) { #endif pendsv_init(); - soft_timer_init(); // Set the MCU frequency and as a side effect the peripheral clock to 48 MHz. set_sys_clock_khz(SYS_CLK_KHZ, false); diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c index 3229aed277b35..58ba8377748b5 100644 --- a/ports/rp2/modmachine.c +++ b/ports/rp2/modmachine.c @@ -121,6 +121,9 @@ static void mp_machine_idle(void) { MICROPY_INTERNAL_WFE(1); } +static void alarm_sleep_callback(uint alarm_id) { +} + static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) { mp_int_t delay_ms = 0; bool use_timer_alarm = false; @@ -190,22 +193,15 @@ static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) { // Disable ROSC. rosc_hw->ctrl = ROSC_CTRL_ENABLE_VALUE_DISABLE << ROSC_CTRL_ENABLE_LSB; + int alarm_num = 2; if (n_args == 0) { #if MICROPY_PY_NETWORK_CYW43 gpio_set_dormant_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true); #endif xosc_dormant(); } else { - bool timer3_enabled = irq_is_enabled(3); - - const uint32_t alarm_num = 3; - const uint32_t irq_num = TIMER_ALARM_IRQ_NUM(timer_hw, alarm_num); + hardware_alarm_claim(alarm_num); if (use_timer_alarm) { - // Make sure ALARM3/IRQ3 is enabled on _this_ core - if (!timer3_enabled) { - irq_set_enabled(irq_num, true); - } - hw_set_bits(&timer_hw->inte, 1u << alarm_num); // Use timer alarm to wake. clocks_hw->sleep_en0 = 0x0; #if PICO_RP2040 @@ -215,8 +211,12 @@ static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) { #else #error Unknown processor #endif - timer_hw->intr = 1u << alarm_num; // clear any IRQ - timer_hw->alarm[alarm_num] = timer_hw->timerawl + delay_ms * 1000; + hardware_alarm_set_callback(alarm_num, alarm_sleep_callback); + if (hardware_alarm_set_target(alarm_num, make_timeout_time_ms(delay_ms))) { + hardware_alarm_set_callback(alarm_num, NULL); + hardware_alarm_unclaim(alarm_num); + alarm_num = -1; + } } else { // TODO: Use RTC alarm to wake. clocks_hw->sleep_en0 = 0x0; @@ -246,11 +246,10 @@ static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) { #endif // Go into low-power mode. - __wfi(); - - if (!timer3_enabled) { - irq_set_enabled(irq_num, false); + if (alarm_num >= 0) { + __wfi(); } + clocks_hw->sleep_en0 |= ~(0u); clocks_hw->sleep_en1 |= ~(0u); } @@ -264,6 +263,11 @@ static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) { // Re-sync mp_hal_time_ns() counter with aon timer. mp_hal_time_ns_set_from_rtc(); + if (alarm_num >= 0) { + hardware_alarm_cancel(alarm_num); + hardware_alarm_set_callback(alarm_num, NULL); + hardware_alarm_unclaim(alarm_num); + } } NORETURN static void mp_machine_deepsleep(size_t n_args, const mp_obj_t *args) { diff --git a/ports/rp2/mphalport.c b/ports/rp2/mphalport.c index 3f50151620a02..5160312259e11 100644 --- a/ports/rp2/mphalport.c +++ b/ports/rp2/mphalport.c @@ -266,15 +266,5 @@ void soft_timer_init(void) { } void mp_wfe_or_timeout(uint32_t timeout_ms) { - soft_timer_entry_t timer; - - // Note the timer doesn't have an associated callback, it just exists to create a - // hardware interrupt to wake the CPU - soft_timer_static_init(&timer, SOFT_TIMER_MODE_ONE_SHOT, 0, NULL); - soft_timer_insert(&timer, timeout_ms); - - __wfe(); - - // Clean up the timer node if it's not already - soft_timer_remove(&timer); + best_effort_wfe_or_timeout(delayed_by_ms(get_absolute_time(), timeout_ms)); } From 7745037319e9c518fccf626148aa0d6b9e65acf0 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 9 Oct 2024 18:03:55 +0100 Subject: [PATCH 04/30] rp2: Add mp_hal_is_pin_reserved. As cyw43 pins might be dynamic, add a function that returns if a pin is reserved. This is used by MICROPY_HW_PIN_RESERVED Signed-off-by: Peter Harper --- ports/rp2/boards/RPI_PICO_W/mpconfigboard.h | 4 +++- ports/rp2/mphalport.c | 8 ++++++++ ports/rp2/mphalport.h | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/ports/rp2/boards/RPI_PICO_W/mpconfigboard.h b/ports/rp2/boards/RPI_PICO_W/mpconfigboard.h index ef812b6301356..45ad6107ba14e 100644 --- a/ports/rp2/boards/RPI_PICO_W/mpconfigboard.h +++ b/ports/rp2/boards/RPI_PICO_W/mpconfigboard.h @@ -20,4 +20,6 @@ #define MICROPY_HW_PIN_EXT_COUNT CYW43_WL_GPIO_COUNT -#define MICROPY_HW_PIN_RESERVED(i) ((i) == CYW43_PIN_WL_HOST_WAKE || (i) == CYW43_PIN_WL_REG_ON) +// If this returns true for a pin then its irq will not be disabled on a soft reboot +int mp_hal_is_pin_reserved(int n); +#define MICROPY_HW_PIN_RESERVED(i) mp_hal_is_pin_reserved(i) diff --git a/ports/rp2/mphalport.c b/ports/rp2/mphalport.c index 5160312259e11..b581b3b59f95d 100644 --- a/ports/rp2/mphalport.c +++ b/ports/rp2/mphalport.c @@ -268,3 +268,11 @@ void soft_timer_init(void) { void mp_wfe_or_timeout(uint32_t timeout_ms) { best_effort_wfe_or_timeout(delayed_by_ms(get_absolute_time(), timeout_ms)); } + +int mp_hal_is_pin_reserved(int n) { + #if MICROPY_PY_NETWORK_CYW43 + return n == CYW43_PIN_WL_HOST_WAKE; + #else + return false; + #endif +} diff --git a/ports/rp2/mphalport.h b/ports/rp2/mphalport.h index da865fb7e85ea..33a1073e1df81 100644 --- a/ports/rp2/mphalport.h +++ b/ports/rp2/mphalport.h @@ -210,5 +210,6 @@ enum { void mp_hal_get_mac(int idx, uint8_t buf[6]); void mp_hal_get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest); void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]); +int mp_hal_is_pin_reserved(int n); #endif // MICROPY_INCLUDED_RP2_MPHALPORT_H From d9e1be3cc04e057dc819d3914cc42acedfe64053 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 9 Oct 2024 18:05:11 +0100 Subject: [PATCH 05/30] rp2: Add RPI_PICO2_W. Signed-off-by: Peter Harper --- ports/rp2/boards/RPI_PICO2_W/board.json | 21 +++++++++++++ ports/rp2/boards/RPI_PICO2_W/manifest.py | 6 ++++ .../boards/RPI_PICO2_W/mpconfigboard.cmake | 17 +++++++++++ ports/rp2/boards/RPI_PICO2_W/mpconfigboard.h | 22 ++++++++++++++ ports/rp2/boards/RPI_PICO2_W/pins.csv | 30 +++++++++++++++++++ 5 files changed, 96 insertions(+) create mode 100644 ports/rp2/boards/RPI_PICO2_W/board.json create mode 100644 ports/rp2/boards/RPI_PICO2_W/manifest.py create mode 100644 ports/rp2/boards/RPI_PICO2_W/mpconfigboard.cmake create mode 100644 ports/rp2/boards/RPI_PICO2_W/mpconfigboard.h create mode 100644 ports/rp2/boards/RPI_PICO2_W/pins.csv diff --git a/ports/rp2/boards/RPI_PICO2_W/board.json b/ports/rp2/boards/RPI_PICO2_W/board.json new file mode 100644 index 0000000000000..f35ea940a2663 --- /dev/null +++ b/ports/rp2/boards/RPI_PICO2_W/board.json @@ -0,0 +1,21 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "BLE", + "Dual-core", + "External Flash", + "USB", + "WiFi" + ], + "images": [ + "rp2-pico2-w.jpg" + ], + "mcu": "rp2350", + "product": "Pico 2 W", + "thumbnail": "", + "url": "https://www.raspberrypi.com/products/raspberry-pi-pico-2/", + "vendor": "Raspberry Pi" +} diff --git a/ports/rp2/boards/RPI_PICO2_W/manifest.py b/ports/rp2/boards/RPI_PICO2_W/manifest.py new file mode 100644 index 0000000000000..4e38f09cdee4f --- /dev/null +++ b/ports/rp2/boards/RPI_PICO2_W/manifest.py @@ -0,0 +1,6 @@ +include("$(PORT_DIR)/boards/manifest.py") + +require("bundle-networking") + +# Bluetooth +require("aioble") diff --git a/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.cmake b/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.cmake new file mode 100644 index 0000000000000..1d9b7fc448a0c --- /dev/null +++ b/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.cmake @@ -0,0 +1,17 @@ +# cmake file for Raspberry Pi Pico 2 W + +set(PICO_BOARD "pico2_w") + +# To change the gpio count for QFN-80 +# set(PICO_NUM_GPIOS 48) + +set(MICROPY_PY_LWIP ON) +set(MICROPY_PY_NETWORK_CYW43 ON) + +# Bluetooth +set(MICROPY_PY_BLUETOOTH ON) +set(MICROPY_BLUETOOTH_BTSTACK ON) +set(MICROPY_PY_BLUETOOTH_CYW43 ON) + +# Board specific version of the frozen manifest +set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) diff --git a/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.h b/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.h new file mode 100644 index 0000000000000..7054499533f97 --- /dev/null +++ b/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.h @@ -0,0 +1,22 @@ +// Board and hardware specific configuration +#define MICROPY_HW_BOARD_NAME "Raspberry Pi Pico 2 W" +#define MICROPY_HW_FLASH_STORAGE_BYTES (PICO_FLASH_SIZE_BYTES - 1024 * 1024) + +// Enable networking. +#define MICROPY_PY_NETWORK 1 +#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "Pico2W" + +// CYW43 driver configuration. +#define CYW43_USE_SPI (1) +#define CYW43_LWIP (1) +#define CYW43_GPIO (1) +#define CYW43_SPI_PIO (1) + +// For debugging mbedtls - also set +// Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose +// #define MODUSSL_MBEDTLS_DEBUG_LEVEL 1 + +#define MICROPY_HW_PIN_EXT_COUNT CYW43_WL_GPIO_COUNT + +int mp_hal_is_pin_reserved(int n); +#define MICROPY_HW_PIN_RESERVED(i) mp_hal_is_pin_reserved(i) diff --git a/ports/rp2/boards/RPI_PICO2_W/pins.csv b/ports/rp2/boards/RPI_PICO2_W/pins.csv new file mode 100644 index 0000000000000..8debb6326e070 --- /dev/null +++ b/ports/rp2/boards/RPI_PICO2_W/pins.csv @@ -0,0 +1,30 @@ +GP0,GPIO0 +GP1,GPIO1 +GP2,GPIO2 +GP3,GPIO3 +GP4,GPIO4 +GP5,GPIO5 +GP6,GPIO6 +GP7,GPIO7 +GP8,GPIO8 +GP9,GPIO9 +GP10,GPIO10 +GP11,GPIO11 +GP12,GPIO12 +GP13,GPIO13 +GP14,GPIO14 +GP15,GPIO15 +GP16,GPIO16 +GP17,GPIO17 +GP18,GPIO18 +GP19,GPIO19 +GP20,GPIO20 +GP21,GPIO21 +GP22,GPIO22 +GP26,GPIO26 +GP27,GPIO27 +GP28,GPIO28 +WL_GPIO0,EXT_GPIO0 +WL_GPIO1,EXT_GPIO1 +WL_GPIO2,EXT_GPIO2 +LED,EXT_GPIO0 From 64d2c2aa95569fe7a72e12d84530eeb4c7afb26b Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Mon, 21 Oct 2024 15:31:24 +0100 Subject: [PATCH 06/30] tests/ports/rp2: Put back lightsleep/machine_idle test for RP2350. This reverts commit b42bb911c663dc90575d6a7fe3ea4760b6559372. Signed-off-by: Peter Harper --- tests/ports/rp2/rp2_lightsleep.py | 9 ++------- tests/ports/rp2/rp2_machine_idle.py | 6 ------ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/tests/ports/rp2/rp2_lightsleep.py b/tests/ports/rp2/rp2_lightsleep.py index 5ce5696e0e18c..3587def68fcd8 100644 --- a/tests/ports/rp2/rp2_lightsleep.py +++ b/tests/ports/rp2/rp2_lightsleep.py @@ -9,18 +9,13 @@ # A range of sleep periods (1 to 512ms) are tested. The total nominal sleep time # is 10.23 seconds, but on most ports this will finish much earlier as interrupts # happen before each timeout expires. -import sys - try: from machine import lightsleep, Pin except ImportError: print("SKIP") raise SystemExit -# RP2350 currently fails this test, needs further investigation. -if "RP2350" in sys.implementation._machine: - print("SKIP") - raise SystemExit +from sys import stdout, platform try: led = Pin(Pin.board.LED, Pin.OUT) @@ -30,7 +25,7 @@ for n in range(100): if led: led.toggle() - sys.stdout.write(chr(ord("a") + (n % 26))) + stdout.write(chr(ord("a") + (n % 26))) lightsleep(2 ** (n % 10)) print("\nDONE") diff --git a/tests/ports/rp2/rp2_machine_idle.py b/tests/ports/rp2/rp2_machine_idle.py index 3135110b82000..f9c28284782f8 100644 --- a/tests/ports/rp2/rp2_machine_idle.py +++ b/tests/ports/rp2/rp2_machine_idle.py @@ -1,4 +1,3 @@ -import sys import machine import time @@ -18,11 +17,6 @@ # Verification uses the average idle time, as individual iterations will always # have outliers due to interrupts, scheduler, etc. -# RP2350 currently fails this test because machine.idle() resumes immediately. -if "RP2350" in sys.implementation._machine: - print("SKIP") - raise SystemExit - ITERATIONS = 500 total = 0 From 366116a5d223ad6fb2c149f1df1d81c8b00f45d7 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Mon, 21 Oct 2024 15:32:06 +0100 Subject: [PATCH 07/30] lib/pico-sdk: Use develop version. Signed-off-by: Peter Harper --- lib/pico-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pico-sdk b/lib/pico-sdk index efe2103f9b284..37085889b0a1d 160000 --- a/lib/pico-sdk +++ b/lib/pico-sdk @@ -1 +1 @@ -Subproject commit efe2103f9b28458a1615ff096054479743ade236 +Subproject commit 37085889b0a1d99d50cf06f77ae08e2541c4c0f7 From 4ee4fa0307f8eb64dfa96234ddcd5e41773a428a Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 23 Oct 2024 16:41:54 +0100 Subject: [PATCH 08/30] rp2: Define cyw43 pins. The cyw43 pins used to be hardcoded and CYW43_PIN_WL_HOST_WAKE and CYW43_PIN_WL_REG_ON were in the pico_w.h board header. This has been changed so the board header just defines the "default version of the pins, e.g. CYW43_DEFAULT_PIN_WL_HOST_WAKE, CYW43_DEFAULT_PIN_WL_REG_ON etc. Set the pin values in cyw43_configport.h so cyw43-driver sees them and allow them to be changed at runtime (dynamic) if required. Signed-off-by: Peter Harper --- ports/rp2/cyw43_configport.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/ports/rp2/cyw43_configport.h b/ports/rp2/cyw43_configport.h index 4b012ce17e994..4294691c66657 100644 --- a/ports/rp2/cyw43_configport.h +++ b/ports/rp2/cyw43_configport.h @@ -53,6 +53,41 @@ #define CYW43_HOST_NAME mod_network_hostname_data +#if CYW43_PIN_WL_DYNAMIC + +// Dynamic pins can be changed at runtime before initialising the CYW43 + +typedef enum cyw43_pin_index_t { + CYW43_PIN_INDEX_WL_REG_ON, + CYW43_PIN_INDEX_WL_DATA_OUT, + CYW43_PIN_INDEX_WL_DATA_IN, + CYW43_PIN_INDEX_WL_HOST_WAKE, + CYW43_PIN_INDEX_WL_CLOCK, + CYW43_PIN_INDEX_WL_CS, + CYW43_PIN_INDEX_WL_COUNT // last +} cyw43_pin_index_t; + +// Function to retrieve a cyw43 dynamic pin +uint cyw43_get_pin_wl(cyw43_pin_index_t pin_id); + +#define CYW43_PIN_WL_REG_ON cyw43_get_pin_wl(CYW43_PIN_INDEX_WL_REG_ON) +#define CYW43_PIN_WL_DATA_OUT cyw43_get_pin_wl(CYW43_PIN_INDEX_WL_DATA_OUT) +#define CYW43_PIN_WL_DATA_IN cyw43_get_pin_wl(CYW43_PIN_INDEX_WL_DATA_IN) +#define CYW43_PIN_WL_HOST_WAKE cyw43_get_pin_wl(CYW43_PIN_INDEX_WL_HOST_WAKE) +#define CYW43_PIN_WL_CLOCK cyw43_get_pin_wl(CYW43_PIN_INDEX_WL_CLOCK) +#define CYW43_PIN_WL_CS cyw43_get_pin_wl(CYW43_PIN_INDEX_WL_CS) + +#else + +#define CYW43_PIN_WL_REG_ON CYW43_DEFAULT_PIN_WL_REG_ON +#define CYW43_PIN_WL_DATA_OUT CYW43_DEFAULT_PIN_WL_DATA_OUT +#define CYW43_PIN_WL_DATA_IN CYW43_DEFAULT_PIN_WL_DATA_IN +#define CYW43_PIN_WL_HOST_WAKE CYW43_DEFAULT_PIN_WL_HOST_WAKE +#define CYW43_PIN_WL_CLOCK CYW43_DEFAULT_PIN_WL_CLOCK +#define CYW43_PIN_WL_CS CYW43_DEFAULT_PIN_WL_CS + +#endif + #define CYW43_SDPCM_SEND_COMMON_WAIT \ if (get_core_num() == 0) { \ cyw43_yield(); \ From ce3c4055224a12aa4a70e784ce101a189fc0c1a6 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Tue, 22 Oct 2024 18:01:34 +0100 Subject: [PATCH 09/30] extmod/network_cyw43.c: Make new overrideable. Signed-off-by: Peter Harper --- extmod/network_cyw43.c | 21 ++++++++++++++++++--- extmod/network_cyw43.h | 3 +++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/extmod/network_cyw43.c b/extmod/network_cyw43.c index 3066cac75d3b7..c518de63f8322 100644 --- a/extmod/network_cyw43.c +++ b/extmod/network_cyw43.c @@ -89,14 +89,29 @@ static void network_cyw43_print(const mp_print_t *print, mp_obj_t self_in, mp_pr ); } + +mp_obj_t network_cyw43_get_interface(mp_int_t type) { + if (type == MOD_NETWORK_STA_IF) { + return MP_OBJ_FROM_PTR(&network_cyw43_wl_sta); + } else { + return MP_OBJ_FROM_PTR(&network_cyw43_wl_ap); + } +} + +// Allow network_cyw43_make_new to be overridden +#ifndef MICROPY_PY_NETWORK_CYW43_MAKE_NEW +#define MICROPY_PY_NETWORK_CYW43_MAKE_NEW network_cyw43_make_new static mp_obj_t network_cyw43_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, 1, false); if (n_args == 0 || mp_obj_get_int(args[0]) == MOD_NETWORK_STA_IF) { - return MP_OBJ_FROM_PTR(&network_cyw43_wl_sta); + return network_cyw43_get_interface(MOD_NETWORK_STA_IF); } else { - return MP_OBJ_FROM_PTR(&network_cyw43_wl_ap); + return network_cyw43_get_interface(MOD_NETWORK_AP_IF); } } +#else +mp_obj_t MICROPY_PY_NETWORK_CYW43_MAKE_NEW(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args); +#endif static mp_obj_t network_cyw43_send_ethernet(mp_obj_t self_in, mp_obj_t buf_in) { network_cyw43_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -558,7 +573,7 @@ MP_DEFINE_CONST_OBJ_TYPE( mp_network_cyw43_type, MP_QSTR_CYW43, MP_TYPE_FLAG_NONE, - make_new, network_cyw43_make_new, + make_new, MICROPY_PY_NETWORK_CYW43_MAKE_NEW, print, network_cyw43_print, locals_dict, &network_cyw43_locals_dict ); diff --git a/extmod/network_cyw43.h b/extmod/network_cyw43.h index 4228bf6e8f91a..ce02cf3843124 100644 --- a/extmod/network_cyw43.h +++ b/extmod/network_cyw43.h @@ -28,4 +28,7 @@ extern const mp_obj_type_t mp_network_cyw43_type; +// Get the interface, where type is either MOD_NETWORK_STA_IF or MOD_NETWORK_AP_IF +mp_obj_t network_cyw43_get_interface(mp_int_t type); + #endif // MICROPY_INCLUDED_EXTMOD_NETWORK_CYW43_H From aace525410b9d4c0765043299ac99a3475b7d240 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 25 Sep 2024 10:37:52 +0100 Subject: [PATCH 10/30] rp2: Support for dynamic pins. Support configuring wireless on arbitrary GPIO pins. e.g. import network wlan = network.WLAN(network.STA_IF, pin_on=2, pin_cs=3, pin_dat=4, pin_clock=5, div_int=3) Signed-off-by: Peter Harper --- ports/rp2/CMakeLists.txt | 7 ++++ ports/rp2/mpconfigport.h | 4 ++ ports/rp2/mpnetworkport.c | 4 ++ ports/rp2/rp2_network_cyw43.c | 70 +++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 ports/rp2/rp2_network_cyw43.c diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 4c85b83440ebe..105bdd501258c 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -195,6 +195,12 @@ set(MICROPY_SOURCE_QSTR ${CMAKE_BINARY_DIR}/pins_${MICROPY_BOARD}.c ) +if (MICROPY_PY_NETWORK_CYW43) + list(APPEND MICROPY_SOURCE_QSTR + ${MICROPY_PORT_DIR}/rp2_network_cyw43.c + ) +endif() + set(PICO_SDK_COMPONENTS boot_bootrom_headers hardware_adc @@ -403,6 +409,7 @@ if (MICROPY_PY_NETWORK_CYW43) list(APPEND MICROPY_SOURCE_PORT machine_pin_cyw43.c + rp2_network_cyw43.c ) target_link_libraries(${MICROPY_TARGET} diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index 15eeab4f34b07..cfa34e6f8ad8d 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -223,6 +223,10 @@ extern const struct _mp_obj_type_t mp_network_cyw43_type; { MP_ROM_QSTR(MP_QSTR_STAT_NO_AP_FOUND), MP_ROM_INT(CYW43_LINK_NONET) }, \ { MP_ROM_QSTR(MP_QSTR_STAT_CONNECT_FAIL), MP_ROM_INT(CYW43_LINK_FAIL) }, \ { MP_ROM_QSTR(MP_QSTR_STAT_GOT_IP), MP_ROM_INT(CYW43_LINK_UP) }, + +// Override network_cyw43_make_new +#define MICROPY_PY_NETWORK_CYW43_MAKE_NEW rp2_network_cyw43_make_new + #else #define MICROPY_HW_NIC_CYW43 #endif diff --git a/ports/rp2/mpnetworkport.c b/ports/rp2/mpnetworkport.c index fcc60b3fe5796..ddb35abcbed86 100644 --- a/ports/rp2/mpnetworkport.c +++ b/ports/rp2/mpnetworkport.c @@ -77,6 +77,10 @@ void cyw43_irq_init(void) { NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV); } +void cyw43_irq_deinit(void) { + gpio_remove_raw_irq_handler(CYW43_PIN_WL_HOST_WAKE, gpio_irq_handler); +} + void cyw43_post_poll_hook(void) { cyw43_has_pending = 0; gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, CYW43_IRQ_LEVEL, true); diff --git a/ports/rp2/rp2_network_cyw43.c b/ports/rp2/rp2_network_cyw43.c new file mode 100644 index 0000000000000..94d5036886dc9 --- /dev/null +++ b/ports/rp2/rp2_network_cyw43.c @@ -0,0 +1,70 @@ +#include "py/runtime.h" +#include "extmod/network_cyw43.h" +#include "extmod/modnetwork.h" +#include "lib/cyw43-driver/src/cyw43.h" + +void cyw43_irq_deinit(void); +void cyw43_irq_init(void); + +#if CYW43_PIN_WL_DYNAMIC +// Defined in cyw43_bus_pio_spi.c +extern int cyw43_set_pins_wl(uint pins[CYW43_PIN_INDEX_WL_COUNT]); +#endif + +#if CYW43_PIO_CLOCK_DIV_DYNAMIC +// Defined in cyw43_bus_pio_spi.c +extern void cyw43_set_pio_clock_divisor(uint16_t clock_div_int, uint8_t clock_div_frac); +#endif + +mp_obj_t rp2_network_cyw43_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_interface, ARG_pin_on, ARG_pin_out, ARG_pin_in, ARG_pin_wake, ARG_pin_clock, ARG_pin_cs, ARG_pin_dat, ARG_div_int, ARG_div_frac }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_interface, MP_ARG_INT, {.u_int = MOD_NETWORK_STA_IF} }, + #if CYW43_PIN_WL_DYNAMIC + { MP_QSTR_pin_on, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + { MP_QSTR_pin_out, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + { MP_QSTR_pin_in, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + { MP_QSTR_pin_wake, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + { MP_QSTR_pin_clock, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + { MP_QSTR_pin_cs, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + { MP_QSTR_pin_dat, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + #endif + #if CYW43_PIO_CLOCK_DIV_DYNAMIC + { MP_QSTR_div_int, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_div_frac, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 0 } }, + #endif + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // Set the pins + #if CYW43_PIN_WL_DYNAMIC + #define SET_PIN_ARG(ARG_ENUM, DEFAULT) args[ARG_ENUM].u_obj != MP_OBJ_NULL ? mp_hal_get_pin_obj(args[ARG_ENUM].u_obj) : (DEFAULT) + uint pins[CYW43_PIN_INDEX_WL_COUNT] = { + SET_PIN_ARG(ARG_pin_on, CYW43_DEFAULT_PIN_WL_REG_ON), + SET_PIN_ARG(ARG_pin_out, SET_PIN_ARG(ARG_pin_dat, CYW43_DEFAULT_PIN_WL_DATA_OUT)), + SET_PIN_ARG(ARG_pin_in, SET_PIN_ARG(ARG_pin_dat, CYW43_DEFAULT_PIN_WL_DATA_IN)), + SET_PIN_ARG(ARG_pin_wake, SET_PIN_ARG(ARG_pin_dat, CYW43_DEFAULT_PIN_WL_HOST_WAKE)), + SET_PIN_ARG(ARG_pin_clock, CYW43_DEFAULT_PIN_WL_CLOCK), + SET_PIN_ARG(ARG_pin_cs, CYW43_DEFAULT_PIN_WL_CS), + }; + + // re-initialise cyw43 + cyw43_irq_deinit(); + cyw43_set_pins_wl(pins); + cyw43_irq_init(); + #endif + + #if CYW43_PIO_CLOCK_DIV_DYNAMIC + // set the pio clock divisor + if (args[ARG_div_int].u_int > 0) { + cyw43_set_pio_clock_divisor((uint16_t)args[ARG_div_int].u_int, (uint16_t)args[ARG_div_frac].u_int); + } + #endif + + if (n_args == 0 || mp_obj_get_int(all_args[ARG_interface]) == MOD_NETWORK_STA_IF) { + return network_cyw43_get_interface(MOD_NETWORK_STA_IF); + } else { + return network_cyw43_get_interface(MOD_NETWORK_AP_IF); + } +} From 036ec831d0a08f7a15eeb30dd77a6d0233af3b40 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Thu, 10 Oct 2024 19:26:21 +0100 Subject: [PATCH 11/30] rp2: Allow extra arguments in Makefile. When building allow the port to be configured on the command line by passing a value for CMAKE_ARGS. Signed-off-by: Peter Harper --- ports/rp2/Makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ports/rp2/Makefile b/ports/rp2/Makefile index f950bc7b90898..be302f3ec2af1 100644 --- a/ports/rp2/Makefile +++ b/ports/rp2/Makefile @@ -30,26 +30,26 @@ endif $(VERBOSE)MAKESILENT = -s -CMAKE_ARGS += -DMICROPY_BOARD=$(BOARD) -DMICROPY_BOARD_DIR="$(abspath $(BOARD_DIR))" +override CMAKE_ARGS += -DMICROPY_BOARD=$(BOARD) -DMICROPY_BOARD_DIR="$(abspath $(BOARD_DIR))" ifdef USER_C_MODULES -CMAKE_ARGS += -DUSER_C_MODULES=${USER_C_MODULES} +override CMAKE_ARGS += -DUSER_C_MODULES=${USER_C_MODULES} endif ifneq ($(FROZEN_MANIFEST),) -CMAKE_ARGS += -DMICROPY_FROZEN_MANIFEST=${FROZEN_MANIFEST} +override CMAKE_ARGS += -DMICROPY_FROZEN_MANIFEST=${FROZEN_MANIFEST} endif ifeq ($(DEBUG),1) -CMAKE_ARGS += -DCMAKE_BUILD_TYPE=Debug +override CMAKE_ARGS += -DCMAKE_BUILD_TYPE=Debug endif ifdef BOARD_VARIANT -CMAKE_ARGS += -DMICROPY_BOARD_VARIANT=$(BOARD_VARIANT) +override CMAKE_ARGS += -DMICROPY_BOARD_VARIANT=$(BOARD_VARIANT) endif ifdef MICROPY_PREVIEW_VERSION_2 -CMAKE_ARGS += -DMICROPY_PREVIEW_VERSION_2=1 +override CMAKE_ARGS += -DMICROPY_PREVIEW_VERSION_2=1 endif HELP_BUILD_ERROR ?= "See \033[1;31mhttps://github.com/micropython/micropython/wiki/Build-Troubleshooting\033[0m" From a002353a571d344cab9177d01766de1075e9aa3d Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Thu, 10 Oct 2024 19:30:32 +0100 Subject: [PATCH 12/30] rp2: Put cyw43 config in separate files. Signed-off-by: Peter Harper --- .../boards/RPI_PICO2_W/mpconfigboard.cmake | 8 +----- ports/rp2/boards/RPI_PICO2_W/mpconfigboard.h | 19 +------------- .../rp2/boards/RPI_PICO_W/mpconfigboard.cmake | 8 +----- ports/rp2/boards/RPI_PICO_W/mpconfigboard.h | 20 +-------------- ports/rp2/enable_cyw43.cmake | 7 ++++++ ports/rp2/enable_cyw43.h | 25 +++++++++++++++++++ 6 files changed, 36 insertions(+), 51 deletions(-) create mode 100644 ports/rp2/enable_cyw43.cmake create mode 100644 ports/rp2/enable_cyw43.h diff --git a/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.cmake b/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.cmake index 1d9b7fc448a0c..b77ff7d979c3c 100644 --- a/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.cmake +++ b/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.cmake @@ -5,13 +5,7 @@ set(PICO_BOARD "pico2_w") # To change the gpio count for QFN-80 # set(PICO_NUM_GPIOS 48) -set(MICROPY_PY_LWIP ON) -set(MICROPY_PY_NETWORK_CYW43 ON) - -# Bluetooth -set(MICROPY_PY_BLUETOOTH ON) -set(MICROPY_BLUETOOTH_BTSTACK ON) -set(MICROPY_PY_BLUETOOTH_CYW43 ON) +include(enable_cyw43.cmake) # Board specific version of the frozen manifest set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) diff --git a/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.h b/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.h index 7054499533f97..a570a00d4d3cd 100644 --- a/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.h +++ b/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.h @@ -2,21 +2,4 @@ #define MICROPY_HW_BOARD_NAME "Raspberry Pi Pico 2 W" #define MICROPY_HW_FLASH_STORAGE_BYTES (PICO_FLASH_SIZE_BYTES - 1024 * 1024) -// Enable networking. -#define MICROPY_PY_NETWORK 1 -#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "Pico2W" - -// CYW43 driver configuration. -#define CYW43_USE_SPI (1) -#define CYW43_LWIP (1) -#define CYW43_GPIO (1) -#define CYW43_SPI_PIO (1) - -// For debugging mbedtls - also set -// Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose -// #define MODUSSL_MBEDTLS_DEBUG_LEVEL 1 - -#define MICROPY_HW_PIN_EXT_COUNT CYW43_WL_GPIO_COUNT - -int mp_hal_is_pin_reserved(int n); -#define MICROPY_HW_PIN_RESERVED(i) mp_hal_is_pin_reserved(i) +#include "enable_cyw43.h" diff --git a/ports/rp2/boards/RPI_PICO_W/mpconfigboard.cmake b/ports/rp2/boards/RPI_PICO_W/mpconfigboard.cmake index cea6c38d73b4e..6cee0a0799669 100644 --- a/ports/rp2/boards/RPI_PICO_W/mpconfigboard.cmake +++ b/ports/rp2/boards/RPI_PICO_W/mpconfigboard.cmake @@ -2,13 +2,7 @@ set(PICO_BOARD "pico_w") -set(MICROPY_PY_LWIP ON) -set(MICROPY_PY_NETWORK_CYW43 ON) - -# Bluetooth -set(MICROPY_PY_BLUETOOTH ON) -set(MICROPY_BLUETOOTH_BTSTACK ON) -set(MICROPY_PY_BLUETOOTH_CYW43 ON) +include(enable_cyw43.cmake) # Board specific version of the frozen manifest set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) diff --git a/ports/rp2/boards/RPI_PICO_W/mpconfigboard.h b/ports/rp2/boards/RPI_PICO_W/mpconfigboard.h index 45ad6107ba14e..468d048674a00 100644 --- a/ports/rp2/boards/RPI_PICO_W/mpconfigboard.h +++ b/ports/rp2/boards/RPI_PICO_W/mpconfigboard.h @@ -4,22 +4,4 @@ // todo: We need something to check our binary size #define MICROPY_HW_FLASH_STORAGE_BYTES (848 * 1024) -// Enable networking. -#define MICROPY_PY_NETWORK 1 -#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "PicoW" - -// CYW43 driver configuration. -#define CYW43_USE_SPI (1) -#define CYW43_LWIP (1) -#define CYW43_GPIO (1) -#define CYW43_SPI_PIO (1) - -// For debugging mbedtls - also set -// Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose -// #define MODUSSL_MBEDTLS_DEBUG_LEVEL 1 - -#define MICROPY_HW_PIN_EXT_COUNT CYW43_WL_GPIO_COUNT - -// If this returns true for a pin then its irq will not be disabled on a soft reboot -int mp_hal_is_pin_reserved(int n); -#define MICROPY_HW_PIN_RESERVED(i) mp_hal_is_pin_reserved(i) +#include "enable_cyw43.h" diff --git a/ports/rp2/enable_cyw43.cmake b/ports/rp2/enable_cyw43.cmake new file mode 100644 index 0000000000000..5b12e86fb20d4 --- /dev/null +++ b/ports/rp2/enable_cyw43.cmake @@ -0,0 +1,7 @@ +set(MICROPY_PY_LWIP ON) +set(MICROPY_PY_NETWORK_CYW43 ON) + +# Bluetooth +set(MICROPY_PY_BLUETOOTH ON) +set(MICROPY_BLUETOOTH_BTSTACK ON) +set(MICROPY_PY_BLUETOOTH_CYW43 ON) diff --git a/ports/rp2/enable_cyw43.h b/ports/rp2/enable_cyw43.h new file mode 100644 index 0000000000000..ab38d62e5aa47 --- /dev/null +++ b/ports/rp2/enable_cyw43.h @@ -0,0 +1,25 @@ +// Enable networking. +#define MICROPY_PY_NETWORK 1 + +#ifndef MICROPY_PY_NETWORK_HOSTNAME_DEFAULT +#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "Pico" +#endif + +// CYW43 driver configuration. +#define CYW43_USE_SPI (1) +#define CYW43_LWIP (1) +#define CYW43_GPIO (1) +#define CYW43_SPI_PIO (1) + +// For debugging mbedtls - also set +// Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose +// #define MODUSSL_MBEDTLS_DEBUG_LEVEL 1 + +#ifndef CYW43_WL_GPIO_COUNT +#define CYW43_WL_GPIO_COUNT 3 +#endif + +#define MICROPY_HW_PIN_EXT_COUNT CYW43_WL_GPIO_COUNT + +int mp_hal_is_pin_reserved(int n); +#define MICROPY_HW_PIN_RESERVED(i) mp_hal_is_pin_reserved(i) From f727c4aa235717a1748b61a6706a1ffe51291301 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Thu, 10 Oct 2024 19:31:42 +0100 Subject: [PATCH 13/30] rp2: Allow pins.csv filename to be configured. Signed-off-by: Peter Harper --- ports/rp2/CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 105bdd501258c..5db1ece63cbcb 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -640,8 +640,12 @@ if(NOT PICO_NUM_EXT_GPIOS) set(PICO_NUM_EXT_GPIOS 10) endif() -if(EXISTS "${MICROPY_BOARD_DIR}/pins.csv") - set(GEN_PINS_BOARD_CSV "${MICROPY_BOARD_DIR}/pins.csv") +if (NOT PICO_PINS_CSV_NAME) + set(PICO_PINS_CSV_NAME pins.csv) +endif() + +if(EXISTS "${MICROPY_BOARD_DIR}/${PICO_PINS_CSV_NAME}") + set(GEN_PINS_BOARD_CSV "${MICROPY_BOARD_DIR}/${PICO_PINS_CSV_NAME}") set(GEN_PINS_CSV_ARG --board-csv "${GEN_PINS_BOARD_CSV}") endif() From 80b155966234c435cf1c93def115ab2584332c8a Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Thu, 10 Oct 2024 19:35:57 +0100 Subject: [PATCH 14/30] rp2: Allow pico to use cyw43. Signed-off-by: Peter Harper --- ports/rp2/boards/RPI_PICO/manifest.py | 7 +++++ ports/rp2/boards/RPI_PICO/mpconfigboard.cmake | 6 ++++ ports/rp2/boards/RPI_PICO/mpconfigboard.h | 9 ++++++ ports/rp2/boards/RPI_PICO/pins_cyw43.csv | 31 +++++++++++++++++++ ports/rp2/boards/RPI_PICO2/manifest.py | 7 +++++ .../rp2/boards/RPI_PICO2/mpconfigboard.cmake | 6 ++++ ports/rp2/boards/RPI_PICO2/mpconfigboard.h | 6 ++++ ports/rp2/boards/RPI_PICO2/pins_cyw43.csv | 31 +++++++++++++++++++ 8 files changed, 103 insertions(+) create mode 100644 ports/rp2/boards/RPI_PICO/manifest.py create mode 100644 ports/rp2/boards/RPI_PICO/pins_cyw43.csv create mode 100644 ports/rp2/boards/RPI_PICO2/manifest.py create mode 100644 ports/rp2/boards/RPI_PICO2/pins_cyw43.csv diff --git a/ports/rp2/boards/RPI_PICO/manifest.py b/ports/rp2/boards/RPI_PICO/manifest.py new file mode 100644 index 0000000000000..fdae49fbf4be2 --- /dev/null +++ b/ports/rp2/boards/RPI_PICO/manifest.py @@ -0,0 +1,7 @@ +# This file is only used if cyw43 is enabled +include("$(PORT_DIR)/boards/manifest.py") + +require("bundle-networking") + +# Bluetooth +require("aioble") diff --git a/ports/rp2/boards/RPI_PICO/mpconfigboard.cmake b/ports/rp2/boards/RPI_PICO/mpconfigboard.cmake index 386bd33285890..352132a5066dd 100644 --- a/ports/rp2/boards/RPI_PICO/mpconfigboard.cmake +++ b/ports/rp2/boards/RPI_PICO/mpconfigboard.cmake @@ -1,3 +1,9 @@ # cmake file for Raspberry Pi Pico set(PICO_BOARD "pico") set(PICO_PLATFORM "rp2040") + +if (PICO_CYW43_SUPPORTED) + include(enable_cyw43.cmake) + set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) + set(PICO_PINS_CSV_NAME pins_cyw43.csv) +endif() diff --git a/ports/rp2/boards/RPI_PICO/mpconfigboard.h b/ports/rp2/boards/RPI_PICO/mpconfigboard.h index c39bc4d489bb6..204bdbb1c5930 100644 --- a/ports/rp2/boards/RPI_PICO/mpconfigboard.h +++ b/ports/rp2/boards/RPI_PICO/mpconfigboard.h @@ -1,3 +1,12 @@ // Board and hardware specific configuration #define MICROPY_HW_BOARD_NAME "Raspberry Pi Pico" + +#if MICROPY_PY_NETWORK_CYW43 +// we have to reduce the flash storage if cyw43 is enabled or else the firmware gets overwritten +#define MICROPY_HW_FLASH_STORAGE_BYTES (848 * 1024) +#include "enable_cyw43.h" +#define CYW43_PIN_WL_DYNAMIC 1 +#define CYW43_PIO_CLOCK_DIV_DYNAMIC 1 +#else #define MICROPY_HW_FLASH_STORAGE_BYTES (1408 * 1024) +#endif diff --git a/ports/rp2/boards/RPI_PICO/pins_cyw43.csv b/ports/rp2/boards/RPI_PICO/pins_cyw43.csv new file mode 100644 index 0000000000000..6459a8d4bfa20 --- /dev/null +++ b/ports/rp2/boards/RPI_PICO/pins_cyw43.csv @@ -0,0 +1,31 @@ +GP0,GPIO0 +GP1,GPIO1 +GP2,GPIO2 +GP3,GPIO3 +GP4,GPIO4 +GP5,GPIO5 +GP6,GPIO6 +GP7,GPIO7 +GP8,GPIO8 +GP9,GPIO9 +GP10,GPIO10 +GP11,GPIO11 +GP12,GPIO12 +GP13,GPIO13 +GP14,GPIO14 +GP15,GPIO15 +GP16,GPIO16 +GP17,GPIO17 +GP18,GPIO18 +GP19,GPIO19 +GP20,GPIO20 +GP21,GPIO21 +GP22,GPIO22 +GP25,GPIO25 +GP26,GPIO26 +GP27,GPIO27 +GP28,GPIO28 +LED,GPIO25 +WL_GPIO0,EXT_GPIO0 +WL_GPIO1,EXT_GPIO1 +WL_GPIO2,EXT_GPIO2 diff --git a/ports/rp2/boards/RPI_PICO2/manifest.py b/ports/rp2/boards/RPI_PICO2/manifest.py new file mode 100644 index 0000000000000..fdae49fbf4be2 --- /dev/null +++ b/ports/rp2/boards/RPI_PICO2/manifest.py @@ -0,0 +1,7 @@ +# This file is only used if cyw43 is enabled +include("$(PORT_DIR)/boards/manifest.py") + +require("bundle-networking") + +# Bluetooth +require("aioble") diff --git a/ports/rp2/boards/RPI_PICO2/mpconfigboard.cmake b/ports/rp2/boards/RPI_PICO2/mpconfigboard.cmake index 48b6545aa3428..73dbc16d055bb 100644 --- a/ports/rp2/boards/RPI_PICO2/mpconfigboard.cmake +++ b/ports/rp2/boards/RPI_PICO2/mpconfigboard.cmake @@ -3,3 +3,9 @@ set(PICO_BOARD "pico2") # To change the gpio count for QFN-80 # set(PICO_NUM_GPIOS 48) + +if (PICO_CYW43_SUPPORTED) + include(enable_cyw43.cmake) + set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) + set(PICO_PINS_CSV_NAME pins_cyw43.csv) +endif() diff --git a/ports/rp2/boards/RPI_PICO2/mpconfigboard.h b/ports/rp2/boards/RPI_PICO2/mpconfigboard.h index 4b5eac6eb3ae3..3812b954ba739 100644 --- a/ports/rp2/boards/RPI_PICO2/mpconfigboard.h +++ b/ports/rp2/boards/RPI_PICO2/mpconfigboard.h @@ -1,3 +1,9 @@ // Board and hardware specific configuration #define MICROPY_HW_BOARD_NAME "Raspberry Pi Pico2" #define MICROPY_HW_FLASH_STORAGE_BYTES (PICO_FLASH_SIZE_BYTES - 1024 * 1024) + +#if MICROPY_PY_NETWORK_CYW43 +#include "enable_cyw43.h" +#define CYW43_PIN_WL_DYNAMIC 1 +#define CYW43_PIO_CLOCK_DIV_DYNAMIC 1 +#endif diff --git a/ports/rp2/boards/RPI_PICO2/pins_cyw43.csv b/ports/rp2/boards/RPI_PICO2/pins_cyw43.csv new file mode 100644 index 0000000000000..6459a8d4bfa20 --- /dev/null +++ b/ports/rp2/boards/RPI_PICO2/pins_cyw43.csv @@ -0,0 +1,31 @@ +GP0,GPIO0 +GP1,GPIO1 +GP2,GPIO2 +GP3,GPIO3 +GP4,GPIO4 +GP5,GPIO5 +GP6,GPIO6 +GP7,GPIO7 +GP8,GPIO8 +GP9,GPIO9 +GP10,GPIO10 +GP11,GPIO11 +GP12,GPIO12 +GP13,GPIO13 +GP14,GPIO14 +GP15,GPIO15 +GP16,GPIO16 +GP17,GPIO17 +GP18,GPIO18 +GP19,GPIO19 +GP20,GPIO20 +GP21,GPIO21 +GP22,GPIO22 +GP25,GPIO25 +GP26,GPIO26 +GP27,GPIO27 +GP28,GPIO28 +LED,GPIO25 +WL_GPIO0,EXT_GPIO0 +WL_GPIO1,EXT_GPIO1 +WL_GPIO2,EXT_GPIO2 From 8fa6e286d3ac688050aef1c2d41b92f967670ec9 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Mon, 4 Nov 2024 14:19:02 +0000 Subject: [PATCH 15/30] rp2: Move cyw43 code from main. The "init" code can now be added to rp2_network_cyw43_make_new. Signed-off-by: Peter Harper --- ports/rp2/main.c | 26 -------------------------- ports/rp2/rp2_network_cyw43.c | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/ports/rp2/main.c b/ports/rp2/main.c index 9a82def6ff079..888e0d1dd7147 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -49,15 +49,11 @@ #include "pico/stdlib.h" #include "pico/binary_info.h" -#include "pico/unique_id.h" #include "hardware/structs/rosc.h" #if MICROPY_PY_LWIP #include "lwip/init.h" #include "lwip/apps/mdns.h" #endif -#if MICROPY_PY_NETWORK_CYW43 -#include "lib/cyw43-driver/src/cyw43.h" -#endif #if PICO_RP2040 #include "RP2040.h" // cmsis, for PendSV_IRQn and SCB/SCB_SCR_SEVONPEND_Msk #elif PICO_RP2350 && PICO_ARM @@ -131,28 +127,6 @@ int main(int argc, char **argv) { #endif #endif - #if MICROPY_PY_NETWORK_CYW43 || MICROPY_PY_BLUETOOTH_CYW43 - { - cyw43_init(&cyw43_state); - cyw43_irq_init(); - cyw43_post_poll_hook(); // enable the irq - uint8_t buf[8]; - memcpy(&buf[0], "PICO", 4); - - // MAC isn't loaded from OTP yet, so use unique id to generate the default AP ssid. - const char hexchr[16] = "0123456789ABCDEF"; - pico_unique_board_id_t pid; - pico_get_unique_board_id(&pid); - buf[4] = hexchr[pid.id[7] >> 4]; - buf[5] = hexchr[pid.id[6] & 0xf]; - buf[6] = hexchr[pid.id[5] >> 4]; - buf[7] = hexchr[pid.id[4] & 0xf]; - cyw43_wifi_ap_set_ssid(&cyw43_state, 8, buf); - cyw43_wifi_ap_set_auth(&cyw43_state, CYW43_AUTH_WPA2_AES_PSK); - cyw43_wifi_ap_set_password(&cyw43_state, 8, (const uint8_t *)"picoW123"); - } - #endif - // Hook for setting up anything that can wait until after other hardware features are initialised. MICROPY_BOARD_EARLY_INIT(); diff --git a/ports/rp2/rp2_network_cyw43.c b/ports/rp2/rp2_network_cyw43.c index 94d5036886dc9..1f14991547b3d 100644 --- a/ports/rp2/rp2_network_cyw43.c +++ b/ports/rp2/rp2_network_cyw43.c @@ -2,6 +2,7 @@ #include "extmod/network_cyw43.h" #include "extmod/modnetwork.h" #include "lib/cyw43-driver/src/cyw43.h" +#include "pico/unique_id.h" void cyw43_irq_deinit(void); void cyw43_irq_init(void); @@ -16,6 +17,30 @@ extern int cyw43_set_pins_wl(uint pins[CYW43_PIN_INDEX_WL_COUNT]); extern void cyw43_set_pio_clock_divisor(uint16_t clock_div_int, uint8_t clock_div_frac); #endif +static void rp2_network_cyw43_init(void) { + static bool cyw43_init_done; + if (!cyw43_init_done) { + cyw43_init(&cyw43_state); + cyw43_irq_init(); + cyw43_post_poll_hook(); // enable the irq + cyw43_init_done = true; + } + uint8_t buf[8]; + memcpy(&buf[0], "PICO", 4); + + // Use unique id to generate the default AP ssid. + const char hexchr[16] = "0123456789ABCDEF"; + pico_unique_board_id_t pid; + pico_get_unique_board_id(&pid); + buf[4] = hexchr[pid.id[7] >> 4]; + buf[5] = hexchr[pid.id[6] & 0xf]; + buf[6] = hexchr[pid.id[5] >> 4]; + buf[7] = hexchr[pid.id[4] & 0xf]; + cyw43_wifi_ap_set_ssid(&cyw43_state, 8, buf); + cyw43_wifi_ap_set_auth(&cyw43_state, CYW43_AUTH_WPA2_AES_PSK); + cyw43_wifi_ap_set_password(&cyw43_state, 8, (const uint8_t *)"picoW123"); +} + mp_obj_t rp2_network_cyw43_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { enum { ARG_interface, ARG_pin_on, ARG_pin_out, ARG_pin_in, ARG_pin_wake, ARG_pin_clock, ARG_pin_cs, ARG_pin_dat, ARG_div_int, ARG_div_frac }; static const mp_arg_t allowed_args[] = { @@ -36,6 +61,7 @@ mp_obj_t rp2_network_cyw43_make_new(const mp_obj_type_t *type, size_t n_args, si }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + rp2_network_cyw43_init(); // Set the pins #if CYW43_PIN_WL_DYNAMIC From c9456721df7ba6e3b1baa656a2d8a653d71dce29 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 6 Aug 2024 19:49:40 +0100 Subject: [PATCH 16/30] ports/rp2: PSRAM support. Add PSRAM support with auto detection. Performs a best-effort attempt to detect attached PSRAM, configure it and *add* it to the MicroPython heap. If PSRAM is not present, should fall back to use internal RAM. Introduce two new port/board defines: * MICROPY_HW_ENABLE_PSRAM to enable PSRAM. * MICROPY_HW_PSRAM_CS_PIN to define the chip-select pin. Changes: ports/rp2/rp2_psram.c/h: Add new PSRAM module. ports/rp2/main.c: Add optional PSRAM support. ports/rp2/CMakeLists.txt: Include rp2_psram.c. ports/rp2/rp2_flash.c: Add buffered write to avoid reads from PSRAM. ports/rp2/mpconfigport.h: Enable MICROPY_GC_SPLIT_HEAP for boards that set MICROPY_HW_ENABLE_PSRAM. Co-authored-by: Kirk Benell Co-authored-by: Mike Bell Signed-off-by: Phil Howard --- ports/rp2/CMakeLists.txt | 1 + ports/rp2/main.c | 8 ++ ports/rp2/mpconfigport.h | 3 + ports/rp2/rp2_flash.c | 48 +++++++++-- ports/rp2/rp2_psram.c | 180 +++++++++++++++++++++++++++++++++++++++ ports/rp2/rp2_psram.h | 11 +++ 6 files changed, 246 insertions(+), 5 deletions(-) create mode 100644 ports/rp2/rp2_psram.c create mode 100644 ports/rp2/rp2_psram.h diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 5db1ece63cbcb..dc95b1a3fda3d 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -165,6 +165,7 @@ set(MICROPY_SOURCE_PORT pendsv.c rp2_flash.c rp2_pio.c + rp2_psram.c rp2_dma.c uart.c usbd.c diff --git a/ports/rp2/main.c b/ports/rp2/main.c index 888e0d1dd7147..d3c22c42f42e3 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -26,6 +26,7 @@ #include +#include "rp2_psram.h" #include "py/compile.h" #include "py/cstack.h" #include "py/runtime.h" @@ -115,7 +116,14 @@ int main(int argc, char **argv) { // Initialise stack extents and GC heap. mp_cstack_init_with_top(&__StackTop, &__StackTop - &__StackBottom); + gc_init(&__GcHeapStart, &__GcHeapEnd); + #if defined(MICROPY_HW_PSRAM_CS_PIN) && MICROPY_HW_ENABLE_PSRAM + size_t psram_size = psram_init(MICROPY_HW_PSRAM_CS_PIN); + if (psram_size) { + gc_add((void *)PSRAM_LOCATION, (void *)(PSRAM_LOCATION + psram_size)); + } + #endif #if MICROPY_PY_LWIP // lwIP doesn't allow to reinitialise itself by subsequent calls to this function diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index cfa34e6f8ad8d..809812adee82b 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -73,6 +73,9 @@ // Memory allocation policies #define MICROPY_GC_STACK_ENTRY_TYPE uint16_t +#ifdef MICROPY_HW_ENABLE_PSRAM +#define MICROPY_GC_SPLIT_HEAP (1) +#endif #define MICROPY_ALLOC_PATH_MAX (128) #define MICROPY_QSTR_BYTES_IN_HASH (1) diff --git a/ports/rp2/rp2_flash.c b/ports/rp2/rp2_flash.c index c1acb54e75748..722bf5c0b76c0 100644 --- a/ports/rp2/rp2_flash.c +++ b/ports/rp2/rp2_flash.c @@ -26,6 +26,7 @@ #include +#include "rp2_psram.h" #include "py/mphal.h" #include "py/runtime.h" #include "extmod/vfs.h" @@ -76,10 +77,21 @@ static uint32_t begin_critical_flash_section(void) { if (multicore_lockout_victim_is_initialized(1 - get_core_num())) { multicore_lockout_start_blocking(); } - return save_and_disable_interrupts(); + uint32_t state = save_and_disable_interrupts(); + + // We're about to invalidate the XIP cache, clean it first to commit any dirty writes to PSRAM + uint8_t *maintenance_ptr = (uint8_t *)XIP_MAINTENANCE_BASE; + for (int i = 1; i < 16 * 1024; i += 8) { + maintenance_ptr[i] = 0; + } + + return state; } static void end_critical_flash_section(uint32_t state) { + #if defined(MICROPY_HW_PSRAM_CS_PIN) && MICROPY_HW_ENABLE_PSRAM + psram_init(MICROPY_HW_PSRAM_CS_PIN); + #endif restore_interrupts(state); if (multicore_lockout_victim_is_initialized(1 - get_core_num())) { multicore_lockout_end_blocking(); @@ -145,11 +157,16 @@ static mp_obj_t rp2_flash_readblocks(size_t n_args, const mp_obj_t *args) { } static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rp2_flash_readblocks_obj, 3, 4, rp2_flash_readblocks); +static inline size_t min_size(size_t a, size_t b) { + return a < b ? a : b; +} + static mp_obj_t rp2_flash_writeblocks(size_t n_args, const mp_obj_t *args) { rp2_flash_obj_t *self = MP_OBJ_TO_PTR(args[0]); uint32_t offset = mp_obj_get_int(args[1]) * BLOCK_SIZE_BYTES; mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); + if (n_args == 3) { mp_uint_t atomic_state = begin_critical_flash_section(); flash_range_erase(self->flash_base + offset, bufinfo.len); @@ -159,10 +176,31 @@ static mp_obj_t rp2_flash_writeblocks(size_t n_args, const mp_obj_t *args) { } else { offset += mp_obj_get_int(args[3]); } - mp_uint_t atomic_state = begin_critical_flash_section(); - flash_range_program(self->flash_base + offset, bufinfo.buf, bufinfo.len); - end_critical_flash_section(atomic_state); - mp_event_handle_nowait(); + + if ((uintptr_t)bufinfo.buf >= SRAM_BASE) { + mp_uint_t atomic_state = begin_critical_flash_section(); + flash_range_program(self->flash_base + offset, bufinfo.buf, bufinfo.len); + end_critical_flash_section(atomic_state); + mp_event_handle_nowait(); + } else { + size_t bytes_left = bufinfo.len; + size_t bytes_offset = 0; + static uint8_t copy_buffer[BLOCK_SIZE_BYTES] = {0}; + + while (bytes_left) { + memcpy(copy_buffer, bufinfo.buf + bytes_offset, min_size(bytes_left, BLOCK_SIZE_BYTES)); + mp_uint_t atomic_state = begin_critical_flash_section(); + flash_range_program(self->flash_base + offset + bytes_offset, copy_buffer, min_size(bytes_left, BLOCK_SIZE_BYTES)); + end_critical_flash_section(atomic_state); + bytes_offset += BLOCK_SIZE_BYTES; + if (bytes_left <= BLOCK_SIZE_BYTES) { + break; + } + bytes_left -= BLOCK_SIZE_BYTES; + mp_event_handle_nowait(); + } + } + // TODO check return value return mp_const_none; } diff --git a/ports/rp2/rp2_psram.c b/ports/rp2/rp2_psram.c new file mode 100644 index 0000000000000..07fd28c49ca8e --- /dev/null +++ b/ports/rp2/rp2_psram.c @@ -0,0 +1,180 @@ +#include "hardware/structs/ioqspi.h" +#include "hardware/structs/qmi.h" +#include "hardware/structs/xip_ctrl.h" +#include "hardware/sync.h" +#include "rp2_psram.h" + + +void __no_inline_not_in_flash_func(psram_set_qmi_timing)() { + // Make sure flash is deselected - QMI doesn't appear to have a busy flag(!) + while ((ioqspi_hw->io[1].status & IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS) != IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS) { + ; + } + + // For > 133 MHz + qmi_hw->m[0].timing = 0x40000202; + + // For <= 133 MHz + // qmi_hw->m[0].timing = 0x40000101; + + // Force a read through XIP to ensure the timing is applied + volatile uint32_t *ptr = (volatile uint32_t *)0x14000000; + (void)*ptr; +} + +size_t __no_inline_not_in_flash_func(psram_detect)() { + int psram_size = 0; + + uint32_t intr_stash = save_and_disable_interrupts(); + + // Try and read the PSRAM ID via direct_csr. + qmi_hw->direct_csr = 30 << QMI_DIRECT_CSR_CLKDIV_LSB | QMI_DIRECT_CSR_EN_BITS; + + // Need to poll for the cooldown on the last XIP transfer to expire + // (via direct-mode BUSY flag) before it is safe to perform the first + // direct-mode operation + while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) { + } + + // Exit out of QMI in case we've inited already + qmi_hw->direct_csr |= QMI_DIRECT_CSR_ASSERT_CS1N_BITS; + + // Transmit as quad. + qmi_hw->direct_tx = QMI_DIRECT_TX_OE_BITS | QMI_DIRECT_TX_IWIDTH_VALUE_Q << QMI_DIRECT_TX_IWIDTH_LSB | 0xf5; + + while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) { + } + + (void)qmi_hw->direct_rx; + + qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS); + + // Read the id + qmi_hw->direct_csr |= QMI_DIRECT_CSR_ASSERT_CS1N_BITS; + uint8_t kgd = 0; + uint8_t eid = 0; + + for (size_t i = 0; i < 7; i++) + { + if (i == 0) { + qmi_hw->direct_tx = 0x9f; + } else { + qmi_hw->direct_tx = 0xff; + } + + while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_TXEMPTY_BITS) == 0) { + } + + while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) { + } + + if (i == 5) { + kgd = qmi_hw->direct_rx; + } else if (i == 6) { + eid = qmi_hw->direct_rx; + } else { + (void)qmi_hw->direct_rx; + } + } + + // Disable direct csr. + qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS | QMI_DIRECT_CSR_EN_BITS); + + if (kgd == 0x5D) { + psram_size = 1024 * 1024; // 1 MiB + uint8_t size_id = eid >> 5; + if (eid == 0x26 || size_id == 2) { + psram_size *= 8; // 8 MiB + } else if (size_id == 0) { + psram_size *= 2; // 2 MiB + } else if (size_id == 1) { + psram_size *= 4; // 4 MiB + } + } + + restore_interrupts(intr_stash); + return psram_size; +} + +size_t __no_inline_not_in_flash_func(psram_init)(uint cs_pin) { + gpio_set_function(cs_pin, GPIO_FUNC_XIP_CS1); + + size_t psram_size = psram_detect(); + + if (!psram_size) { + return 0; + } + + psram_set_qmi_timing(); + + // Enable direct mode, PSRAM CS, clkdiv of 10. + qmi_hw->direct_csr = 10 << QMI_DIRECT_CSR_CLKDIV_LSB | \ + QMI_DIRECT_CSR_EN_BITS | \ + QMI_DIRECT_CSR_AUTO_CS1N_BITS; + while (qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) { + ; + } + + // Enable QPI mode on the PSRAM + const uint CMD_QPI_EN = 0x35; + qmi_hw->direct_tx = QMI_DIRECT_TX_NOPUSH_BITS | CMD_QPI_EN; + + while (qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) { + ; + } + + #if 0 + // Set PSRAM timing for APS6404: + // - Max select assumes a sys clock speed >= 240MHz + // - Min deselect assumes a sys clock speed <= 305MHz + // - Clkdiv of 2 is OK up to 266MHz. + qmi_hw->m[1].timing = 1 << QMI_M1_TIMING_COOLDOWN_LSB | + QMI_M1_TIMING_PAGEBREAK_VALUE_1024 << QMI_M1_TIMING_PAGEBREAK_LSB | + 30 << QMI_M1_TIMING_MAX_SELECT_LSB | + 5 << QMI_M1_TIMING_MIN_DESELECT_LSB | + 3 << QMI_M1_TIMING_RXDELAY_LSB | + 2 << QMI_M1_TIMING_CLKDIV_LSB; + #else + // Set PSRAM timing for APS6404: + // - Max select assumes a sys clock speed >= 120MHz + // - Min deselect assumes a sys clock speed <= 138MHz + // - Clkdiv of 1 is OK up to 133MHz. + qmi_hw->m[1].timing = 1 << QMI_M1_TIMING_COOLDOWN_LSB | + QMI_M1_TIMING_PAGEBREAK_VALUE_1024 << QMI_M1_TIMING_PAGEBREAK_LSB | + 15 << QMI_M1_TIMING_MAX_SELECT_LSB | + 2 << QMI_M1_TIMING_MIN_DESELECT_LSB | + 2 << QMI_M1_TIMING_RXDELAY_LSB | + 1 << QMI_M1_TIMING_CLKDIV_LSB; + #endif + + // Set PSRAM commands and formats + qmi_hw->m[1].rfmt = + QMI_M0_RFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_PREFIX_WIDTH_LSB | \ + QMI_M0_RFMT_ADDR_WIDTH_VALUE_Q << QMI_M0_RFMT_ADDR_WIDTH_LSB | \ + QMI_M0_RFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_SUFFIX_WIDTH_LSB | \ + QMI_M0_RFMT_DUMMY_WIDTH_VALUE_Q << QMI_M0_RFMT_DUMMY_WIDTH_LSB | \ + QMI_M0_RFMT_DATA_WIDTH_VALUE_Q << QMI_M0_RFMT_DATA_WIDTH_LSB | \ + QMI_M0_RFMT_PREFIX_LEN_VALUE_8 << QMI_M0_RFMT_PREFIX_LEN_LSB | \ + 6 << QMI_M0_RFMT_DUMMY_LEN_LSB; + + qmi_hw->m[1].rcmd = 0xEB; + + qmi_hw->m[1].wfmt = + QMI_M0_WFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_WFMT_PREFIX_WIDTH_LSB | \ + QMI_M0_WFMT_ADDR_WIDTH_VALUE_Q << QMI_M0_WFMT_ADDR_WIDTH_LSB | \ + QMI_M0_WFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M0_WFMT_SUFFIX_WIDTH_LSB | \ + QMI_M0_WFMT_DUMMY_WIDTH_VALUE_Q << QMI_M0_WFMT_DUMMY_WIDTH_LSB | \ + QMI_M0_WFMT_DATA_WIDTH_VALUE_Q << QMI_M0_WFMT_DATA_WIDTH_LSB | \ + QMI_M0_WFMT_PREFIX_LEN_VALUE_8 << QMI_M0_WFMT_PREFIX_LEN_LSB; + + qmi_hw->m[1].wcmd = 0x38; + + // Disable direct mode + qmi_hw->direct_csr = 0; + + // Enable writes to PSRAM + hw_set_bits(&xip_ctrl_hw->ctrl, XIP_CTRL_WRITABLE_M1_BITS); + + // TODO: Detect PSRAM ID and size + return psram_size; +} diff --git a/ports/rp2/rp2_psram.h b/ports/rp2/rp2_psram.h new file mode 100644 index 0000000000000..cd791602cdd68 --- /dev/null +++ b/ports/rp2/rp2_psram.h @@ -0,0 +1,11 @@ +#include "pico/stdlib.h" + +#ifndef MICROPY_INCLUDED_RP2_MACHINE_PSRAM_H +#define MICROPY_INCLUDED_RP2_MACHINE_PSRAM_H + +#define PSRAM_LOCATION _u(0x11000000) + +extern void psram_set_qmi_timing(); +extern size_t psram_init(uint cs_pin); + +#endif From 9a15f1fc452f97c9b698fb9cacc85db86d8555f4 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 9 Aug 2024 10:16:55 +0100 Subject: [PATCH 17/30] ports/rp2: PSRAM: Fix RP2040/Pico build. Signed-off-by: Phil Howard --- ports/rp2/CMakeLists.txt | 7 ++++++- ports/rp2/rp2_flash.c | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index dc95b1a3fda3d..a5979f3901f29 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -165,7 +165,6 @@ set(MICROPY_SOURCE_PORT pendsv.c rp2_flash.c rp2_pio.c - rp2_psram.c rp2_dma.c uart.c usbd.c @@ -174,6 +173,12 @@ set(MICROPY_SOURCE_PORT ${CMAKE_BINARY_DIR}/pins_${MICROPY_BOARD}.c ) +if(PICO_RP2350) + list(APPEND MICROPY_SOURCE_PORT + rp2_psram.c + ) +endif() + set(MICROPY_SOURCE_QSTR ${MICROPY_SOURCE_PY} ${MICROPY_DIR}/shared/readline/readline.c diff --git a/ports/rp2/rp2_flash.c b/ports/rp2/rp2_flash.c index 722bf5c0b76c0..4386986011db2 100644 --- a/ports/rp2/rp2_flash.c +++ b/ports/rp2/rp2_flash.c @@ -79,11 +79,13 @@ static uint32_t begin_critical_flash_section(void) { } uint32_t state = save_and_disable_interrupts(); + #if defined(MICROPY_HW_PSRAM_CS_PIN) && MICROPY_HW_ENABLE_PSRAM // We're about to invalidate the XIP cache, clean it first to commit any dirty writes to PSRAM uint8_t *maintenance_ptr = (uint8_t *)XIP_MAINTENANCE_BASE; for (int i = 1; i < 16 * 1024; i += 8) { maintenance_ptr[i] = 0; } + #endif return state; } From 245c5297744a0c392e7b197cdd7383950cecf6d4 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 9 Aug 2024 14:15:10 +0100 Subject: [PATCH 18/30] ports/rp2: Re-init PSRAM on CPU freq change. Signed-off-by: Phil Howard --- ports/rp2/modmachine.c | 4 +++ ports/rp2/rp2_psram.c | 60 ++++++++++++++++++++++-------------------- 2 files changed, 35 insertions(+), 29 deletions(-) diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c index 58ba8377748b5..2081d4a913088 100644 --- a/ports/rp2/modmachine.c +++ b/ports/rp2/modmachine.c @@ -31,6 +31,7 @@ #include "mp_usbd.h" #include "modmachine.h" #include "uart.h" +#include "rp2_psram.h" #include "clocks_extra.h" #include "hardware/pll.h" #include "hardware/structs/rosc.h" @@ -115,6 +116,9 @@ static void mp_machine_set_freq(size_t n_args, const mp_obj_t *args) { setup_default_uart(); mp_uart_init(); #endif + #if defined(MICROPY_HW_PSRAM_CS_PIN) && MICROPY_HW_ENABLE_PSRAM + psram_init(MICROPY_HW_PSRAM_CS_PIN); + #endif } static void mp_machine_idle(void) { diff --git a/ports/rp2/rp2_psram.c b/ports/rp2/rp2_psram.c index 07fd28c49ca8e..90c370c86a55e 100644 --- a/ports/rp2/rp2_psram.c +++ b/ports/rp2/rp2_psram.c @@ -1,6 +1,7 @@ #include "hardware/structs/ioqspi.h" #include "hardware/structs/qmi.h" #include "hardware/structs/xip_ctrl.h" +#include "hardware/clocks.h" #include "hardware/sync.h" #include "rp2_psram.h" @@ -11,11 +12,13 @@ void __no_inline_not_in_flash_func(psram_set_qmi_timing)() { ; } - // For > 133 MHz - qmi_hw->m[0].timing = 0x40000202; - - // For <= 133 MHz - // qmi_hw->m[0].timing = 0x40000101; + if (clock_get_hz(clk_sys) > 133000000) { + // For > 133 MHz + qmi_hw->m[0].timing = 0x40000202; + } else { + // For <= 133 MHz + qmi_hw->m[0].timing = 0x40000101; + } // Force a read through XIP to ensure the timing is applied volatile uint32_t *ptr = (volatile uint32_t *)0x14000000; @@ -123,29 +126,29 @@ size_t __no_inline_not_in_flash_func(psram_init)(uint cs_pin) { ; } - #if 0 - // Set PSRAM timing for APS6404: - // - Max select assumes a sys clock speed >= 240MHz - // - Min deselect assumes a sys clock speed <= 305MHz - // - Clkdiv of 2 is OK up to 266MHz. - qmi_hw->m[1].timing = 1 << QMI_M1_TIMING_COOLDOWN_LSB | - QMI_M1_TIMING_PAGEBREAK_VALUE_1024 << QMI_M1_TIMING_PAGEBREAK_LSB | - 30 << QMI_M1_TIMING_MAX_SELECT_LSB | - 5 << QMI_M1_TIMING_MIN_DESELECT_LSB | - 3 << QMI_M1_TIMING_RXDELAY_LSB | - 2 << QMI_M1_TIMING_CLKDIV_LSB; - #else - // Set PSRAM timing for APS6404: - // - Max select assumes a sys clock speed >= 120MHz - // - Min deselect assumes a sys clock speed <= 138MHz - // - Clkdiv of 1 is OK up to 133MHz. - qmi_hw->m[1].timing = 1 << QMI_M1_TIMING_COOLDOWN_LSB | - QMI_M1_TIMING_PAGEBREAK_VALUE_1024 << QMI_M1_TIMING_PAGEBREAK_LSB | - 15 << QMI_M1_TIMING_MAX_SELECT_LSB | - 2 << QMI_M1_TIMING_MIN_DESELECT_LSB | - 2 << QMI_M1_TIMING_RXDELAY_LSB | - 1 << QMI_M1_TIMING_CLKDIV_LSB; - #endif + if (clock_get_hz(clk_sys) >= 120000000) { + // Set PSRAM timing for APS6404: + // - Max select assumes a sys clock speed >= 120MHz + // - Min deselect assumes a sys clock speed <= 305MHz + // - Clkdiv of 2 is OK up to 266MHz. + qmi_hw->m[1].timing = 1 << QMI_M1_TIMING_COOLDOWN_LSB | + QMI_M1_TIMING_PAGEBREAK_VALUE_1024 << QMI_M1_TIMING_PAGEBREAK_LSB | + 15 << QMI_M1_TIMING_MAX_SELECT_LSB | + 5 << QMI_M1_TIMING_MIN_DESELECT_LSB | + 3 << QMI_M1_TIMING_RXDELAY_LSB | + 2 << QMI_M1_TIMING_CLKDIV_LSB; + } else { + // Set PSRAM timing for APS6404: + // - Max select assumes a sys clock speed >= 120MHz + // - Min deselect assumes a sys clock speed <= 138MHz + // - Clkdiv of 1 is OK up to 133MHz. + qmi_hw->m[1].timing = 1 << QMI_M1_TIMING_COOLDOWN_LSB | + QMI_M1_TIMING_PAGEBREAK_VALUE_1024 << QMI_M1_TIMING_PAGEBREAK_LSB | + 15 << QMI_M1_TIMING_MAX_SELECT_LSB | + 2 << QMI_M1_TIMING_MIN_DESELECT_LSB | + 2 << QMI_M1_TIMING_RXDELAY_LSB | + 1 << QMI_M1_TIMING_CLKDIV_LSB; + } // Set PSRAM commands and formats qmi_hw->m[1].rfmt = @@ -175,6 +178,5 @@ size_t __no_inline_not_in_flash_func(psram_init)(uint cs_pin) { // Enable writes to PSRAM hw_set_bits(&xip_ctrl_hw->ctrl, XIP_CTRL_WRITABLE_M1_BITS); - // TODO: Detect PSRAM ID and size return psram_size; } From 607ffa4c97d100edec08c8580dd53b5bbcfd4783 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 9 Aug 2024 14:15:33 +0100 Subject: [PATCH 19/30] ports/rp2: Make split-heap optional. My tests found issues when PSRAM is combined with the existing RAM in a split-heap configuration. Since this option is not enabled by default on RP2 I have changed it to be optional. PSRAM will be used exclusively if MICROPY_GC_SPLIT_HEAP == 0, it will be added to RAM if MICROPY_GC_SPLIT_HEAP == 1, and the system will fall back to RAM only if it's not detected. Signed-off-by: Phil Howard --- ports/rp2/main.c | 10 +++++++++- ports/rp2/mpconfigport.h | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/ports/rp2/main.c b/ports/rp2/main.c index d3c22c42f42e3..482515342a94b 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -117,12 +117,20 @@ int main(int argc, char **argv) { // Initialise stack extents and GC heap. mp_cstack_init_with_top(&__StackTop, &__StackTop - &__StackBottom); - gc_init(&__GcHeapStart, &__GcHeapEnd); #if defined(MICROPY_HW_PSRAM_CS_PIN) && MICROPY_HW_ENABLE_PSRAM size_t psram_size = psram_init(MICROPY_HW_PSRAM_CS_PIN); if (psram_size) { + #if MICROPY_GC_SPLIT_HEAP + gc_init(&__GcHeapStart, &__GcHeapEnd); gc_add((void *)PSRAM_LOCATION, (void *)(PSRAM_LOCATION + psram_size)); + #else + gc_init((void *)PSRAM_LOCATION, (void *)(PSRAM_LOCATION + psram_size)); + #endif + } else { + gc_init(&__GcHeapStart, &__GcHeapEnd); } + #else + gc_init(&__GcHeapStart, &__GcHeapEnd); #endif #if MICROPY_PY_LWIP diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index 809812adee82b..70c3ce2156052 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -73,8 +73,8 @@ // Memory allocation policies #define MICROPY_GC_STACK_ENTRY_TYPE uint16_t -#ifdef MICROPY_HW_ENABLE_PSRAM -#define MICROPY_GC_SPLIT_HEAP (1) +#ifndef MICROPY_GC_SPLIT_HEAP +#define MICROPY_GC_SPLIT_HEAP (0) // whether PSRAM is added to or replaces the heap #endif #define MICROPY_ALLOC_PATH_MAX (128) #define MICROPY_QSTR_BYTES_IN_HASH (1) From f401fb35eb2156a19966ec4190a986f5d671b352 Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Sun, 11 Aug 2024 17:34:04 +0100 Subject: [PATCH 20/30] ports/rp2: Compute QMI timing based on system clock. Signed-off-by: Mike Bell --- ports/rp2/rp2_psram.c | 65 ++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/ports/rp2/rp2_psram.c b/ports/rp2/rp2_psram.c index 90c370c86a55e..e3da848d09265 100644 --- a/ports/rp2/rp2_psram.c +++ b/ports/rp2/rp2_psram.c @@ -12,13 +12,15 @@ void __no_inline_not_in_flash_func(psram_set_qmi_timing)() { ; } - if (clock_get_hz(clk_sys) > 133000000) { - // For > 133 MHz - qmi_hw->m[0].timing = 0x40000202; - } else { - // For <= 133 MHz - qmi_hw->m[0].timing = 0x40000101; - } + // Use the minimum divisor assuming a 133MHz flash. + // RX delay equal to the divisor means sampling at the same time as the next falling edge of SCK after the + // falling edge that generated the data. This is pretty tight at 133MHz but seems to work with the Winbond flash chips. + const int max_flash_freq = 133000000; + const int divisor = (clock_get_hz(clk_sys) + max_flash_freq - 1) / max_flash_freq; + const int rxdelay = divisor; + qmi_hw->m[0].timing = (1 << QMI_M0_TIMING_COOLDOWN_LSB) | + rxdelay << QMI_M1_TIMING_RXDELAY_LSB | + divisor << QMI_M1_TIMING_CLKDIV_LSB; // Force a read through XIP to ensure the timing is applied volatile uint32_t *ptr = (volatile uint32_t *)0x14000000; @@ -126,30 +128,35 @@ size_t __no_inline_not_in_flash_func(psram_init)(uint cs_pin) { ; } - if (clock_get_hz(clk_sys) >= 120000000) { - // Set PSRAM timing for APS6404: - // - Max select assumes a sys clock speed >= 120MHz - // - Min deselect assumes a sys clock speed <= 305MHz - // - Clkdiv of 2 is OK up to 266MHz. - qmi_hw->m[1].timing = 1 << QMI_M1_TIMING_COOLDOWN_LSB | - QMI_M1_TIMING_PAGEBREAK_VALUE_1024 << QMI_M1_TIMING_PAGEBREAK_LSB | - 15 << QMI_M1_TIMING_MAX_SELECT_LSB | - 5 << QMI_M1_TIMING_MIN_DESELECT_LSB | - 3 << QMI_M1_TIMING_RXDELAY_LSB | - 2 << QMI_M1_TIMING_CLKDIV_LSB; - } else { - // Set PSRAM timing for APS6404: - // - Max select assumes a sys clock speed >= 120MHz - // - Min deselect assumes a sys clock speed <= 138MHz - // - Clkdiv of 1 is OK up to 133MHz. - qmi_hw->m[1].timing = 1 << QMI_M1_TIMING_COOLDOWN_LSB | - QMI_M1_TIMING_PAGEBREAK_VALUE_1024 << QMI_M1_TIMING_PAGEBREAK_LSB | - 15 << QMI_M1_TIMING_MAX_SELECT_LSB | - 2 << QMI_M1_TIMING_MIN_DESELECT_LSB | - 2 << QMI_M1_TIMING_RXDELAY_LSB | - 1 << QMI_M1_TIMING_CLKDIV_LSB; + // Set PSRAM timing for APS6404 + // + // Using an rxdelay equal to the divisor isn't enough when running the APS6404 close to 133MHz. + // So: don't allow running at divisor 1 above 100MHz (because delay of 2 would be too late), + // and add an extra 1 to the rxdelay if the divided clock is > 100MHz (i.e. sys clock > 200MHz). + const int max_psram_freq = 133000000; + const int clock_hz = clock_get_hz(clk_sys); + int divisor = (clock_hz + max_psram_freq - 1) / max_psram_freq; + if (divisor == 1 && clock_hz > 100000000) { + divisor = 2; + } + int rxdelay = divisor; + if (clock_hz / divisor > 100000000) { + rxdelay += 1; } + // - Max select must be <= 8us. The value is given in multiples of 64 system clocks. + // - Min deselect must be >= 18ns. The value is given in system clock cycles - ceil(divisor / 2). + const int clock_period_fs = 1000000000000000ll / clock_hz; + const int max_select = (125 * 1000000) / clock_period_fs; // 125 = 8000ns / 64 + const int min_deselect = (18 * 1000000 + (clock_period_fs - 1)) / clock_period_fs - (divisor + 1) / 2; + + qmi_hw->m[1].timing = 1 << QMI_M1_TIMING_COOLDOWN_LSB | + QMI_M1_TIMING_PAGEBREAK_VALUE_1024 << QMI_M1_TIMING_PAGEBREAK_LSB | + max_select << QMI_M1_TIMING_MAX_SELECT_LSB | + min_deselect << QMI_M1_TIMING_MIN_DESELECT_LSB | + rxdelay << QMI_M1_TIMING_RXDELAY_LSB | + divisor << QMI_M1_TIMING_CLKDIV_LSB; + // Set PSRAM commands and formats qmi_hw->m[1].rfmt = QMI_M0_RFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_PREFIX_WIDTH_LSB | \ From 405d1d15bfc6c0c695d21215188a7e0223f511d3 Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Sun, 11 Aug 2024 17:45:15 +0100 Subject: [PATCH 21/30] ports/rp2: Fix garbage collection with large heap. Signed-off-by: Mike Bell --- ports/rp2/mpconfigport.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index 70c3ce2156052..87eee29bb6797 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -71,8 +71,16 @@ #define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES) #endif +#ifndef MICROPY_HW_ENABLE_PSRAM +#define MICROPY_HW_ENABLE_PSRAM (0) +#endif + // Memory allocation policies +#if MICROPY_HW_ENABLE_PSRAM +#define MICROPY_GC_STACK_ENTRY_TYPE uint32_t +#else #define MICROPY_GC_STACK_ENTRY_TYPE uint16_t +#endif #ifndef MICROPY_GC_SPLIT_HEAP #define MICROPY_GC_SPLIT_HEAP (0) // whether PSRAM is added to or replaces the heap #endif From af1a22d66a2eb3aea8995df3221aad23b5ea54c6 Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Sun, 11 Aug 2024 20:52:34 +0100 Subject: [PATCH 22/30] ports/rp2: Remove flash timing control from PSRAM. Signed-off-by: Mike Bell --- ports/rp2/rp2_psram.c | 23 ----------------------- ports/rp2/rp2_psram.h | 1 - 2 files changed, 24 deletions(-) diff --git a/ports/rp2/rp2_psram.c b/ports/rp2/rp2_psram.c index e3da848d09265..30f87adaf4122 100644 --- a/ports/rp2/rp2_psram.c +++ b/ports/rp2/rp2_psram.c @@ -6,27 +6,6 @@ #include "rp2_psram.h" -void __no_inline_not_in_flash_func(psram_set_qmi_timing)() { - // Make sure flash is deselected - QMI doesn't appear to have a busy flag(!) - while ((ioqspi_hw->io[1].status & IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS) != IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS) { - ; - } - - // Use the minimum divisor assuming a 133MHz flash. - // RX delay equal to the divisor means sampling at the same time as the next falling edge of SCK after the - // falling edge that generated the data. This is pretty tight at 133MHz but seems to work with the Winbond flash chips. - const int max_flash_freq = 133000000; - const int divisor = (clock_get_hz(clk_sys) + max_flash_freq - 1) / max_flash_freq; - const int rxdelay = divisor; - qmi_hw->m[0].timing = (1 << QMI_M0_TIMING_COOLDOWN_LSB) | - rxdelay << QMI_M1_TIMING_RXDELAY_LSB | - divisor << QMI_M1_TIMING_CLKDIV_LSB; - - // Force a read through XIP to ensure the timing is applied - volatile uint32_t *ptr = (volatile uint32_t *)0x14000000; - (void)*ptr; -} - size_t __no_inline_not_in_flash_func(psram_detect)() { int psram_size = 0; @@ -110,8 +89,6 @@ size_t __no_inline_not_in_flash_func(psram_init)(uint cs_pin) { return 0; } - psram_set_qmi_timing(); - // Enable direct mode, PSRAM CS, clkdiv of 10. qmi_hw->direct_csr = 10 << QMI_DIRECT_CSR_CLKDIV_LSB | \ QMI_DIRECT_CSR_EN_BITS | \ diff --git a/ports/rp2/rp2_psram.h b/ports/rp2/rp2_psram.h index cd791602cdd68..718e7a1ea9e76 100644 --- a/ports/rp2/rp2_psram.h +++ b/ports/rp2/rp2_psram.h @@ -5,7 +5,6 @@ #define PSRAM_LOCATION _u(0x11000000) -extern void psram_set_qmi_timing(); extern size_t psram_init(uint cs_pin); #endif From 5884d37ee85ccc644b3f2068dfff1fc27e985ea4 Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Sun, 11 Aug 2024 21:39:05 +0100 Subject: [PATCH 23/30] ports/rp2: Set flash divisor appropriately. Signed-off-by: Mike Bell --- ports/rp2/main.c | 4 +++ ports/rp2/modmachine.c | 12 ++++++++ ports/rp2/rp2_flash.c | 69 ++++++++++++++++++++++++++++++++++++++++++ ports/rp2/rp2_flash.h | 7 +++++ 4 files changed, 92 insertions(+) create mode 100644 ports/rp2/rp2_flash.h diff --git a/ports/rp2/main.c b/ports/rp2/main.c index 482515342a94b..67060df7a88a3 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -27,6 +27,7 @@ #include #include "rp2_psram.h" +#include "rp2_flash.h" #include "py/compile.h" #include "py/cstack.h" #include "py/runtime.h" @@ -89,6 +90,9 @@ int main(int argc, char **argv) { // Hook for setting up anything that needs to be super early in the bootup process. MICROPY_BOARD_STARTUP(); + // Set the flash divisor to an appropriate value + rp2_flash_set_timing(); + #if MICROPY_HW_ENABLE_UART_REPL bi_decl(bi_program_feature("UART REPL")) setup_default_uart(); diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c index 2081d4a913088..b48be754e668d 100644 --- a/ports/rp2/modmachine.c +++ b/ports/rp2/modmachine.c @@ -32,6 +32,7 @@ #include "modmachine.h" #include "uart.h" #include "rp2_psram.h" +#include "rp2_flash.h" #include "clocks_extra.h" #include "hardware/pll.h" #include "hardware/structs/rosc.h" @@ -95,6 +96,11 @@ static mp_obj_t mp_machine_get_freq(void) { static void mp_machine_set_freq(size_t n_args, const mp_obj_t *args) { mp_int_t freq = mp_obj_get_int(args[0]); + + // If necessary, increase the flash divider before increasing the clock speed + const int old_freq = clock_get_hz(clk_sys); + rp2_flash_set_timing_for_freq(MAX(freq, old_freq)); + if (!set_sys_clock_khz(freq / 1000, false)) { mp_raise_ValueError(MP_ERROR_TEXT("cannot change frequency")); } @@ -112,6 +118,12 @@ static void mp_machine_set_freq(size_t n_args, const mp_obj_t *args) { } } } + + // If clock speed was reduced, maybe we can reduce the flash divider + if (freq < old_freq) { + rp2_flash_set_timing_for_freq(freq); + } + #if MICROPY_HW_ENABLE_UART_REPL setup_default_uart(); mp_uart_init(); diff --git a/ports/rp2/rp2_flash.c b/ports/rp2/rp2_flash.c index 4386986011db2..45f2ec70e1017 100644 --- a/ports/rp2/rp2_flash.c +++ b/ports/rp2/rp2_flash.c @@ -33,6 +33,12 @@ #include "modrp2.h" #include "hardware/flash.h" #include "pico/binary_info.h" +#ifdef PICO_RP2350 +#include "hardware/structs/ioqspi.h" +#include "hardware/structs/qmi.h" +#else +#include "hardware/structs/ssi.h" +#endif #define BLOCK_SIZE_BYTES (FLASH_SECTOR_SIZE) @@ -71,6 +77,48 @@ bi_decl(bi_block_device( BINARY_INFO_BLOCK_DEV_FLAG_WRITE | BINARY_INFO_BLOCK_DEV_FLAG_PT_UNKNOWN)); +// Function to set the flash divisor to the correct divisor, assumes interrupts disabled +// and core1 locked out if relevant. +static void __no_inline_not_in_flash_func(rp2_flash_set_timing_internal)(int clock_hz) { + + // Use the minimum divisor assuming a 133MHz flash. + const int max_flash_freq = 133000000; + int divisor = (clock_hz + max_flash_freq - 1) / max_flash_freq; + + #if PICO_RP2350 + // Make sure flash is deselected - QMI doesn't appear to have a busy flag(!) + while ((ioqspi_hw->io[1].status & IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS) != IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS) { + ; + } + + // RX delay equal to the divisor means sampling at the same time as the next falling edge of SCK after the + // falling edge that generated the data. This is pretty tight at 133MHz but seems to work with the Winbond flash chips. + const int rxdelay = divisor; + qmi_hw->m[0].timing = (1 << QMI_M0_TIMING_COOLDOWN_LSB) | + rxdelay << QMI_M1_TIMING_RXDELAY_LSB | + divisor << QMI_M1_TIMING_CLKDIV_LSB; + + // Force a read through XIP to ensure the timing is applied + volatile uint32_t *ptr = (volatile uint32_t *)0x14000000; + (void)*ptr; + #else + // RP2040 SSI hardware only supports even divisors + if (divisor & 1) { + divisor += 1; + } + + // Wait for SSI not busy + while (ssi_hw->sr & SSI_SR_BUSY_BITS) { + ; + } + + // Disable, set the new divisor, and re-enable + hw_clear_bits(&ssi_hw->ssienr, SSI_SSIENR_SSI_EN_BITS); + ssi_hw->baudr = divisor; + hw_set_bits(&ssi_hw->ssienr, SSI_SSIENR_SSI_EN_BITS); + #endif +} + // Flash erase and write must run with interrupts disabled and the other core suspended, // because the XIP bit gets disabled. static uint32_t begin_critical_flash_section(void) { @@ -94,6 +142,7 @@ static void end_critical_flash_section(uint32_t state) { #if defined(MICROPY_HW_PSRAM_CS_PIN) && MICROPY_HW_ENABLE_PSRAM psram_init(MICROPY_HW_PSRAM_CS_PIN); #endif + rp2_flash_set_timing_internal(clock_get_hz(clk_sys)); restore_interrupts(state); if (multicore_lockout_victim_is_initialized(1 - get_core_num())) { multicore_lockout_end_blocking(); @@ -250,3 +299,23 @@ MP_DEFINE_CONST_OBJ_TYPE( make_new, rp2_flash_make_new, locals_dict, &rp2_flash_locals_dict ); + +// Modify the flash timing. Ensure flash access is suspended while +// the timings are altered. +void rp2_flash_set_timing_for_freq(int clock_hz) { + if (multicore_lockout_victim_is_initialized(1 - get_core_num())) { + multicore_lockout_start_blocking(); + } + uint32_t state = save_and_disable_interrupts(); + + rp2_flash_set_timing_internal(clock_hz); + + restore_interrupts(state); + if (multicore_lockout_victim_is_initialized(1 - get_core_num())) { + multicore_lockout_end_blocking(); + } +} + +void rp2_flash_set_timing() { + rp2_flash_set_timing_for_freq(clock_get_hz(clk_sys)); +} diff --git a/ports/rp2/rp2_flash.h b/ports/rp2/rp2_flash.h new file mode 100644 index 0000000000000..d5cf3ba2acac0 --- /dev/null +++ b/ports/rp2/rp2_flash.h @@ -0,0 +1,7 @@ +#ifndef MICROPY_INCLUDED_RP2_MACHINE_FLASH_H +#define MICROPY_INCLUDED_RP2_MACHINE_FLASH_H + +extern void rp2_flash_set_timing_for_freq(int clock_hz); +extern void rp2_flash_set_timing(); + +#endif From 153ca96e643ab67e2f7f7058516b7dc91219e0f2 Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Thu, 15 Aug 2024 14:01:57 +0100 Subject: [PATCH 24/30] ports/rp2: Reset flash timing before PSRAM timing. Signed-off-by: Mike Bell --- ports/rp2/rp2_flash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/rp2/rp2_flash.c b/ports/rp2/rp2_flash.c index 45f2ec70e1017..eae219f49ea9e 100644 --- a/ports/rp2/rp2_flash.c +++ b/ports/rp2/rp2_flash.c @@ -139,10 +139,10 @@ static uint32_t begin_critical_flash_section(void) { } static void end_critical_flash_section(uint32_t state) { + rp2_flash_set_timing_internal(clock_get_hz(clk_sys)); #if defined(MICROPY_HW_PSRAM_CS_PIN) && MICROPY_HW_ENABLE_PSRAM psram_init(MICROPY_HW_PSRAM_CS_PIN); #endif - rp2_flash_set_timing_internal(clock_get_hz(clk_sys)); restore_interrupts(state); if (multicore_lockout_victim_is_initialized(1 - get_core_num())) { multicore_lockout_end_blocking(); From e49da694f8fb79490c35cdd94a2b5d582c8ba6f6 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 30 Sep 2024 16:57:19 +0100 Subject: [PATCH 25/30] ports/rp2: Move PSRAM init earlier in startup. Try to avoid causing an upset with USB startup by detecting PSRAM as early as possible. Signed-off-by: Phil Howard --- ports/rp2/main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ports/rp2/main.c b/ports/rp2/main.c index 67060df7a88a3..9eb8ae5b63d19 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -82,6 +82,10 @@ int main(int argc, char **argv) { SCB->SCR |= SCB_SCR_SEVONPEND_Msk; #endif + #if defined(MICROPY_HW_PSRAM_CS_PIN) && MICROPY_HW_ENABLE_PSRAM + size_t psram_size = psram_init(MICROPY_HW_PSRAM_CS_PIN); + #endif + pendsv_init(); // Set the MCU frequency and as a side effect the peripheral clock to 48 MHz. @@ -122,7 +126,6 @@ int main(int argc, char **argv) { mp_cstack_init_with_top(&__StackTop, &__StackTop - &__StackBottom); #if defined(MICROPY_HW_PSRAM_CS_PIN) && MICROPY_HW_ENABLE_PSRAM - size_t psram_size = psram_init(MICROPY_HW_PSRAM_CS_PIN); if (psram_size) { #if MICROPY_GC_SPLIT_HEAP gc_init(&__GcHeapStart, &__GcHeapEnd); From 14dca1ffaf5163a8c8956843273e9d0d99d152c2 Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Sun, 13 Oct 2024 15:57:11 +0100 Subject: [PATCH 26/30] ports/rp2: Further PSRAM setup tweaks. Move PSRAM setup to immediately after flash timing setup. Disable interrupts while setting up PSRAM. Signed-off-by: Mike Bell --- ports/rp2/main.c | 8 ++++---- ports/rp2/rp2_psram.c | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/ports/rp2/main.c b/ports/rp2/main.c index 9eb8ae5b63d19..31f4bc8af78ca 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -82,10 +82,6 @@ int main(int argc, char **argv) { SCB->SCR |= SCB_SCR_SEVONPEND_Msk; #endif - #if defined(MICROPY_HW_PSRAM_CS_PIN) && MICROPY_HW_ENABLE_PSRAM - size_t psram_size = psram_init(MICROPY_HW_PSRAM_CS_PIN); - #endif - pendsv_init(); // Set the MCU frequency and as a side effect the peripheral clock to 48 MHz. @@ -97,6 +93,10 @@ int main(int argc, char **argv) { // Set the flash divisor to an appropriate value rp2_flash_set_timing(); + #if defined(MICROPY_HW_PSRAM_CS_PIN) && MICROPY_HW_ENABLE_PSRAM + size_t psram_size = psram_init(MICROPY_HW_PSRAM_CS_PIN); + #endif + #if MICROPY_HW_ENABLE_UART_REPL bi_decl(bi_program_feature("UART REPL")) setup_default_uart(); diff --git a/ports/rp2/rp2_psram.c b/ports/rp2/rp2_psram.c index 30f87adaf4122..ae6a3fb0a562f 100644 --- a/ports/rp2/rp2_psram.c +++ b/ports/rp2/rp2_psram.c @@ -9,8 +9,6 @@ size_t __no_inline_not_in_flash_func(psram_detect)() { int psram_size = 0; - uint32_t intr_stash = save_and_disable_interrupts(); - // Try and read the PSRAM ID via direct_csr. qmi_hw->direct_csr = 30 << QMI_DIRECT_CSR_CLKDIV_LSB | QMI_DIRECT_CSR_EN_BITS; @@ -76,13 +74,14 @@ size_t __no_inline_not_in_flash_func(psram_detect)() { } } - restore_interrupts(intr_stash); return psram_size; } size_t __no_inline_not_in_flash_func(psram_init)(uint cs_pin) { gpio_set_function(cs_pin, GPIO_FUNC_XIP_CS1); + uint32_t intr_stash = save_and_disable_interrupts(); + size_t psram_size = psram_detect(); if (!psram_size) { @@ -162,5 +161,7 @@ size_t __no_inline_not_in_flash_func(psram_init)(uint cs_pin) { // Enable writes to PSRAM hw_set_bits(&xip_ctrl_hw->ctrl, XIP_CTRL_WRITABLE_M1_BITS); + restore_interrupts(intr_stash); + return psram_size; } From 84ba6673f19cfaf1c4b21d443450ce14c8ecff24 Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Mon, 28 Oct 2024 18:38:45 +0000 Subject: [PATCH 27/30] ports/rp2: Better fix to cache cleaning. Signed-off-by: Mike Bell --- ports/rp2/rp2_flash.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ports/rp2/rp2_flash.c b/ports/rp2/rp2_flash.c index eae219f49ea9e..f464c048b76e7 100644 --- a/ports/rp2/rp2_flash.c +++ b/ports/rp2/rp2_flash.c @@ -129,7 +129,10 @@ static uint32_t begin_critical_flash_section(void) { #if defined(MICROPY_HW_PSRAM_CS_PIN) && MICROPY_HW_ENABLE_PSRAM // We're about to invalidate the XIP cache, clean it first to commit any dirty writes to PSRAM - uint8_t *maintenance_ptr = (uint8_t *)XIP_MAINTENANCE_BASE; + // Use the upper 16k of the maintenance space (0x1bffc000 through 0x1bffffff) to workaround + // incorrect behaviour of the XIP clean operation, where it also alters the tag of the associated + // cache line: https://forums.raspberrypi.com/viewtopic.php?t=378249#p2263677 + volatile uint8_t *maintenance_ptr = (volatile uint8_t *)(XIP_SRAM_BASE + (XIP_MAINTENANCE_BASE - XIP_BASE)); for (int i = 1; i < 16 * 1024; i += 8) { maintenance_ptr[i] = 0; } From 4d5899f69fc95bdd07cb0dc73936f77cc50e7e68 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Fri, 8 Nov 2024 16:55:37 +0000 Subject: [PATCH 28/30] rp2: Set MICROPY_PY_NETWORK_HOSTNAME_DEFAULT. For pico_w and pico2_w. This had inadvertently been removed. Signed-off-by: Peter Harper --- ports/rp2/boards/RPI_PICO2_W/mpconfigboard.h | 2 ++ ports/rp2/boards/RPI_PICO_W/mpconfigboard.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.h b/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.h index a570a00d4d3cd..49345ce5f1d9c 100644 --- a/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.h +++ b/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.h @@ -2,4 +2,6 @@ #define MICROPY_HW_BOARD_NAME "Raspberry Pi Pico 2 W" #define MICROPY_HW_FLASH_STORAGE_BYTES (PICO_FLASH_SIZE_BYTES - 1024 * 1024) +#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "Pico2W" + #include "enable_cyw43.h" diff --git a/ports/rp2/boards/RPI_PICO_W/mpconfigboard.h b/ports/rp2/boards/RPI_PICO_W/mpconfigboard.h index 468d048674a00..5b4530a01f67e 100644 --- a/ports/rp2/boards/RPI_PICO_W/mpconfigboard.h +++ b/ports/rp2/boards/RPI_PICO_W/mpconfigboard.h @@ -4,4 +4,6 @@ // todo: We need something to check our binary size #define MICROPY_HW_FLASH_STORAGE_BYTES (848 * 1024) +#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "PicoW" + #include "enable_cyw43.h" From a48c6dfb7b59f70ace60a7d4ee129c036e2f984a Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Fri, 8 Nov 2024 16:32:33 +0000 Subject: [PATCH 29/30] rp2: Put back soft_timer_init. or else nothing will work! Signed-off-by: Peter Harper --- ports/rp2/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/rp2/main.c b/ports/rp2/main.c index 31f4bc8af78ca..a00983170a8a6 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -83,6 +83,7 @@ int main(int argc, char **argv) { #endif pendsv_init(); + soft_timer_init(); // Set the MCU frequency and as a side effect the peripheral clock to 48 MHz. set_sys_clock_khz(SYS_CLK_KHZ, false); From 22e04e2e05f1f6f7d07ba255d1381466e0a0c4e6 Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Sun, 17 Nov 2024 14:59:02 +0000 Subject: [PATCH 30/30] ports/rp2: PSRAM linker script. --- ports/rp2/CMakeLists.txt | 11 +- ports/rp2/main.c | 10 +- ports/rp2/memmap_mp_rp2350_psram.ld | 322 ++++++++++++++++++++++++++++ ports/rp2/rp2_psram.h | 2 - 4 files changed, 339 insertions(+), 6 deletions(-) create mode 100644 ports/rp2/memmap_mp_rp2350_psram.ld diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index a5979f3901f29..79fe796fce5b1 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -173,10 +173,13 @@ set(MICROPY_SOURCE_PORT ${CMAKE_BINARY_DIR}/pins_${MICROPY_BOARD}.c ) -if(PICO_RP2350) +if(MICROPY_HW_ENABLE_PSRAM) list(APPEND MICROPY_SOURCE_PORT rp2_psram.c ) + target_compile_definitions(${MICROPY_TARGET} PRIVATE + MICROPY_HW_ENABLE_PSRAM=1 + ) endif() set(MICROPY_SOURCE_QSTR @@ -606,7 +609,11 @@ if (PICO_ON_DEVICE AND NOT PICO_NO_FLASH AND NOT PICO_COPY_TO_RAM) if(PICO_RP2040) pico_set_linker_script(${MICROPY_TARGET} ${CMAKE_CURRENT_LIST_DIR}/memmap_mp_rp2040.ld) elseif(PICO_RP2350) - pico_set_linker_script(${MICROPY_TARGET} ${CMAKE_CURRENT_LIST_DIR}/memmap_mp_rp2350.ld) + if (MICROPY_HW_ENABLE_PSRAM) + pico_set_linker_script(${MICROPY_TARGET} ${CMAKE_CURRENT_LIST_DIR}/memmap_mp_rp2350_psram.ld) + else() + pico_set_linker_script(${MICROPY_TARGET} ${CMAKE_CURRENT_LIST_DIR}/memmap_mp_rp2350.ld) + endif() endif() endif() diff --git a/ports/rp2/main.c b/ports/rp2/main.c index a00983170a8a6..91528100fdfa7 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -66,6 +66,7 @@ extern uint8_t __StackTop, __StackBottom; extern uint8_t __GcHeapStart, __GcHeapEnd; +extern uint8_t __PsramGcHeapStart, __PsramGcHeapEnd; // Embed version info in the binary in machine readable form bi_decl(bi_program_version_string(MICROPY_GIT_TAG)); @@ -128,11 +129,16 @@ int main(int argc, char **argv) { #if defined(MICROPY_HW_PSRAM_CS_PIN) && MICROPY_HW_ENABLE_PSRAM if (psram_size) { + // Linker script assumes a 2MB PSRAM, increase the size accordingly. + size_t psram_additional_size = 0; + if (psram_size > 2 * 1024 * 1024) { + psram_additional_size = psram_size - 2 * 1024 * 1024; + } #if MICROPY_GC_SPLIT_HEAP gc_init(&__GcHeapStart, &__GcHeapEnd); - gc_add((void *)PSRAM_LOCATION, (void *)(PSRAM_LOCATION + psram_size)); + gc_add(&__PsramGcHeapStart, &__PsramGcHeapEnd + psram_additional_size); #else - gc_init((void *)PSRAM_LOCATION, (void *)(PSRAM_LOCATION + psram_size)); + gc_init(&__PsramGcHeapStart, &__PsramGcHeapEnd + psram_additional_size); #endif } else { gc_init(&__GcHeapStart, &__GcHeapEnd); diff --git a/ports/rp2/memmap_mp_rp2350_psram.ld b/ports/rp2/memmap_mp_rp2350_psram.ld new file mode 100644 index 0000000000000..c63572bbcb5d3 --- /dev/null +++ b/ports/rp2/memmap_mp_rp2350_psram.ld @@ -0,0 +1,322 @@ +/* Based on GCC ARM embedded samples. + Defines the following symbols for use by code: + __exidx_start + __exidx_end + __etext + __data_start__ + __preinit_array_start + __preinit_array_end + __init_array_start + __init_array_end + __fini_array_start + __fini_array_end + __data_end__ + __bss_start__ + __bss_end__ + __end__ + end + __HeapLimit + __StackLimit + __StackTop + __stack (== StackTop) +*/ + +MEMORY +{ + FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 4096k + RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 512k + SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k + SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k + PSRAM(rw) : ORIGIN = 0x11000000, LENGTH = 2048k +} + +ENTRY(_entry_point) + +SECTIONS +{ + .flash_begin : { + __flash_binary_start = .; + } > FLASH + + /* The bootrom will enter the image at the point indicated in your + IMAGE_DEF, which is usually the reset handler of your vector table. + + The debugger will use the ELF entry point, which is the _entry_point + symbol, and in our case is *different from the bootrom's entry point.* + This is used to go back through the bootrom on debugger launches only, + to perform the same initial flash setup that would be performed on a + cold boot. + */ + + .text : { + __logical_binary_start = .; + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + KEEP (*(.reset)) + /* TODO revisit this now memset/memcpy/float in ROM */ + /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from + * FLASH ... we will include any thing excluded here in .data below by default */ + *(.init) + *libgcc.a:cmse_nonsecure_call.o + /* Change for MicroPython... exclude gc.c, parse.c, vm.c from flash */ + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a: *gc.c.obj *vm.c.obj *parse.c.obj) .text*) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(SORT(.preinit_array.*))) + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + *(.eh_frame*) + . = ALIGN(4); + } > FLASH + + /* Note the boot2 section is optional, and should be discarded if there is + no reference to it *inside* the binary, as it is not called by the + bootrom. (The bootrom performs a simple best-effort XIP setup and + leaves it to the binary to do anything more sophisticated.) However + there is still a size limit of 256 bytes, to ensure the boot2 can be + stored in boot RAM. + + Really this is a "XIP setup function" -- the name boot2 is historic and + refers to its dual-purpose on RP2040, where it also handled vectoring + from the bootrom into the user image. + */ + + .boot2 : { + __boot2_start__ = .; + *(.boot2) + __boot2_end__ = .; + } > FLASH + + ASSERT(__boot2_end__ - __boot2_start__ <= 256, + "ERROR: Pico second stage bootloader must be no more than 256 bytes in size") + + .rodata : { + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) + *(.srodata*) + . = ALIGN(4); + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > FLASH + __binary_info_end = .; + . = ALIGN(4); + + .ram_vector_table (NOLOAD): { + *(.ram_vector_table) + } > RAM + + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + + .data : { + __data_start__ = .; + *(vtable) + + *(.time_critical*) + + /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ + *(.text*) + . = ALIGN(4); + *(.rodata*) + . = ALIGN(4); + + *(.data*) + *(.sdata*) + + . = ALIGN(4); + *(.after_data.*) + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__mutex_array_start = .); + KEEP(*(SORT(.mutex_array.*))) + KEEP(*(.mutex_array)) + PROVIDE_HIDDEN (__mutex_array_end = .); + + *(.jcr) + . = ALIGN(4); + } > RAM AT> FLASH + + .tdata : { + . = ALIGN(4); + *(.tdata .tdata.* .gnu.linkonce.td.*) + /* All data end */ + __tdata_end = .; + } > RAM AT> FLASH + PROVIDE(__data_end__ = .); + + /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ + __etext = LOADADDR(.data); + + .tbss (NOLOAD) : { + . = ALIGN(4); + __bss_start__ = .; + __tls_base = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + + __tls_end = .; + } > RAM + + .bss (NOLOAD) : { + . = ALIGN(4); + __tbss_end = .; + + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + PROVIDE(__global_pointer$ = . + 2K); + *(.sbss*) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (NOLOAD): + { + __end__ = .; + end = __end__; + KEEP(*(.heap*)) + /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however + to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */ + /* Change for MicroPython: don't include this, it increases reported firmware size. + /* . = ORIGIN(RAM) + LENGTH(RAM); */ + __HeapLimit = .; + } > RAM + + /* Start and end symbols must be word-aligned */ + .scratch_x : { + __scratch_x_start__ = .; + *(.scratch_x.*) + . = ALIGN(4); + __scratch_x_end__ = .; + } > SCRATCH_X AT > FLASH + __scratch_x_source__ = LOADADDR(.scratch_x); + + .scratch_y : { + __scratch_y_start__ = .; + *(.scratch_y.*) + . = ALIGN(4); + __scratch_y_end__ = .; + } > SCRATCH_Y AT > FLASH + __scratch_y_source__ = LOADADDR(.scratch_y); + + /* .stack*_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later + * + * stack1 section may be empty/missing if platform_launch_core1 is not used */ + + /* by default we put core 0 stack at the end of scratch Y, so that if core 1 + * stack is not used then all of SCRATCH_X is free. + */ + .stack1_dummy (NOLOAD): + { + *(.stack1*) + } > SCRATCH_X + .stack_dummy (NOLOAD): + { + KEEP(*(.stack*)) + } > SCRATCH_Y + + .flash_end : { + KEEP(*(.embedded_end_block*)) + PROVIDE(__flash_binary_end = .); + } > FLASH =0xaa + + /* PSRAM data section */ + .psram_data (NOLOAD): { + . = ALIGN(4); + *(.psram_data*) + PROVIDE(__psram_data_end = .); + } > PSRAM + + /* stack limit is poorly named, but historically is maximum heap ptr */ + __StackLimit = __bss_end__ + __micropy_c_heap_size__; + + /* Define start and end of internal RAM GC heap */ + __GcHeapStart = __StackLimit; /* after the C heap (sbrk limit) */ + __GcHeapEnd = ORIGIN(RAM) + LENGTH(RAM) - __micropy_extra_stack__; + + /* Define start and end of PSRAM GC heap */ + __PsramGcHeapStart = __psram_data_end; /* after the C heap (sbrk limit) */ + __PsramGcHeapEnd = ORIGIN(PSRAM) + LENGTH(PSRAM); + + /* Define start and end of C stack */ + __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); + __StackBottom = __GcHeapEnd; + PROVIDE(__stack = __StackTop); + + /* picolibc and LLVM */ + PROVIDE (__heap_start = __end__); + PROVIDE (__heap_end = __HeapLimit); + PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); + PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); + PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); + + /* llvm-libc */ + PROVIDE (_end = __end__); + PROVIDE (__llvm_libc_heap_limit = __HeapLimit); + + /* Ensure internal RAM didn't overflow */ + ASSERT((__GcHeapEnd - __GcHeapStart) > 0, "Main RAM overflow") + + /* Check GC heap is at least 128kB */ + ASSERT((__PsramGcHeapEnd - __PsramGcHeapStart) > 128*1024, "GcHeap is too small") + + ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary info must be in first 1024 bytes of the binary") + ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded block must be in first 4096 bytes of the binary") + + /* todo assert on extra code */ +} diff --git a/ports/rp2/rp2_psram.h b/ports/rp2/rp2_psram.h index 718e7a1ea9e76..29ef54f8a3617 100644 --- a/ports/rp2/rp2_psram.h +++ b/ports/rp2/rp2_psram.h @@ -3,8 +3,6 @@ #ifndef MICROPY_INCLUDED_RP2_MACHINE_PSRAM_H #define MICROPY_INCLUDED_RP2_MACHINE_PSRAM_H -#define PSRAM_LOCATION _u(0x11000000) - extern size_t psram_init(uint cs_pin); #endif