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 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 diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 4baaf7debf6c5..79fe796fce5b1 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -173,6 +173,15 @@ set(MICROPY_SOURCE_PORT ${CMAKE_BINARY_DIR}/pins_${MICROPY_BOARD}.c ) +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 ${MICROPY_SOURCE_PY} ${MICROPY_DIR}/shared/readline/readline.c @@ -195,7 +204,14 @@ 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 hardware_base hardware_boot_lock @@ -222,6 +238,7 @@ set(PICO_SDK_COMPONENTS pico_base_headers pico_binary_info pico_bootrom + pico_flash pico_multicore pico_platform pico_platform_compiler @@ -401,6 +418,7 @@ if (MICROPY_PY_NETWORK_CYW43) list(APPEND MICROPY_SOURCE_PORT machine_pin_cyw43.c + rp2_network_cyw43.c ) target_link_libraries(${MICROPY_TARGET} @@ -591,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() @@ -631,8 +653,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() 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" 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 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..b77ff7d979c3c --- /dev/null +++ b/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.cmake @@ -0,0 +1,11 @@ +# 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) + +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 new file mode 100644 index 0000000000000..49345ce5f1d9c --- /dev/null +++ b/ports/rp2/boards/RPI_PICO2_W/mpconfigboard.h @@ -0,0 +1,7 @@ +// 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) + +#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "Pico2W" + +#include "enable_cyw43.h" 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 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 ef812b6301356..5b4530a01f67e 100644 --- a/ports/rp2/boards/RPI_PICO_W/mpconfigboard.h +++ b/ports/rp2/boards/RPI_PICO_W/mpconfigboard.h @@ -4,20 +4,6 @@ // 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" +#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 - -#define MICROPY_HW_PIN_RESERVED(i) ((i) == CYW43_PIN_WL_HOST_WAKE || (i) == CYW43_PIN_WL_REG_ON) +#include "enable_cyw43.h" 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(); \ 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) diff --git a/ports/rp2/main.c b/ports/rp2/main.c index d6bf448267152..91528100fdfa7 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -26,6 +26,8 @@ #include +#include "rp2_psram.h" +#include "rp2_flash.h" #include "py/compile.h" #include "py/cstack.h" #include "py/runtime.h" @@ -49,15 +51,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 @@ -68,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)); @@ -93,6 +92,13 @@ 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 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(); @@ -120,7 +126,26 @@ int main(int argc, char **argv) { // Initialise stack extents and GC heap. mp_cstack_init_with_top(&__StackTop, &__StackTop - &__StackBottom); + + #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(&__PsramGcHeapStart, &__PsramGcHeapEnd + psram_additional_size); + #else + gc_init(&__PsramGcHeapStart, &__PsramGcHeapEnd + psram_additional_size); + #endif + } else { + gc_init(&__GcHeapStart, &__GcHeapEnd); + } + #else gc_init(&__GcHeapStart, &__GcHeapEnd); + #endif #if MICROPY_PY_LWIP // lwIP doesn't allow to reinitialise itself by subsequent calls to this function @@ -132,28 +157,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/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/modmachine.c b/ports/rp2/modmachine.c index cd73552dd9874..b48be754e668d 100644 --- a/ports/rp2/modmachine.c +++ b/ports/rp2/modmachine.c @@ -31,6 +31,8 @@ #include "mp_usbd.h" #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" @@ -94,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")); } @@ -111,16 +118,28 @@ 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(); #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) { 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 +209,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 +227,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; @@ -228,7 +244,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 @@ -246,11 +262,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 +279,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/mpconfigport.h b/ports/rp2/mpconfigport.h index 15eeab4f34b07..87eee29bb6797 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -71,8 +71,19 @@ #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 #define MICROPY_ALLOC_PATH_MAX (128) #define MICROPY_QSTR_BYTES_IN_HASH (1) @@ -223,6 +234,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/mphalport.c b/ports/rp2/mphalport.c index 3f50151620a02..b581b3b59f95d 100644 --- a/ports/rp2/mphalport.c +++ b/ports/rp2/mphalport.c @@ -266,15 +266,13 @@ 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(); + best_effort_wfe_or_timeout(delayed_by_ms(get_absolute_time(), timeout_ms)); +} - // Clean up the timer node if it's not already - soft_timer_remove(&timer); +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 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_flash.c b/ports/rp2/rp2_flash.c index c1acb54e75748..f464c048b76e7 100644 --- a/ports/rp2/rp2_flash.c +++ b/ports/rp2/rp2_flash.c @@ -26,12 +26,19 @@ #include +#include "rp2_psram.h" #include "py/mphal.h" #include "py/runtime.h" #include "extmod/vfs.h" #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) @@ -70,16 +77,75 @@ 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) { 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(); + + #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 + // 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; + } + #endif + + return state; } 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 restore_interrupts(state); if (multicore_lockout_victim_is_initialized(1 - get_core_num())) { multicore_lockout_end_blocking(); @@ -145,11 +211,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 +230,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; } @@ -210,3 +302,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 diff --git a/ports/rp2/rp2_network_cyw43.c b/ports/rp2/rp2_network_cyw43.c new file mode 100644 index 0000000000000..1f14991547b3d --- /dev/null +++ b/ports/rp2/rp2_network_cyw43.c @@ -0,0 +1,96 @@ +#include "py/runtime.h" +#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); + +#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 + +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[] = { + { 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); + rp2_network_cyw43_init(); + + // 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); + } +} diff --git a/ports/rp2/rp2_psram.c b/ports/rp2/rp2_psram.c new file mode 100644 index 0000000000000..ae6a3fb0a562f --- /dev/null +++ b/ports/rp2/rp2_psram.c @@ -0,0 +1,167 @@ +#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" + + +size_t __no_inline_not_in_flash_func(psram_detect)() { + int psram_size = 0; + + // 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 + } + } + + 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) { + return 0; + } + + // 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) { + ; + } + + // 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 | \ + 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); + + restore_interrupts(intr_stash); + + return psram_size; +} diff --git a/ports/rp2/rp2_psram.h b/ports/rp2/rp2_psram.h new file mode 100644 index 0000000000000..29ef54f8a3617 --- /dev/null +++ b/ports/rp2/rp2_psram.h @@ -0,0 +1,8 @@ +#include "pico/stdlib.h" + +#ifndef MICROPY_INCLUDED_RP2_MACHINE_PSRAM_H +#define MICROPY_INCLUDED_RP2_MACHINE_PSRAM_H + +extern size_t psram_init(uint cs_pin); + +#endif 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