From a493f5aec3048571eaeb5cfa699a8d07cee3fac0 Mon Sep 17 00:00:00 2001 From: Ran Bao Date: Thu, 4 Apr 2024 21:04:53 +1300 Subject: [PATCH 01/11] Limit flash region to 1M-0x100 --- .vscode/settings.json | 6 +- CMakeLists.txt | 1 + scripts/linker_scripts/initial_deployment.ld | 250 +++++++++++++++++++ src/CMakeLists.txt | 4 +- src/binary_header.c | 4 + 5 files changed, 262 insertions(+), 3 deletions(-) create mode 100644 scripts/linker_scripts/initial_deployment.ld create mode 100644 src/binary_header.c diff --git a/.vscode/settings.json b/.vscode/settings.json index ba8a705..c8b0ba7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -40,6 +40,10 @@ "cleanup_mode.h": "c", "charge_mode.h": "c", "http_rest.h": "c", - "motors.h": "c" + "motors.h": "c", + "defs.h": "c", + "code.h": "c", + "binary_info.h": "c", + "structure.h": "c" } } diff --git a/CMakeLists.txt b/CMakeLists.txt index 0aaea4b..4309eb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,6 +117,7 @@ if (PICO_BOARD STREQUAL "pico_w" ) endif() target_link_options("${TARGET_NAME}" PUBLIC -Wl,--gc-sections -Wl,--print-memory-usage) +set_target_properties("${TARGET_NAME}" PROPERTIES PICO_TARGET_LINKER_SCRIPT ${SCRIPTS_DIRECTORY}/linker_scripts/initial_deployment.ld) # set( CMAKE_VERBOSE_MAKEFILE on ) # Generate extra outputs diff --git a/scripts/linker_scripts/initial_deployment.ld b/scripts/linker_scripts/initial_deployment.ld new file mode 100644 index 0000000..3c3427b --- /dev/null +++ b/scripts/linker_scripts/initial_deployment.ld @@ -0,0 +1,250 @@ +/* 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_BL(rx) : ORIGIN = 0x10000000, LENGTH = 0x100 + FLASH(rx) : ORIGIN = 0x10000100, LENGTH = 1024k - 0x100 + RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k + SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k + SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k +} + +ENTRY(_entry_point) + +SECTIONS +{ + /* 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 + in the Raspberry Pi Pico SDK + */ + .boot2 : { + __boot2_start__ = .; + KEEP (*(.boot2)) + __boot2_end__ = .; + } > FLASH_BL + + ASSERT(__boot2_end__ - __boot2_start__ == 256, + "ERROR: Pico second stage bootloader must be 256 bytes in size") + + /* 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 + symbol if present, otherwise defaults to start of .text. + This can be used to transfer control back to the bootrom on debugger + launches only, to perform proper flash setup. + */ + + .flash_begin : { + __flash_binary_start = .; + } > FLASH + + .text : { + __logical_binary_start = .; + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_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) + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .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) + + *(.eh_frame*) + . = ALIGN(4); + } > FLASH + + .rodata : { + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) + . = 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 + + .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*) + + . = 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 = .); + + . = 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 = .); + + *(.jcr) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + } > RAM AT> FLASH + /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ + __etext = LOADADDR(.data); + + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > 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); + + .bss : { + . = ALIGN(4); + __bss_start__ = .; + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (NOLOAD): + { + __end__ = .; + end = __end__; + KEEP(*(.heap*)) + __HeapLimit = .; + } > RAM + + /* .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 : { + PROVIDE(__flash_binary_end = .); + } > FLASH + + /* stack limit is poorly named, but historically is maximum heap ptr */ + __StackLimit = ORIGIN(RAM) + LENGTH(RAM); + __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); + __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); + __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); + __StackBottom = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* Check if data + heap + stack exceeds RAM limit */ + 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") + /* todo assert on extra code */ +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 63f78eb..fe03347 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ # Generate PIO headers -pico_generate_pio_header(app ${SRC_DIRECTORY}/ws2812.pio OUTPUT_DIR ${SRC_DIRECTORY}/generated) +pico_generate_pio_header(${TARGET_NAME} ${SRC_DIRECTORY}/ws2812.pio OUTPUT_DIR ${SRC_DIRECTORY}/generated) # Generate PIO headers -pico_generate_pio_header(app ${SRC_DIRECTORY}/stepper.pio OUTPUT_DIR ${SRC_DIRECTORY}/generated) +pico_generate_pio_header(${TARGET_NAME} ${SRC_DIRECTORY}/stepper.pio OUTPUT_DIR ${SRC_DIRECTORY}/generated) # Find Python, as Python is required to convert pages into source find_package (Python COMPONENTS Interpreter REQUIRED) diff --git a/src/binary_header.c b/src/binary_header.c new file mode 100644 index 0000000..267d863 --- /dev/null +++ b/src/binary_header.c @@ -0,0 +1,4 @@ +#include +#include + +bi_decl(bi_program_description("APP1")) From 7301d24ebe2d42d613798a00239c2860262f4bba Mon Sep 17 00:00:00 2001 From: Ran Bao Date: Thu, 4 Apr 2024 21:58:44 +1300 Subject: [PATCH 02/11] disable binary header --- CMakeLists.txt | 2 ++ src/binary_header.c | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4309eb5..379c145 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,8 @@ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdata-sections -ffunction-sections") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdata-sections -ffunction-sections") # SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +# Add definitions +add_definitions(-DPICO_NO_BINARY_INFO) # Application add_executable("${TARGET_NAME}") diff --git a/src/binary_header.c b/src/binary_header.c index 267d863..3024c2b 100644 --- a/src/binary_header.c +++ b/src/binary_header.c @@ -1,4 +1,5 @@ #include -#include -bi_decl(bi_program_description("APP1")) +typedef struct { + +} binary_header_t; \ No newline at end of file From f81c21b1387bf970cd7444420cb1cd8ce54daa8d Mon Sep 17 00:00:00 2001 From: Ran Bao Date: Thu, 4 Apr 2024 23:01:24 +1300 Subject: [PATCH 03/11] Refactor CMakeFile to build 3 targets --- .vscode/settings.json | 3 +- CMakeLists.txt | 105 +++++--- scripts/linker_scripts/bank0.ld | 262 +++++++++++++++++++ scripts/linker_scripts/bank1.ld | 262 +++++++++++++++++++ scripts/linker_scripts/initial_deployment.ld | 7 + src/CMakeLists.txt | 10 +- 6 files changed, 607 insertions(+), 42 deletions(-) create mode 100644 scripts/linker_scripts/bank0.ld create mode 100644 scripts/linker_scripts/bank1.ld diff --git a/.vscode/settings.json b/.vscode/settings.json index c8b0ba7..e5a2696 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -44,6 +44,7 @@ "defs.h": "c", "code.h": "c", "binary_info.h": "c", - "structure.h": "c" + "structure.h": "c", + "stepper.pio.h": "c" } } diff --git a/CMakeLists.txt b/CMakeLists.txt index da30cad..1e6dd81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 3.25) # Set project data set(PROJECT_NAME "OpenTricklerController") -set(TARGET_NAME "app") message("CMAKE_SOURCE_DIR: ${CMAKE_SOURCE_DIR}") @@ -46,12 +45,6 @@ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdata-sections -ffunction-sections -Wa # Add definitions add_definitions(-DPICO_NO_BINARY_INFO) -# Application -add_executable("${TARGET_NAME}") - -# Include source -include_directories(${SRC_DIRECTORY}) - # Pull in FreeRTOS include(${FREERTOS_SRC_DIRECTORY}/portable/ThirdParty/GCC/RP2040/FreeRTOS_Kernel_import.cmake) @@ -69,8 +62,6 @@ target_sources(trinamic INTERFACE ) target_include_directories(trinamic INTERFACE ${TMC_SRC_DIRECTORY}) - - # Pull in u8g2 mui add_library(u8g2_mui ${U8G2_MUI_DIRECTORY}/mui_u8g2.c @@ -80,47 +71,89 @@ add_library(u8g2_mui ) target_link_libraries(u8g2_mui u8g2) -# Pull in src -add_subdirectory(${SRC_DIRECTORY}) - # Collect all source files file(GLOB SRC ${SRC_DIRECTORY}/*.c ${SRC_DIRECTORY}/*.cpp) -# Include application source file -target_sources("${TARGET_NAME}" PUBLIC + +# Pull in source code as library +add_library(app_base ${SRC} ) - -# Include additional headers -target_include_directories("${TARGET_NAME}" PUBLIC ${CMAKE_SOURCE_DIR}/targets) - -# Include libraries1 -target_link_libraries("${TARGET_NAME}" - pico_stdlib - hardware_pio - hardware_spi - hardware_i2c +target_include_directories(app_base PUBLIC + ${SRC_DIRECTORY} + ${SRC_DIRECTORY}/generated + ${PICO_BOARD_HEADER_DIRS} +) +target_link_libraries(app_base FreeRTOS-Kernel FreeRTOS-Kernel-Heap4 u8g2 u8g2_mui trinamic + pico_stdlib + hardware_pio + hardware_spi + hardware_i2c + pico_cyw43_arch_lwip_sys_freertos + pico_lwip_freertos +) + +# Pull in src to generate extra files +add_subdirectory(${SRC_DIRECTORY}) + +# #################################################### +# Build Deployment Application # +###################################################### +add_executable(initial_deployment) + +# Include libraries1 +target_link_libraries(initial_deployment + app_base + app_version +) + +target_link_options(initial_deployment PUBLIC -Wl,--gc-sections -Wl,--print-memory-usage) +set_target_properties(initial_deployment PROPERTIES PICO_TARGET_LINKER_SCRIPT ${SCRIPTS_DIRECTORY}/linker_scripts/initial_deployment.ld) +# set( CMAKE_VERBOSE_MAKEFILE on ) + +# Generate extra outputs +pico_add_extra_outputs(initial_deployment) + + +# #################################################### +# Build Bank0 Application # +###################################################### +add_executable(fw_bank0) + +# Include libraries1 +target_link_libraries(fw_bank0 + app_base + app_version +) + +target_link_options(fw_bank0 PUBLIC -Wl,--gc-sections -Wl,--print-memory-usage) +set_target_properties(fw_bank0 PROPERTIES PICO_TARGET_LINKER_SCRIPT ${SCRIPTS_DIRECTORY}/linker_scripts/bank0.ld) +# set( CMAKE_VERBOSE_MAKEFILE on ) + +# Generate extra outputs +pico_add_extra_outputs(fw_bank0) + + +# #################################################### +# Build Bank1 Application # +###################################################### +add_executable(fw_bank1) + +# Include libraries1 +target_link_libraries(fw_bank1 + app_base app_version ) -if (PICO_BOARD STREQUAL "pico_w" ) - message("Using PICO_W board, link cyw43") - target_link_libraries("${TARGET_NAME}" - pico_cyw43_arch_lwip_sys_freertos - pico_lwip_freertos - # pico_lwip_http - ) -endif() - -target_link_options("${TARGET_NAME}" PUBLIC -Wl,--gc-sections -Wl,--print-memory-usage) -set_target_properties("${TARGET_NAME}" PROPERTIES PICO_TARGET_LINKER_SCRIPT ${SCRIPTS_DIRECTORY}/linker_scripts/initial_deployment.ld) +target_link_options(fw_bank1 PUBLIC -Wl,--gc-sections -Wl,--print-memory-usage) +set_target_properties(fw_bank1 PROPERTIES PICO_TARGET_LINKER_SCRIPT ${SCRIPTS_DIRECTORY}/linker_scripts/bank1.ld) # set( CMAKE_VERBOSE_MAKEFILE on ) # Generate extra outputs -pico_add_extra_outputs("${TARGET_NAME}") +pico_add_extra_outputs(fw_bank1) diff --git a/scripts/linker_scripts/bank0.ld b/scripts/linker_scripts/bank0.ld new file mode 100644 index 0000000..929b97f --- /dev/null +++ b/scripts/linker_scripts/bank0.ld @@ -0,0 +1,262 @@ +/* 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_BL(rx) : ORIGIN = 0x10000000, LENGTH = 0x100 + FLASH(rx) : ORIGIN = 0x10000100, LENGTH = 1024k - 0x100 + RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k + SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k + SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k +} + +ENTRY(_entry_point) + +SECTIONS +{ + /* + * BS2 is removed from the deployment package * + + 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 + in the Raspberry Pi Pico SDK + + .boot2 : { + __boot2_start__ = .; + KEEP (*(.boot2)) + __boot2_end__ = .; + } > FLASH_BL + + ASSERT(__boot2_end__ - __boot2_start__ == 256, + "ERROR: Pico second stage bootloader must be 256 bytes in size") + + */ + + /* 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 + symbol if present, otherwise defaults to start of .text. + This can be used to transfer control back to the bootrom on debugger + launches only, to perform proper flash setup. + */ + + .flash_begin : { + __flash_binary_start = .; + } > FLASH + + .text : { + __logical_binary_start = .; + KEEP (*(.vectors)) + + /* Remove binary info header + KEEP (*(.binary_info_header)) + __binary_info_header_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) + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .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) + + *(.eh_frame*) + . = ALIGN(4); + } > FLASH + + .rodata : { + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) + . = 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 + + .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*) + + . = 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 = .); + + . = 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 = .); + + *(.jcr) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + } > RAM AT> FLASH + /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ + __etext = LOADADDR(.data); + + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > 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); + + .bss : { + . = ALIGN(4); + __bss_start__ = .; + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (NOLOAD): + { + __end__ = .; + end = __end__; + KEEP(*(.heap*)) + __HeapLimit = .; + } > RAM + + /* .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 : { + PROVIDE(__flash_binary_end = .); + } > FLASH + + /* stack limit is poorly named, but historically is maximum heap ptr */ + __StackLimit = ORIGIN(RAM) + LENGTH(RAM); + __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); + __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); + __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); + __StackBottom = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") + + /* Remove binary info header + ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary") + */ + + /* todo assert on extra code */ +} diff --git a/scripts/linker_scripts/bank1.ld b/scripts/linker_scripts/bank1.ld new file mode 100644 index 0000000..7abb049 --- /dev/null +++ b/scripts/linker_scripts/bank1.ld @@ -0,0 +1,262 @@ +/* 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_BL(rx) : ORIGIN = 0x10000000, LENGTH = 0x100 + FLASH(rx) : ORIGIN = 0x10000000 + 1024k, LENGTH = 1024k - 0x100 + RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k + SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k + SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k +} + +ENTRY(_entry_point) + +SECTIONS +{ + /* + * BS2 is removed from the deployment package * + + 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 + in the Raspberry Pi Pico SDK + + .boot2 : { + __boot2_start__ = .; + KEEP (*(.boot2)) + __boot2_end__ = .; + } > FLASH_BL + + ASSERT(__boot2_end__ - __boot2_start__ == 256, + "ERROR: Pico second stage bootloader must be 256 bytes in size") + + */ + + /* 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 + symbol if present, otherwise defaults to start of .text. + This can be used to transfer control back to the bootrom on debugger + launches only, to perform proper flash setup. + */ + + .flash_begin : { + __flash_binary_start = .; + } > FLASH + + .text : { + __logical_binary_start = .; + KEEP (*(.vectors)) + + /* Remove binary info header + KEEP (*(.binary_info_header)) + __binary_info_header_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) + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .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) + + *(.eh_frame*) + . = ALIGN(4); + } > FLASH + + .rodata : { + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) + . = 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 + + .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*) + + . = 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 = .); + + . = 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 = .); + + *(.jcr) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + } > RAM AT> FLASH + /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ + __etext = LOADADDR(.data); + + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > 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); + + .bss : { + . = ALIGN(4); + __bss_start__ = .; + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (NOLOAD): + { + __end__ = .; + end = __end__; + KEEP(*(.heap*)) + __HeapLimit = .; + } > RAM + + /* .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 : { + PROVIDE(__flash_binary_end = .); + } > FLASH + + /* stack limit is poorly named, but historically is maximum heap ptr */ + __StackLimit = ORIGIN(RAM) + LENGTH(RAM); + __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); + __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); + __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); + __StackBottom = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") + + /* Remove binary info header + ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary") + */ + + /* todo assert on extra code */ +} diff --git a/scripts/linker_scripts/initial_deployment.ld b/scripts/linker_scripts/initial_deployment.ld index 3c3427b..7c4e34c 100644 --- a/scripts/linker_scripts/initial_deployment.ld +++ b/scripts/linker_scripts/initial_deployment.ld @@ -61,8 +61,12 @@ SECTIONS .text : { __logical_binary_start = .; KEEP (*(.vectors)) + + /* Remove binary info header KEEP (*(.binary_info_header)) __binary_info_header_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 @@ -245,6 +249,9 @@ SECTIONS /* Check if data + heap + stack exceeds RAM limit */ ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") + /* Remove binary info header ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary") + */ + /* todo assert on extra code */ } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fe03347..7bd4503 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ # Generate PIO headers -pico_generate_pio_header(${TARGET_NAME} ${SRC_DIRECTORY}/ws2812.pio OUTPUT_DIR ${SRC_DIRECTORY}/generated) +pico_generate_pio_header(app_base ${SRC_DIRECTORY}/ws2812.pio OUTPUT_DIR ${SRC_DIRECTORY}/generated) # Generate PIO headers -pico_generate_pio_header(${TARGET_NAME} ${SRC_DIRECTORY}/stepper.pio OUTPUT_DIR ${SRC_DIRECTORY}/generated) +pico_generate_pio_header(app_base ${SRC_DIRECTORY}/stepper.pio OUTPUT_DIR ${SRC_DIRECTORY}/generated) # Find Python, as Python is required to convert pages into source find_package (Python COMPONENTS Interpreter REQUIRED) @@ -22,7 +22,7 @@ add_custom_command( COMMENT "Generating web_portal.html header" ) -add_dependencies("${TARGET_NAME}" generate_web_portal_header) +add_dependencies(app_base generate_web_portal_header) # wizard.html @@ -38,7 +38,7 @@ add_custom_command( COMMENT "Generating wizard.html header" ) -add_dependencies("${TARGET_NAME}" generate_wizard_header) +add_dependencies(app_base generate_wizard_header) # display_mirror.html @@ -54,7 +54,7 @@ add_custom_command( COMMENT "Generating display_mirror.html header" ) -add_dependencies("${TARGET_NAME}" generate_display_mirror) +add_dependencies(app_base generate_display_mirror) # Generate version From 6a82a1f1c606fee7740a28f1c6fea5e1e38c3d46 Mon Sep 17 00:00:00 2001 From: Ran Bao Date: Thu, 4 Apr 2024 23:06:43 +1300 Subject: [PATCH 04/11] Fix dependency --- CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e6dd81..622d9cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,6 +97,7 @@ target_link_libraries(app_base hardware_i2c pico_cyw43_arch_lwip_sys_freertos pico_lwip_freertos + app_version ) # Pull in src to generate extra files @@ -110,7 +111,6 @@ add_executable(initial_deployment) # Include libraries1 target_link_libraries(initial_deployment app_base - app_version ) target_link_options(initial_deployment PUBLIC -Wl,--gc-sections -Wl,--print-memory-usage) @@ -129,7 +129,6 @@ add_executable(fw_bank0) # Include libraries1 target_link_libraries(fw_bank0 app_base - app_version ) target_link_options(fw_bank0 PUBLIC -Wl,--gc-sections -Wl,--print-memory-usage) @@ -148,7 +147,6 @@ add_executable(fw_bank1) # Include libraries1 target_link_libraries(fw_bank1 app_base - app_version ) target_link_options(fw_bank1 PUBLIC -Wl,--gc-sections -Wl,--print-memory-usage) From e1fb84bd5cbc68d7f4cd33a32b85d0d4957458fd Mon Sep 17 00:00:00 2001 From: Ran Bao Date: Tue, 9 Apr 2024 20:59:50 +1200 Subject: [PATCH 05/11] Minor update --- scripts/linker_scripts/bank0.ld | 2 +- scripts/linker_scripts/bank1.ld | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/linker_scripts/bank0.ld b/scripts/linker_scripts/bank0.ld index 929b97f..bdbef11 100644 --- a/scripts/linker_scripts/bank0.ld +++ b/scripts/linker_scripts/bank0.ld @@ -24,7 +24,7 @@ MEMORY { FLASH_BL(rx) : ORIGIN = 0x10000000, LENGTH = 0x100 - FLASH(rx) : ORIGIN = 0x10000100, LENGTH = 1024k - 0x100 + FLASH(rx) : ORIGIN = 0x10000100, LENGTH = 1M - 0x100 RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k diff --git a/scripts/linker_scripts/bank1.ld b/scripts/linker_scripts/bank1.ld index 7abb049..2108213 100644 --- a/scripts/linker_scripts/bank1.ld +++ b/scripts/linker_scripts/bank1.ld @@ -24,7 +24,7 @@ MEMORY { FLASH_BL(rx) : ORIGIN = 0x10000000, LENGTH = 0x100 - FLASH(rx) : ORIGIN = 0x10000000 + 1024k, LENGTH = 1024k - 0x100 + FLASH(rx) : ORIGIN = 0x10000000 + 1M, LENGTH = 1M - 0x100 RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k From 68b033cdb633ced07aef4e1bb306f31204a00111 Mon Sep 17 00:00:00 2001 From: Ran Bao Date: Tue, 9 Apr 2024 23:41:38 +1200 Subject: [PATCH 06/11] Add concept for the app header --- .vscode/settings.json | 3 ++- CMakeLists.txt | 6 +++--- scripts/linker_scripts/bank0.ld | 15 +++++++++++--- scripts/linker_scripts/bank1.ld | 15 +++++++++++--- scripts/linker_scripts/initial_deployment.ld | 17 ++++++++++++---- src/app_header.c | 21 ++++++++++++++++++++ src/app_header.h | 19 ++++++++++++++++++ src/binary_header.c | 5 ----- src/eeprom.c | 5 ++++- 9 files changed, 86 insertions(+), 20 deletions(-) create mode 100644 src/app_header.c create mode 100644 src/app_header.h delete mode 100644 src/binary_header.c diff --git a/.vscode/settings.json b/.vscode/settings.json index e5a2696..6a009d4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -45,6 +45,7 @@ "code.h": "c", "binary_info.h": "c", "structure.h": "c", - "stepper.pio.h": "c" + "stepper.pio.h": "c", + "app_header.h": "c" } } diff --git a/CMakeLists.txt b/CMakeLists.txt index 622d9cf..71f4e4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,10 +40,10 @@ set(PICO_BOARD_HEADER_DIRS "${CMAKE_SOURCE_DIR}/targets") # Append compiler flags SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdata-sections -ffunction-sections -Wall -Werror") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdata-sections -ffunction-sections -Wall -Werror") -# SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + # Add definitions -add_definitions(-DPICO_NO_BINARY_INFO) +add_definitions(-DPICO_NO_BINARY_INFO) # remove binary info from pico-sdk. We will implement our own # Pull in FreeRTOS include(${FREERTOS_SRC_DIRECTORY}/portable/ThirdParty/GCC/RP2040/FreeRTOS_Kernel_import.cmake) @@ -151,7 +151,7 @@ target_link_libraries(fw_bank1 target_link_options(fw_bank1 PUBLIC -Wl,--gc-sections -Wl,--print-memory-usage) set_target_properties(fw_bank1 PROPERTIES PICO_TARGET_LINKER_SCRIPT ${SCRIPTS_DIRECTORY}/linker_scripts/bank1.ld) -# set( CMAKE_VERBOSE_MAKEFILE on ) + # Generate extra outputs pico_add_extra_outputs(fw_bank1) diff --git a/scripts/linker_scripts/bank0.ld b/scripts/linker_scripts/bank0.ld index bdbef11..7adfd7a 100644 --- a/scripts/linker_scripts/bank0.ld +++ b/scripts/linker_scripts/bank0.ld @@ -23,8 +23,9 @@ MEMORY { - FLASH_BL(rx) : ORIGIN = 0x10000000, LENGTH = 0x100 - FLASH(rx) : ORIGIN = 0x10000100, LENGTH = 1M - 0x100 + FLASH_BOOT2(rx) : ORIGIN = 0x10000000, LENGTH = 0x100 + FLASH(rx) : ORIGIN = 0x10000100, LENGTH = 1M - 0x100 - 0x100 + FLASH_APP_HEADER (r): ORIGIN = 0x10100000 - 0x100, LENGTH = 0x100 RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k @@ -45,7 +46,7 @@ SECTIONS __boot2_start__ = .; KEEP (*(.boot2)) __boot2_end__ = .; - } > FLASH_BL + } > FLASH_BOOT2 ASSERT(__boot2_end__ - __boot2_start__ == 256, "ERROR: Pico second stage bootloader must be 256 bytes in size") @@ -59,6 +60,14 @@ SECTIONS launches only, to perform proper flash setup. */ + .app_header_section : { + __app_header_start = .; + KEEP (*(.app_header)) + __app_header_end = .; + } > FLASH_APP_HEADER + ASSERT(__app_header_end - __app_header_start < 0x100, + "ERROR: App header must be smaller than 0x100 bytes") + .flash_begin : { __flash_binary_start = .; } > FLASH diff --git a/scripts/linker_scripts/bank1.ld b/scripts/linker_scripts/bank1.ld index 2108213..d1201da 100644 --- a/scripts/linker_scripts/bank1.ld +++ b/scripts/linker_scripts/bank1.ld @@ -23,8 +23,9 @@ MEMORY { - FLASH_BL(rx) : ORIGIN = 0x10000000, LENGTH = 0x100 - FLASH(rx) : ORIGIN = 0x10000000 + 1M, LENGTH = 1M - 0x100 + FLASH_BOOT2(rx) : ORIGIN = 0x10000000, LENGTH = 0x100 + FLASH(rx) : ORIGIN = 0x10100000, LENGTH = 1M - 0x100 - 0x100 + FLASH_APP_HEADER (r): ORIGIN = 0x10200000 - 0x100 - 0x100, LENGTH = 0x100 RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k @@ -45,7 +46,7 @@ SECTIONS __boot2_start__ = .; KEEP (*(.boot2)) __boot2_end__ = .; - } > FLASH_BL + } > FLASH_BOOT2 ASSERT(__boot2_end__ - __boot2_start__ == 256, "ERROR: Pico second stage bootloader must be 256 bytes in size") @@ -59,6 +60,14 @@ SECTIONS launches only, to perform proper flash setup. */ + .app_header_section : { + __app_header_start = .; + KEEP (*(.app_header)) + __app_header_end = .; + } > FLASH_APP_HEADER + ASSERT(__app_header_end - __app_header_start < 0x100, + "ERROR: App header must be smaller than 0x100 bytes") + .flash_begin : { __flash_binary_start = .; } > FLASH diff --git a/scripts/linker_scripts/initial_deployment.ld b/scripts/linker_scripts/initial_deployment.ld index 7c4e34c..1fdee04 100644 --- a/scripts/linker_scripts/initial_deployment.ld +++ b/scripts/linker_scripts/initial_deployment.ld @@ -23,8 +23,9 @@ MEMORY { - FLASH_BL(rx) : ORIGIN = 0x10000000, LENGTH = 0x100 - FLASH(rx) : ORIGIN = 0x10000100, LENGTH = 1024k - 0x100 + FLASH_BOOT2(rx) : ORIGIN = 0x10000000, LENGTH = 0x100 + FLASH(rx) : ORIGIN = 0x10000100, LENGTH = 1M - 0x100 - 0x100 + FLASH_APP_HEADER (r): ORIGIN = 0x10100000 - 0x100, LENGTH = 0x100 RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k @@ -42,7 +43,7 @@ SECTIONS __boot2_start__ = .; KEEP (*(.boot2)) __boot2_end__ = .; - } > FLASH_BL + } > FLASH_BOOT2 ASSERT(__boot2_end__ - __boot2_start__ == 256, "ERROR: Pico second stage bootloader must be 256 bytes in size") @@ -54,6 +55,14 @@ SECTIONS launches only, to perform proper flash setup. */ + .app_header_section : { + __app_header_start = .; + KEEP (*(.app_header)) + __app_header_end = .; + } > FLASH_APP_HEADER + ASSERT(__app_header_end - __app_header_start < 0x100, + "ERROR: App header must be smaller than 0x100 bytes") + .flash_begin : { __flash_binary_start = .; } > FLASH @@ -252,6 +261,6 @@ SECTIONS /* Remove binary info header ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary") */ - + /* todo assert on extra code */ } diff --git a/src/app_header.c b/src/app_header.c new file mode 100644 index 0000000..ae51e9d --- /dev/null +++ b/src/app_header.c @@ -0,0 +1,21 @@ +#include "app_header.h" + +#ifdef __cplusplus + extern "C" + { +#endif + +__attribute__ ((section (".app_header"))) +__attribute__ ((used)) +const app_header_t __app_header = { + .app_header_rev = 1, + .flash_partition_idx = 0, + .vcs_hash = "0x12345", + .build_type = "Debug", + .firmware_version = "1.2.3-dirty", +}; + + +#ifdef __cplusplus + } +#endif \ No newline at end of file diff --git a/src/app_header.h b/src/app_header.h new file mode 100644 index 0000000..dc57a5a --- /dev/null +++ b/src/app_header.h @@ -0,0 +1,19 @@ +#ifndef APP_HEADER_H_ +#define APP_HEADER_H_ + +#include + +typedef struct { + uint32_t app_header_rev; + uint32_t flash_partition_idx; + char vcs_hash[16]; + char build_type[16]; + char firmware_version[32]; + +} app_header_t; + + +extern app_header_t * __app_header_start; + + +#endif // APP_HEADER_H_ diff --git a/src/binary_header.c b/src/binary_header.c deleted file mode 100644 index 3024c2b..0000000 --- a/src/binary_header.c +++ /dev/null @@ -1,5 +0,0 @@ -#include - -typedef struct { - -} binary_header_t; \ No newline at end of file diff --git a/src/eeprom.c b/src/eeprom.c index b8867ef..c2c93cc 100644 --- a/src/eeprom.c +++ b/src/eeprom.c @@ -21,6 +21,9 @@ #include "rotary_button.h" #include "version.h" #include "profile.h" +#include "app_header.h" + +extern const app_header_t __app_header; extern bool cat24c256_eeprom_erase(); @@ -233,7 +236,7 @@ bool http_rest_system_control(struct fs_file *file, int num_params, char *params "%s" "{\"s0\":\"%s\",\"s1\":\"%s\",\"s2\":\"%s\",\"s3\":\"%s\",\"s4\":%s,\"s5\":%s,\"s6\":%s}", http_json_header, - metadata.unique_id, version_string, vcs_hash, build_type, + metadata.unique_id, __app_header.firmware_version, __app_header.vcs_hash, __app_header.build_type, boolean_to_string(save_to_eeprom_flag), boolean_to_string(erase_eeprom_flag), boolean_to_string(software_reset_flag)); From 20f5d0d6889108f8f465d6b4ebbbf276646fc1f9 Mon Sep 17 00:00:00 2001 From: Ran Bao Date: Wed, 10 Apr 2024 22:16:53 +1200 Subject: [PATCH 07/11] Combine the application header with version string --- CMakeLists.txt | 4 +- scripts/gen_app_header.py | 108 ++++++++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 27 +++++++--- src/app_header.c | 21 -------- src/app_header.h | 10 +++- src/eeprom.c | 5 +- src/mui_menu.c | 12 ++--- 7 files changed, 149 insertions(+), 38 deletions(-) create mode 100644 scripts/gen_app_header.py delete mode 100644 src/app_header.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 71f4e4f..f6ddb8e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,7 +97,6 @@ target_link_libraries(app_base hardware_i2c pico_cyw43_arch_lwip_sys_freertos pico_lwip_freertos - app_version ) # Pull in src to generate extra files @@ -111,6 +110,7 @@ add_executable(initial_deployment) # Include libraries1 target_link_libraries(initial_deployment app_base + app_version_0 ) target_link_options(initial_deployment PUBLIC -Wl,--gc-sections -Wl,--print-memory-usage) @@ -129,6 +129,7 @@ add_executable(fw_bank0) # Include libraries1 target_link_libraries(fw_bank0 app_base + app_version_0 ) target_link_options(fw_bank0 PUBLIC -Wl,--gc-sections -Wl,--print-memory-usage) @@ -147,6 +148,7 @@ add_executable(fw_bank1) # Include libraries1 target_link_libraries(fw_bank1 app_base + app_version_1 ) target_link_options(fw_bank1 PUBLIC -Wl,--gc-sections -Wl,--print-memory-usage) diff --git a/scripts/gen_app_header.py b/scripts/gen_app_header.py new file mode 100644 index 0000000..30936df --- /dev/null +++ b/scripts/gen_app_header.py @@ -0,0 +1,108 @@ +import argparse +import logging +import subprocess +import sys +import re +import os + + +GIT_VERSION_COMMAND = ["git", "describe", "--tags", "--long", "--dirty", "--always"] + +GIT_VERSION_PATTERN_REGEX = r'v(?P\d+)\.(?P\d+)-(?P\d+)-g(?P[a-f0-9]+)(?P-dirty)?' + + +C_SOURCE_TEMPLATE = """// ---------------------------------------------------------------------- // +// This file is auto-generated by gen_application_header.py; do not edit! // +// ---------------------------------------------------------------------- // + +#include "app_header.h" + +#ifdef __cplusplus +extern "C" +{{ +#endif + +__attribute__ ((section (".app_header"))) +__attribute__ ((used)) +const app_header_t __app_header = {{ + .app_header_rev = {app_header_rev}, + .flash_partition_idx = {flash_partition_idx}, + .vcs_hash = "{vcs_hash}", + .build_type = "{build_type}", + .firmware_version = "{firmware_version}", +}}; + + +const app_header_t * get_app_header(void) +{{ + return &__app_header; +}} + + +#ifdef __cplusplus +}} +#endif +""" + + +def main(output_path, build_type, flash_partition_idx): + output = subprocess.check_output(GIT_VERSION_COMMAND, text=True) + + logging.debug(f'Raw output: {output}') + match = re.match(GIT_VERSION_PATTERN_REGEX, output) + + version_string = "unknown" + hash_string = "" + + if match: + groupdict = match.groupdict() + + major = groupdict['major'] + minor = groupdict['minor'] + patch = groupdict['patch'] + short_hash = groupdict['short_hash'] + dirty = groupdict['dirty'] + + dirty_string = "" + if dirty: # In case the dirty is None + dirty_string = dirty + + version_string = f"{major}.{minor}.{patch}{dirty_string}" + hash_string = short_hash + + c_source_string = C_SOURCE_TEMPLATE.format( + app_header_rev=1, + flash_partition_idx=flash_partition_idx, + vcs_hash=hash_string, + build_type=build_type, + firmware_version=version_string, + ) + + c_source_filepath = os.path.join(output_path, f"app_header_{flash_partition_idx}.c") + with open(c_source_filepath, "w") as fp: + logging.debug(f"Write to {c_source_filepath}") + fp.write(c_source_string) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + + parser.add_argument('-o', '--output_filepath', help="The output filepath that the C source will be written to", required=True) + parser.add_argument('--build-type', help="CMake build type", required=True) + parser.add_argument('--flash-partition-idx', help="Flash partition index, it could be either 0 or 1", required=True) + + parser.add_argument('-v', '--verbose', action='count', default=0) + + + args = parser.parse_args() + + logging_levels = {0: logging.ERROR, + 1: logging.DEBUG, + 2: logging.INFO, + 3: logging.WARNING, + 4: logging.ERROR, + 5: logging.CRITICAL} + + logging.basicConfig(stream=sys.stdout, level=logging_levels[args.verbose]) + + main(args.output_filepath, args.build_type, args.flash_partition_idx) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7bd4503..e6017ae 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,7 @@ pico_generate_pio_header(app_base ${SRC_DIRECTORY}/stepper.pio OUTPUT_DIR ${SRC_ # Find Python, as Python is required to convert pages into source find_package (Python COMPONENTS Interpreter REQUIRED) +MESSAGE("Python_EXECUTABLE: ${Python_EXECUTABLE}") # Generate HTML header # Reference: https://cliutils.gitlab.io/modern-cmake/chapters/basics/programs.html @@ -57,14 +58,26 @@ add_custom_command( add_dependencies(app_base generate_display_mirror) -# Generate version -MESSAGE("Python_EXECUTABLE: ${Python_EXECUTABLE}") +# Generate two app headers. The target will select the one to linked against +add_custom_command( + OUTPUT + "${SRC_DIRECTORY}/generated/app_header_0.c" + "non_exist_file0" + COMMAND "${Python_EXECUTABLE}" "${SCRIPTS_DIRECTORY}/gen_app_header.py" -o ${SRC_DIRECTORY}/generated --build-type="${CMAKE_BUILD_TYPE}" --flash-partition-idx=0 + COMMENT "Generating version" +) +add_library(app_version_0 INTERFACE) +target_include_directories(app_version_0 INTERFACE ${SRC_DIRECTORY}) +target_sources(app_version_0 INTERFACE "${SRC_DIRECTORY}/generated/app_header_0.c") + + add_custom_command( OUTPUT - "${SRC_DIRECTORY}/generated/version.c" - "${SRC_DIRECTORY}/generated/version.h" - "non_exist_file" - COMMAND "${Python_EXECUTABLE}" "${SCRIPTS_DIRECTORY}/gen_version.py" -o ${SRC_DIRECTORY}/generated --build-type="${CMAKE_BUILD_TYPE}" + "${SRC_DIRECTORY}/generated/app_header_1.c" + "non_exist_file1" + COMMAND "${Python_EXECUTABLE}" "${SCRIPTS_DIRECTORY}/gen_app_header.py" -o ${SRC_DIRECTORY}/generated --build-type="${CMAKE_BUILD_TYPE}" --flash-partition-idx=1 COMMENT "Generating version" ) -add_library(app_version "${SRC_DIRECTORY}/generated/version.c") +add_library(app_version_1 INTERFACE) +target_include_directories(app_version_1 INTERFACE ${SRC_DIRECTORY}) +target_sources(app_version_1 INTERFACE "${SRC_DIRECTORY}/generated/app_header_0.c") diff --git a/src/app_header.c b/src/app_header.c deleted file mode 100644 index ae51e9d..0000000 --- a/src/app_header.c +++ /dev/null @@ -1,21 +0,0 @@ -#include "app_header.h" - -#ifdef __cplusplus - extern "C" - { -#endif - -__attribute__ ((section (".app_header"))) -__attribute__ ((used)) -const app_header_t __app_header = { - .app_header_rev = 1, - .flash_partition_idx = 0, - .vcs_hash = "0x12345", - .build_type = "Debug", - .firmware_version = "1.2.3-dirty", -}; - - -#ifdef __cplusplus - } -#endif \ No newline at end of file diff --git a/src/app_header.h b/src/app_header.h index dc57a5a..ec38f77 100644 --- a/src/app_header.h +++ b/src/app_header.h @@ -12,8 +12,16 @@ typedef struct { } app_header_t; +#ifdef __cplusplus +extern "C" +{ +#endif -extern app_header_t * __app_header_start; +const app_header_t * get_app_header(); + +#ifdef __cplusplus +} +#endif #endif // APP_HEADER_H_ diff --git a/src/eeprom.c b/src/eeprom.c index c2c93cc..91d0a9c 100644 --- a/src/eeprom.c +++ b/src/eeprom.c @@ -19,7 +19,6 @@ #include "app.h" #include "neopixel_led.h" #include "rotary_button.h" -#include "version.h" #include "profile.h" #include "app_header.h" @@ -231,12 +230,14 @@ bool http_rest_system_control(struct fs_file *file, int num_params, char *params } // Response + const app_header_t * app_header = get_app_header(); + snprintf(eeprom_config_json_buffer, sizeof(eeprom_config_json_buffer), "%s" "{\"s0\":\"%s\",\"s1\":\"%s\",\"s2\":\"%s\",\"s3\":\"%s\",\"s4\":%s,\"s5\":%s,\"s6\":%s}", http_json_header, - metadata.unique_id, __app_header.firmware_version, __app_header.vcs_hash, __app_header.build_type, + metadata.unique_id, app_header->firmware_version, app_header->vcs_hash, app_header->build_type, boolean_to_string(save_to_eeprom_flag), boolean_to_string(erase_eeprom_flag), boolean_to_string(software_reset_flag)); diff --git a/src/mui_menu.c b/src/mui_menu.c index 5c63c99..d6cfca6 100644 --- a/src/mui_menu.c +++ b/src/mui_menu.c @@ -10,10 +10,9 @@ #include "scale.h" #include "charge_mode.h" -#include "version.h" #include "common.h" #include "profile.h" - +#include "app_header.h" extern uint8_t charge_weight_digits[]; extern AppState_t exit_state; @@ -50,21 +49,22 @@ uint8_t render_version_page(mui_t * ui, uint8_t msg) { switch (msg) { case MUIF_MSG_DRAW: { + const app_header_t * app_header = get_app_header(); u8g2_uint_t x = mui_get_x(ui); u8g2_uint_t y = mui_get_y(ui); u8g2_t *u8g2 = mui_get_U8g2(ui); - char buf[32]; + char buf[40]; u8g2_SetFont(u8g2, u8g2_font_profont11_tf); - snprintf(buf, sizeof(buf), "Ver: %s", version_string); + snprintf(buf, sizeof(buf), "Ver: %s", app_header->firmware_version); u8g2_DrawStr(u8g2, x, y, buf); - snprintf(buf, sizeof(buf), "VCS: %s", vcs_hash); + snprintf(buf, sizeof(buf), "VCS: %s", app_header->vcs_hash); u8g2_DrawStr(u8g2, x, y + 10, buf); - snprintf(buf, sizeof(buf), "Build: %s", build_type); + snprintf(buf, sizeof(buf), "Build: %s", app_header->build_type); u8g2_DrawStr(u8g2, x, y + 20, buf); break; From 0ade4eb5c93ed6c6e3600f5441f0b268054e4363 Mon Sep 17 00:00:00 2001 From: Ran Bao Date: Thu, 11 Apr 2024 23:06:03 +1200 Subject: [PATCH 08/11] Fix build failure --- CMakeLists.txt | 6 +++--- src/CMakeLists.txt | 22 ++++++++++++++-------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f6ddb8e..bf8ee26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,7 +110,7 @@ add_executable(initial_deployment) # Include libraries1 target_link_libraries(initial_deployment app_base - app_version_0 + app_header_0 ) target_link_options(initial_deployment PUBLIC -Wl,--gc-sections -Wl,--print-memory-usage) @@ -129,7 +129,7 @@ add_executable(fw_bank0) # Include libraries1 target_link_libraries(fw_bank0 app_base - app_version_0 + app_header_0 ) target_link_options(fw_bank0 PUBLIC -Wl,--gc-sections -Wl,--print-memory-usage) @@ -148,7 +148,7 @@ add_executable(fw_bank1) # Include libraries1 target_link_libraries(fw_bank1 app_base - app_version_1 + app_header_1 ) target_link_options(fw_bank1 PUBLIC -Wl,--gc-sections -Wl,--print-memory-usage) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e6017ae..3af5ed4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -64,11 +64,11 @@ add_custom_command( "${SRC_DIRECTORY}/generated/app_header_0.c" "non_exist_file0" COMMAND "${Python_EXECUTABLE}" "${SCRIPTS_DIRECTORY}/gen_app_header.py" -o ${SRC_DIRECTORY}/generated --build-type="${CMAKE_BUILD_TYPE}" --flash-partition-idx=0 - COMMENT "Generating version" + COMMENT "Generating app header 0" ) -add_library(app_version_0 INTERFACE) -target_include_directories(app_version_0 INTERFACE ${SRC_DIRECTORY}) -target_sources(app_version_0 INTERFACE "${SRC_DIRECTORY}/generated/app_header_0.c") +add_library(app_header_0) +target_include_directories(app_header_0 PRIVATE ${SRC_DIRECTORY}) +target_sources(app_header_0 PRIVATE "${SRC_DIRECTORY}/generated/app_header_0.c") add_custom_command( @@ -76,8 +76,14 @@ add_custom_command( "${SRC_DIRECTORY}/generated/app_header_1.c" "non_exist_file1" COMMAND "${Python_EXECUTABLE}" "${SCRIPTS_DIRECTORY}/gen_app_header.py" -o ${SRC_DIRECTORY}/generated --build-type="${CMAKE_BUILD_TYPE}" --flash-partition-idx=1 - COMMENT "Generating version" + COMMENT "Generating app header 1" ) -add_library(app_version_1 INTERFACE) -target_include_directories(app_version_1 INTERFACE ${SRC_DIRECTORY}) -target_sources(app_version_1 INTERFACE "${SRC_DIRECTORY}/generated/app_header_0.c") +add_library(app_header_1) +target_include_directories(app_header_1 PRIVATE ${SRC_DIRECTORY}) +target_sources(app_header_1 PRIVATE "${SRC_DIRECTORY}/generated/app_header_1.c") + + +# Add modules +# add_library(eeprom INTERFACE) +# target_include_directories(eeprom INTERFACE ${SRC_DIRECTORY}) +# target_sources(eeprom INTERFACE "${SRC_DIRECTORY}/generated/eeprom.c") From 763b1cafac2c446b9bb34b12cf28c2431e437f2a Mon Sep 17 00:00:00 2001 From: Ran Bao Date: Fri, 12 Apr 2024 22:33:14 +1200 Subject: [PATCH 09/11] Refactor the build system to build component independently --- CMakeLists.txt | 24 +++++++- src/CMakeLists.txt | 136 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 155 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bf8ee26..8daa320 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,7 +78,9 @@ file(GLOB SRC ${SRC_DIRECTORY}/*.c # Pull in source code as library add_library(app_base - ${SRC} + # ${SRC} + "${SRC_DIRECTORY}/app.cpp" + "${SRC_DIRECTORY}/freertos_hooks.c" ) target_include_directories(app_base PUBLIC ${SRC_DIRECTORY} @@ -97,6 +99,26 @@ target_link_libraries(app_base hardware_i2c pico_cyw43_arch_lwip_sys_freertos pico_lwip_freertos + + # Source libraries + access_point_mode + button + charge_mode + cleanup_mode + common + http_server + rest_server + eeprom + menu + display + motors + neopixel + wireless + profile + and_scale + steinberg_scale + gng_scale + scale ) # Pull in src to generate extra files diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3af5ed4..d8294f3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -83,7 +83,135 @@ target_include_directories(app_header_1 PRIVATE ${SRC_DIRECTORY}) target_sources(app_header_1 PRIVATE "${SRC_DIRECTORY}/generated/app_header_1.c") -# Add modules -# add_library(eeprom INTERFACE) -# target_include_directories(eeprom INTERFACE ${SRC_DIRECTORY}) -# target_sources(eeprom INTERFACE "${SRC_DIRECTORY}/generated/eeprom.c") +## Add modules +# Common +add_library(common INTERFACE) +target_include_directories(common INTERFACE ${SRC_DIRECTORY}) +target_sources(common INTERFACE "${SRC_DIRECTORY}/common.c") + +# Access point mode +add_library(access_point_mode INTERFACE) +target_include_directories(access_point_mode INTERFACE ${SRC_DIRECTORY}) +target_sources(access_point_mode INTERFACE "${SRC_DIRECTORY}/access_point_mode.c") + +# G&G Scale +add_library(gng_scale INTERFACE) +target_include_directories(gng_scale INTERFACE ${SRC_DIRECTORY}) +target_sources(gng_scale INTERFACE + "${SRC_DIRECTORY}/gng_scale.c" +) + +# A&D Scale +add_library(and_scale INTERFACE) +target_include_directories(and_scale INTERFACE ${SRC_DIRECTORY}) +target_sources(and_scale INTERFACE + "${SRC_DIRECTORY}/and_scale_calibrate.c" + "${SRC_DIRECTORY}/and_scale.c" +) + +# Steinberg scale +add_library(steinberg_scale INTERFACE) +target_include_directories(steinberg_scale INTERFACE ${SRC_DIRECTORY}) +target_sources(steinberg_scale INTERFACE + "${SRC_DIRECTORY}/steinberg_scale.c" +) + +# Scale (abstract class) +add_library(scale INTERFACE) +target_include_directories(scale INTERFACE ${SRC_DIRECTORY}) +target_sources(scale INTERFACE + "${SRC_DIRECTORY}/scale.c" +) + +# Button +add_library(button INTERFACE) +target_include_directories(button INTERFACE ${SRC_DIRECTORY}) +target_sources(button INTERFACE + "${SRC_DIRECTORY}/button.c" + "${SRC_DIRECTORY}/rotary_button.cpp" +) + +# Charge mode +add_library(charge_mode INTERFACE) +target_include_directories(charge_mode INTERFACE ${SRC_DIRECTORY}) +target_sources(charge_mode INTERFACE + "${SRC_DIRECTORY}/charge_mode.cpp" + "${SRC_DIRECTORY}/FloatRingBuffer.cpp" +) + +# Cleanup mode +add_library(cleanup_mode INTERFACE) +target_include_directories(cleanup_mode INTERFACE ${SRC_DIRECTORY}) +target_sources(cleanup_mode INTERFACE + "${SRC_DIRECTORY}/cleanup_mode.cpp" +) + +# HTTP server +add_library(http_server INTERFACE) +target_include_directories(http_server INTERFACE ${SRC_DIRECTORY}) +target_sources(http_server INTERFACE + "${SRC_DIRECTORY}/dhcpserver.c" + "${SRC_DIRECTORY}/dnsserver.c" + "${SRC_DIRECTORY}/http_rest.c" +) + +# REST server +add_library(rest_server INTERFACE) +target_include_directories(rest_server INTERFACE ${SRC_DIRECTORY}) +target_sources(rest_server INTERFACE + "${SRC_DIRECTORY}/rest_endpoints.c" + "${SRC_DIRECTORY}/rest_app_control.c" + +) + +# EEPROM +add_library(eeprom INTERFACE) +target_include_directories(eeprom INTERFACE ${SRC_DIRECTORY}) +target_sources(eeprom INTERFACE + "${SRC_DIRECTORY}/eeprom.c" + "${SRC_DIRECTORY}/cat24c256_eeprom.c" +) + +# Menu +add_library(menu INTERFACE) +target_include_directories(menu INTERFACE ${SRC_DIRECTORY}) +target_sources(menu INTERFACE + "${SRC_DIRECTORY}/menu.cpp" + "${SRC_DIRECTORY}/mui_menu.c" +) + +# Display +add_library(display INTERFACE) +target_include_directories(display INTERFACE ${SRC_DIRECTORY}) +target_sources(display INTERFACE + "${SRC_DIRECTORY}/display.c" + "${SRC_DIRECTORY}/uc1701_display.c" +) + +# Motors +add_library(motors INTERFACE) +target_include_directories(motors INTERFACE ${SRC_DIRECTORY}) +target_sources(motors INTERFACE + "${SRC_DIRECTORY}/motors.c" +) + +# Neopixel +add_library(neopixel INTERFACE) +target_include_directories(neopixel INTERFACE ${SRC_DIRECTORY}) +target_sources(neopixel INTERFACE + "${SRC_DIRECTORY}/neopixel_led.c" +) + +# Profile +add_library(profile INTERFACE) +target_include_directories(profile INTERFACE ${SRC_DIRECTORY}) +target_sources(profile INTERFACE + "${SRC_DIRECTORY}/profile.c" +) + +# Wireless +add_library(wireless INTERFACE) +target_include_directories(wireless INTERFACE ${SRC_DIRECTORY}) +target_sources(wireless INTERFACE + "${SRC_DIRECTORY}/wireless.c" +) From b624c30b36ac4eb5a9447782479f87336dfb8349 Mon Sep 17 00:00:00 2001 From: Ran Bao Date: Tue, 16 Apr 2024 20:12:46 +1200 Subject: [PATCH 10/11] Add boot3 experimental code --- .vscode/settings.json | 13 +- CMakeLists.txt | 1 + scripts/gen_app_header.py | 2 +- src/CMakeLists.txt | 2 + src/app.cpp | 1 - src/app_header.h | 1 + src/boot3/CMakeLists.txt | 0 src/boot3/bl_crt0.S | 337 ++++++++++++++++++++++++++++++++++++++ src/boot3/bootloader.c | 4 + 9 files changed, 358 insertions(+), 3 deletions(-) create mode 100644 src/boot3/CMakeLists.txt create mode 100644 src/boot3/bl_crt0.S create mode 100644 src/boot3/bootloader.c diff --git a/.vscode/settings.json b/.vscode/settings.json index 6a009d4..f10d07f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -46,6 +46,17 @@ "binary_info.h": "c", "structure.h": "c", "stepper.pio.h": "c", - "app_header.h": "c" + "app_header.h": "c", + "pico.h": "c", + "critical_section.h": "c", + "*.in": "c", + "vreg.h": "c", + "resets.h": "c", + "address_mapped.h": "c", + "m0plus.h": "c", + "stdint.h": "c", + "rp2040_config.h": "c", + "rp2040.h": "c", + "core_cm0plus.h": "c" } } diff --git a/CMakeLists.txt b/CMakeLists.txt index 8daa320..0a361c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,6 +99,7 @@ target_link_libraries(app_base hardware_i2c pico_cyw43_arch_lwip_sys_freertos pico_lwip_freertos + cmsis_core # Source libraries access_point_mode diff --git a/scripts/gen_app_header.py b/scripts/gen_app_header.py index 30936df..5e36ea3 100644 --- a/scripts/gen_app_header.py +++ b/scripts/gen_app_header.py @@ -14,7 +14,6 @@ C_SOURCE_TEMPLATE = """// ---------------------------------------------------------------------- // // This file is auto-generated by gen_application_header.py; do not edit! // // ---------------------------------------------------------------------- // - #include "app_header.h" #ifdef __cplusplus @@ -27,6 +26,7 @@ const app_header_t __app_header = {{ .app_header_rev = {app_header_rev}, .flash_partition_idx = {flash_partition_idx}, + .crc = 0, .vcs_hash = "{vcs_hash}", .build_type = "{build_type}", .firmware_version = "{firmware_version}", diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d8294f3..a58fa27 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -69,6 +69,7 @@ add_custom_command( add_library(app_header_0) target_include_directories(app_header_0 PRIVATE ${SRC_DIRECTORY}) target_sources(app_header_0 PRIVATE "${SRC_DIRECTORY}/generated/app_header_0.c") +target_link_libraries(app_header_0 cmsis_core) add_custom_command( @@ -81,6 +82,7 @@ add_custom_command( add_library(app_header_1) target_include_directories(app_header_1 PRIVATE ${SRC_DIRECTORY}) target_sources(app_header_1 PRIVATE "${SRC_DIRECTORY}/generated/app_header_1.c") +target_link_libraries(app_header_1 cmsis_core) ## Add modules diff --git a/src/app.cpp b/src/app.cpp index 2966bb8..07cbc3b 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -28,7 +28,6 @@ #include "profile.h" - uint8_t software_reboot() { watchdog_reboot(0, 0, 0); diff --git a/src/app_header.h b/src/app_header.h index ec38f77..5ec7cf6 100644 --- a/src/app_header.h +++ b/src/app_header.h @@ -6,6 +6,7 @@ typedef struct { uint32_t app_header_rev; uint32_t flash_partition_idx; + uint32_t crc; char vcs_hash[16]; char build_type[16]; char firmware_version[32]; diff --git a/src/boot3/CMakeLists.txt b/src/boot3/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/boot3/bl_crt0.S b/src/boot3/bl_crt0.S new file mode 100644 index 0000000..d061108 --- /dev/null +++ b/src/boot3/bl_crt0.S @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "pico.h" +#include "hardware/regs/m0plus.h" +#include "hardware/regs/addressmap.h" +#include "hardware/regs/sio.h" +#include "pico/asm_helper.S" +#include "pico/binary_info/defs.h" + +#ifdef NDEBUG +#ifndef COLLAPSE_IRQS +#define COLLAPSE_IRQS +#endif +#endif + +.syntax unified +.cpu cortex-m0plus +.thumb + +.section .vectors, "ax" +.align 2 + +.global __vectors, __VECTOR_TABLE +__VECTOR_TABLE: +__vectors: +.word __StackTop +.word _reset_handler +.word isr_nmi +.word isr_hardfault +.word isr_invalid // Reserved, should never fire +.word isr_invalid // Reserved, should never fire +.word isr_invalid // Reserved, should never fire +.word isr_invalid // Reserved, should never fire +.word isr_invalid // Reserved, should never fire +.word isr_invalid // Reserved, should never fire +.word isr_invalid // Reserved, should never fire +.word isr_svcall +.word isr_invalid // Reserved, should never fire +.word isr_invalid // Reserved, should never fire +.word isr_pendsv +.word isr_systick +.word isr_irq0 +.word isr_irq1 +.word isr_irq2 +.word isr_irq3 +.word isr_irq4 +.word isr_irq5 +.word isr_irq6 +.word isr_irq7 +.word isr_irq8 +.word isr_irq9 +.word isr_irq10 +.word isr_irq11 +.word isr_irq12 +.word isr_irq13 +.word isr_irq14 +.word isr_irq15 +.word isr_irq16 +.word isr_irq17 +.word isr_irq18 +.word isr_irq19 +.word isr_irq20 +.word isr_irq21 +.word isr_irq22 +.word isr_irq23 +.word isr_irq24 +.word isr_irq25 +.word isr_irq26 +.word isr_irq27 +.word isr_irq28 +.word isr_irq29 +.word isr_irq30 +.word isr_irq31 + +// all default exception handlers do nothing, and we can check for them being set to our +// default values by seeing if they point to somewhere between __defaults_isrs_start and __default_isrs_end +.global __default_isrs_start +__default_isrs_start: + +// Declare a weak symbol for each ISR. +// By default, they will fall through to the undefined IRQ handler below (breakpoint), +// but can be overridden by C functions with correct name. + +.macro decl_isr_bkpt name +.weak \name +.type \name,%function +.thumb_func +\name: + bkpt #0 +.endm + +// these are separated out for clarity +decl_isr_bkpt isr_invalid +decl_isr_bkpt isr_nmi +decl_isr_bkpt isr_hardfault +decl_isr_bkpt isr_svcall +decl_isr_bkpt isr_pendsv +decl_isr_bkpt isr_systick + +.global __default_isrs_end +__default_isrs_end: + +.macro decl_isr name +.weak \name +.type \name,%function +.thumb_func +\name: +.endm + +decl_isr isr_irq0 +decl_isr isr_irq1 +decl_isr isr_irq2 +decl_isr isr_irq3 +decl_isr isr_irq4 +decl_isr isr_irq5 +decl_isr isr_irq6 +decl_isr isr_irq7 +decl_isr isr_irq8 +decl_isr isr_irq9 +decl_isr isr_irq10 +decl_isr isr_irq11 +decl_isr isr_irq12 +decl_isr isr_irq13 +decl_isr isr_irq14 +decl_isr isr_irq15 +decl_isr isr_irq16 +decl_isr isr_irq17 +decl_isr isr_irq18 +decl_isr isr_irq19 +decl_isr isr_irq20 +decl_isr isr_irq21 +decl_isr isr_irq22 +decl_isr isr_irq23 +decl_isr isr_irq24 +decl_isr isr_irq25 +decl_isr isr_irq26 +decl_isr isr_irq27 +decl_isr isr_irq28 +decl_isr isr_irq29 +decl_isr isr_irq30 +decl_isr isr_irq31 + +// All unhandled USER IRQs fall through to here +.global __unhandled_user_irq +.thumb_func +__unhandled_user_irq: + mrs r0, ipsr + subs r0, #16 +.global unhandled_user_irq_num_in_r0 +unhandled_user_irq_num_in_r0: + bkpt #0 + +// ---------------------------------------------------------------------------- + +.section .binary_info_header, "a" + +// Header must be in first 256 bytes of main image (i.e. excluding flash boot2). +// For flash builds we put it immediately after vector table; for NO_FLASH the +// vectors are at a +0x100 offset because the bootrom enters RAM images directly +// at their lowest address, so we put the header in the VTOR alignment hole. + +#if !PICO_NO_BINARY_INFO +binary_info_header: +.word BINARY_INFO_MARKER_START +.word __binary_info_start +.word __binary_info_end +.word data_cpy_table // we may need to decode pointers that are in RAM at runtime. +.word BINARY_INFO_MARKER_END +#endif + +// ---------------------------------------------------------------------------- + +.section .reset, "ax" + +// On flash builds, the vector table comes first in the image (conventional). +// On NO_FLASH builds, the reset handler section comes first, as the entry +// point is at offset 0 (fixed due to bootrom), and VTOR is highly-aligned. +// Image is entered in various ways: +// +// - NO_FLASH builds are entered from beginning by UF2 bootloader +// +// - Flash builds vector through the table into _reset_handler from boot2 +// +// - Either type can be entered via _entry_point by the debugger, and flash builds +// must then be sent back round the boot sequence to properly initialise flash + +// ELF entry point: +.type _entry_point,%function +.thumb_func +.global _entry_point +_entry_point: + +#if PICO_NO_FLASH + // Vector through our own table (SP, VTOR will not have been set up at + // this point). Same path for debugger entry and bootloader entry. + ldr r0, =__vectors +#else + // Debugger tried to run code after loading, so SSI is in 03h-only mode. + // Go back through bootrom + boot2 to properly initialise flash. + movs r0, #0 +#endif + ldr r1, =(PPB_BASE + M0PLUS_VTOR_OFFSET) + str r0, [r1] + ldmia r0!, {r1, r2} + msr msp, r1 + bx r2 + +// Reset handler: +// - initialises .data +// - clears .bss +// - calls runtime_init +// - calls main +// - calls exit (which should eventually hang the processor via _exit) + +.type _reset_handler,%function +.thumb_func +_reset_handler: + // Only core 0 should run the C runtime startup code; core 1 is normally + // sleeping in the bootrom at this point but check to be sure + ldr r0, =(SIO_BASE + SIO_CPUID_OFFSET) + ldr r0, [r0] + cmp r0, #0 + bne hold_non_core0_in_bootrom + + // In a NO_FLASH binary, don't perform .data copy, since it's loaded + // in-place by the SRAM load. Still need to clear .bss +#if !PICO_NO_FLASH + adr r4, data_cpy_table + + // assume there is at least one entry +1: + ldmia r4!, {r1-r3} + cmp r1, #0 + beq 2f + bl data_cpy + b 1b +2: +#endif + + // Zero out the BSS + ldr r1, =__bss_start__ + ldr r2, =__bss_end__ + movs r0, #0 + b bss_fill_test +bss_fill_loop: + stm r1!, {r0} +bss_fill_test: + cmp r1, r2 + bne bss_fill_loop + +platform_entry: // symbol for stack traces + // Use 32-bit jumps, in case these symbols are moved out of branch range + // (e.g. if main is in SRAM and crt0 in flash) + ldr r1, =runtime_init + blx r1 + ldr r1, =main + blx r1 + ldr r1, =exit + blx r1 + // exit should not return. If it does, hang the core. + // (fall thru into our hang _exit impl +1: // separate label because _exit can be moved out of branch range + bkpt #0 + b 1b + +#if !PICO_NO_FLASH +data_cpy_loop: + ldm r1!, {r0} + stm r2!, {r0} +data_cpy: + cmp r2, r3 + blo data_cpy_loop + bx lr +#endif + +// Note the data copy table is still included for NO_FLASH builds, even though +// we skip the copy, because it is listed in binary info + +.align 2 +data_cpy_table: +#if PICO_COPY_TO_RAM +.word __ram_text_source__ +.word __ram_text_start__ +.word __ram_text_end__ +#endif +.word __etext +.word __data_start__ +.word __data_end__ + +.word __scratch_x_source__ +.word __scratch_x_start__ +.word __scratch_x_end__ + +.word __scratch_y_source__ +.word __scratch_y_start__ +.word __scratch_y_end__ + +.word 0 // null terminator + +// ---------------------------------------------------------------------------- +// Provide safe defaults for _exit and runtime_init +// Full implementations usually provided by platform.c + +.weak runtime_init +.type runtime_init,%function +.thumb_func +runtime_init: + bx lr + +// ---------------------------------------------------------------------------- +// If core 1 somehow gets into crt0 due to a spectacular VTOR mishap, we need to +// catch it and send back to the sleep-and-launch code in the bootrom. Shouldn't +// happen (it should sleep in the ROM until given an entry point via the +// cross-core FIFOs) but it's good to be defensive. + +hold_non_core0_in_bootrom: + ldr r0, = 'W' | ('V' << 8) + bl rom_func_lookup + bx r0 + +// ---------------------------------------------------------------------------- +// Stack/heap dummies to set size + +.section .stack +// align to allow for memory protection (although this alignment is pretty much ignored by linker script) +.align 5 + .equ StackSize, PICO_STACK_SIZE +.space StackSize + +.section .heap +.align 2 + .equ HeapSize, PICO_HEAP_SIZE +.space HeapSize diff --git a/src/boot3/bootloader.c b/src/boot3/bootloader.c new file mode 100644 index 0000000..f00d673 --- /dev/null +++ b/src/boot3/bootloader.c @@ -0,0 +1,4 @@ + +void main(void) { + +} \ No newline at end of file From 5823f659651c9531e237d8a5a45cd00f63449a1a Mon Sep 17 00:00:00 2001 From: Ran Bao Date: Wed, 29 May 2024 21:32:02 +1200 Subject: [PATCH 11/11] fix build error --- CMakeLists.txt | 2 ++ src/CMakeLists.txt | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 71dd511..34474b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,7 +120,9 @@ target_link_libraries(app_base and_scale steinberg_scale gng_scale + ussolid_scale scale + servo_gate ) # Pull in src to generate extra files diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a58fa27..5d6cc87 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -118,6 +118,13 @@ target_sources(steinberg_scale INTERFACE "${SRC_DIRECTORY}/steinberg_scale.c" ) +# U.S.solid scale +add_library(ussolid_scale INTERFACE) +target_include_directories(ussolid_scale INTERFACE ${SRC_DIRECTORY}) +target_sources(ussolid_scale INTERFACE + "${SRC_DIRECTORY}/ussolid_scale.c" +) + # Scale (abstract class) add_library(scale INTERFACE) target_include_directories(scale INTERFACE ${SRC_DIRECTORY}) @@ -217,3 +224,10 @@ target_include_directories(wireless INTERFACE ${SRC_DIRECTORY}) target_sources(wireless INTERFACE "${SRC_DIRECTORY}/wireless.c" ) + +# Servo Gate +add_library(servo_gate INTERFACE) +target_include_directories(servo_gate INTERFACE ${SRC_DIRECTORY}) +target_sources(servo_gate INTERFACE + "${SRC_DIRECTORY}/servo_gate.c" +)