Enable OTA support for RP2350 (#2472)

The RP2350 has a different blob header requirement to identify a working
image.  Ensure that header is present in the OTA loader.

Update the PicoOTA examples for the 2350
This commit is contained in:
Earle F. Philhower, III 2024-09-17 15:05:42 -07:00 committed by GitHub
parent 4504d72972
commit 2063a2d23d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 9752 additions and 57 deletions

View file

@ -1,8 +1,6 @@
OTA Updates OTA Updates
=========== ===========
**NOTE:** OTA is not yet supported on the RP2350. PRs gladly accepted!
Introduction Introduction
------------ ------------

View file

@ -7,7 +7,6 @@ is supported by the core with some minor caveats:
* PSRAM is supported via a new ``pmalloc`` call and ``PSRAM`` variable decorator. * PSRAM is supported via a new ``pmalloc`` call and ``PSRAM`` variable decorator.
* Both RP2350A and RP2350B (48 GPIOs) are supported. * Both RP2350A and RP2350B (48 GPIOs) are supported.
* Only ARM mode is available. For RISC-V (Hazard3), please use the raw SDK. * Only ARM mode is available. For RISC-V (Hazard3), please use the raw SDK.
* OTA is not yet supported.
P2350-E9 Errata ("Increased leakage current on Bank 0 GPIO when pad input is enabled") P2350-E9 Errata ("Increased leakage current on Bank 0 GPIO when pad input is enabled")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -21,6 +21,9 @@
__stack (== StackTop) __stack (== StackTop)
*/ */
MEMORY MEMORY
{ {
FLASH(rx) : ORIGIN = 0x10000000, LENGTH = __FLASH_LENGTH__ FLASH(rx) : ORIGIN = 0x10000000, LENGTH = __FLASH_LENGTH__
@ -42,6 +45,20 @@ SECTIONS
__flash_binary_start = .; __flash_binary_start = .;
} > FLASH } > FLASH
.ota : {
/* Start image with OTA */
KEEP (*(.OTA))
*ota.o
} > FLASH
.partition : {
. = __flash_binary_start + 0x2ff0;
LONG(__FS_START__)
LONG(__FS_END__)
LONG(__EEPROM_START__)
LONG(__FLASH_LENGTH__)
} > FLASH
/* The bootrom will enter the image at the point indicated in your /* The bootrom will enter the image at the point indicated in your
IMAGE_DEF, which is usually the reset handler of your vector table. IMAGE_DEF, which is usually the reset handler of your vector table.
@ -53,8 +70,8 @@ SECTIONS
*/ */
.text : { .text : {
__logical_binary_start = .;
KEEP (*(.vectors)) KEEP (*(.vectors))
__logical_binary_start = .;
KEEP (*(.binary_info_header)) KEEP (*(.binary_info_header))
__binary_info_header_end = .; __binary_info_header_end = .;
KEEP (*(.embedded_block)) KEEP (*(.embedded_block))
@ -276,7 +293,7 @@ SECTIONS
.flash_end : { .flash_end : {
KEEP(*(.embedded_end_block*)) KEEP(*(.embedded_end_block*))
PROVIDE(__flash_binary_end = .); PROVIDE(__flash_binary_end = .);
} > FLASH =0xaa } > FLASH = 0xaa
.psram (NOLOAD) : { .psram (NOLOAD) : {
__psram_start__ = .; __psram_start__ = .;

Binary file not shown.

View file

@ -12,7 +12,8 @@
#include <PicoOTA.h> #include <PicoOTA.h>
#include <LittleFS.h> #include <LittleFS.h>
#include "blink_100_1000.h" #include "blink_100_1000_rp2040.h"
#include "blink_500_500_rp2350.h"
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);

View file

@ -1,3 +1,4 @@
#ifdef PICO_RP2040
const unsigned char blink_gz[] = { const unsigned char blink_gz[] = {
0x1f, 0x8b, 0x08, 0x08, 0x86, 0x7e, 0xf3, 0x62, 0x02, 0x03, 0x73, 0x6b, 0x1f, 0x8b, 0x08, 0x08, 0x86, 0x7e, 0xf3, 0x62, 0x02, 0x03, 0x73, 0x6b,
0x65, 0x74, 0x63, 0x68, 0x5f, 0x61, 0x75, 0x67, 0x31, 0x30, 0x61, 0x2e, 0x65, 0x74, 0x63, 0x68, 0x5f, 0x61, 0x75, 0x67, 0x31, 0x30, 0x61, 0x2e,
@ -3896,3 +3897,4 @@ const unsigned char blink_gz[] = {
0x03, 0xeb, 0x79, 0x7c, 0xf6, 0x3f, 0x01, 0xa8, 0x7b, 0x69, 0xf7, 0x10, 0x03, 0xeb, 0x79, 0x7c, 0xf6, 0x3f, 0x01, 0xa8, 0x7b, 0x69, 0xf7, 0x10,
0x11, 0x01, 0x00 0x11, 0x01, 0x00
}; };
#endif

File diff suppressed because it is too large Load diff

View file

@ -9,7 +9,8 @@
#include <PicoOTA.h> #include <PicoOTA.h>
#include <LittleFS.h> #include <LittleFS.h>
#include "blink_100_1000.h" #include "blink_100_1000_rp2040.h"
#include "blink_500_500_rp2350.h"
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);

View file

@ -1,3 +1,4 @@
#ifdef PICO_RP2040
const unsigned char blink[] = { const unsigned char blink[] = {
0x00, 0xb5, 0x32, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21, 0x00, 0xb5, 0x32, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21,
0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2e, 0x4b, 0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2e, 0x4b,
@ -5826,3 +5827,4 @@ const unsigned char blink[] = {
0xc1, 0x45, 0x00, 0x10, 0x9d, 0x48, 0x00, 0x10, 0xad, 0x4b, 0x00, 0x10, 0xc1, 0x45, 0x00, 0x10, 0x9d, 0x48, 0x00, 0x10, 0xad, 0x4b, 0x00, 0x10,
0xed, 0x63, 0x00, 0x10 0xed, 0x63, 0x00, 0x10
}; };
#endif

File diff suppressed because it is too large Load diff

View file

@ -7,10 +7,14 @@ if (${cpu} MATCHES "rp2040")
set(PICO_BOARD pico) set(PICO_BOARD pico)
set(PICO_PLATFORM rp2040) set(PICO_PLATFORM rp2040)
set(PICO_CYW43_SUPPORTED 0) set(PICO_CYW43_SUPPORTED 0)
set(OBJARCH armv6-m)
set(WRAP -Wl,--wrap=clocks_init)
elseif(${cpu} MATCHES "rp2350") elseif(${cpu} MATCHES "rp2350")
set(PICO_BOARD pico2) set(PICO_BOARD pico2)
set(PICO_PLATFORM rp2350) set(PICO_PLATFORM rp2350)
set(PICO_CYW43_SUPPORTED 0) set(PICO_CYW43_SUPPORTED 0)
set(OBJARCH armv8-m)
set(WRAP )
else() else()
message(FATAL_ERROR "Unknown CPU, '${cpu}'") message(FATAL_ERROR "Unknown CPU, '${cpu}'")
endif() endif()
@ -71,7 +75,7 @@ target_compile_options(ota PUBLIC
) )
target_link_options(ota PUBLIC target_link_options(ota PUBLIC
-Wl,--wrap=clocks_init ${WRAP}
-Wl,--wrap=exit -Wl,--wrap=exit
-Wl,--wrap=atexit -Wl,--wrap=atexit
-Wl,--wrap=panic_unsupported -Wl,--wrap=panic_unsupported
@ -97,7 +101,7 @@ target_link_libraries(ota
) )
add_custom_command(TARGET ota POST_BUILD add_custom_command(TARGET ota POST_BUILD
COMMAND ../../system/arm-none-eabi/bin/arm-none-eabi-ld -r -A armv6-m -b binary -o ota.o ota.bin COMMAND ../../system/arm-none-eabi/bin/arm-none-eabi-ld -r -A ${OBJARCH} -b binary -o ota.o ota.bin
COMMAND ../../system/arm-none-eabi/bin/arm-none-eabi-objcopy --rename-section .data=.OTA ota.o ../../lib/${cpu}/ota.o COMMAND ../../system/arm-none-eabi/bin/arm-none-eabi-objcopy --rename-section .data=.OTA ota.o ../../lib/${cpu}/ota.o
COMMAND cp ../ota_command.h ../../include/${cpu}/pico_base/pico/. COMMAND cp ../ota_command.h ../../include/${cpu}/pico_base/pico/.
) )

View file

@ -23,19 +23,17 @@
MEMORY MEMORY
{ {
FLASH(rx) : ORIGIN = 0x10000100, LENGTH = 16384k INCLUDE "pico_flash_region.ld"
RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 212k RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 212k
/* We split RAM into main (where the flash->ram code will be copied) and GLOBALS which has all large arrays */
/* By placing those arrays at the end of RAM we can avoid overwriting uninitialize_ram from the main app as */
/* long as those vars are stored after 12K by using an alignment value in the main app linker file. */
GLOBALS(rwx) : ORIGIN = 0x20035000, LENGTH = 44k GLOBALS(rwx) : ORIGIN = 0x20035000, LENGTH = 44k
SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k
SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k
} }
ENTRY(_entry_point) ENTRY(_entry_point)
SECTIONS { SECTIONS
{
/* Second stage bootloader is prepended to the image. It must be 256 bytes big /* Second stage bootloader is prepended to the image. It must be 256 bytes big
and checksummed. It is usually built by the boot_stage2 target and checksummed. It is usually built by the boot_stage2 target
in the Raspberry Pi Pico SDK in the Raspberry Pi Pico SDK
@ -45,24 +43,19 @@ SECTIONS {
.globals (NOLOAD) : { .globals (NOLOAD) : {
} > GLOBALS } > GLOBALS
.flash_begin : { .flash_begin : {
__flash_binary_start = .; __flash_binary_start = .;
} > FLASH } > FLASH
/*
.boot2 : {
__boot2_start__ = .;
KEEP (*(.boot2))
__boot2_end__ = .;
} > FLASH
ASSERT(__boot2_end__ - __boot2_start__ == 256, /* The bootrom will enter the image at the point indicated in your
"ERROR: Pico second stage bootloader must be 256 bytes in size") IMAGE_DEF, which is usually the reset handler of your vector table.
*/
/* The second stage will always enter the image at the start of .text.
The debugger will use the ELF entry point, which is the _entry_point The debugger will use the ELF entry point, which is the _entry_point
symbol if present, otherwise defaults to start of .text. symbol, and in our case is *different from the bootrom's entry point.*
This can be used to transfer control back to the bootrom on debugger This is used to go back through the bootrom on debugger launches only,
launches only, to perform proper flash setup. to perform the same initial flash setup that would be performed on a
cold boot.
*/ */
.flashtext : { .flashtext : {
@ -70,8 +63,11 @@ SECTIONS {
KEEP (*(.vectors)) KEEP (*(.vectors))
KEEP (*(.binary_info_header)) KEEP (*(.binary_info_header))
__binary_info_header_end = .; __binary_info_header_end = .;
KEEP (*(.embedded_block))
__embedded_block_end = .;
KEEP (*(.reset)) KEEP (*(.reset))
} . = ALIGN(4);
} > FLASH
.rodata : { .rodata : {
/* segments not marked as .flashdata are instead pulled into .data (in RAM) to avoid accidental flash accesses */ /* segments not marked as .flashdata are instead pulled into .data (in RAM) to avoid accidental flash accesses */
@ -79,23 +75,39 @@ SECTIONS {
. = ALIGN(4); . = ALIGN(4);
} > FLASH } > FLASH
.ARM.extab : { .ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*) *(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH } > FLASH
__exidx_start = .; __exidx_start = .;
.ARM.exidx : { .ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*) *(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH } > FLASH
__exidx_end = .; __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); . = ALIGN(4);
/* Vector table goes first in RAM, to avoid large alignment hole */ /* Vector table goes first in RAM, to avoid large alignment hole */
.ram_vector_table (COPY): { .ram_vector_table (NOLOAD): {
*(.ram_vector_table) *(.ram_vector_table)
} > RAM } > RAM
.uninitialized_data (NOLOAD): {
. = ALIGN(4);
*(.uninitialized_data*)
} > RAM
.text : { .text : {
__ram_text_start__ = .; __ram_text_start__ = .;
*(.init) *(.init)
@ -119,7 +131,7 @@ SECTIONS {
__ram_text_end__ = .; __ram_text_end__ = .;
} > RAM AT> FLASH } > RAM AT> FLASH
__ram_text_source__ = LOADADDR(.text); __ram_text_source__ = LOADADDR(.text);
. = ALIGN(4);
.data : { .data : {
__data_start__ = .; __data_start__ = .;
@ -176,6 +188,50 @@ SECTIONS {
*(.uninitialized_data*) *(.uninitialized_data*)
} > RAM } > RAM
.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 : {
. = 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 */
. = ORIGIN(RAM) + LENGTH(RAM);
__HeapLimit = .;
} > RAM
/* Start and end symbols must be word-aligned */ /* Start and end symbols must be word-aligned */
.scratch_x : { .scratch_x : {
__scratch_x_start__ = .; __scratch_x_start__ = .;
@ -193,22 +249,6 @@ SECTIONS {
} > SCRATCH_Y AT > FLASH } > SCRATCH_Y AT > FLASH
__scratch_y_source__ = LOADADDR(.scratch_y); __scratch_y_source__ = LOADADDR(.scratch_y);
.bss : {
. = ALIGN(4);
__bss_start__ = .;
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} > RAM
.heap (COPY): {
__end__ = .;
end = __end__;
*(.heap*)
__HeapLimit = .;
} > RAM
/* .stack*_dummy section doesn't contains any symbols. It is only /* .stack*_dummy section doesn't contains any symbols. It is only
* used for linker to calculate size of stack sections, and assign * used for linker to calculate size of stack sections, and assign
* values to stack symbols later * values to stack symbols later
@ -218,16 +258,19 @@ SECTIONS {
/* by default we put core 0 stack at the end of scratch Y, so that if core 1 /* 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. * stack is not used then all of SCRATCH_X is free.
*/ */
.stack1_dummy (COPY): { .stack1_dummy (NOLOAD):
{
*(.stack1*) *(.stack1*)
} > SCRATCH_X } > SCRATCH_X
.stack_dummy (COPY): { .stack_dummy (NOLOAD):
*(.stack*) {
KEEP(*(.stack*))
} > SCRATCH_Y } > SCRATCH_Y
.flash_end : { .flash_end : {
__flash_binary_end = .; KEEP(*(.embedded_end_block*))
} > FLASH PROVIDE(__flash_binary_end = .);
} > FLASH =0xaa
/* stack limit is poorly named, but historically is maximum heap ptr */ /* stack limit is poorly named, but historically is maximum heap ptr */
__StackLimit = ORIGIN(RAM) + LENGTH(RAM); __StackLimit = ORIGIN(RAM) + LENGTH(RAM);
@ -237,10 +280,23 @@ SECTIONS {
__StackBottom = __StackTop - SIZEOF(.stack_dummy); __StackBottom = __StackTop - SIZEOF(.stack_dummy);
PROVIDE(__stack = __StackTop); 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 if data + heap + stack exceeds RAM limit */ /* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
/* ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary")*/ 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 */ /* todo assert on extra code */
} }