From 525fce717030e0be98adcd983c1df663717a74a5 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 28 Jun 2024 16:01:12 +0100 Subject: [PATCH 01/31] py/usermod.cmake: Check target exists in usermod_gather_sources. Check a target exists before accessing properties. Otherwise usermod_gather_sources would recurse into garbage property names and break. Signed-off-by: Phil Howard --- py/usermod.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/py/usermod.cmake b/py/usermod.cmake index 853276283746d..c814369a4865e 100644 --- a/py/usermod.cmake +++ b/py/usermod.cmake @@ -5,6 +5,10 @@ function(usermod_gather_sources SOURCES_VARNAME INCLUDE_DIRECTORIES_VARNAME INCL if (NOT ${LIB} IN_LIST ${INCLUDED_VARNAME}) list(APPEND ${INCLUDED_VARNAME} ${LIB}) + if (NOT TARGET ${LIB}) + return() + endif() + # Gather library sources get_target_property(lib_sources ${LIB} INTERFACE_SOURCES) if (lib_sources) From 70a884d6ec7dfec4ef4f18aa1871db4d70a06129 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Aug 2024 14:26:27 +1000 Subject: [PATCH 02/31] lib/pico-sdk: Update to version 2.0.0. Adds support for the new RP2350 MCU. Signed-off-by: Damien George --- lib/pico-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pico-sdk b/lib/pico-sdk index 6a7db34ff6334..efe2103f9b284 160000 --- a/lib/pico-sdk +++ b/lib/pico-sdk @@ -1 +1 @@ -Subproject commit 6a7db34ff63345a7badec79ebea3aaef1712f374 +Subproject commit efe2103f9b28458a1615ff096054479743ade236 From 815d6a131d81eded59d17aa854eb006ff8c19e2b Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 22 May 2024 15:34:32 +0100 Subject: [PATCH 03/31] rp2/mpconfigport: Set MCU name for RP2350. Signed-off-by: Damien George --- ports/rp2/mpconfigport.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index b34b4fc09c72d..80fe9f37c10ce 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -35,7 +35,16 @@ #include "mpconfigboard.h" // Board and hardware specific configuration +#if PICO_RP2040 #define MICROPY_HW_MCU_NAME "RP2040" +#elif PICO_RP2350 && PICO_ARM +#define MICROPY_HW_MCU_NAME "RP2350" +#elif PICO_RP2350 && PICO_RISCV +#define MICROPY_HW_MCU_NAME "RP2350-RISCV" +#else +#error Unknown MCU +#endif + #ifndef MICROPY_HW_ENABLE_UART_REPL #define MICROPY_HW_ENABLE_UART_REPL (0) // useful if there is no USB #endif From c90d996c9da51103a6be1b41b2c2664a730b0d8e Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 22 May 2024 15:49:46 +0100 Subject: [PATCH 04/31] rp2: Update custom linker scripts for new pico-sdk. Signed-off-by: Phil Howard Signed-off-by: Damien George --- ports/rp2/CMakeLists.txt | 2 +- .../rp2/{memmap_mp.ld => memmap_mp_rp2040.ld} | 0 ports/rp2/memmap_mp_rp2350.ld | 312 ++++++++++++++++++ 3 files changed, 313 insertions(+), 1 deletion(-) rename ports/rp2/{memmap_mp.ld => memmap_mp_rp2040.ld} (100%) create mode 100644 ports/rp2/memmap_mp_rp2350.ld diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 19c7178fc7266..54b7e84bc9804 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -525,7 +525,7 @@ endif() # a linker script modification) until we explicitly add macro calls around the function # defs to move them into RAM. if (PICO_ON_DEVICE AND NOT PICO_NO_FLASH AND NOT PICO_COPY_TO_RAM) - pico_set_linker_script(${MICROPY_TARGET} ${CMAKE_CURRENT_LIST_DIR}/memmap_mp.ld) + pico_set_linker_script(${MICROPY_TARGET} ${CMAKE_CURRENT_LIST_DIR}/memmap_mp_${PICO_PLATFORM}.ld) endif() pico_add_extra_outputs(${MICROPY_TARGET}) diff --git a/ports/rp2/memmap_mp.ld b/ports/rp2/memmap_mp_rp2040.ld similarity index 100% rename from ports/rp2/memmap_mp.ld rename to ports/rp2/memmap_mp_rp2040.ld diff --git a/ports/rp2/memmap_mp_rp2350.ld b/ports/rp2/memmap_mp_rp2350.ld new file mode 100644 index 0000000000000..1e1cbbfd70296 --- /dev/null +++ b/ports/rp2/memmap_mp_rp2350.ld @@ -0,0 +1,312 @@ +/* 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 +} + +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 + + /* stack limit is poorly named, but historically is maximum heap ptr */ + __StackLimit = __bss_end__ + __micropy_c_heap_size__; + + /* Define start and end of GC heap */ + __GcHeapStart = __StackLimit; /* after the C heap (sbrk limit) */ + __GcHeapEnd = ORIGIN(RAM) + LENGTH(RAM) - __micropy_extra_stack__; + + /* 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); + + /* Check GC heap is at least 64 KB */ + /* This is half the minimum RAM suggested for full-featured MicroPython. + * This value accounts for large static buffers included in user C or C++ + * modules, which might significantly reduce the available heap but also + * lower demand for memory at runtime. + */ + ASSERT((__GcHeapEnd - __GcHeapStart) > 64*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 */ +} From d1423ef7a23793de3777e84d985f9902241e788e Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 22 May 2024 15:24:24 +0100 Subject: [PATCH 05/31] rp2/modmachine: Implement lightsleep for RP2350. This isn't fully working, the CPU often wakes up early. That will be fixed when a newer version of pico-sdk is released. Signed-off-by: Damien George --- ports/rp2/modmachine.c | 52 +++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c index 372c17bcf9d6b..0acae25499996 100644 --- a/ports/rp2/modmachine.c +++ b/ports/rp2/modmachine.c @@ -162,6 +162,9 @@ static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) { } clock_stop(clk_adc); + #if PICO_RP2350 + clock_stop(clk_hstx); + #endif // CLK_REF = XOSC clock_configure(clk_ref, CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC, 0, xosc_hz, xosc_hz); @@ -170,7 +173,9 @@ static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) { clock_configure(clk_sys, CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF, 0, xosc_hz, xosc_hz); // CLK_RTC = XOSC / 256 + #if PICO_RP2040 clock_configure(clk_rtc, 0, CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC, xosc_hz, xosc_hz / 256); + #endif // CLK_PERI = CLK_SYS clock_configure(clk_peri, 0, CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS, xosc_hz, xosc_hz); @@ -190,38 +195,63 @@ static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) { #endif xosc_dormant(); } else { - uint32_t sleep_en0 = clocks_hw->sleep_en0; - uint32_t sleep_en1 = clocks_hw->sleep_en1; bool timer3_enabled = irq_is_enabled(3); - clocks_hw->sleep_en0 = CLOCKS_SLEEP_EN0_CLK_RTC_RTC_BITS; + const uint32_t alarm_num = 3; + const uint32_t irq_num = TIMER_ALARM_IRQ_NUM(timer_hw, alarm_num); if (use_timer_alarm) { // Make sure ALARM3/IRQ3 is enabled on _this_ core - timer_hw->inte |= 1 << 3; if (!timer3_enabled) { - irq_set_enabled(3, true); + 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 clocks_hw->sleep_en1 = CLOCKS_SLEEP_EN1_CLK_SYS_TIMER_BITS; - timer_hw->alarm[3] = timer_hw->timerawl + delay_ms * 1000; + #elif PICO_RP2350 + clocks_hw->sleep_en1 = CLOCKS_SLEEP_EN1_CLK_REF_TICKS_BITS | CLOCKS_SLEEP_EN1_CLK_SYS_TIMER0_BITS; + #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; } else { // TODO: Use RTC alarm to wake. - clocks_hw->sleep_en1 = 0; + clocks_hw->sleep_en0 = 0x0; + clocks_hw->sleep_en1 = 0x0; } if (!disable_usb) { clocks_hw->sleep_en0 |= CLOCKS_SLEEP_EN0_CLK_SYS_PLL_USB_BITS; + #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; + #else + #error Unknown processor + #endif } + #if PICO_ARM + // Configure SLEEPDEEP bits on Cortex-M CPUs. + #if PICO_RP2040 scb_hw->scr |= M0PLUS_SCR_SLEEPDEEP_BITS; + #elif PICO_RP2350 + scb_hw->scr |= M33_SCR_SLEEPDEEP_BITS; + #else + #error Unknown processor + #endif + #endif + + // Go into low-power mode. __wfi(); - scb_hw->scr &= ~M0PLUS_SCR_SLEEPDEEP_BITS; + if (!timer3_enabled) { - irq_set_enabled(3, false); + irq_set_enabled(irq_num, false); } - clocks_hw->sleep_en0 = sleep_en0; - clocks_hw->sleep_en1 = sleep_en1; + clocks_hw->sleep_en0 |= ~(0u); + clocks_hw->sleep_en1 |= ~(0u); } // Enable ROSC. From 27aeade832665c434b0150c6fd32a455e6865eef Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Mon, 3 Jun 2024 16:14:43 +0100 Subject: [PATCH 06/31] rp2/rp2_dma: Generalise DMA for RP2350. Two new bits were added to the ctrl register, and existing bits were shifted, so use DMA_CH0_CTRL_TRIG_xxx constants to generalise the code. Signed-off-by: Damien George --- ports/rp2/rp2_dma.c | 46 +++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/ports/rp2/rp2_dma.c b/ports/rp2/rp2_dma.c index 3afcf8b5d63af..78f69e6452758 100644 --- a/ports/rp2/rp2_dma.c +++ b/ports/rp2/rp2_dma.c @@ -57,23 +57,28 @@ typedef struct _rp2_dma_ctrl_field_t { } rp2_dma_ctrl_field_t; static rp2_dma_ctrl_field_t rp2_dma_ctrl_fields_table[] = { - { MP_QSTR_enable, 0, 1, 0 }, - { MP_QSTR_high_pri, 1, 1, 0 }, - { MP_QSTR_size, 2, 2, 0 }, - { MP_QSTR_inc_read, 4, 1, 0 }, - { MP_QSTR_inc_write, 5, 1, 0 }, - { MP_QSTR_ring_size, 6, 4, 0 }, - { MP_QSTR_ring_sel, 10, 1, 0 }, - { MP_QSTR_chain_to, 11, 4, 0 }, - { MP_QSTR_treq_sel, 15, 6, 0 }, - { MP_QSTR_irq_quiet, 21, 1, 0 }, - { MP_QSTR_bswap, 22, 1, 0 }, - { MP_QSTR_sniff_en, 23, 1, 0 }, - { MP_QSTR_busy, 24, 1, 1 }, - // bits 25 through 28 are reserved - { MP_QSTR_write_err, 29, 1, 0 }, - { MP_QSTR_read_err, 30, 1, 0 }, - { MP_QSTR_ahb_err, 31, 1, 1 }, + { MP_QSTR_enable, DMA_CH0_CTRL_TRIG_EN_LSB, 1, 0 }, + { MP_QSTR_high_pri, DMA_CH0_CTRL_TRIG_HIGH_PRIORITY_LSB, 1, 0 }, + { MP_QSTR_size, DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB, 2, 0 }, + { MP_QSTR_inc_read, DMA_CH0_CTRL_TRIG_INCR_READ_LSB, 1, 0 }, + #if PICO_RP2350 + { MP_QSTR_inc_read_rev, DMA_CH0_CTRL_TRIG_INCR_READ_REV_LSB, 1, 0 }, + #endif + { MP_QSTR_inc_write, DMA_CH0_CTRL_TRIG_INCR_WRITE_LSB, 1, 0 }, + #if PICO_RP2350 + { MP_QSTR_inc_write_rev, DMA_CH0_CTRL_TRIG_INCR_WRITE_REV_LSB, 1, 0 }, + #endif + { MP_QSTR_ring_size, DMA_CH0_CTRL_TRIG_RING_SIZE_LSB, 4, 0 }, + { MP_QSTR_ring_sel, DMA_CH0_CTRL_TRIG_RING_SEL_LSB, 1, 0 }, + { MP_QSTR_chain_to, DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB, 4, 0 }, + { MP_QSTR_treq_sel, DMA_CH0_CTRL_TRIG_TREQ_SEL_LSB, 6, 0 }, + { MP_QSTR_irq_quiet, DMA_CH0_CTRL_TRIG_IRQ_QUIET_LSB, 1, 0 }, + { MP_QSTR_bswap, DMA_CH0_CTRL_TRIG_BSWAP_LSB, 1, 0 }, + { MP_QSTR_sniff_en, DMA_CH0_CTRL_TRIG_SNIFF_EN_LSB, 1, 0 }, + { MP_QSTR_busy, DMA_CH0_CTRL_TRIG_BUSY_LSB, 1, 1 }, + { MP_QSTR_write_err, DMA_CH0_CTRL_TRIG_WRITE_ERROR_LSB, 1, 0 }, + { MP_QSTR_read_err, DMA_CH0_CTRL_TRIG_READ_ERROR_LSB, 1, 0 }, + { MP_QSTR_ahb_err, DMA_CH0_CTRL_TRIG_AHB_ERROR_LSB, 1, 1 }, }; static const uint32_t rp2_dma_ctrl_field_count = MP_ARRAY_SIZE(rp2_dma_ctrl_fields_table); @@ -298,7 +303,12 @@ static mp_obj_t rp2_dma_active(size_t n_args, const mp_obj_t *args) { static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rp2_dma_active_obj, 1, 2, rp2_dma_active); // Default is quiet, unpaced, read and write incrementing, word transfers, enabled -#define DEFAULT_DMA_CONFIG (1 << 21) | (0x3f << 15) | (1 << 5) | (1 << 4) | (2 << 2) | (1 << 0) +#define DEFAULT_DMA_CONFIG (1 << DMA_CH0_CTRL_TRIG_IRQ_QUIET_LSB) | \ + (DMA_CH0_CTRL_TRIG_TREQ_SEL_VALUE_PERMANENT << DMA_CH0_CTRL_TRIG_TREQ_SEL_LSB) | \ + (1 << DMA_CH0_CTRL_TRIG_INCR_WRITE_LSB) | \ + (1 << DMA_CH0_CTRL_TRIG_INCR_READ_LSB) | \ + (2 << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB) | \ + (1 << DMA_CH0_CTRL_TRIG_EN_LSB) // DMA.pack_ctrl(...) static mp_obj_t rp2_dma_pack_ctrl(size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { From d2c85c74dabc33a4574422d8970d2b25bcc22b7a Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Thu, 23 May 2024 10:57:14 +0100 Subject: [PATCH 07/31] rp2: Integrate RP2350 and use aon_timer instead of rtc API. This commit separates various build settings and include files that are specific to RP2040 and RP2350, and uses the aon_timer interface instead of rtc, to work across both MCU variants. Signed-off-by: Damien George Signed-off-by: Phil Howard --- ports/rp2/CMakeLists.txt | 49 +++++++++++-- ports/rp2/boards/RPI_PICO/mpconfigboard.cmake | 1 + ports/rp2/fatfs_port.c | 11 +-- ports/rp2/machine_rtc.c | 69 ++++++++----------- ports/rp2/main.c | 25 ++++--- ports/rp2/mbedtls/mbedtls_port.c | 8 +-- ports/rp2/modmachine.c | 1 + ports/rp2/modtime.c | 30 ++++---- ports/rp2/mphalport.c | 24 +++++-- ports/rp2/mpnetworkport.c | 7 ++ ports/rp2/pendsv.c | 7 ++ 11 files changed, 142 insertions(+), 90 deletions(-) diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 54b7e84bc9804..6f66181546271 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -191,19 +191,26 @@ set(PICO_SDK_COMPONENTS hardware_pll hardware_pwm hardware_regs - hardware_rtc + hardware_resets hardware_spi hardware_structs hardware_sync + hardware_sync_spin_lock hardware_timer hardware_uart hardware_watchdog hardware_xosc + pico_aon_timer pico_base_headers pico_binary_info pico_bootrom pico_multicore pico_platform + pico_platform_compiler + pico_platform_panic + pico_platform_sections + pico_runtime + pico_runtime_init pico_stdio pico_stdlib pico_sync @@ -224,14 +231,24 @@ pico_add_library(pico_float_micropython) # pico_float_micropython: add pico-sdk float and our libm source files. target_sources(pico_float_micropython INTERFACE - ${PICO_SDK_PATH}/src/rp2_common/pico_float/float_aeabi.S - ${PICO_SDK_PATH}/src/rp2_common/pico_float/float_init_rom.c - ${PICO_SDK_PATH}/src/rp2_common/pico_float/float_v1_rom_shim.S ${MICROPY_SOURCE_LIB_LIBM} ${MICROPY_SOURCE_LIB_LIBM_SQRT_SW} ${MICROPY_PORT_DIR}/libm_extra.c ) +if(PICO_RP2040) + target_sources(pico_float_micropython INTERFACE + ${PICO_SDK_PATH}/src/rp2_common/pico_float/float_aeabi_rp2040.S + ${PICO_SDK_PATH}/src/rp2_common/pico_float/float_init_rom_rp2040.c + ${PICO_SDK_PATH}/src/rp2_common/pico_float/float_v1_rom_shim_rp2040.S + ) +elseif(PICO_RP2350) + target_sources(pico_float_micropython INTERFACE + ${PICO_SDK_PATH}/src/rp2_common/pico_float/float_aeabi_dcp.S + ${PICO_SDK_PATH}/src/rp2_common/pico_float/float_conv_m33.S + ) +endif() + # pico_float_micropython: wrap low-level floating-point ops, to call the pico-sdk versions. pico_wrap_function(pico_float_micropython __aeabi_fdiv) pico_wrap_function(pico_float_micropython __aeabi_fmul) @@ -253,7 +270,9 @@ pico_wrap_function(pico_float_micropython __aeabi_ul2f) pico_wrap_function(pico_float_micropython __aeabi_f2iz) pico_wrap_function(pico_float_micropython __aeabi_f2lz) pico_wrap_function(pico_float_micropython __aeabi_f2uiz) -pico_wrap_function(pico_float_micropython __aeabi_f2ulz) +if(PICO_RP2040) + pico_wrap_function(pico_float_micropython __aeabi_f2ulz) +endif() pico_wrap_function(pico_float_micropython __aeabi_f2d) if (MICROPY_PY_LWIP) @@ -507,9 +526,18 @@ target_compile_definitions(${MICROPY_TARGET} PRIVATE PICO_NO_PROGRAM_VERSION_STRING=1 # do it ourselves in main.c MICROPY_BUILD_TYPE="${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION} ${CMAKE_BUILD_TYPE}" PICO_NO_BI_STDIO_UART=1 # we call it UART REPL - PICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1 ) +if(PICO_RP2040) + target_compile_definitions(${MICROPY_TARGET} PRIVATE + PICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1 + ) +elseif(PICO_RP2350) + target_compile_definitions(${MICROPY_TARGET} PRIVATE + PICO_EMBED_XIP_SETUP=1 # to put flash into continuous read mode + ) +endif() + target_link_libraries(${MICROPY_TARGET} ${PICO_SDK_COMPONENTS} ) @@ -525,7 +553,11 @@ endif() # a linker script modification) until we explicitly add macro calls around the function # defs to move them into RAM. if (PICO_ON_DEVICE AND NOT PICO_NO_FLASH AND NOT PICO_COPY_TO_RAM) - pico_set_linker_script(${MICROPY_TARGET} ${CMAKE_CURRENT_LIST_DIR}/memmap_mp_${PICO_PLATFORM}.ld) + 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) + endif() endif() pico_add_extra_outputs(${MICROPY_TARGET}) @@ -544,6 +576,9 @@ foreach(comp ${PICO_SDK_COMPONENTS}) micropy_gather_target_properties(${comp}_headers) endforeach() +set(MICROPY_CPP_FLAGS_EXTRA ${PICO_COMMON_LANG_FLAGS}) +separate_arguments(MICROPY_CPP_FLAGS_EXTRA) + # Include the main MicroPython cmake rules. include(${MICROPY_DIR}/py/mkrules.cmake) diff --git a/ports/rp2/boards/RPI_PICO/mpconfigboard.cmake b/ports/rp2/boards/RPI_PICO/mpconfigboard.cmake index 13269e81e52e5..386bd33285890 100644 --- a/ports/rp2/boards/RPI_PICO/mpconfigboard.cmake +++ b/ports/rp2/boards/RPI_PICO/mpconfigboard.cmake @@ -1,2 +1,3 @@ # cmake file for Raspberry Pi Pico set(PICO_BOARD "pico") +set(PICO_PLATFORM "rp2040") diff --git a/ports/rp2/fatfs_port.c b/ports/rp2/fatfs_port.c index 9706b6fe7dc70..1ce505dd69e3f 100644 --- a/ports/rp2/fatfs_port.c +++ b/ports/rp2/fatfs_port.c @@ -25,10 +25,13 @@ */ #include "lib/oofatfs/ff.h" -#include "hardware/rtc.h" +#include "pico/aon_timer.h" +#include "shared/timeutils/timeutils.h" MP_WEAK DWORD get_fattime(void) { - datetime_t t; - rtc_get_datetime(&t); - return ((t.year - 1980) << 25) | ((t.month) << 21) | ((t.day) << 16) | ((t.hour) << 11) | ((t.min) << 5) | (t.sec / 2); + struct timespec ts; + timeutils_struct_time_t tm; + aon_timer_get_time(&ts); + timeutils_seconds_since_epoch_to_struct_time(ts.tv_sec, &tm); + return ((tm.tm_year - 1980) << 25) | ((tm.tm_mon) << 21) | ((tm.tm_mday) << 16) | ((tm.tm_hour) << 11) | ((tm.tm_min) << 5) | (tm.tm_sec / 2); } diff --git a/ports/rp2/machine_rtc.c b/ports/rp2/machine_rtc.c index ce224be711b89..0d8fdef30f322 100644 --- a/ports/rp2/machine_rtc.c +++ b/ports/rp2/machine_rtc.c @@ -30,6 +30,8 @@ #include #include +#include "pico/aon_timer.h" + #include "py/nlr.h" #include "py/obj.h" #include "py/runtime.h" @@ -37,8 +39,6 @@ #include "py/mperrno.h" #include "extmod/modmachine.h" #include "shared/timeutils/timeutils.h" -#include "hardware/rtc.h" -#include "pico/util/datetime.h" typedef struct _machine_rtc_obj_t { mp_obj_base_t base; @@ -50,14 +50,12 @@ static const machine_rtc_obj_t machine_rtc_obj = {{&machine_rtc_type}}; static mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { // check arguments mp_arg_check_num(n_args, n_kw, 0, 0, false); - bool r = rtc_running(); + bool r = aon_timer_is_running(); if (!r) { - // This shouldn't happen as rtc_init() is already called in main so - // it's here just in case - rtc_init(); - datetime_t t = { .month = 1, .day = 1 }; - rtc_set_datetime(&t); + // This shouldn't happen. it's here just in case + struct timespec ts = { 0, 0 }; + aon_timer_start(&ts); mp_hal_time_ns_set_from_rtc(); } // return constant object @@ -66,47 +64,36 @@ static mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, s static mp_obj_t machine_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) { if (n_args == 1) { - bool ret; - datetime_t t; - - ret = rtc_get_datetime(&t); - if (!ret) { - mp_raise_OSError(MP_EIO); - } - + struct timespec ts; + timeutils_struct_time_t tm; + aon_timer_get_time(&ts); + timeutils_seconds_since_epoch_to_struct_time(ts.tv_sec, &tm); mp_obj_t tuple[8] = { - mp_obj_new_int(t.year), - mp_obj_new_int(t.month), - mp_obj_new_int(t.day), - mp_obj_new_int(t.dotw), - mp_obj_new_int(t.hour), - mp_obj_new_int(t.min), - mp_obj_new_int(t.sec), - mp_obj_new_int(0) + mp_obj_new_int(tm.tm_year), + mp_obj_new_int(tm.tm_mon), + mp_obj_new_int(tm.tm_mday), + mp_obj_new_int(tm.tm_wday), + mp_obj_new_int(tm.tm_hour), + mp_obj_new_int(tm.tm_min), + mp_obj_new_int(tm.tm_sec), + mp_obj_new_int(0), }; - return mp_obj_new_tuple(8, tuple); } else { mp_obj_t *items; - mp_obj_get_array_fixed_n(args[1], 8, &items); - - datetime_t t = { - .year = mp_obj_get_int(items[0]), - .month = mp_obj_get_int(items[1]), - .day = mp_obj_get_int(items[2]), - .hour = mp_obj_get_int(items[4]), - .min = mp_obj_get_int(items[5]), - .sec = mp_obj_get_int(items[6]), + timeutils_struct_time_t tm = { + .tm_year = mp_obj_get_int(items[0]), + .tm_mon = mp_obj_get_int(items[1]), + .tm_mday = mp_obj_get_int(items[2]), + .tm_hour = mp_obj_get_int(items[4]), + .tm_min = mp_obj_get_int(items[5]), + .tm_sec = mp_obj_get_int(items[6]), }; - // Deliberately ignore the weekday argument and compute the proper value - t.dotw = timeutils_calc_weekday(t.year, t.month, t.day); - - if (!rtc_set_datetime(&t)) { - mp_raise_OSError(MP_EINVAL); - } + struct timespec ts = { 0, 0 }; + ts.tv_sec = timeutils_seconds_since_epoch(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + aon_timer_set_time(&ts); mp_hal_time_ns_set_from_rtc(); - } return mp_const_none; } diff --git a/ports/rp2/main.c b/ports/rp2/main.c index 7fb4a648679e7..012e26f484fde 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -47,11 +47,9 @@ #include "genhdr/mpversion.h" #include "mp_usbd.h" -#include "RP2040.h" // cmsis, for PendSV_IRQn and SCB/SCB_SCR_SEVONPEND_Msk #include "pico/stdlib.h" #include "pico/binary_info.h" #include "pico/unique_id.h" -#include "hardware/rtc.h" #include "hardware/structs/rosc.h" #if MICROPY_PY_LWIP #include "lwip/init.h" @@ -60,6 +58,15 @@ #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 +#include "RP2350.h" // cmsis, for PendSV_IRQn and SCB/SCB_SCR_SEVONPEND_Msk +#else +#error Unknown processor +#endif +#include "pico/aon_timer.h" +#include "shared/timeutils/timeutils.h" extern uint8_t __StackTop, __StackBottom; extern uint8_t __GcHeapStart, __GcHeapEnd; @@ -106,17 +113,9 @@ int main(int argc, char **argv) { #endif // Start and initialise the RTC - datetime_t t = { - .year = 2021, - .month = 1, - .day = 1, - .dotw = 4, // 0 is Monday, so 4 is Friday - .hour = 0, - .min = 0, - .sec = 0, - }; - rtc_init(); - rtc_set_datetime(&t); + struct timespec ts = { 0, 0 }; + ts.tv_sec = timeutils_seconds_since_epoch(2021, 1, 1, 0, 0, 0); + aon_timer_start(&ts); mp_hal_time_ns_set_from_rtc(); // Initialise stack extents and GC heap. diff --git a/ports/rp2/mbedtls/mbedtls_port.c b/ports/rp2/mbedtls/mbedtls_port.c index 9b1e0d20e1700..521d815d2bedd 100644 --- a/ports/rp2/mbedtls/mbedtls_port.c +++ b/ports/rp2/mbedtls/mbedtls_port.c @@ -29,9 +29,9 @@ #include "mbedtls_config_port.h" -#include "hardware/rtc.h" #include "shared/timeutils/timeutils.h" #include "mbedtls/platform_time.h" +#include "pico/aon_timer.h" extern uint8_t rosc_random_u8(size_t cycles); @@ -44,9 +44,9 @@ int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t } time_t rp2_rtctime_seconds(time_t *timer) { - datetime_t t; - rtc_get_datetime(&t); - return timeutils_seconds_since_epoch(t.year, t.month, t.day, t.hour, t.min, t.sec); + struct timespec ts; + aon_timer_get_time(&ts); + return ts.tv_sec; } mbedtls_ms_time_t mbedtls_ms_time(void) { diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c index 0acae25499996..798078faf6527 100644 --- a/ports/rp2/modmachine.c +++ b/ports/rp2/modmachine.c @@ -41,6 +41,7 @@ #include "pico/bootrom.h" #include "pico/stdlib.h" #include "pico/unique_id.h" +#include "pico/runtime_init.h" #if MICROPY_PY_NETWORK_CYW43 #include "lib/cyw43-driver/src/cyw43.h" #endif diff --git a/ports/rp2/modtime.c b/ports/rp2/modtime.c index 21e5cb459b283..7d6dd8fd97112 100644 --- a/ports/rp2/modtime.c +++ b/ports/rp2/modtime.c @@ -26,28 +26,30 @@ #include "py/obj.h" #include "shared/timeutils/timeutils.h" -#include "hardware/rtc.h" +#include "pico/aon_timer.h" // Return the localtime as an 8-tuple. static mp_obj_t mp_time_localtime_get(void) { - datetime_t t; - rtc_get_datetime(&t); + struct timespec ts; + aon_timer_get_time(&ts); + timeutils_struct_time_t tm; + timeutils_seconds_since_epoch_to_struct_time(ts.tv_sec, &tm); mp_obj_t tuple[8] = { - mp_obj_new_int(t.year), - mp_obj_new_int(t.month), - mp_obj_new_int(t.day), - mp_obj_new_int(t.hour), - mp_obj_new_int(t.min), - mp_obj_new_int(t.sec), - mp_obj_new_int(t.dotw), - mp_obj_new_int(timeutils_year_day(t.year, t.month, t.day)), + mp_obj_new_int(tm.tm_year), + mp_obj_new_int(tm.tm_mon), + mp_obj_new_int(tm.tm_mday), + mp_obj_new_int(tm.tm_hour), + mp_obj_new_int(tm.tm_min), + mp_obj_new_int(tm.tm_sec), + mp_obj_new_int(tm.tm_wday), + mp_obj_new_int(tm.tm_yday), }; return mp_obj_new_tuple(8, tuple); } // Return the number of seconds since the Epoch. static mp_obj_t mp_time_time_get(void) { - datetime_t t; - rtc_get_datetime(&t); - return mp_obj_new_int_from_ull(timeutils_seconds_since_epoch(t.year, t.month, t.day, t.hour, t.min, t.sec)); + struct timespec ts; + aon_timer_get_time(&ts); + return mp_obj_new_int_from_ull(ts.tv_sec); } diff --git a/ports/rp2/mphalport.c b/ports/rp2/mphalport.c index aa5415d6c842d..3fcc011b62676 100644 --- a/ports/rp2/mphalport.c +++ b/ports/rp2/mphalport.c @@ -37,16 +37,18 @@ #include "tusb.h" #include "uart.h" #include "hardware/irq.h" -#include "hardware/rtc.h" #include "pico/unique_id.h" +#include "pico/aon_timer.h" #if MICROPY_PY_NETWORK_CYW43 #include "lib/cyw43-driver/src/cyw43.h" #endif +#if PICO_RP2040 // This needs to be added to the result of time_us_64() to get the number of // microseconds since the Epoch. static uint64_t time_us_64_offset_from_epoch; +#endif #if MICROPY_HW_ENABLE_UART_REPL || MICROPY_HW_USB_CDC @@ -145,27 +147,35 @@ void mp_hal_delay_ms(mp_uint_t ms) { } void mp_hal_time_ns_set_from_rtc(void) { + #if PICO_RP2040 // Outstanding RTC register writes need at least two RTC clock cycles to // update. (See RP2040 datasheet section 4.8.4 "Reference clock"). mp_hal_delay_us(44); // Sample RTC and time_us_64() as close together as possible, so the offset // calculated for the latter can be as accurate as possible. - datetime_t t; - rtc_get_datetime(&t); + struct timespec ts; + aon_timer_get_time(&ts); uint64_t us = time_us_64(); - // Calculate the difference between the RTC Epoch seconds and time_us_64(). - uint64_t s = timeutils_seconds_since_epoch(t.year, t.month, t.day, t.hour, t.min, t.sec); - time_us_64_offset_from_epoch = (uint64_t)s * 1000000ULL - us; + // Calculate the difference between the RTC Epoch and time_us_64(). + time_us_64_offset_from_epoch = ((uint64_t)ts.tv_sec * 1000000ULL) + ((uint64_t)ts.tv_nsec / 1000ULL) - us; + #endif } uint64_t mp_hal_time_ns(void) { - // The RTC only has seconds resolution, so instead use time_us_64() to get a more + #if PICO_RP2040 + // The RTC probably has limited resolution, so instead use time_us_64() to get a more // precise measure of Epoch time. Both these "clocks" are clocked from the same // source so they remain synchronised, and only differ by a fixed offset (calculated // in mp_hal_time_ns_set_from_rtc). return (time_us_64_offset_from_epoch + time_us_64()) * 1000ULL; + #else + // aon timer has ms resolution + struct timespec ts; + aon_timer_get_time(&ts); + return ((uint64_t)ts.tv_sec * 1000000000ULL) + (uint64_t)ts.tv_nsec; + #endif } // Generate a random locally administered MAC address (LAA) diff --git a/ports/rp2/mpnetworkport.c b/ports/rp2/mpnetworkport.c index e58adb3ba3595..fcc60b3fe5796 100644 --- a/ports/rp2/mpnetworkport.c +++ b/ports/rp2/mpnetworkport.c @@ -43,7 +43,14 @@ static soft_timer_entry_t mp_network_soft_timer; #include "lib/cyw43-driver/src/cyw43.h" #include "lib/cyw43-driver/src/cyw43_stats.h" #include "hardware/irq.h" + +#if PICO_RP2040 #include "RP2040.h" // cmsis, for NVIC_SetPriority and PendSV_IRQn +#elif PICO_RP2350 +#include "RP2350.h" // cmsis, for NVIC_SetPriority and PendSV_IRQn +#else +#error Unknown processor +#endif #define CYW43_IRQ_LEVEL GPIO_IRQ_LEVEL_HIGH #define CYW43_SHARED_IRQ_HANDLER_PRIORITY PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY diff --git a/ports/rp2/pendsv.c b/ports/rp2/pendsv.c index 6cfe624c3037f..2f06871b3ac5b 100644 --- a/ports/rp2/pendsv.c +++ b/ports/rp2/pendsv.c @@ -28,7 +28,14 @@ #include "py/mpconfig.h" #include "mutex_extra.h" #include "pendsv.h" + +#if PICO_RP2040 #include "RP2040.h" +#elif PICO_RP2350 +#include "RP2350.h" +#else +#error Unknown chip +#endif #if MICROPY_PY_NETWORK_CYW43 #include "lib/cyw43-driver/src/cyw43_stats.h" From 6d39418f699edc6532d84bf1be53fe8d00d92752 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 1 Jul 2024 15:29:57 +0100 Subject: [PATCH 08/31] rp2: Add support for 48-pin RP2350 variant. Update NUM_GPIOS to match NUM_BANK0_GPIOS, and increase bit-width of variables that store pin numbers. Signed-off-by: Phil Howard --- ports/rp2/boards/make-pins.py | 2 +- ports/rp2/machine_pin.c | 2 +- ports/rp2/machine_pin.h | 2 +- ports/rp2/mphalport.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ports/rp2/boards/make-pins.py b/ports/rp2/boards/make-pins.py index 3acf5b9516997..f4ce74e5a42b3 100755 --- a/ports/rp2/boards/make-pins.py +++ b/ports/rp2/boards/make-pins.py @@ -9,7 +9,7 @@ import boardgen # This is NUM_BANK0_GPIOS. Pin indices are 0 to 29 (inclusive). -NUM_GPIOS = 30 +NUM_GPIOS = 48 # Up to 32 additional extended pins (e.g. via the wifi chip or io expanders). NUM_EXT_GPIOS = 32 diff --git a/ports/rp2/machine_pin.c b/ports/rp2/machine_pin.c index de217785690c2..e1a545a09234c 100644 --- a/ports/rp2/machine_pin.c +++ b/ports/rp2/machine_pin.c @@ -89,7 +89,7 @@ static const mp_irq_methods_t machine_pin_irq_methods; extern const machine_pin_obj_t machine_pin_obj_table[NUM_BANK0_GPIOS]; // Mask with "1" indicating that the corresponding pin is in simulated open-drain mode. -uint32_t machine_pin_open_drain_mask; +uint64_t machine_pin_open_drain_mask; #if MICROPY_HW_PIN_EXT_COUNT static inline bool is_ext_pin(__unused const machine_pin_obj_t *self) { diff --git a/ports/rp2/machine_pin.h b/ports/rp2/machine_pin.h index b3349188e8ba1..196132019e609 100644 --- a/ports/rp2/machine_pin.h +++ b/ports/rp2/machine_pin.h @@ -49,7 +49,7 @@ typedef struct _machine_pin_af_obj_t { typedef struct _machine_pin_obj_t { mp_obj_base_t base; qstr name; - uint8_t id : 5; + uint8_t id : 6; #if MICROPY_HW_PIN_EXT_COUNT uint8_t is_ext : 1; uint8_t is_output : 1; diff --git a/ports/rp2/mphalport.h b/ports/rp2/mphalport.h index 09ad54dd1eb78..1d260c8bd8b61 100644 --- a/ports/rp2/mphalport.h +++ b/ports/rp2/mphalport.h @@ -119,7 +119,7 @@ static inline mp_uint_t mp_hal_get_cpu_freq(void) { #define MP_HAL_PIN_PULL_UP (1) #define MP_HAL_PIN_PULL_DOWN (2) -extern uint32_t machine_pin_open_drain_mask; +extern uint64_t machine_pin_open_drain_mask; mp_hal_pin_obj_t mp_hal_get_pin_obj(mp_obj_t pin_in); From a3d1c59ca3db93278624055074af081f8cf747e1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 2 Sep 2024 16:29:49 +1000 Subject: [PATCH 09/31] rp2/machine_pin: Move decl of machine_pin_obj_table to public header. So other code can include `machine_pin.h` and use the pin name macros such as `pin_GPIO0`. Signed-off-by: Damien George --- ports/rp2/machine_pin.c | 1 - ports/rp2/machine_pin.h | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/rp2/machine_pin.c b/ports/rp2/machine_pin.c index e1a545a09234c..79f91232f77a6 100644 --- a/ports/rp2/machine_pin.c +++ b/ports/rp2/machine_pin.c @@ -86,7 +86,6 @@ typedef struct _machine_pin_irq_obj_t { } machine_pin_irq_obj_t; static const mp_irq_methods_t machine_pin_irq_methods; -extern const machine_pin_obj_t machine_pin_obj_table[NUM_BANK0_GPIOS]; // Mask with "1" indicating that the corresponding pin is in simulated open-drain mode. uint64_t machine_pin_open_drain_mask; diff --git a/ports/rp2/machine_pin.h b/ports/rp2/machine_pin.h index 196132019e609..2d85bdcadc165 100644 --- a/ports/rp2/machine_pin.h +++ b/ports/rp2/machine_pin.h @@ -64,6 +64,8 @@ extern const mp_obj_type_t machine_pin_af_type; // Include all of the individual pin objects #include "genhdr/pins.h" +extern const machine_pin_obj_t machine_pin_obj_table[NUM_BANK0_GPIOS]; + extern const mp_obj_type_t pin_cpu_pins_obj_type; extern const mp_obj_dict_t machine_pin_cpu_pins_locals_dict; From e6093c0fbdc7e9da5e044aaa4442bb125939aef9 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 2 Jul 2024 17:39:02 +0100 Subject: [PATCH 10/31] rp2/rp2_pio: Add support for RP2350A/B variants in PIO interface. Add support for 32 and 48 pin variants of RP2350. Add new `PIO.gpio_base()` method, mirroring the Pico SDK. Signed-off-by: Phil Howard Signed-off-by: Damien George --- docs/library/rp2.PIO.rst | 11 +++++ ports/rp2/rp2_pio.c | 92 ++++++++++++++++++++++++++++++++++------ 2 files changed, 90 insertions(+), 13 deletions(-) diff --git a/docs/library/rp2.PIO.rst b/docs/library/rp2.PIO.rst index e0675af1e9a2c..f922456c8c483 100644 --- a/docs/library/rp2.PIO.rst +++ b/docs/library/rp2.PIO.rst @@ -27,6 +27,17 @@ Constructors Methods ------- +.. method:: PIO.gpio_base([base]) + + Query and optionally set the current GPIO base for this PIO instance. + + If an argument is given then it must be a pin (or integer corresponding to a pin + number), restricted to either GPIO0 or GPIO16. The GPIO base will then be set to + that pin. Setting the GPIO base must be done before any programs are added or state + machines created. + + Returns the current GPIO base pin. + .. method:: PIO.add_program(program) Add the *program* to the instruction memory of this PIO instance. diff --git a/ports/rp2/rp2_pio.c b/ports/rp2/rp2_pio.c index 0ca91656f84ef..56c576581e0df 100644 --- a/ports/rp2/rp2_pio.c +++ b/ports/rp2/rp2_pio.c @@ -31,6 +31,7 @@ #include "py/mperrno.h" #include "py/mphal.h" #include "shared/runtime/mpirq.h" +#include "machine_pin.h" #include "modrp2.h" #include "hardware/clocks.h" @@ -54,7 +55,7 @@ typedef struct _rp2_state_machine_obj_t { PIO pio; uint8_t irq; uint8_t sm; // 0-3 - uint8_t id; // 0-7 + uint8_t id; // 0-7 on RP2040, or 0-11 on RP2350 } rp2_state_machine_obj_t; typedef struct _rp2_state_machine_irq_obj_t { @@ -63,11 +64,11 @@ typedef struct _rp2_state_machine_irq_obj_t { uint8_t trigger; } rp2_state_machine_irq_obj_t; -static const rp2_state_machine_obj_t rp2_state_machine_obj[8]; -static uint8_t rp2_state_machine_initial_pc[8]; +static const rp2_state_machine_obj_t rp2_state_machine_obj[NUM_PIOS * 4]; +static uint8_t rp2_state_machine_initial_pc[NUM_PIOS * 4]; // These masks keep track of PIO instruction memory used by this module. -static uint32_t rp2_pio_instruction_memory_usage_mask[2]; +static uint32_t rp2_pio_instruction_memory_usage_mask[NUM_PIOS]; static const rp2_state_machine_obj_t *rp2_state_machine_get_object(mp_int_t sm_id); static void rp2_state_machine_reset_all(void); @@ -104,8 +105,19 @@ static void pio1_irq0(void) { pio_irq0(pio1); } +#if NUM_PIOS >= 3 +static void pio2_irq0(void) { + pio_irq0(pio2); +} +#endif + // Returns the correct irq0 handler wrapper for a given pio static inline irq_handler_t rp2_pio_get_irq_handler(PIO pio) { + #if NUM_PIOS >= 3 + if (pio == pio2) { + return pio2_irq0; + } + #endif return pio == pio0 ? pio0_irq0 : pio1_irq0; } @@ -172,6 +184,12 @@ void rp2_pio_deinit(void) { irq_set_enabled(PIO1_IRQ_0, false); irq_remove_handler(PIO1_IRQ_0, pio1_irq0); } + #if NUM_PIOS >= 3 + if (irq_get_exclusive_handler(PIO2_IRQ_0) == pio2_irq0) { + irq_set_enabled(PIO2_IRQ_0, false); + irq_remove_handler(PIO2_IRQ_0, pio2_irq0); + } + #endif rp2_state_machine_reset_all(); @@ -180,6 +198,9 @@ void rp2_pio_deinit(void) { // and their PIO programs should remain intact. rp2_pio_remove_all_managed_programs(pio0); rp2_pio_remove_all_managed_programs(pio1); + #if NUM_PIOS >= 3 + rp2_pio_remove_all_managed_programs(pio2); + #endif } /******************************************************************************/ @@ -212,7 +233,7 @@ static void asm_pio_override_shiftctrl(mp_obj_t arg, uint32_t bits, uint32_t lsb } } -static void asm_pio_get_pins(const char *type, mp_obj_t prog_pins, mp_obj_t arg_base, asm_pio_config_t *config) { +static void asm_pio_get_pins(PIO pio, const char *type, mp_obj_t prog_pins, mp_obj_t arg_base, asm_pio_config_t *config) { if (prog_pins != mp_const_none) { // The PIO program specified pins for initialisation on out/set/sideset. if (mp_obj_is_integer(prog_pins)) { @@ -238,13 +259,21 @@ static void asm_pio_get_pins(const char *type, mp_obj_t prog_pins, mp_obj_t arg_ if (arg_base != mp_const_none) { // The instantiation of the PIO program specified a base pin. config->base = mp_hal_get_pin_obj(arg_base); + + #if PICO_PIO_USE_GPIO_BASE + // Check the base is within range of the configured gpio_base. + uint gpio_base = pio_get_gpio_base(pio); + if ((gpio_base == 0 && config->base >= 32) || (gpio_base == 16 && config->base < 16)) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("%s_base not within gpio_base range"), type); + } + #endif } } static void asm_pio_init_gpio(PIO pio, uint32_t sm, asm_pio_config_t *config) { - uint32_t pinmask = ((1 << config->count) - 1) << config->base; - pio_sm_set_pins_with_mask(pio, sm, config->pinvals << config->base, pinmask); - pio_sm_set_pindirs_with_mask(pio, sm, config->pindirs << config->base, pinmask); + uint32_t pinmask = ((1 << config->count) - 1) << (config->base - pio_get_gpio_base(pio)); + pio_sm_set_pins_with_mask(pio, sm, config->pinvals << (config->base - pio_get_gpio_base(pio)), pinmask); + pio_sm_set_pindirs_with_mask(pio, sm, config->pindirs << (config->base - pio_get_gpio_base(pio)), pinmask); for (size_t i = 0; i < config->count; ++i) { gpio_set_function(config->base + i, GPIO_FUNC_PIO0 + pio_get_index(pio)); } @@ -258,6 +287,9 @@ static const mp_irq_methods_t rp2_pio_irq_methods; static rp2_pio_obj_t rp2_pio_obj[] = { { { &rp2_pio_type }, pio0, PIO0_IRQ_0 }, { { &rp2_pio_type }, pio1, PIO1_IRQ_0 }, + #if NUM_PIOS >= 3 + { { &rp2_pio_type }, pio2, PIO2_IRQ_0 }, + #endif }; static void rp2_pio_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { @@ -357,6 +389,31 @@ static mp_obj_t rp2_pio_state_machine(size_t n_args, const mp_obj_t *pos_args, m } MP_DEFINE_CONST_FUN_OBJ_KW(rp2_pio_state_machine_obj, 2, rp2_pio_state_machine); +#if PICO_PIO_USE_GPIO_BASE +// PIO.gpio_base([base]) +static mp_obj_t rp2_pio_gpio_base(size_t n_args, const mp_obj_t *args) { + rp2_pio_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + if (n_args > 1) { + // Set gpio_base value. + uint gpio_base = mp_hal_get_pin_obj(args[1]); + + // Must be 0 for GPIOs 0 to 31 inclusive, or 16 for GPIOs 16 to 48 inclusive. + if (!(gpio_base == 0 || gpio_base == 16)) { + mp_raise_ValueError("invalid GPIO base"); + } + + if (pio_set_gpio_base(self->pio, gpio_base) != PICO_OK) { + mp_raise_OSError(MP_EINVAL); + } + } + + // Return current gpio_base value. + return pio_get_gpio_base(self->pio) == 0 ? (mp_obj_t)pin_GPIO0 : (mp_obj_t)pin_GPIO16; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rp2_pio_gpio_base_obj, 1, 2, rp2_pio_gpio_base); +#endif + // PIO.irq(handler=None, trigger=IRQ_SM0|IRQ_SM1|IRQ_SM2|IRQ_SM3, hard=False) static mp_obj_t rp2_pio_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_handler, ARG_trigger, ARG_hard }; @@ -410,6 +467,9 @@ static mp_obj_t rp2_pio_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k static MP_DEFINE_CONST_FUN_OBJ_KW(rp2_pio_irq_obj, 1, rp2_pio_irq); static const mp_rom_map_elem_t rp2_pio_locals_dict_table[] = { + #if PICO_PIO_USE_GPIO_BASE + { MP_ROM_QSTR(MP_QSTR_gpio_base), MP_ROM_PTR(&rp2_pio_gpio_base_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_add_program), MP_ROM_PTR(&rp2_pio_add_program_obj) }, { MP_ROM_QSTR(MP_QSTR_remove_program), MP_ROM_PTR(&rp2_pio_remove_program_obj) }, { MP_ROM_QSTR(MP_QSTR_state_machine), MP_ROM_PTR(&rp2_pio_state_machine_obj) }, @@ -486,6 +546,12 @@ static const rp2_state_machine_obj_t rp2_state_machine_obj[] = { { { &rp2_state_machine_type }, pio1, PIO1_IRQ_0, 1, 5 }, { { &rp2_state_machine_type }, pio1, PIO1_IRQ_0, 2, 6 }, { { &rp2_state_machine_type }, pio1, PIO1_IRQ_0, 3, 7 }, + #if NUM_PIOS >= 3 + { { &rp2_state_machine_type }, pio2, PIO2_IRQ_0, 0, 8 }, + { { &rp2_state_machine_type }, pio2, PIO2_IRQ_0, 1, 9 }, + { { &rp2_state_machine_type }, pio2, PIO2_IRQ_0, 2, 10 }, + { { &rp2_state_machine_type }, pio2, PIO2_IRQ_0, 3, 11 }, + #endif }; static const rp2_state_machine_obj_t *rp2_state_machine_get_object(mp_int_t sm_id) { @@ -604,14 +670,14 @@ static mp_obj_t rp2_state_machine_init_helper(const rp2_state_machine_obj_t *sel // Configure out pins, if needed. asm_pio_config_t out_config = ASM_PIO_CONFIG_DEFAULT; - asm_pio_get_pins("out", prog[PROG_OUT_PINS], args[ARG_out_base].u_obj, &out_config); + asm_pio_get_pins(self->pio, "out", prog[PROG_OUT_PINS], args[ARG_out_base].u_obj, &out_config); if (out_config.base >= 0) { sm_config_set_out_pins(&config, out_config.base, out_config.count); } // Configure set pin, if needed. asm_pio_config_t set_config = ASM_PIO_CONFIG_DEFAULT; - asm_pio_get_pins("set", prog[PROG_SET_PINS], args[ARG_set_base].u_obj, &set_config); + asm_pio_get_pins(self->pio, "set", prog[PROG_SET_PINS], args[ARG_set_base].u_obj, &set_config); if (set_config.base >= 0) { sm_config_set_set_pins(&config, set_config.base, set_config.count); } @@ -623,7 +689,7 @@ static mp_obj_t rp2_state_machine_init_helper(const rp2_state_machine_obj_t *sel // Configure sideset pin, if needed. asm_pio_config_t sideset_config = ASM_PIO_CONFIG_DEFAULT; - asm_pio_get_pins("sideset", prog[PROG_SIDESET_PINS], args[ARG_sideset_base].u_obj, &sideset_config); + asm_pio_get_pins(self->pio, "sideset", prog[PROG_SIDESET_PINS], args[ARG_sideset_base].u_obj, &sideset_config); if (sideset_config.base >= 0) { uint32_t count = sideset_config.count; if (config.execctrl & (1 << PIO_SM0_EXECCTRL_SIDE_EN_LSB)) { @@ -951,5 +1017,5 @@ static const mp_irq_methods_t rp2_state_machine_irq_methods = { .info = rp2_state_machine_irq_info, }; -MP_REGISTER_ROOT_POINTER(void *rp2_pio_irq_obj[2]); -MP_REGISTER_ROOT_POINTER(void *rp2_state_machine_irq_obj[8]); +MP_REGISTER_ROOT_POINTER(void *rp2_pio_irq_obj[NUM_PIOS]); +MP_REGISTER_ROOT_POINTER(void *rp2_state_machine_irq_obj[NUM_PIOS * 4]); From 4af09de19cbcf8acef549d094eab846b87ea46ba Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Mon, 8 Jul 2024 15:57:13 +0100 Subject: [PATCH 11/31] rp2/boards/make-pins.py: Pass num-gpios/num-ext-gpios into make-pins. NUM_GPIOS amd NUM_EXT_GPIOS are currently hardcoded in make-pins.py, which makes it difficult to support SoCs with different pin count. This commit generalises make-pins.py by passing in the pin count in via the new arguments `--num-gpios` and `--num-ext-gpios`. These default to the current values supported by Pico, namely 30/10. This can be changed with PICO_NUM_GPIOS and PICO_NUM_EXT_GPIOS in `mpconfigboard.cmake`. Signed-off-by: Damien George --- ports/rp2/CMakeLists.txt | 10 +++++++++- ports/rp2/boards/make-pins.py | 35 +++++++++++++++++++++++++++-------- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 6f66181546271..0d5b10f337380 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -588,6 +588,14 @@ set(GEN_PINS_MKPINS "${MICROPY_PORT_DIR}/boards/make-pins.py") set(GEN_PINS_SRC "${CMAKE_BINARY_DIR}/pins_${MICROPY_BOARD}.c") set(GEN_PINS_HDR "${MICROPY_GENHDR_DIR}/pins.h") +if(NOT PICO_NUM_GPIOS) + set(PICO_NUM_GPIOS 30) +endif() + +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") set(GEN_PINS_CSV_ARG --board-csv "${GEN_PINS_BOARD_CSV}") @@ -600,7 +608,7 @@ target_sources(${MICROPY_TARGET} PRIVATE # Generate pins add_custom_command( OUTPUT ${GEN_PINS_HDR} ${GEN_PINS_SRC} - COMMAND ${Python3_EXECUTABLE} ${GEN_PINS_MKPINS} ${GEN_PINS_CSV_ARG} --af-csv ${GEN_PINS_AF_CSV} --prefix ${GEN_PINS_PREFIX} --output-source ${GEN_PINS_SRC} --output-header ${GEN_PINS_HDR} + COMMAND ${Python3_EXECUTABLE} ${GEN_PINS_MKPINS} ${GEN_PINS_CSV_ARG} --af-csv ${GEN_PINS_AF_CSV} --prefix ${GEN_PINS_PREFIX} --output-source ${GEN_PINS_SRC} --num-gpios ${PICO_NUM_GPIOS} --num-ext-gpios ${PICO_NUM_EXT_GPIOS} --output-header ${GEN_PINS_HDR} DEPENDS ${GEN_PINS_AF_CSV} ${GEN_PINS_BOARD_CSV} diff --git a/ports/rp2/boards/make-pins.py b/ports/rp2/boards/make-pins.py index f4ce74e5a42b3..1da2edb7cacd6 100755 --- a/ports/rp2/boards/make-pins.py +++ b/ports/rp2/boards/make-pins.py @@ -9,9 +9,9 @@ import boardgen # This is NUM_BANK0_GPIOS. Pin indices are 0 to 29 (inclusive). -NUM_GPIOS = 48 +NUM_GPIOS = None # Up to 32 additional extended pins (e.g. via the wifi chip or io expanders). -NUM_EXT_GPIOS = 32 +NUM_EXT_GPIOS = None class Rp2Pin(boardgen.Pin): @@ -108,12 +108,6 @@ def __init__(self): enable_af=True, ) - # Pre-define the pins (i.e. don't require them to be listed in pins.csv). - for i in range(NUM_GPIOS): - self.add_cpu_pin("GPIO{}".format(i)) - for i in range(NUM_EXT_GPIOS): - self.add_cpu_pin("EXT_GPIO{}".format(i)) - # Provided by pico-sdk. def cpu_table_size(self): return "NUM_BANK0_GPIOS" @@ -128,6 +122,31 @@ def print_source(self, out_source): super().print_source(out_source) self.print_cpu_locals_dict(out_source) + def extra_args(self, parser): + parser.add_argument("--num-gpios", type=int) + parser.add_argument("--num-ext-gpios", type=int) + + def load_inputs(self, out_source): + global NUM_GPIOS + global NUM_EXT_GPIOS + + # Needed by validate_cpu_pin_name + NUM_GPIOS = self.args.num_gpios + NUM_EXT_GPIOS = self.args.num_ext_gpios + + if NUM_GPIOS is None: + raise boardgen.PinGeneratorError("Please pass num-gpios") + + if NUM_EXT_GPIOS is None: + NUM_EXT_GPIOS = 0 + # Pre-define the pins (i.e. don't require them to be listed in pins.csv). + for i in range(NUM_GPIOS): + self.add_cpu_pin("GPIO{}".format(i)) + for i in range(NUM_EXT_GPIOS): + self.add_cpu_pin("EXT_GPIO{}".format(i)) + + super().load_inputs(out_source) + if __name__ == "__main__": Rp2PinGenerator().main() From 733052f6b9a5d3e470ede99c04a4f440e789ebac Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 10 Jul 2024 12:44:59 +0100 Subject: [PATCH 12/31] rp2/machine_pin: Use 64-bit gpio functions to allow gpios >=32 to work. Signed-off-by: Damien George --- ports/rp2/machine_pin.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ports/rp2/machine_pin.c b/ports/rp2/machine_pin.c index 79f91232f77a6..8fdde114bd311 100644 --- a/ports/rp2/machine_pin.c +++ b/ports/rp2/machine_pin.c @@ -297,7 +297,7 @@ static mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_ mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("invalid pin af: %d"), af); } gpio_set_function(self->id, af); - machine_pin_open_drain_mask &= ~(1 << self->id); + machine_pin_open_drain_mask &= ~(1ULL << self->id); } } @@ -379,7 +379,7 @@ static mp_obj_t machine_pin_low(mp_obj_t self_in) { } else if (GPIO_IS_OPEN_DRAIN(self->id)) { gpio_set_dir(self->id, GPIO_OUT); } else { - gpio_clr_mask(1u << self->id); + gpio_clr_mask64(1ULL << self->id); } return mp_const_none; } @@ -395,7 +395,7 @@ static mp_obj_t machine_pin_high(mp_obj_t self_in) { } else if (GPIO_IS_OPEN_DRAIN(self->id)) { gpio_set_dir(self->id, GPIO_IN); } else { - gpio_set_mask(1u << self->id); + gpio_set_mask64(1ULL << self->id); } return mp_const_none; } @@ -416,7 +416,7 @@ static mp_obj_t machine_pin_toggle(mp_obj_t self_in) { gpio_set_dir(self->id, GPIO_OUT); } } else { - gpio_xor_mask(1u << self->id); + gpio_xor_mask64(1ULL << self->id); } return mp_const_none; } From 57f4cabff93a11e27c61ecb181664e0d70c7ced1 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 8 Jul 2024 16:22:56 +0100 Subject: [PATCH 13/31] rp2/machine_pin: Generalise gpio_irq handler for pins >32. Fix the gpio_irq function so that it looks at all six iobank0_hw->intr[n] registers, for up to 48 IOs. Signed-off-by: Phil Howard --- ports/rp2/machine_pin.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/rp2/machine_pin.c b/ports/rp2/machine_pin.c index 8fdde114bd311..8ba0b44a684f7 100644 --- a/ports/rp2/machine_pin.c +++ b/ports/rp2/machine_pin.c @@ -86,6 +86,7 @@ typedef struct _machine_pin_irq_obj_t { } machine_pin_irq_obj_t; static const mp_irq_methods_t machine_pin_irq_methods; +static const int num_intr_regs = sizeof(iobank0_hw->intr) / sizeof(iobank0_hw->intr[0]); // Mask with "1" indicating that the corresponding pin is in simulated open-drain mode. uint64_t machine_pin_open_drain_mask; @@ -99,7 +100,7 @@ static inline bool is_ext_pin(__unused const machine_pin_obj_t *self) { #endif static void gpio_irq(void) { - for (int i = 0; i < 4; ++i) { + for (int i = 0; i < num_intr_regs; ++i) { uint32_t intr = iobank0_hw->intr[i]; if (intr) { for (int j = 0; j < 8; ++j) { From d0bc42796b1fce183f2bb5ddfdde05bd7c9f6b18 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 10 Jul 2024 16:01:16 +0100 Subject: [PATCH 14/31] rp2/clocks_extra: Update runtime_clocks_init based on new pico-sdk. Signed-off-by: Damien George --- ports/rp2/CMakeLists.txt | 3 +- ports/rp2/clocks_extra.c | 68 +++++++++++++++++++++++++++++++--------- ports/rp2/clocks_extra.h | 2 +- ports/rp2/modmachine.c | 2 +- 4 files changed, 58 insertions(+), 17 deletions(-) diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 0d5b10f337380..40672a8b31655 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -181,6 +181,7 @@ set(PICO_SDK_COMPONENTS cmsis_core hardware_adc hardware_base + hardware_boot_lock hardware_clocks hardware_dma hardware_flash @@ -487,7 +488,7 @@ target_compile_options(${MICROPY_TARGET} PRIVATE target_link_options(${MICROPY_TARGET} PRIVATE -Wl,--defsym=__micropy_c_heap_size__=${MICROPY_C_HEAP_SIZE} -Wl,--wrap=dcd_event_handler - -Wl,--wrap=clocks_init + -Wl,--wrap=runtime_init_clocks ) # Apply optimisations to performance-critical source code. diff --git a/ports/rp2/clocks_extra.c b/ports/rp2/clocks_extra.c index e2c97962cb43d..73def24b80455 100644 --- a/ports/rp2/clocks_extra.c +++ b/ports/rp2/clocks_extra.c @@ -13,22 +13,36 @@ #include "hardware/xosc.h" #include "hardware/irq.h" #include "hardware/gpio.h" +#include "hardware/ticks.h" +#if PICO_RP2040 +// The RTC clock frequency is 48MHz divided by power of 2 (to ensure an integer +// division ratio will be used in the clocks block). A divisor of 1024 generates +// an RTC clock tick of 46875Hz. This frequency is relatively close to the +// customary 32 or 32.768kHz 'slow clock' crystals and provides good timing resolution. #define RTC_CLOCK_FREQ_HZ (USB_CLK_KHZ * KHZ / 1024) +#endif + +static void start_all_ticks(void) { + uint32_t cycles = clock_get_hz(clk_ref) / MHZ; + // Note RP2040 has a single tick generator in the watchdog which serves + // watchdog, system timer and M0+ SysTick; The tick generator is clocked from clk_ref + // but is now adapted by the hardware_ticks library for compatibility with RP2350 + // npte: hardware_ticks library now provides an adapter for RP2040 + + for (int i = 0; i < (int)TICK_COUNT; ++i) { + tick_start((tick_gen_num_t)i, cycles); + } +} // Wrap the SDK's clocks_init() function to save code size -void __wrap_clocks_init(void) { - clocks_init_optional_usb(true); +void __wrap_runtime_init_clocks(void) { + runtime_init_clocks_optional_usb(true); } -// Copy of clocks_init() from pico-sdk, with USB +// Copy of runtime_init_clocks() from pico-sdk, with USB // PLL and clock init made optional (for light sleep wakeup). -void clocks_init_optional_usb(bool init_usb) { - // Start tick in watchdog, the argument is in 'cycles per microsecond' i.e. MHz - watchdog_start_tick(XOSC_KHZ / KHZ); - - // Modification: removed FPGA check here - +void runtime_init_clocks_optional_usb(bool init_usb) { // Disable resus that may be enabled from previous software clocks_hw->resus.ctrl = 0; @@ -46,14 +60,26 @@ void clocks_init_optional_usb(bool init_usb) { } /// \tag::pll_init[] - pll_init(pll_sys, PLL_COMMON_REFDIV, PLL_SYS_VCO_FREQ_KHZ * KHZ, PLL_SYS_POSTDIV1, PLL_SYS_POSTDIV2); + pll_init(pll_sys, PLL_COMMON_REFDIV, PLL_SYS_VCO_FREQ_HZ, PLL_SYS_POSTDIV1, PLL_SYS_POSTDIV2); if (init_usb) { - pll_init(pll_usb, PLL_COMMON_REFDIV, PLL_USB_VCO_FREQ_KHZ * KHZ, PLL_USB_POSTDIV1, PLL_USB_POSTDIV2); + pll_init(pll_usb, PLL_COMMON_REFDIV, PLL_USB_VCO_FREQ_HZ, PLL_USB_POSTDIV1, PLL_USB_POSTDIV2); } /// \end::pll_init[] // Configure clocks - // CLK_REF = XOSC (usually) 12MHz / 1 = 12MHz + + // todo amy, what is this N1,2,4 meant to mean? + // RP2040 CLK_REF = XOSC (usually) 12MHz / 1 = 12MHz + // RP2350 CLK_REF = XOSC (XOSC_MHZ) / N (1,2,4) = 12MHz + + // clk_ref aux select is 0 because: + // + // - RP2040: no aux mux on clk_ref, so this field is don't-care. + // + // - RP2350: there is an aux mux, but we are selecting one of the + // non-aux inputs to the glitchless mux, so the aux select doesn't + // matter. The value of 0 here happens to be the sys PLL. + clock_configure(clk_ref, CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC, 0, // No aux mux @@ -85,18 +111,32 @@ void clocks_init_optional_usb(bool init_usb) { USB_CLK_KHZ * KHZ, USB_CLK_KHZ * KHZ); + #if HAS_RP2040_RTC // CLK RTC = PLL USB 48MHz / 1024 = 46875Hz clock_configure(clk_rtc, 0, // No GLMUX CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB, USB_CLK_KHZ * KHZ, RTC_CLOCK_FREQ_HZ); + #endif - // CLK PERI = clk_sys. Used as reference clock for Peripherals. No dividers so just select and enable - // Normally choose clk_sys or clk_usb + // CLK PERI = clk_sys. Used as reference clock for UART and SPI serial. clock_configure(clk_peri, 0, CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS, SYS_CLK_KHZ * KHZ, SYS_CLK_KHZ * KHZ); + + #if PICO_RP2350 + // CLK_HSTX = clk_sys. Transmit bit clock for the HSTX peripheral. + clock_configure(clk_hstx, + 0, + CLOCKS_CLK_HSTX_CTRL_AUXSRC_VALUE_CLK_SYS, + SYS_CLK_KHZ * KHZ, + SYS_CLK_KHZ * KHZ); + #endif + + // Finally, all clocks are configured so start the ticks + // The ticks use clk_ref so now that is configured we can start them + start_all_ticks(); } diff --git a/ports/rp2/clocks_extra.h b/ports/rp2/clocks_extra.h index 40f77f53bd850..7d630e5088f5c 100644 --- a/ports/rp2/clocks_extra.h +++ b/ports/rp2/clocks_extra.h @@ -28,6 +28,6 @@ #include "hardware/clocks.h" -void clocks_init_optional_usb(bool init_usb); +void runtime_init_clocks_optional_usb(bool init_usb); #endif // MICROPY_INCLUDED_RP2_CLOCKS_EXTRA_H diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c index 798078faf6527..2faf0bc6f8713 100644 --- a/ports/rp2/modmachine.c +++ b/ports/rp2/modmachine.c @@ -259,7 +259,7 @@ static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) { rosc_hw->ctrl = ROSC_CTRL_ENABLE_VALUE_ENABLE << ROSC_CTRL_ENABLE_LSB; // Bring back all clocks. - clocks_init_optional_usb(disable_usb); + runtime_init_clocks_optional_usb(disable_usb); MICROPY_END_ATOMIC_SECTION(my_interrupts); } From 34e463d861c5ebb33ec317749a008d461616cfbc Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 5 Aug 2024 22:02:13 +0100 Subject: [PATCH 15/31] rp2/machine_adc: Add ADC support for RP2350B. Signed-off-by: Damien George --- ports/rp2/machine_adc.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ports/rp2/machine_adc.c b/ports/rp2/machine_adc.c index 3594f4b124022..40c216d59bc8d 100644 --- a/ports/rp2/machine_adc.c +++ b/ports/rp2/machine_adc.c @@ -31,9 +31,8 @@ #include "hardware/adc.h" #include "machine_pin.h" -#define ADC_IS_VALID_GPIO(gpio) ((gpio) >= 26 && (gpio) <= 29) -#define ADC_CHANNEL_FROM_GPIO(gpio) ((gpio) - 26) -#define ADC_CHANNEL_TEMPSENSOR (4) +#define ADC_IS_VALID_GPIO(gpio) ((gpio) >= ADC_BASE_PIN && (gpio) < (ADC_BASE_PIN + NUM_ADC_CHANNELS)) +#define ADC_CHANNEL_FROM_GPIO(gpio) ((gpio) - ADC_BASE_PIN) static uint16_t adc_config_and_read_u16(uint32_t channel) { adc_select_input(channel); @@ -47,7 +46,7 @@ static uint16_t adc_config_and_read_u16(uint32_t channel) { // MicroPython bindings for machine.ADC #define MICROPY_PY_MACHINE_ADC_CLASS_CONSTANTS \ - { MP_ROM_QSTR(MP_QSTR_CORE_TEMP), MP_ROM_INT(ADC_CHANNEL_TEMPSENSOR) }, \ + { MP_ROM_QSTR(MP_QSTR_CORE_TEMP), MP_ROM_INT(ADC_TEMPERATURE_CHANNEL_NUM) }, \ typedef struct _machine_adc_obj_t { mp_obj_base_t base; @@ -75,7 +74,7 @@ static mp_obj_t mp_machine_adc_make_new(const mp_obj_type_t *type, size_t n_args if (mp_obj_is_int(source)) { channel = mp_obj_get_int(source); - if (!(channel >= 0 && channel <= ADC_CHANNEL_TEMPSENSOR)) { + if (!(channel >= 0 && channel < NUM_ADC_CHANNELS)) { // Not a valid ADC channel, fallback to searching for a pin. channel = -1; } @@ -116,7 +115,7 @@ static mp_obj_t mp_machine_adc_make_new(const mp_obj_type_t *type, size_t n_args adc_gpio_init(pin->id); channel = ADC_CHANNEL_FROM_GPIO(pin->id); } - } else if (channel == ADC_CHANNEL_TEMPSENSOR) { + } else if (channel == ADC_TEMPERATURE_CHANNEL_NUM) { // Enable temperature sensor. adc_set_temp_sensor_enabled(1); } From 4fc6cf914187f7cf6b03d943dea50b457331beab Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Aug 2024 14:34:22 +1000 Subject: [PATCH 16/31] rp2: Add support for RP2350 in RISCV mode. As part of this change, the RV32I native emitter is enabled on RISCV board variants. Signed-off-by: Damien George --- ports/rp2/CMakeLists.txt | 41 ++++++++++++++++++++++++++++++++++++---- ports/rp2/main.c | 6 +++--- ports/rp2/mpconfigport.h | 8 +++++++- ports/rp2/pendsv.c | 14 +++++++++++--- 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 40672a8b31655..13a370c633b85 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -93,6 +93,14 @@ include(${MICROPY_DIR}/py/usermod.cmake) add_executable(${MICROPY_TARGET}) +# Provide a C-level definitions of PICO_ARM. +# (The pico-sdk already defines PICO_RISCV when it's enabled.) +if(PICO_ARM) + target_compile_definitions(pico_platform_headers INTERFACE + PICO_ARM=1 + ) +endif() + set(MICROPY_QSTRDEFS_PORT ${MICROPY_PORT_DIR}/qstrdefsport.h ) @@ -108,7 +116,6 @@ set(MICROPY_SOURCE_LIB ${MICROPY_DIR}/shared/netutils/netutils.c ${MICROPY_DIR}/shared/netutils/trace.c ${MICROPY_DIR}/shared/readline/readline.c - ${MICROPY_DIR}/shared/runtime/gchelper_thumb1.s ${MICROPY_DIR}/shared/runtime/gchelper_native.c ${MICROPY_DIR}/shared/runtime/interrupt_char.c ${MICROPY_DIR}/shared/runtime/mpirq.c @@ -123,6 +130,16 @@ set(MICROPY_SOURCE_LIB ${MICROPY_DIR}/shared/tinyusb/mp_usbd_runtime.c ) +if(PICO_ARM) + list(APPEND MICROPY_SOURCE_LIB + ${MICROPY_DIR}/shared/runtime/gchelper_thumb1.s + ) +elseif(PICO_RISCV) + list(APPEND MICROPY_SOURCE_LIB + ${MICROPY_DIR}/shared/runtime/gchelper_rv32i.s + ) +endif() + set(MICROPY_SOURCE_DRIVERS ${MICROPY_DIR}/drivers/bus/softspi.c ${MICROPY_DIR}/drivers/dht/dht.c @@ -178,7 +195,6 @@ set(MICROPY_SOURCE_QSTR ) set(PICO_SDK_COMPONENTS - cmsis_core hardware_adc hardware_base hardware_boot_lock @@ -222,6 +238,17 @@ set(PICO_SDK_COMPONENTS tinyusb_device ) +if(PICO_ARM) + list(APPEND PICO_SDK_COMPONENTS + cmsis_core + ) +elseif(PICO_RISCV) + list(APPEND PICO_SDK_COMPONENTS + hardware_hazard3 + hardware_riscv + ) +endif() + # Use our custom pico_float_micropython float implementation. This is needed for two reasons: # - to fix inf handling in pico-sdk's __wrap___aeabi_fadd(); # - so we can use our own libm functions, to fix inaccuracies in the pico-sdk versions. @@ -243,7 +270,7 @@ if(PICO_RP2040) ${PICO_SDK_PATH}/src/rp2_common/pico_float/float_init_rom_rp2040.c ${PICO_SDK_PATH}/src/rp2_common/pico_float/float_v1_rom_shim_rp2040.S ) -elseif(PICO_RP2350) +elseif(PICO_RP2350 AND PICO_ARM) target_sources(pico_float_micropython INTERFACE ${PICO_SDK_PATH}/src/rp2_common/pico_float/float_aeabi_dcp.S ${PICO_SDK_PATH}/src/rp2_common/pico_float/float_conv_m33.S @@ -491,6 +518,12 @@ target_link_options(${MICROPY_TARGET} PRIVATE -Wl,--wrap=runtime_init_clocks ) +if(PICO_RP2350) + target_link_options(${MICROPY_TARGET} PRIVATE + -Wl,--defsym=__micropy_extra_stack__=4096 + ) +endif() + # Apply optimisations to performance-critical source code. set_source_files_properties( ${MICROPY_PY_DIR}/map.c @@ -563,7 +596,7 @@ endif() pico_add_extra_outputs(${MICROPY_TARGET}) -pico_find_compiler(PICO_COMPILER_SIZE ${PICO_GCC_TRIPLE}-size) +pico_find_compiler_with_triples(PICO_COMPILER_SIZE "${PICO_GCC_TRIPLE}" size) add_custom_command(TARGET ${MICROPY_TARGET} POST_BUILD diff --git a/ports/rp2/main.c b/ports/rp2/main.c index 012e26f484fde..8d7b353731a1f 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -60,10 +60,8 @@ #endif #if PICO_RP2040 #include "RP2040.h" // cmsis, for PendSV_IRQn and SCB/SCB_SCR_SEVONPEND_Msk -#elif PICO_RP2350 +#elif PICO_RP2350 && PICO_ARM #include "RP2350.h" // cmsis, for PendSV_IRQn and SCB/SCB_SCR_SEVONPEND_Msk -#else -#error Unknown processor #endif #include "pico/aon_timer.h" #include "shared/timeutils/timeutils.h" @@ -82,7 +80,9 @@ bi_decl(bi_program_feature_group_with_flags(BINARY_INFO_TAG_MICROPYTHON, int main(int argc, char **argv) { // This is a tickless port, interrupts should always trigger SEV. + #if PICO_ARM SCB->SCR |= SCB_SCR_SEVONPEND_Msk; + #endif pendsv_init(); soft_timer_init(); diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index 80fe9f37c10ce..9a11e6048c6b4 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -78,10 +78,16 @@ // MicroPython emitters #define MICROPY_PERSISTENT_CODE_LOAD (1) +#if PICO_ARM #define MICROPY_EMIT_THUMB (1) -#define MICROPY_EMIT_THUMB_ARMV7M (0) #define MICROPY_EMIT_INLINE_THUMB (1) +#if PICO_RP2040 +#define MICROPY_EMIT_THUMB_ARMV7M (0) #define MICROPY_EMIT_INLINE_THUMB_FLOAT (0) +#endif +#elif PICO_RISCV +#define MICROPY_EMIT_RV32 (1) +#endif // Optimisations #define MICROPY_OPT_COMPUTED_GOTO (1) diff --git a/ports/rp2/pendsv.c b/ports/rp2/pendsv.c index 2f06871b3ac5b..905a5aa162ec5 100644 --- a/ports/rp2/pendsv.c +++ b/ports/rp2/pendsv.c @@ -31,10 +31,10 @@ #if PICO_RP2040 #include "RP2040.h" -#elif PICO_RP2350 +#elif PICO_RP2350 && PICO_ARM #include "RP2350.h" -#else -#error Unknown chip +#elif PICO_RISCV +#include "pico/aon_timer.h" #endif #if MICROPY_PY_NETWORK_CYW43 @@ -43,6 +43,8 @@ static pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS]; +void PendSV_Handler(void); + // Using the nowait variant here as softtimer updates PendSV from the loop of mp_wfe_or_timeout(), // where we don't want the CPU event bit to be set. static recursive_mutex_nowait_t pendsv_mutex; @@ -75,10 +77,16 @@ void pendsv_resume(void) { void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) { pendsv_dispatch_table[slot] = f; if (pendsv_mutex.mutex.enter_count == 0) { + #if PICO_ARM // There is a race here where other core calls pendsv_suspend() before // ISR can execute, but dispatch will happen later when other core // calls pendsv_resume(). SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; + #elif PICO_RISCV + struct timespec ts; + aon_timer_get_time(&ts); + aon_timer_enable_alarm(&ts, PendSV_Handler, false); + #endif } else { #if MICROPY_PY_NETWORK_CYW43 CYW43_STAT_INC(PENDSV_DISABLED_COUNT); From f2f08ef2d9ebf29d1c01dfe5720a46d49b6e5125 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Aug 2024 14:35:23 +1000 Subject: [PATCH 17/31] rp2/Makefile: Allow CMAKE_ARGS to be set by user. Signed-off-by: Damien George --- ports/rp2/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/rp2/Makefile b/ports/rp2/Makefile index b6e8852169217..f950bc7b90898 100644 --- a/ports/rp2/Makefile +++ b/ports/rp2/Makefile @@ -30,7 +30,7 @@ endif $(VERBOSE)MAKESILENT = -s -CMAKE_ARGS = -DMICROPY_BOARD=$(BOARD) -DMICROPY_BOARD_DIR="$(abspath $(BOARD_DIR))" +CMAKE_ARGS += -DMICROPY_BOARD=$(BOARD) -DMICROPY_BOARD_DIR="$(abspath $(BOARD_DIR))" ifdef USER_C_MODULES CMAKE_ARGS += -DUSER_C_MODULES=${USER_C_MODULES} From 7a78e5ae7c89077efdc6d4e18b55c8ea52b3d30c Mon Sep 17 00:00:00 2001 From: Dryw Wade Date: Mon, 5 Aug 2024 13:47:25 -0600 Subject: [PATCH 18/31] rp2/machine_bitstream: Set SysTick reset value. In case it doesn't have the correct value. Signed-off-by: Damien George --- ports/rp2/machine_bitstream.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/rp2/machine_bitstream.c b/ports/rp2/machine_bitstream.c index b65ec02147b40..8240fdad60636 100644 --- a/ports/rp2/machine_bitstream.c +++ b/ports/rp2/machine_bitstream.c @@ -48,6 +48,10 @@ void __time_critical_func(machine_bitstream_high_low)(mp_hal_pin_obj_t pin, uint } } mp_hal_pin_output(pin); + + // Set systick reset value. + systick_hw->rvr = 0x00FFFFFF; + // Enable the systick counter, source CPU clock. systick_hw->csr = 5; From 957cea23d53ca3f9e912ad04570c813020828eb2 Mon Sep 17 00:00:00 2001 From: Dryw Wade Date: Tue, 6 Aug 2024 16:13:57 -0600 Subject: [PATCH 19/31] rp2/machine_uart: Allow new TX/RX pins on RP2350. Signed-off-by: Damien George --- ports/rp2/machine_uart.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ports/rp2/machine_uart.c b/ports/rp2/machine_uart.c index 955e4a8479913..5fe6e31fde2ef 100644 --- a/ports/rp2/machine_uart.c +++ b/ports/rp2/machine_uart.c @@ -69,8 +69,13 @@ #define MAX_BUFFER_SIZE (32766) #define IS_VALID_PERIPH(uart, pin) (((((pin) + 4) & 8) >> 3) == (uart)) +#if PICO_RP2350 +#define IS_VALID_TX(uart, pin) (((pin) & 1) == 0 && IS_VALID_PERIPH(uart, pin)) +#define IS_VALID_RX(uart, pin) (((pin) & 1) == 1 && IS_VALID_PERIPH(uart, pin)) +#else #define IS_VALID_TX(uart, pin) (((pin) & 3) == 0 && IS_VALID_PERIPH(uart, pin)) #define IS_VALID_RX(uart, pin) (((pin) & 3) == 1 && IS_VALID_PERIPH(uart, pin)) +#endif #define IS_VALID_CTS(uart, pin) (((pin) & 3) == 2 && IS_VALID_PERIPH(uart, pin)) #define IS_VALID_RTS(uart, pin) (((pin) & 3) == 3 && IS_VALID_PERIPH(uart, pin)) @@ -398,8 +403,8 @@ static void mp_machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, __dsb(); // make sure UARTLCR_H register is written to uart_set_fifo_enabled(self->uart, true); __dsb(); // make sure UARTLCR_H register is written to - gpio_set_function(self->tx, GPIO_FUNC_UART); - gpio_set_function(self->rx, GPIO_FUNC_UART); + gpio_set_function(self->tx, UART_FUNCSEL_NUM(self->uart, self->tx)); + gpio_set_function(self->rx, UART_FUNCSEL_NUM(self->uart, self->rx)); if (self->invert & UART_INVERT_RX) { gpio_set_inover(self->rx, GPIO_OVERRIDE_INVERT); } From ea2eed1b2307ae561e27997be86d7fc4494ed8e4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Aug 2024 22:26:14 +1000 Subject: [PATCH 20/31] rp2/mphalport: Implement mp_hal_ticks_cpu for RISCV using mcycle. Signed-off-by: Damien George --- ports/rp2/mphalport.c | 11 +++++++++++ ports/rp2/mphalport.h | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/ports/rp2/mphalport.c b/ports/rp2/mphalport.c index 3fcc011b62676..3f50151620a02 100644 --- a/ports/rp2/mphalport.c +++ b/ports/rp2/mphalport.c @@ -125,6 +125,17 @@ mp_uint_t mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { return did_write ? ret : 0; } +#if PICO_RISCV +__attribute__((naked)) mp_uint_t mp_hal_ticks_cpu(void) { + __asm volatile ( + "li a0, 4\n" // mask value to uninhibit mcycle counter + "csrw mcountinhibit, a0\n" // uninhibit mcycle counter + "csrr a0, mcycle\n" // get mcycle counter + "ret\n" + ); +} +#endif + void mp_hal_delay_us(mp_uint_t us) { // Avoid calling sleep_us() and invoking the alarm pool by splitting long // sleeps into an optional longer sleep and a shorter busy-wait diff --git a/ports/rp2/mphalport.h b/ports/rp2/mphalport.h index 1d260c8bd8b61..da865fb7e85ea 100644 --- a/ports/rp2/mphalport.h +++ b/ports/rp2/mphalport.h @@ -96,11 +96,15 @@ static inline mp_uint_t mp_hal_ticks_ms(void) { return to_ms_since_boot(get_absolute_time()); } +#if PICO_ARM static inline mp_uint_t mp_hal_ticks_cpu(void) { // ticks_cpu() is defined as using the highest-resolution timing source // in the system. This is usually a CPU clock, but doesn't have to be. return time_us_32(); } +#elif PICO_RISCV +mp_uint_t mp_hal_ticks_cpu(void); +#endif static inline mp_uint_t mp_hal_get_cpu_freq(void) { return clock_get_hz(clk_sys); From fa15ae4503d87933c619a32110f8bd5e8817aece Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Aug 2024 22:26:37 +1000 Subject: [PATCH 21/31] rp2/machine_bitstream: Implement bitstream for RISC-V using mcycle. Signed-off-by: Damien George --- ports/rp2/machine_bitstream.c | 46 +++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/ports/rp2/machine_bitstream.c b/ports/rp2/machine_bitstream.c index 8240fdad60636..4ef97f0c86839 100644 --- a/ports/rp2/machine_bitstream.c +++ b/ports/rp2/machine_bitstream.c @@ -34,6 +34,25 @@ #define MP_HAL_BITSTREAM_NS_OVERHEAD (9) +#if PICO_RISCV + +__attribute__((naked)) void mcycle_init(void) { + __asm volatile ( + "li a0, 4\n" + "csrw mcountinhibit, a0\n" + "ret\n" + ); +} + +__attribute__((naked)) uint32_t mcycle_get(void) { + __asm volatile ( + "csrr a0, mcycle\n" + "ret\n" + ); +} + +#endif + void __time_critical_func(machine_bitstream_high_low)(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) { uint32_t fcpu_mhz = mp_hal_get_cpu_freq() / 1000000; // Convert ns to clock ticks [high_time_0, period_0, high_time_1, period_1]. @@ -49,14 +68,16 @@ void __time_critical_func(machine_bitstream_high_low)(mp_hal_pin_obj_t pin, uint } mp_hal_pin_output(pin); + uint32_t irq_state = mp_hal_quiet_timing_enter(); + + #if PICO_ARM + // Set systick reset value. systick_hw->rvr = 0x00FFFFFF; // Enable the systick counter, source CPU clock. systick_hw->csr = 5; - uint32_t irq_state = mp_hal_quiet_timing_enter(); - for (size_t i = 0; i < len; ++i) { uint8_t b = buf[i]; for (size_t j = 0; j < 8; ++j) { @@ -72,6 +93,27 @@ void __time_critical_func(machine_bitstream_high_low)(mp_hal_pin_obj_t pin, uint } } + #elif PICO_RISCV + + mcycle_init(); + + for (size_t i = 0; i < len; ++i) { + uint8_t b = buf[i]; + for (size_t j = 0; j < 8; ++j) { + uint32_t *t = &timing_ns[b >> 6 & 2]; + uint32_t start_ticks = mcycle_get(); + mp_hal_pin_high(pin); + while ((mcycle_get() - start_ticks) < t[0]) { + } + b <<= 1; + mp_hal_pin_low(pin); + while ((mcycle_get() - start_ticks) < t[1]) { + } + } + } + + #endif + mp_hal_quiet_timing_exit(irq_state); } From 8cc7c64d01a597da8190873432fcb6b267e6a1bb Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 13 Aug 2024 10:34:23 +1000 Subject: [PATCH 22/31] rp2: Workaround pico_aon_timer timezone binary size increase. Provide stub implementations of localtime_r() and mktime() to avoid code size increase. Reported upstream at https://github.com/raspberrypi/pico-sdk/issues/1810 This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton --- ports/rp2/CMakeLists.txt | 1 + ports/rp2/datetime_patch.c | 42 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 ports/rp2/datetime_patch.c diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 13a370c633b85..4baaf7debf6c5 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -147,6 +147,7 @@ set(MICROPY_SOURCE_DRIVERS set(MICROPY_SOURCE_PORT clocks_extra.c + datetime_patch.c fatfs_port.c help.c machine_bitstream.c diff --git a/ports/rp2/datetime_patch.c b/ports/rp2/datetime_patch.c new file mode 100644 index 0000000000000..810af4cf1650d --- /dev/null +++ b/ports/rp2/datetime_patch.c @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 Angus Gratton + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "py/mpconfig.h" +#include "shared/timeutils/timeutils.h" + +// This is a workaround for the issue that pico-sdk datetime.c will otherwise +// pull in a lot of libc code for time zone support. +// +// Upstream issue is https://github.com/raspberrypi/pico-sdk/issues/1810 + +struct tm *localtime_r(const time_t *__restrict time, struct tm *__restrict local_time) { + return gmtime_r(time, local_time); +} + +time_t mktime(struct tm *__restrict tm) { + return timeutils_mktime(tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); +} From 27904ae4b9003eac743d031499325f7680699990 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 15 Aug 2024 16:18:09 +0100 Subject: [PATCH 23/31] rp2/machine_pwm: Add RP2350 slices to machine.PWM. Signed-off-by: Phil Howard --- ports/rp2/machine_pwm.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ports/rp2/machine_pwm.c b/ports/rp2/machine_pwm.c index 4c0bc2c103243..fd20be5ec2f6f 100644 --- a/ports/rp2/machine_pwm.c +++ b/ports/rp2/machine_pwm.c @@ -67,10 +67,20 @@ static machine_pwm_obj_t machine_pwm_obj[] = { {{&machine_pwm_type}, 6, PWM_CHAN_B, 0, DUTY_NOT_SET, 0 }, {{&machine_pwm_type}, 7, PWM_CHAN_A, 0, DUTY_NOT_SET, 0 }, {{&machine_pwm_type}, 7, PWM_CHAN_B, 0, DUTY_NOT_SET, 0 }, + #if NUM_PWM_SLICES == 12 + {{&machine_pwm_type}, 8, PWM_CHAN_A, 0, DUTY_NOT_SET, 0 }, + {{&machine_pwm_type}, 8, PWM_CHAN_B, 0, DUTY_NOT_SET, 0 }, + {{&machine_pwm_type}, 9, PWM_CHAN_A, 0, DUTY_NOT_SET, 0 }, + {{&machine_pwm_type}, 9, PWM_CHAN_B, 0, DUTY_NOT_SET, 0 }, + {{&machine_pwm_type}, 10, PWM_CHAN_A, 0, DUTY_NOT_SET, 0 }, + {{&machine_pwm_type}, 10, PWM_CHAN_B, 0, DUTY_NOT_SET, 0 }, + {{&machine_pwm_type}, 11, PWM_CHAN_A, 0, DUTY_NOT_SET, 0 }, + {{&machine_pwm_type}, 11, PWM_CHAN_B, 0, DUTY_NOT_SET, 0 }, + #endif }; static bool defer_start; -static bool slice_freq_set[8]; +static bool slice_freq_set[NUM_PWM_SLICES]; static void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq); static void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u16); @@ -155,7 +165,7 @@ static mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args // Stop all active slices. void machine_pwm_deinit_all(void) { - for (int i = 0; i < 8; i++) { + for (int i = 0; i < NUM_PWM_SLICES; i++) { slice_freq_set[i] = false; pwm_set_enabled(machine_pwm_obj[i].slice, false); } From 137e9e8c799f05a4a5190441d9b3bb2a503337c9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 23 Sep 2024 13:11:42 +1000 Subject: [PATCH 24/31] rp2/main: Set CPU frequency to default for the MCU. Signed-off-by: Damien George --- ports/rp2/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/rp2/main.c b/ports/rp2/main.c index 8d7b353731a1f..d6bf448267152 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -88,7 +88,7 @@ int main(int argc, char **argv) { soft_timer_init(); // Set the MCU frequency and as a side effect the peripheral clock to 48 MHz. - set_sys_clock_khz(125000, false); + set_sys_clock_khz(SYS_CLK_KHZ, false); // Hook for setting up anything that needs to be super early in the bootup process. MICROPY_BOARD_STARTUP(); From e32e13f7e4ece573235c67db725b1874a7c89ac6 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 22 May 2024 15:21:56 +0100 Subject: [PATCH 25/31] rp2/boards/RPI_PICO2: Add new RPI_PICO2 board definition. This is the same form-factor as the Pico but with an RP2350. Signed-off-by: Damien George --- ports/rp2/boards/RPI_PICO2/board.json | 22 +++++++++++++++ .../rp2/boards/RPI_PICO2/mpconfigboard.cmake | 5 ++++ ports/rp2/boards/RPI_PICO2/mpconfigboard.h | 3 ++ .../boards/RPI_PICO2/mpconfigvariant.cmake | 1 + .../RPI_PICO2/mpconfigvariant_RISCV.cmake | 1 + ports/rp2/boards/RPI_PICO2/pins.csv | 28 +++++++++++++++++++ 6 files changed, 60 insertions(+) create mode 100644 ports/rp2/boards/RPI_PICO2/board.json create mode 100644 ports/rp2/boards/RPI_PICO2/mpconfigboard.cmake create mode 100644 ports/rp2/boards/RPI_PICO2/mpconfigboard.h create mode 100644 ports/rp2/boards/RPI_PICO2/mpconfigvariant.cmake create mode 100644 ports/rp2/boards/RPI_PICO2/mpconfigvariant_RISCV.cmake create mode 100644 ports/rp2/boards/RPI_PICO2/pins.csv diff --git a/ports/rp2/boards/RPI_PICO2/board.json b/ports/rp2/boards/RPI_PICO2/board.json new file mode 100644 index 0000000000000..8f3e4bde71a2e --- /dev/null +++ b/ports/rp2/boards/RPI_PICO2/board.json @@ -0,0 +1,22 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "Dual-core", + "External Flash", + "USB" + ], + "images": [ + "rp2-pico2.jpg" + ], + "mcu": "rp2350", + "product": "Pico 2", + "thumbnail": "", + "url": "https://www.raspberrypi.com/products/raspberry-pi-pico-2/", + "variants": { + "RISCV": "RISC-V CPU mode" + }, + "vendor": "Raspberry Pi" +} diff --git a/ports/rp2/boards/RPI_PICO2/mpconfigboard.cmake b/ports/rp2/boards/RPI_PICO2/mpconfigboard.cmake new file mode 100644 index 0000000000000..48b6545aa3428 --- /dev/null +++ b/ports/rp2/boards/RPI_PICO2/mpconfigboard.cmake @@ -0,0 +1,5 @@ +# cmake file for Raspberry Pi Pico2 +set(PICO_BOARD "pico2") + +# To change the gpio count for QFN-80 +# set(PICO_NUM_GPIOS 48) diff --git a/ports/rp2/boards/RPI_PICO2/mpconfigboard.h b/ports/rp2/boards/RPI_PICO2/mpconfigboard.h new file mode 100644 index 0000000000000..4b5eac6eb3ae3 --- /dev/null +++ b/ports/rp2/boards/RPI_PICO2/mpconfigboard.h @@ -0,0 +1,3 @@ +// 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) diff --git a/ports/rp2/boards/RPI_PICO2/mpconfigvariant.cmake b/ports/rp2/boards/RPI_PICO2/mpconfigvariant.cmake new file mode 100644 index 0000000000000..6fe039ba51bba --- /dev/null +++ b/ports/rp2/boards/RPI_PICO2/mpconfigvariant.cmake @@ -0,0 +1 @@ +set(PICO_PLATFORM "rp2350") diff --git a/ports/rp2/boards/RPI_PICO2/mpconfigvariant_RISCV.cmake b/ports/rp2/boards/RPI_PICO2/mpconfigvariant_RISCV.cmake new file mode 100644 index 0000000000000..65a97fc3350d1 --- /dev/null +++ b/ports/rp2/boards/RPI_PICO2/mpconfigvariant_RISCV.cmake @@ -0,0 +1 @@ +set(PICO_PLATFORM "rp2350-riscv") diff --git a/ports/rp2/boards/RPI_PICO2/pins.csv b/ports/rp2/boards/RPI_PICO2/pins.csv new file mode 100644 index 0000000000000..16e334026424f --- /dev/null +++ b/ports/rp2/boards/RPI_PICO2/pins.csv @@ -0,0 +1,28 @@ +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 From f9cebe676e156e8568cf272837917187cc3743a8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 9 Aug 2024 12:32:48 +1000 Subject: [PATCH 26/31] tools/ci.sh: Add RPI_PICO2 to CI. Signed-off-by: Damien George --- tools/ci.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/ci.sh b/tools/ci.sh index feb40cc4ff34a..6f0f23a1c4810 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -309,6 +309,8 @@ function ci_rp2_build { make ${MAKEOPTS} -C ports/rp2 make ${MAKEOPTS} -C ports/rp2 BOARD=RPI_PICO_W submodules make ${MAKEOPTS} -C ports/rp2 BOARD=RPI_PICO_W USER_C_MODULES=../../examples/usercmodule/micropython.cmake + make ${MAKEOPTS} -C ports/rp2 BOARD=RPI_PICO2 submodules + make ${MAKEOPTS} -C ports/rp2 BOARD=RPI_PICO2 make ${MAKEOPTS} -C ports/rp2 BOARD=W5100S_EVB_PICO submodules make ${MAKEOPTS} -C ports/rp2 BOARD=W5100S_EVB_PICO From fda7ae83a879c6be878febea70b604093e2de3b2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 7 Aug 2024 17:03:22 +1000 Subject: [PATCH 27/31] tests/ports/rp2: Update DMA test to work on RP2350. Signed-off-by: Damien George --- tests/ports/rp2/rp2_dma.py | 22 +++++++++++++++++++--- tests/ports/rp2/rp2_dma.py.exp | 19 +++++++++++++++++-- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/tests/ports/rp2/rp2_dma.py b/tests/ports/rp2/rp2_dma.py index 2459213f4c014..62ec1dcf24d14 100644 --- a/tests/ports/rp2/rp2_dma.py +++ b/tests/ports/rp2/rp2_dma.py @@ -1,21 +1,36 @@ # Test rp2.DMA functionality. +import sys import time import machine import rp2 +is_rp2350 = "RP2350" in sys.implementation._machine + src = bytes(i & 0xFF for i in range(16 * 1024)) print("# test basic usage") dma = rp2.DMA() + +# Test printing. print(dma) -print(rp2.DMA.unpack_ctrl(dma.pack_ctrl())) + +# Test pack_ctrl/unpack_ctrl. +ctrl_dict = rp2.DMA.unpack_ctrl(dma.pack_ctrl()) +if is_rp2350: + for entry in ("inc_read_rev", "inc_write_rev"): + assert entry in ctrl_dict + del ctrl_dict[entry] +for key, value in sorted(ctrl_dict.items()): + print(key, value) + +# Test register access. dma.read = 0 dma.write = 0 dma.count = 0 dma.ctrl = dma.pack_ctrl() -print(dma.read, dma.write, dma.count, dma.ctrl & 0x01FFFFFF, dma.channel, dma.registers) +print(dma.read, dma.write, dma.count, dma.ctrl & 0x01F, dma.channel, dma.registers) dma.close() # Test closing when already closed. @@ -62,7 +77,8 @@ def run_and_time_dma(dma): dma.count = len(dest) // 4 dma.ctrl = dma.pack_ctrl() dt = run_and_time_dma(dma) -print(70 <= dt <= 110) +expected_dt_range = range(40, 70) if is_rp2350 else range(70, 125) +print(dt in expected_dt_range) print(dest[:8], dest[-8:]) dma.close() diff --git a/tests/ports/rp2/rp2_dma.py.exp b/tests/ports/rp2/rp2_dma.py.exp index 79f17626ace2a..6fad5429b291d 100644 --- a/tests/ports/rp2/rp2_dma.py.exp +++ b/tests/ports/rp2/rp2_dma.py.exp @@ -1,7 +1,22 @@ # test basic usage DMA(0) -{'inc_read': 1, 'high_pri': 0, 'write_err': 0, 'ring_sel': 0, 'enable': 1, 'treq_sel': 63, 'sniff_en': 0, 'irq_quiet': 1, 'read_err': 0, 'chain_to': 0, 'busy': 0, 'inc_write': 1, 'ring_size': 0, 'bswap': 0, 'size': 2, 'ahb_err': 0} -0 0 0 4161593 0 +ahb_err 0 +bswap 0 +busy 0 +chain_to 0 +enable 1 +high_pri 0 +inc_read 1 +inc_write 1 +irq_quiet 1 +read_err 0 +ring_sel 0 +ring_size 0 +size 2 +sniff_en 0 +treq_sel 63 +write_err 0 +0 0 0 25 0 ValueError # test memory copy True From 651b63cd79229e9c8073885f926e26ef1a7f081a Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 9 Aug 2024 11:25:01 +1000 Subject: [PATCH 28/31] tests/ports/rp2: Add simple rp2-specific UART test. To test construction of UART instances. Signed-off-by: Damien George --- tests/ports/rp2/rp2_uart.py | 10 ++++++++++ tests/ports/rp2/rp2_uart.py.exp | 1 + 2 files changed, 11 insertions(+) create mode 100644 tests/ports/rp2/rp2_uart.py create mode 100644 tests/ports/rp2/rp2_uart.py.exp diff --git a/tests/ports/rp2/rp2_uart.py b/tests/ports/rp2/rp2_uart.py new file mode 100644 index 0000000000000..da88599344795 --- /dev/null +++ b/tests/ports/rp2/rp2_uart.py @@ -0,0 +1,10 @@ +# Test construction of machine.UART objects. + +import sys +from machine import UART + +print(UART(0, tx=0, rx=1)) + +if "RP2350" in sys.implementation._machine: + # Test that UART can be constructed using other tx/rx pins. + UART(0, tx=2, rx=3) diff --git a/tests/ports/rp2/rp2_uart.py.exp b/tests/ports/rp2/rp2_uart.py.exp new file mode 100644 index 0000000000000..72cd5fb00f6c4 --- /dev/null +++ b/tests/ports/rp2/rp2_uart.py.exp @@ -0,0 +1 @@ +UART(0, baudrate=115200, bits=8, parity=None, stop=1, tx=0, rx=1, txbuf=256, rxbuf=256, timeout=0, timeout_char=1, invert=None, irq=0) From b42bb911c663dc90575d6a7fe3ea4760b6559372 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 11 Oct 2024 13:40:35 +1100 Subject: [PATCH 29/31] tests/ports/rp2: Update lightsleep/machine_idle to skip on RP2350. Signed-off-by: Damien George --- tests/ports/rp2/rp2_lightsleep.py | 9 +++++++-- tests/ports/rp2/rp2_machine_idle.py | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/ports/rp2/rp2_lightsleep.py b/tests/ports/rp2/rp2_lightsleep.py index 3587def68fcd8..5ce5696e0e18c 100644 --- a/tests/ports/rp2/rp2_lightsleep.py +++ b/tests/ports/rp2/rp2_lightsleep.py @@ -9,13 +9,18 @@ # 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 -from sys import stdout, platform +# RP2350 currently fails this test, needs further investigation. +if "RP2350" in sys.implementation._machine: + print("SKIP") + raise SystemExit try: led = Pin(Pin.board.LED, Pin.OUT) @@ -25,7 +30,7 @@ for n in range(100): if led: led.toggle() - stdout.write(chr(ord("a") + (n % 26))) + sys.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 f9c28284782f8..3135110b82000 100644 --- a/tests/ports/rp2/rp2_machine_idle.py +++ b/tests/ports/rp2/rp2_machine_idle.py @@ -1,3 +1,4 @@ +import sys import machine import time @@ -17,6 +18,11 @@ # 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 b33f64792f6cff9a14f935ac568e82ec385bf54d Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 11 Oct 2024 13:41:28 +1100 Subject: [PATCH 30/31] tests/run-tests.py: Only run inlineasm tests on rp2 ARM targets. Signed-off-by: Damien George --- tests/run-tests.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/run-tests.py b/tests/run-tests.py index a9fb458f2cde4..f9f8413077abf 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -1095,7 +1095,9 @@ def main(): elif args.target in ("renesas-ra"): test_dirs += ("float", "inlineasm", "ports/renesas-ra") elif args.target == "rp2": - test_dirs += ("float", "stress", "inlineasm", "thread", "ports/rp2") + test_dirs += ("float", "stress", "thread", "ports/rp2") + if "arm" in args.mpy_cross_flags: + test_dirs += ("inlineasm",) elif args.target == "esp32": test_dirs += ("float", "stress", "thread") elif args.target in ("esp8266", "minimal", "nrf"): From 51663b9aa71e40bbb3e82bde4918f03adb35ff62 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 11 Oct 2024 13:41:48 +1100 Subject: [PATCH 31/31] rp2/machine_uart: Clear timeout_char when UART is first constructed. Otherwise a previous value of `timeout_char` may be left over after a soft reset. Signed-off-by: Damien George --- ports/rp2/machine_uart.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/rp2/machine_uart.c b/ports/rp2/machine_uart.c index 5fe6e31fde2ef..54791cdc59436 100644 --- a/ports/rp2/machine_uart.c +++ b/ports/rp2/machine_uart.c @@ -390,6 +390,7 @@ static void mp_machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, if (n_args > 0 || kw_args->used > 0 || self->baudrate == 0) { if (self->baudrate == 0) { self->baudrate = DEFAULT_UART_BAUDRATE; + self->timeout_char = 0; } // Make sure timeout_char is at least as long as a whole character (13 bits to be safe).