From 504eced7881fc01323ab2ce4b8219ad84fa49b01 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Tue, 1 Oct 2024 22:33:41 -0400 Subject: [PATCH 01/17] build: Add bootloader build flag -b in per_build Instead of having to dig around cmake cache Signed-off-by: Eileen Yoon --- CMakeLists.txt | 1 - per_build.py | 9 ++++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2436e264..1a22220f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,6 @@ if(ret EQUAL "1") endif() # Check for bootloader generation -option(BOOTLOADER_BUILD "Build the bootlaoder components" OFF) if (NOT BOOTLOADER_BUILD) message(STATUS "Not building applications for bootloaders.") else() diff --git a/per_build.py b/per_build.py index 46c5e1b1..b23740d2 100644 --- a/per_build.py +++ b/per_build.py @@ -61,7 +61,13 @@ def log_success(phrase): help="don't run unit tests" ) -parser.add_option("-v", "--verbose", +parser.add_option("-b", "--bootloader", + dest="bootloader", + action="store_true", default=False, + help="build bootloader components" +) + +parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, help="verbose build commnad output" @@ -88,6 +94,7 @@ def log_success(phrase): "-B", str(BUILD_DIR), "-G", "Ninja", f"-DCMAKE_BUILD_TYPE={BUILD_TYPE}", + f"-DBOOTLOADER_BUILD={'ON' if options.bootloader else 'OFF'}", ] NINJA_OPTIONS = [ From 4f82f0bd9207d39871e6a2b1a6df16b3045c42fa Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Wed, 9 Oct 2024 10:00:23 -0400 Subject: [PATCH 02/17] build: don't skip build task for bootloader builds Now that we have a --bootloader flag in per_build.py Signed-off-by: Eileen Yoon --- .vscode/launch.json | 28 ++++++++++++++-------------- .vscode/tasks.json | 8 ++++++++ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index b493d1e9..2751597d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -189,7 +189,7 @@ "-d", "${workspaceFolder}/source/a_box" ], - "preLaunchTask": "build", + "preLaunchTask": "build_bl", "runToEntryPoint": "main" }, { "name": "BL App - Main Module", @@ -208,7 +208,7 @@ "-d", "${workspaceFolder}/source/main_module" ], - "preLaunchTask": "build", + "preLaunchTask": "build_bl", "runToEntryPoint": "main" }, { "name": "BL App - Dashboard", @@ -227,7 +227,7 @@ "-d", "${workspaceFolder}/source/dashboard" ], - "preLaunchTask": "build", + "preLaunchTask": "build_bl", "runToEntryPoint": "main" }, { "name": "BL App - Torque Vectoring", @@ -246,7 +246,7 @@ "-d", "${workspaceFolder}/source/torque_vector" ], - "preLaunchTask": "build", + "preLaunchTask": "build_bl", "runToEntryPoint": "main" }, { "name": "BL App - A_Box", @@ -265,7 +265,7 @@ "-d", "${workspaceFolder}/source/a_box" ], - "preLaunchTask": "build", + "preLaunchTask": "build_bl", "runToEntryPoint": "main" }, { "name": "BL App - PDU", @@ -284,7 +284,7 @@ "-d", "${workspaceFolder}/source/pdu" ], - "preLaunchTask": "build", + "preLaunchTask": "build_bl", "runToEntryPoint": "main" }, { "name": "BL App - DAQ", @@ -303,7 +303,7 @@ "-d", "${workspaceFolder}/source/daq" ], - "preLaunchTask": "build", + "preLaunchTask": "build_bl", "runToEntryPoint": "main" }, { "name": "BL App - l4_testing", @@ -341,7 +341,7 @@ "-d", "${workspaceFolder}/source/bootloader" ], - // "preLaunchTask": "build", + "preLaunchTask": "build_bl", "runToEntryPoint": "Reset_Handler" }, { @@ -361,7 +361,7 @@ "-d", "${workspaceFolder}/source/bootloader" ], - // "preLaunchTask": "build", + "preLaunchTask": "build_bl", "runToEntryPoint": "Reset_Handler" }, { "name": "BL Bootloader - Torque Vectoring", @@ -380,7 +380,7 @@ "-d", "${workspaceFolder}/source/bootloader" ], - // "preLaunchTask": "build", + "preLaunchTask": "build_bl", "runToEntryPoint": "Reset_Handler" }, { @@ -400,7 +400,7 @@ "-d", "${workspaceFolder}/source/bootloader" ], - // "preLaunchTask": "build", + "preLaunchTask": "build_bl", "runToEntryPoint": "Reset_Handler" }, { "name": "BL Bootloader - PDU", @@ -419,7 +419,7 @@ "-d", "${workspaceFolder}/source/bootloader" ], - // "preLaunchTask": "build", + "preLaunchTask": "build_bl", "runToEntryPoint": "Reset_Handler" }, { "name": "BL Bootloader - DAQ", @@ -438,7 +438,7 @@ "-d", "${workspaceFolder}/source/bootloader" ], - // "preLaunchTask": "build", + "preLaunchTask": "build_bl", "runToEntryPoint": "Reset_Handler" }, { @@ -458,7 +458,7 @@ "-d", "${workspaceFolder}/source/bootloader" ], - // "preLaunchTask": "build", + "preLaunchTask": "build_bl", "runToEntryPoint": "Reset_Handler" }, ] diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 31f60f9c..6c70d3ea 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,6 +12,14 @@ "isDefault": true } }, + { + "label": "build_bl", + "type": "shell", + "command": "python3 per_build.py --bootloader", + "group": { + "kind": "build", + } + }, { "label": "Submodule Update", "group": "none", From 5cf1b4b10fd03c2adacbae002eb32454bf9977ba Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Fri, 4 Oct 2024 16:16:27 -0400 Subject: [PATCH 03/17] build: Add -c shortcut for --clean in per_build Signed-off-by: Eileen Yoon --- per_build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/per_build.py b/per_build.py index b23740d2..97d127d9 100644 --- a/per_build.py +++ b/per_build.py @@ -43,7 +43,7 @@ def log_success(phrase): help="firmware target to build. Defaults to `all`" ) -parser.add_option("--clean", +parser.add_option("-c", "--clean", dest="clean", action="store_true", default=False, help="remove build artifacts" From 23e7e67425ce369b8dfd4d8ecd76f4e457fcd105 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Wed, 2 Oct 2024 22:04:36 -0400 Subject: [PATCH 04/17] build: Remove ihex gap-fill zero padding flag Depends on discontiguous segments support Signed-off-by: Eileen Yoon --- cmake/utils.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/utils.cmake b/cmake/utils.cmake index 5d82b64b..fcad5023 100644 --- a/cmake/utils.cmake +++ b/cmake/utils.cmake @@ -31,7 +31,7 @@ function(postbuild_target TARGET_NAME) ) add_custom_command(TARGET ${TARGET_NAME} POST_BUILD - COMMAND arm-none-eabi-objcopy -S -O ihex --gap-fill 0 ${TARGET_NAME} ${COMPONENT_OUTPUT_DIR}/${OUTPUT_FILE_NAME}.hex + COMMAND arm-none-eabi-objcopy -S -O ihex ${TARGET_NAME} ${COMPONENT_OUTPUT_DIR}/${OUTPUT_FILE_NAME}.hex COMMENT "Generateing HEX file" ) From 098b1fdfab41765922d52cfcc80a6d9edae34b86 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Wed, 2 Oct 2024 22:09:37 -0400 Subject: [PATCH 05/17] build: Fix typo in cmake ihex comment Signed-off-by: Eileen Yoon --- cmake/utils.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/utils.cmake b/cmake/utils.cmake index fcad5023..03b95ad9 100644 --- a/cmake/utils.cmake +++ b/cmake/utils.cmake @@ -32,7 +32,7 @@ function(postbuild_target TARGET_NAME) add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND arm-none-eabi-objcopy -S -O ihex ${TARGET_NAME} ${COMPONENT_OUTPUT_DIR}/${OUTPUT_FILE_NAME}.hex - COMMENT "Generateing HEX file" + COMMENT "Generating HEX file" ) add_custom_command(TARGET ${TARGET_NAME} POST_BUILD From 83b8ace5854b1b672ec72d4d71eb601e365accb4 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Thu, 3 Oct 2024 20:11:08 -0400 Subject: [PATCH 06/17] bl: Count by words written instead of address pos Count the number of words written instead of incrementing the current address directly. Needed for discontiguous segments support Signed-off-by: Eileen Yoon --- source/bootloader/bootloader/bootloader.c | 46 ++++++++++++----------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/source/bootloader/bootloader/bootloader.c b/source/bootloader/bootloader/bootloader.c index f6b76981..fc837709 100644 --- a/source/bootloader/bootloader/bootloader.c +++ b/source/bootloader/bootloader/bootloader.c @@ -1,12 +1,12 @@ /** * @file process.c * @author your name (you@domain.com) - * @brief + * @brief * @version 0.1 * @date 2022-02-28 - * + * * @copyright Copyright (c) 2022 - * + * */ #include "bootloader.h" @@ -21,7 +21,8 @@ static uint32_t* app_flash_start_address; /* Store the start address of the Application, never changes */ static volatile uint32_t* app_flash_current_address; /* Current address we are writing to */ -static volatile uint32_t* app_flash_end_address; /* Expected end address to stop writing */ +static volatile uint32_t app_flash_size = 0; +static volatile uint32_t app_flash_written = 0; static volatile uint32_t* bootloader_ms; extern q_handle_t q_tx_can; @@ -41,8 +42,8 @@ void BL_init(uint32_t* app_flash_start, volatile uint32_t* bootloader_ms_ptr) #endif app_flash_start_address = app_flash_start; - app_flash_end_address = app_flash_start; - app_flash_current_address = app_flash_start; + app_flash_current_address = app_flash_start; // base + app_flash_written = 0; bootloader_ms = bootloader_ms_ptr; } @@ -59,10 +60,11 @@ void BL_processCommand(BLCmd_t cmd, uint32_t data) { case BLCMD_START: { - app_flash_current_address = app_flash_start_address; - app_flash_end_address += data; // Number of words + app_flash_current_address = app_flash_start_address; // init + app_flash_size = data; // Number of words + app_flash_written = 0; *bootloader_ms = 0; - + #ifndef DEBUG if (PHAL_flashErase(app_flash_start_address, data) != FLASH_OK) { @@ -84,7 +86,7 @@ void BL_processCommand(BLCmd_t cmd, uint32_t data) } case BLCMD_CRC: { - if (bl_unlock && app_flash_current_address == app_flash_end_address) + if (bl_unlock && app_flash_written == app_flash_size) { if (CRC->DR != data) BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_CRC_FAIL); @@ -108,7 +110,7 @@ void BL_processCommand(BLCmd_t cmd, uint32_t data) } else if (!bl_unlock) BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_LOCKED); - else + else BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_LOW_ADDR); break; } @@ -151,17 +153,17 @@ void bitstream_data_CALLBACK(CanParsedData_t* msg_data_a) #if (APP_ID == APP_L4_TESTING) PHAL_writeGPIO(GPIOB, 7, 1); #endif - uint64_t data; + uint64_t data; if (bl_unlock) { - if(app_flash_current_address >= app_flash_start_address && - app_flash_current_address < app_flash_end_address) - { + if (app_flash_written < app_flash_size) + { num_msg++; data = *((uint64_t *) msg_data_a->raw_data); + uint32_t curr_addr = (uint32_t) app_flash_current_address + app_flash_written * sizeof(uint32_t); // Skip the first two words - if (app_flash_current_address == app_flash_start_address) + if (!app_flash_written) { CRC->DR = first_word = *((uint32_t *) msg_data_a->raw_data); CRC->DR = second_word = *((uint32_t *) msg_data_a->raw_data + 1); @@ -170,7 +172,7 @@ void bitstream_data_CALLBACK(CanParsedData_t* msg_data_a) { // Address is 2-word aligned, do the actual programming now #ifndef DEBUG - if (PHAL_flashWriteU64((uint32_t) app_flash_current_address, data) != FLASH_OK) + if (PHAL_flashWriteU64(curr_addr, data) != FLASH_OK) { BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_FLASH); bl_unlock = false; @@ -178,15 +180,17 @@ void bitstream_data_CALLBACK(CanParsedData_t* msg_data_a) else #endif { - CRC->DR = *(app_flash_current_address); - CRC->DR = *(app_flash_current_address + 1); + CRC->DR = *((uint32_t *)curr_addr); + CRC->DR = *((uint32_t *)(curr_addr + sizeof(uint32_t))); } } *bootloader_ms = 0; // Reset timeout counter, message received! - app_flash_current_address += 2; // wrote 64 bits + app_flash_written += 2; // wrote 64 bits } else + { BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_ADDR_BOUND); + } } #if (APP_ID == APP_L4_TESTING) @@ -195,7 +199,7 @@ void bitstream_data_CALLBACK(CanParsedData_t* msg_data_a) } /* - Component specific callbacks + Component specific callbacks */ // Quickly setup case statments for send function based on Node ID From 97e187fb79239ee139989591dd1190eadc99c087 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Sun, 6 Oct 2024 15:58:44 -0400 Subject: [PATCH 07/17] bl: Support discontiguous firmware segments Instead of padding firmware with zeros / sending zeros from daqapp, properly handle jumps in address segments. Use local segments_written counter and add command to reset relative segment base address API changes: BLCMD_START: firmware size != flash region to delete if discontiguous. Send end_addr - start_addr as num words to erase from 0x8002000 BLCMD_SET_SIZE: set unpadded size (sum of segments) i.e. num words to transfer separately BLCMD_SET_ADDR: set relative base address of current segment TODO Breaks daqapp but not the standalone bl.py impl TODO checksum/handshake for addr changes Signed-off-by: Eileen Yoon --- common/bootloader/bootloader_common.h | 10 ++++--- source/bootloader/bootloader/bootloader.c | 31 +++++++++++++++++----- source/bootloader/bootloader/bootloader.h | 32 +++++++++++------------ 3 files changed, 46 insertions(+), 27 deletions(-) diff --git a/common/bootloader/bootloader_common.h b/common/bootloader/bootloader_common.h index 076b5e6d..fba35068 100644 --- a/common/bootloader/bootloader_common.h +++ b/common/bootloader/bootloader_common.h @@ -1,13 +1,13 @@ /** * @file bootloader_common.h * @author Adam Busch (busch8@purdue.edu) - * @brief Common bootloader functions for all firmware components. + * @brief Common bootloader functions for all firmware components. * Useful for entering the bootloader to download new firmware * @version 0.1 * @date 2022-03-10 - * + * * @copyright Copyright (c) 2022 - * + * */ #ifndef _BOOTLOADER_COMMON_H_ #define _BOOTLOADER_COMMON_H_ @@ -27,7 +27,9 @@ typedef enum { BLCMD_START = 0x1, /* Request to start firmware download */ BLCMD_CRC = 0x3, /* Final CRC-32b check of firmware */ - BLCMD_RST = 0x5 /* Request for reset */ + BLCMD_RST = 0x5, /* Request for reset */ + BLCMD_SET_ADDR = 0x6, /* Jump relative base address (used for discontiguous firmware segments) */ + BLCMD_SET_SIZE = 0x7, /* Set number of discontiguous firmware words to transfer */ } BLCmd_t; typedef enum { diff --git a/source/bootloader/bootloader/bootloader.c b/source/bootloader/bootloader/bootloader.c index fc837709..fda67e7d 100644 --- a/source/bootloader/bootloader/bootloader.c +++ b/source/bootloader/bootloader/bootloader.c @@ -23,6 +23,7 @@ static uint32_t* app_flash_start_address; /* Store the start address static volatile uint32_t* app_flash_current_address; /* Current address we are writing to */ static volatile uint32_t app_flash_size = 0; static volatile uint32_t app_flash_written = 0; +static volatile uint32_t app_flash_segment_written = 0; static volatile uint32_t* bootloader_ms; extern q_handle_t q_tx_can; @@ -44,6 +45,7 @@ void BL_init(uint32_t* app_flash_start, volatile uint32_t* bootloader_ms_ptr) app_flash_start_address = app_flash_start; app_flash_current_address = app_flash_start; // base app_flash_written = 0; + app_flash_segment_written = 0; bootloader_ms = bootloader_ms_ptr; } @@ -60,13 +62,14 @@ void BL_processCommand(BLCmd_t cmd, uint32_t data) { case BLCMD_START: { + // data: padded total flash size (num words), i.e. end addr - start addr app_flash_current_address = app_flash_start_address; // init - app_flash_size = data; // Number of words app_flash_written = 0; + app_flash_segment_written = 0; *bootloader_ms = 0; #ifndef DEBUG - if (PHAL_flashErase(app_flash_start_address, data) != FLASH_OK) + if (data && PHAL_flashErase(app_flash_start_address, data) != FLASH_OK) { BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_FLASH); bl_unlock = false; @@ -77,15 +80,16 @@ void BL_processCommand(BLCmd_t cmd, uint32_t data) { BL_sendStatusMessage(BLSTAT_METDATA_RX, (uint32_t) data); } - num_msg = 0; - bl_unlock = true; flash_complete = false; + num_msg = 0; first_word = second_word = 0; CRC->CR |= CRC_CR_RESET; // Reset CRC + bl_unlock = true; break; } case BLCMD_CRC: { + // data: CRC checksum if (bl_unlock && app_flash_written == app_flash_size) { if (CRC->DR != data) @@ -114,6 +118,20 @@ void BL_processCommand(BLCmd_t cmd, uint32_t data) BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_LOW_ADDR); break; } + case BLCMD_SET_SIZE: + { + // data: unpadded firmware size i.e. sum of segments + // should be called only once + app_flash_size = data; // num crc words to transfer + break; + } + case BLCMD_SET_ADDR: + { + // data: new relative base address of segment + app_flash_current_address = (uint32_t* )data; + app_flash_segment_written = 0; // reset local counter + break; + } case BLCMD_RST: // Bootloader_ResetForFirmwareDownload(); break; @@ -137,7 +155,7 @@ bool BL_flashComplete(void) volatile uint32_t* BL_getCurrentFlashAddress(void) { - return app_flash_current_address; + return app_flash_current_address + app_flash_segment_written; } void BL_timeout(void) @@ -160,7 +178,7 @@ void bitstream_data_CALLBACK(CanParsedData_t* msg_data_a) { num_msg++; data = *((uint64_t *) msg_data_a->raw_data); - uint32_t curr_addr = (uint32_t) app_flash_current_address + app_flash_written * sizeof(uint32_t); + uint32_t curr_addr = (uint32_t) app_flash_current_address + app_flash_segment_written * sizeof(uint32_t); // Skip the first two words if (!app_flash_written) @@ -186,6 +204,7 @@ void bitstream_data_CALLBACK(CanParsedData_t* msg_data_a) } *bootloader_ms = 0; // Reset timeout counter, message received! app_flash_written += 2; // wrote 64 bits + app_flash_segment_written += 2; } else { diff --git a/source/bootloader/bootloader/bootloader.h b/source/bootloader/bootloader/bootloader.h index 5b9388a3..fb19a929 100644 --- a/source/bootloader/bootloader/bootloader.h +++ b/source/bootloader/bootloader/bootloader.h @@ -1,12 +1,12 @@ /** * @file process.h * @author your name (you@domain.com) - * @brief + * @brief * @version 0.1 * @date 2022-02-28 - * + * * @copyright Copyright (c) 2022 - * + * */ #ifndef _PROCESS_H #define _PROCESS_H @@ -17,18 +17,17 @@ #include "node_defs.h" #include "common/bootloader/bootloader_common.h" - typedef enum { BLSTAT_INVALID = 0, /* Invalid operation */ BLSTAT_BOOT = 1, /* Bootloader boot alert */ - BLSTAT_WAIT = 2, /* Waiting to get BLCMD */ - BLSTAT_METDATA_RX = 3, /* Progress update for bootloader download */ + BLSTAT_WAIT = 2, /* Stage 1: RST done, waiting for BLCMD */ + BLSTAT_METDATA_RX = 3, /* Stage 2: Flash erase done */ BLSTAT_PROGRESS = 4, /* Progress update for bootloader download */ - BLSTAT_DONE = 5, /* Completed the application download with CRC pass */ + BLSTAT_DONE = 5, /* Stage 3: Completed firmware transfer with CRC checksum */ BLSTAT_JUMP_TO_APP = 6, /* About to jump to application */ BLSTAT_INVAID_APP = 7, /* Did not attempt to boot because the starting address was invalid */ - BLSTAT_UNKNOWN_CMD = 8, /* Incorrect CAN command message format */ + BLSTAT_UNKNOWN_CMD = 8, /* Incorrect CAN command message format */ } BLStatus_t; typedef enum @@ -44,23 +43,23 @@ void BL_init(uint32_t* app_flash_start, volatile uint32_t* bootloader_ms_ptr); /** * @brief Process an incoming bootlaoder command - * - * @param cmd - * @param data + * + * @param cmd + * @param data */ void BL_processCommand(BLCmd_t cmd, uint32_t data); /** * @brief The entire application has been written to flash. - * - * @return true - * @return false + * + * @return true + * @return false */ bool BL_flashComplete(void); /** * @brief Send a Bootloader status message with the correct app ID - * + * * @param cmd Command/status enum, see BLStatus_t * @param data Status data, context specific */ @@ -70,5 +69,4 @@ bool BL_flashStarted(void); void BL_timeout(void); volatile uint32_t* BL_getCurrentFlashAddress(void); - -#endif \ No newline at end of file +#endif From 112da02a810b0a90f67ebf650c67c71aaf7864f1 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Sun, 6 Oct 2024 16:01:09 -0400 Subject: [PATCH 08/17] bl: Reenable bootloader RST command Don't send the command from daqapp side instead of commenting it out here Signed-off-by: Eileen Yoon --- source/bootloader/bootloader/bootloader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/bootloader/bootloader/bootloader.c b/source/bootloader/bootloader/bootloader.c index fda67e7d..92371b21 100644 --- a/source/bootloader/bootloader/bootloader.c +++ b/source/bootloader/bootloader/bootloader.c @@ -133,7 +133,7 @@ void BL_processCommand(BLCmd_t cmd, uint32_t data) break; } case BLCMD_RST: - // Bootloader_ResetForFirmwareDownload(); + Bootloader_ResetForFirmwareDownload(); break; default: { From c5c12792564e8201a53e924c84671a8bf12610f2 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Sun, 6 Oct 2024 16:08:26 -0400 Subject: [PATCH 09/17] bl: send_status_flag should be true at first boot daqapp side polls for the WAIT message. If the flag is not true at boot we have to wait a whole systick cycle for the flag to be set true. Signed-off-by: Eileen Yoon --- source/bootloader/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/bootloader/main.c b/source/bootloader/main.c index f90087ab..210e4fa3 100644 --- a/source/bootloader/main.c +++ b/source/bootloader/main.c @@ -96,7 +96,7 @@ extern char _estack; /* The start location of the stack */ static volatile uint32_t bootloader_ms = 0; static volatile uint32_t bootloader_ms_2 = 0; static volatile bool bootloader_timeout = false; -static volatile bool send_status_flag = false; +static volatile bool send_status_flag = true; static bool send_flash_address = false; int main (void) From c0cd5320f7cd5d353d4f5412d4d0893d1059e481 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Mon, 7 Oct 2024 21:20:09 -0400 Subject: [PATCH 10/17] bl: Reset send_status_flag on BL timeout So we don't have to wait a whole systick cycle waiting for WAIT command Signed-off-by: Eileen Yoon --- source/bootloader/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/bootloader/main.c b/source/bootloader/main.c index 210e4fa3..2889587e 100644 --- a/source/bootloader/main.c +++ b/source/bootloader/main.c @@ -238,6 +238,7 @@ void SysTick_Handler(void) } if (bootloader_ms >= 3000) { + send_status_flag = true; bootloader_timeout = true; } break; @@ -249,6 +250,7 @@ void SysTick_Handler(void) // Allow some time in case bootloader request present if (bootloader_ms >= 500) { + send_status_flag = true; bootloader_timeout = true; } break; From 93b7cb6b994ab357aab3b16090b2090afcf8040c Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Sun, 6 Oct 2024 18:48:03 -0400 Subject: [PATCH 11/17] bl: Fix CAN RF0R RX0 bit clearing logic error Should be &= ~mask not &= !mask CAN_RF0R_FOVR0 > 0 and anything & !1 is always 0 so currently it zeros out the entire register instead of clearing the single RFOR bit TODO there's an identical chunk of daq code Signed-off-by: Eileen Yoon --- source/bootloader/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/bootloader/main.c b/source/bootloader/main.c index 2889587e..073f0f35 100644 --- a/source/bootloader/main.c +++ b/source/bootloader/main.c @@ -383,10 +383,10 @@ void CAN1_RX0_IRQHandler() #endif can_irq_hits ++; if (CAN1->RF0R & CAN_RF0R_FOVR0) // FIFO Overrun - CAN1->RF0R &= !(CAN_RF0R_FOVR0); + CAN1->RF0R &= ~(CAN_RF0R_FOVR0); if (CAN1->RF0R & CAN_RF0R_FULL0) // FIFO Full - CAN1->RF0R &= !(CAN_RF0R_FULL0); + CAN1->RF0R &= ~(CAN_RF0R_FULL0); if (CAN1->RF0R & CAN_RF0R_FMP0_Msk) // Release message pending { From b6411bee53f6266b748621efad35a17aefd16074 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Thu, 10 Oct 2024 20:39:57 -0400 Subject: [PATCH 12/17] bl: Hush annoying bl progress message No use, clogs bus Signed-off-by: Eileen Yoon --- source/bootloader/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/bootloader/main.c b/source/bootloader/main.c index 073f0f35..3420de5b 100644 --- a/source/bootloader/main.c +++ b/source/bootloader/main.c @@ -153,8 +153,8 @@ int main (void) if (!BL_flashStarted()) BL_sendStatusMessage(BLSTAT_WAIT, bootloader_ms); - else - BL_sendStatusMessage(BLSTAT_PROGRESS, (uint32_t) BL_getCurrentFlashAddress()); + //else + // BL_sendStatusMessage(BLSTAT_PROGRESS, (uint32_t) BL_getCurrentFlashAddress()); } // Send all pending CAN messages @@ -180,7 +180,7 @@ int main (void) // an address can not start with 0xFF for the MSP BL_sendStatusMessage(BLSTAT_JUMP_TO_APP, 0); send_pending_can(); - + jump_to_application(); @@ -188,7 +188,7 @@ int main (void) BL_sendStatusMessage(BLSTAT_INVAID_APP, bootloader_shared_memory.reset_count); bootloader_shared_memory.reset_reason = RESET_REASON_BAD_FIRMWARE; send_pending_can(); - + NVIC_SystemReset(); } From 400bfe2141c659ac31768beefcc586565bc03a5f Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Thu, 21 Nov 2024 17:54:10 -0500 Subject: [PATCH 13/17] f4/flash: unlock flash before return Signed-off-by: Eileen Yoon --- common/phal_F4_F7/flash/flash.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/common/phal_F4_F7/flash/flash.c b/common/phal_F4_F7/flash/flash.c index 1af47e5e..06ea161a 100644 --- a/common/phal_F4_F7/flash/flash.c +++ b/common/phal_F4_F7/flash/flash.c @@ -14,7 +14,7 @@ /** * @brief Convert address to sector number * Assumes addr is within flash addr space - * + * * @param addr Flash address * @return The flash sector */ @@ -139,7 +139,11 @@ uint8_t PHAL_flashErasePage(uint8_t page) while ((FLASH->SR & FLASH_SR_BSY) && ++timeout < PHAL_FLASH_TIMEOUT) asm("nop"); - if (timeout == PHAL_FLASH_TIMEOUT) return FLASH_TIMEOUT; + if (timeout == PHAL_FLASH_TIMEOUT) + { + flashLock(); + return FLASH_TIMEOUT; + } // Disable page erase and clear the page request FLASH->CR &= ~(FLASH_CR_SER | FLASH_CR_SNB_Msk); From 94144dabb2c311fea30d759e07fad7e99cca5e71 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Mon, 25 Nov 2024 16:11:30 -0500 Subject: [PATCH 14/17] f4/flash: Add useless flash read u32 fn Signed-off-by: Eileen Yoon --- common/phal_F4_F7/flash/flash.c | 21 +++++++++++++++++++++ common/phal_F4_F7/flash/flash.h | 2 ++ 2 files changed, 23 insertions(+) diff --git a/common/phal_F4_F7/flash/flash.c b/common/phal_F4_F7/flash/flash.c index 06ea161a..26ad4326 100644 --- a/common/phal_F4_F7/flash/flash.c +++ b/common/phal_F4_F7/flash/flash.c @@ -60,6 +60,27 @@ static void flashLock() FLASH->CR |= FLASH_CR_LOCK; // Set-only bit, will be cleared upon next succcessful flash unlock } +uint32_t PHAL_flashReadU32(uint32_t addr) +{ + // technically it's undef bheavior if we read flash while writing but this is slow +#if 0 + uint32_t val = 0xFFFFFFFF; + uint8_t ret; + if (addr < FLASH_BASE || addr > FLASH_END) + return 0xFFFFFFFF; + + ret = flashUnlock(); + if (ret != FLASH_OK) return ret; + + val = *((__IO uint32_t*) addr); + + flashLock(); +#else + uint32_t val = *((__IO uint32_t*) addr); +#endif + return val; +} + uint8_t PHAL_flashWriteU32(uint32_t Address, uint32_t value) { uint32_t timeout = 0; diff --git a/common/phal_F4_F7/flash/flash.h b/common/phal_F4_F7/flash/flash.h index 413d81f9..9e60c71e 100644 --- a/common/phal_F4_F7/flash/flash.h +++ b/common/phal_F4_F7/flash/flash.h @@ -66,6 +66,8 @@ enum #define MAX_FLASH_SECTOR (8-1) #endif +uint32_t PHAL_flashReadU32(uint32_t addr); + uint8_t PHAL_flashWriteU32(uint32_t address, uint32_t value); uint8_t PHAL_flashWriteU64(uint32_t address, uint64_t data); uint8_t PHAL_flashErasePage(uint8_t page); From 4621645962cb062c30239b05eb89b8b1070ac5e0 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Mon, 25 Nov 2024 16:12:03 -0500 Subject: [PATCH 15/17] f4/flash: Add buffered flash write function Signed-off-by: Eileen Yoon --- common/phal_F4_F7/flash/flash.c | 38 +++++++++++++++++++++++++++++++-- common/phal_F4_F7/flash/flash.h | 2 ++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/common/phal_F4_F7/flash/flash.c b/common/phal_F4_F7/flash/flash.c index 26ad4326..567adebc 100644 --- a/common/phal_F4_F7/flash/flash.c +++ b/common/phal_F4_F7/flash/flash.c @@ -106,8 +106,7 @@ uint8_t PHAL_flashWriteU32(uint32_t Address, uint32_t value) // Write word *(__IO uint32_t*)Address = value; - asm("nop"); - asm("nop"); + __DSB(); while ((FLASH->SR & FLASH_SR_BSY) && ++timeout < PHAL_FLASH_TIMEOUT) asm("nop"); @@ -135,6 +134,41 @@ uint8_t PHAL_flashWriteU64(uint32_t Address, uint64_t Data) return ret; } +uint8_t PHAL_flashWriteU32_Buffered(uint32_t Address, uint32_t *data, uint32_t count) +{ + uint32_t timeout = 0; + uint8_t ret; + ret = flashUnlock(); + if (ret != FLASH_OK) return ret; + + // Wait until not busy + while ((FLASH->SR & FLASH_SR_BSY) && ++timeout < PHAL_FLASH_TIMEOUT) + asm("nop"); + if (timeout == PHAL_FLASH_TIMEOUT) return FLASH_TIMEOUT; + timeout = 0; + + // Set 32 bit parallelism (see RM 0090 Page 85) + FLASH->CR &= ~(FLASH_CR_PSIZE_Msk); + FLASH->CR |= FLASH_CR_PSIZE_1; + + // Enable flash programming + FLASH->CR |= FLASH_CR_PG; + + for (uint32_t i = 0; i < count; i++) + *(__IO uint32_t *)(Address + i * 4) = data[i]; + __DSB(); + + while ((FLASH->SR & FLASH_SR_BSY) && ++timeout < PHAL_FLASH_TIMEOUT) + asm("nop"); + if (timeout == PHAL_FLASH_TIMEOUT) return FLASH_TIMEOUT; + + // Disable flash programming + FLASH->CR &= ~(FLASH_CR_PG); + flashLock(); + + return FLASH_OK; +} + uint8_t PHAL_flashErasePage(uint8_t page) { // Validate page request diff --git a/common/phal_F4_F7/flash/flash.h b/common/phal_F4_F7/flash/flash.h index 9e60c71e..32521214 100644 --- a/common/phal_F4_F7/flash/flash.h +++ b/common/phal_F4_F7/flash/flash.h @@ -69,6 +69,8 @@ enum uint32_t PHAL_flashReadU32(uint32_t addr); uint8_t PHAL_flashWriteU32(uint32_t address, uint32_t value); +uint8_t PHAL_flashWriteU32_Buffered(uint32_t Address, uint32_t *data, uint32_t count); + uint8_t PHAL_flashWriteU64(uint32_t address, uint64_t data); uint8_t PHAL_flashErasePage(uint8_t page); uint8_t PHAL_flashErase(uint32_t *addr, uint32_t words); From 0d5742254784c83e4fceae0a16f8670aa96b94d7 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Mon, 25 Nov 2024 16:49:16 -0500 Subject: [PATCH 16/17] f4/crc: Add CRC PHAL Signed-off-by: Eileen Yoon --- common/phal_F4_F7/crc/crc.c | 75 +++++++++++++++++++++++++++++++++++++ common/phal_F4_F7/crc/crc.h | 31 +++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 common/phal_F4_F7/crc/crc.c create mode 100644 common/phal_F4_F7/crc/crc.h diff --git a/common/phal_F4_F7/crc/crc.c b/common/phal_F4_F7/crc/crc.c new file mode 100644 index 00000000..3c041217 --- /dev/null +++ b/common/phal_F4_F7/crc/crc.c @@ -0,0 +1,75 @@ +/** + * @file crc.c + * @author Eileen Yoon (eyn@purdue.edu) + * @brief Hardware CRC32 w/ software fallback + * @version 0.1 + * @date 2024-11-25 + * + * @copyright Copyright (c) 2024 + * + */ + +#include "crc.h" + +void PHAL_CRC32_Reset(void) +{ + // CRC initializaion +#if defined(STM32L496xx) || defined(STM32L432xx) || defined(STM32F732xx) + RCC->AHB1ENR |= RCC_AHB1ENR_CRCEN; // Clock the CRC peripheral + CRC->INIT = 0xFFFFFFFF; // Reset initial value + CRC->CR &= ~CRC_CR_POLYSIZE_Msk; // Set 32 bit (00) + CRC->POL = 0x04C11DB7; // CRC-32b (Ethernet Polynomial) + CRC->CR |= CRC_CR_RESET; // Reset CRC +#else + RCC->AHB1ENR |= RCC_AHB1ENR_CRCEN; // F4 only supports CRC-32b + CRC->CR = CRC_CR_RESET; +#endif +} + +void PHAL_CRC32_Init(void) +{ + PHAL_CRC32_Reset(); +} + +uint32_t PHAL_CRC32_Calculate(uint32_t *data, uint32_t count) +{ + PHAL_CRC32_Reset(); + __DSB(); + + for (uint32_t i = 0; i < count; i++) + CRC->DR = data[i]; + + return CRC->DR; +} + +static const uint32_t crc32b_LUT[16] = { + 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, + 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, + 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, + 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, +}; + +static inline uint32_t update_crc(uint32_t crc, uint32_t data) +{ + crc = crc ^ data; // Apply all 32-bits + + // Process 32-bits, 4 at a time, or 8 rounds + crc = (crc << 4) ^ crc32b_LUT[crc >> 28]; + crc = (crc << 4) ^ crc32b_LUT[crc >> 28]; + crc = (crc << 4) ^ crc32b_LUT[crc >> 28]; + crc = (crc << 4) ^ crc32b_LUT[crc >> 28]; + crc = (crc << 4) ^ crc32b_LUT[crc >> 28]; + crc = (crc << 4) ^ crc32b_LUT[crc >> 28]; + crc = (crc << 4) ^ crc32b_LUT[crc >> 28]; + crc = (crc << 4) ^ crc32b_LUT[crc >> 28]; + + return crc; +} + +uint32_t PHAL_CRC32_CalculateSW(uint32_t *data, uint32_t count) +{ + uint32_t crc = 0xFFFFFFFF; + for (uint32_t i = 0; i < count; i++) + crc = update_crc(crc, data[i]); + return crc; +} diff --git a/common/phal_F4_F7/crc/crc.h b/common/phal_F4_F7/crc/crc.h new file mode 100644 index 00000000..b5cd6f90 --- /dev/null +++ b/common/phal_F4_F7/crc/crc.h @@ -0,0 +1,31 @@ +/** + * @file crc.h + * @author Eileen Yoon (eyn@purdue.edu) + * @brief Hardware CRC32 w/ software fallback + * @version 0.1 + * @date 2024-11-25 + * + * @copyright Copyright (c) 2024 + * + */ + +#ifndef _PHAL_CRC_H +#define _PHAL_CRC_H + +#if defined(STM32F407xx) +#include "stm32f4xx.h" +#include "system_stm32f4xx.h" +#elif defined(STM32F732xx) +#include "stm32f7xx.h" +#include "system_stm32f7xx.h" +#else +#error "Please define a MCU arch" +#endif + +void PHAL_CRC32_Reset(void); + +uint32_t PHAL_CRC32_Calculate(uint32_t *data, uint32_t count); + +uint32_t PHAL_CRC32_CalculateSW(uint32_t *data, uint32_t count); + +#endif // _PHAL_CRC_H From c825de226e4d7f8a1407a8dfbbe239b551d04979 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Mon, 25 Nov 2024 16:12:47 -0500 Subject: [PATCH 17/17] bootloader: Bootloader overhaul v2 Signed-off-by: Eileen Yoon --- common/bootloader/bootloader_common.h | 4 +- common/linker/STM32F407VGTx_FLASH_APP.ld | 2 +- common/linker/STM32F407VGTx_FLASH_BL.ld | 4 +- source/bootloader/CMakeLists.txt | 12 +- source/bootloader/bootloader/bootloader.c | 419 +++++++++++++--------- source/bootloader/bootloader/bootloader.h | 38 +- source/bootloader/main.c | 329 ++--------------- 7 files changed, 303 insertions(+), 505 deletions(-) diff --git a/common/bootloader/bootloader_common.h b/common/bootloader/bootloader_common.h index fba35068..27a1768f 100644 --- a/common/bootloader/bootloader_common.h +++ b/common/bootloader/bootloader_common.h @@ -27,9 +27,9 @@ typedef enum { BLCMD_START = 0x1, /* Request to start firmware download */ BLCMD_CRC = 0x3, /* Final CRC-32b check of firmware */ + BLCMD_CRC_BACKUP = 0x2, + BLCMD_JUMP = 0x4, /* Request to start firmware download */ BLCMD_RST = 0x5, /* Request for reset */ - BLCMD_SET_ADDR = 0x6, /* Jump relative base address (used for discontiguous firmware segments) */ - BLCMD_SET_SIZE = 0x7, /* Set number of discontiguous firmware words to transfer */ } BLCmd_t; typedef enum { diff --git a/common/linker/STM32F407VGTx_FLASH_APP.ld b/common/linker/STM32F407VGTx_FLASH_APP.ld index 4e1c34b1..762a529d 100644 --- a/common/linker/STM32F407VGTx_FLASH_APP.ld +++ b/common/linker/STM32F407VGTx_FLASH_APP.ld @@ -48,7 +48,7 @@ MEMORY { CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K - FLASH (rx) : ORIGIN = 0x8004000, LENGTH = 1008K + FLASH (rx) : ORIGIN = 0x8008000, LENGTH = 992K } /* Sections */ diff --git a/common/linker/STM32F407VGTx_FLASH_BL.ld b/common/linker/STM32F407VGTx_FLASH_BL.ld index af717668..a6c05240 100644 --- a/common/linker/STM32F407VGTx_FLASH_BL.ld +++ b/common/linker/STM32F407VGTx_FLASH_BL.ld @@ -43,14 +43,14 @@ _estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ _Min_Heap_Size = 0x200; /* required amount of heap */ _Min_Stack_Size = 0x400; /* required amount of stack */ -PROVIDE(_eboot_flash = 0x08004000); /* End of the bootloader flash, this is where the application begins*/ +PROVIDE(_eboot_flash = 0x08008000); /* End of the bootloader flash, this is where the application begins*/ /* Memories definition */ MEMORY { CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K - FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 16K + FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 32K } /* Sections */ diff --git a/source/bootloader/CMakeLists.txt b/source/bootloader/CMakeLists.txt index e3d51f34..d8ea6484 100644 --- a/source/bootloader/CMakeLists.txt +++ b/source/bootloader/CMakeLists.txt @@ -5,8 +5,8 @@ get_filename_component(COMPONENT_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) STRING(TOLOWER ${COMPONENT_NAME} COMPONENT_NAME) -set(L432_BOOTLOADER_NAMES l4_testing) -set(L496_BOOTLOADER_NAMES ) +#set(L432_BOOTLOADER_NAMES l4_testing) +#set(L496_BOOTLOADER_NAMES ) set(F407_BOOTLOADER_NAMES dashboard main_module pdu a_box f4_testing daq) set(F732_BOOTLOADER_NAMES torquevector f7_testing) if (BOOTLOADER_BUILD) @@ -18,7 +18,7 @@ if (BOOTLOADER_BUILD) target_compile_definitions(${TARGET_NAME} PUBLIC APP_ID=APP_${BL_NAME_UPPER}) # Propreties are set in order to make the common component - set_target_properties(${TARGET_NAME} PROPERTIES + set_target_properties(${TARGET_NAME} PROPERTIES COMPONENT_NAME ${COMPONENT_NAME}_${BL_NAME} COMPONENT_DIR ${CMAKE_CURRENT_LIST_DIR} LINKER_SCRIPT "STM32L432KCUx_FLASH" @@ -36,7 +36,7 @@ if (BOOTLOADER_BUILD) target_compile_definitions(${TARGET_NAME} PUBLIC APP_ID=APP_${BL_NAME_UPPER}) # Propreties are set in order to make the common component - set_target_properties(${TARGET_NAME} PROPERTIES + set_target_properties(${TARGET_NAME} PROPERTIES COMPONENT_NAME ${COMPONENT_NAME}_${BL_NAME} COMPONENT_DIR ${CMAKE_CURRENT_LIST_DIR} LINKER_SCRIPT "STM32L496VGTx_FLASH" @@ -54,7 +54,7 @@ if (BOOTLOADER_BUILD) target_compile_definitions(${TARGET_NAME} PUBLIC APP_ID=APP_${BL_NAME_UPPER}) # Propreties are set in order to make the common component - set_target_properties(${TARGET_NAME} PROPERTIES + set_target_properties(${TARGET_NAME} PROPERTIES COMPONENT_NAME ${COMPONENT_NAME}_${BL_NAME} COMPONENT_DIR ${CMAKE_CURRENT_LIST_DIR} LINKER_SCRIPT "STM32F407VGTx_FLASH" @@ -71,7 +71,7 @@ if (BOOTLOADER_BUILD) target_compile_definitions(${TARGET_NAME} PUBLIC APP_ID=APP_${BL_NAME_UPPER}) # Propreties are set in order to make the common component - set_target_properties(${TARGET_NAME} PROPERTIES + set_target_properties(${TARGET_NAME} PROPERTIES COMPONENT_NAME ${COMPONENT_NAME}_${BL_NAME} COMPONENT_DIR ${CMAKE_CURRENT_LIST_DIR} LINKER_SCRIPT "STM32F732RETX_FLASH" diff --git a/source/bootloader/bootloader/bootloader.c b/source/bootloader/bootloader/bootloader.c index 92371b21..29dda969 100644 --- a/source/bootloader/bootloader/bootloader.c +++ b/source/bootloader/bootloader/bootloader.c @@ -1,11 +1,14 @@ /** - * @file process.c - * @author your name (you@domain.com) - * @brief + * @file bootloader.c + * @author Eileen Yoon (eyn@purdue.edu) + * @brief CAN Bootloader: + * - Double bank flash buffer + CRC + * - Download/Upload firmware over buffered CAN TP + * - Load/store backup firmware * @version 0.1 - * @date 2022-02-28 + * @date 2024-11-24 * - * @copyright Copyright (c) 2022 + * @copyright Copyright (c) 2024 * */ @@ -17,211 +20,289 @@ #if defined(STM32F407xx) || defined(STM32F732xx) #include "common/phal_F4_F7/flash/flash.h" #include "common/phal_F4_F7/gpio/gpio.h" +#include "common/phal_F4_F7/crc/crc.h" #endif -static uint32_t* app_flash_start_address; /* Store the start address of the Application, never changes */ -static volatile uint32_t* app_flash_current_address; /* Current address we are writing to */ -static volatile uint32_t app_flash_size = 0; -static volatile uint32_t app_flash_written = 0; -static volatile uint32_t app_flash_segment_written = 0; -static volatile uint32_t* bootloader_ms; +/* F4: + * 0x08000000 ] 16K [bootloader code] + * 0x08004000 ] 16K [metadata region/boot manager] + * 0x08008000 ] 256K [application] + * 0x08040000 ] 256K [temporary buffer] + * 0x08080000 ] 256K [backup firmware] + */ -extern q_handle_t q_tx_can; +#define MAX_FIRMWARE_SIZE 0x40000 -void BL_init(uint32_t* app_flash_start, volatile uint32_t* bootloader_ms_ptr) -{ - // CRC initializaion -#if defined(STM32L496xx) || defined(STM32L432xx) || defined(STM32F732xx) - RCC->AHB1ENR |= RCC_AHB1ENR_CRCEN; // Clock the CRC peripheral - CRC->INIT = 0xFFFFFFFF; // Reset initial value - CRC->CR &= ~CRC_CR_POLYSIZE_Msk; // Set 32 bit (00) - CRC->POL = 0x04C11DB7; // CRC-32b (Ethernet Polynomial) - CRC->CR |= CRC_CR_RESET; // Reset CRC +#define BL_ADDRESS_BOOTLOADER 0x08000000 // 0: bootloader (sector 0, 16K) +#define BL_ADDRESS_CRC 0x08004000 // 1: crc metadata (sector 1, 16K) +#define BL_ADDRESS_APP 0x08008000 // 2: application (256K) +//#define BL_ENABLE_DOUBLE_BANK +#if defined(BL_ENABLE_DOUBLE_BANK) +#define BL_ADDRESS_BUFFER 0x08040000 // 3: temporary buffer (256K) #else - RCC->AHB1ENR |= RCC_AHB1ENR_CRCEN; - CRC->CR = CRC_CR_RESET; +#define BL_ADDRESS_BUFFER BL_ADDRESS_APP #endif +#define BL_ADDRESS_BACKUP 0x08080000 // 4: last known good firmware (256K) - app_flash_start_address = app_flash_start; - app_flash_current_address = app_flash_start; // base - app_flash_written = 0; - app_flash_segment_written = 0; - bootloader_ms = bootloader_ms_ptr; -} +#define BL_ADDRESS_CRC_CRC ((BL_ADDRESS_CRC) + 0) +#define BL_ADDRESS_CRC_ADDR ((BL_ADDRESS_CRC) + 4) +#define BL_ADDRESS_CRC_SIZE ((BL_ADDRESS_CRC) + 8) -//#define DEBUG static bool bl_unlock = false; -static bool flash_complete = false; -static uint32_t num_msg = 0; -static uint32_t first_word = 0; -static uint32_t second_word = 0; +static volatile uint32_t firmware_size_total = 0; -void BL_processCommand(BLCmd_t cmd, uint32_t data) +// flash write buffering +#define BUFFER_SIZE 128 +static uint32_t buffer[BUFFER_SIZE]; +static uint32_t buffer_index = 0; +// #define EXECUTE_FROM_RAM __attribute__ ((section(".RamFunc"))) + +extern char __isr_vector_start; /* VA of the vector table for the bootloader */ +extern char _eboot_flash; /* End of the bootlaoder flash region, same as the application start address */ +extern char _estack; /* The start location of the stack */ + +static void BL_JumptoApplication(void) { - switch (cmd) + uint32_t app_reset_handler_address = *(uint32_t*) (((void *) &_eboot_flash + 4)); + uint32_t msp = (uint32_t) *((uint32_t*) (((void *) &_eboot_flash))); + uint32_t estack = (uint32_t) ((uint32_t*) (((void *) &_estack))); + + // Confirm app exists + if (app_reset_handler_address == 0xFFFFFFFF || + app_reset_handler_address <= BL_ADDRESS_CRC || msp != estack) + return; + + // Reset all of our used peripherals + RCC->AHB1RSTR |= RCC_AHB1RSTR_CRCRST; + RCC->AHB1RSTR &= ~(RCC_AHB1RSTR_CRCRST); +#if defined(STM32F407xx) || defined(STM32F732xx) + RCC->APB1RSTR |= RCC_APB1RSTR_CAN1RST; + RCC->APB1RSTR &= ~(RCC_APB1RSTR_CAN1RST); +#else + RCC->APB1RSTR1 |= RCC_APB1RSTR1_CAN1RST; + RCC->APB1RSTR1 &= ~(RCC_APB1RSTR1_CAN1RST); +#endif + SysTick->CTRL = 0; + SysTick->LOAD = 0; + SysTick->VAL = 0; + + // Make sure the interrupts are disabled before we start attempting to jump to the app + // Getting an interrupt after we set VTOR would be bad. + // Actually jump to application + __disable_irq(); + __set_MSP(msp); + SCB->VTOR = (uint32_t) (uint32_t*) (((void *) &_eboot_flash)); + __enable_irq(); + ((void(*)(void)) app_reset_handler_address)(); // jump +} + +void BL_checkAndBoot(void) +{ + // Check 16K metadata region to decide what to boot + uint32_t crc_stored = PHAL_flashReadU32(BL_ADDRESS_CRC_CRC); + uint32_t addr = PHAL_flashReadU32(BL_ADDRESS_CRC_ADDR); + uint32_t size = PHAL_flashReadU32(BL_ADDRESS_CRC_SIZE); + if (crc_stored && size && (size < MAX_FIRMWARE_SIZE) && (addr >= FLASH_BASE) && (addr <= FLASH_END)) { - case BLCMD_START: - { - // data: padded total flash size (num words), i.e. end addr - start addr - app_flash_current_address = app_flash_start_address; // init - app_flash_written = 0; - app_flash_segment_written = 0; - *bootloader_ms = 0; - - #ifndef DEBUG - if (data && PHAL_flashErase(app_flash_start_address, data) != FLASH_OK) - { - BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_FLASH); - bl_unlock = false; - return; - } - else - #endif - { - BL_sendStatusMessage(BLSTAT_METDATA_RX, (uint32_t) data); - } - flash_complete = false; - num_msg = 0; - first_word = second_word = 0; - CRC->CR |= CRC_CR_RESET; // Reset CRC - bl_unlock = true; - break; - } - case BLCMD_CRC: + if (PHAL_CRC32_Calculate((uint32_t *)addr, size / 4) == crc_stored) { - // data: CRC checksum - if (bl_unlock && app_flash_written == app_flash_size) - { - if (CRC->DR != data) - BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_CRC_FAIL); - else - { - // Firmware download successful - // Program first double word - if (PHAL_flashWriteU64((uint32_t) app_flash_start_address, (((uint64_t) second_word) << 32) | first_word) != FLASH_OK) - { - BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_FLASH); - bl_unlock = false; - flash_complete = false; - } - else - { - BL_sendStatusMessage(BLSTAT_DONE, 0); - bl_unlock = false; - flash_complete = true; - } - } - } - else if (!bl_unlock) - BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_LOCKED); - else - BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_LOW_ADDR); - break; - } - case BLCMD_SET_SIZE: - { - // data: unpadded firmware size i.e. sum of segments - // should be called only once - app_flash_size = data; // num crc words to transfer - break; - } - case BLCMD_SET_ADDR: - { - // data: new relative base address of segment - app_flash_current_address = (uint32_t* )data; - app_flash_segment_written = 0; // reset local counter - break; - } - case BLCMD_RST: - Bootloader_ResetForFirmwareDownload(); - break; - default: - { - BL_sendStatusMessage(BLSTAT_UNKNOWN_CMD, cmd); - break; + BL_JumptoApplication(); } } } -bool BL_flashStarted(void) +static int BL_processCommand_Start(uint32_t size) { - return bl_unlock; -} + firmware_size_total = 0; -bool BL_flashComplete(void) -{ - return (num_msg > 10) && flash_complete; + // TODO store CRC + size at the end of firmware + if (!size || size >= MAX_FIRMWARE_SIZE || size & 3) + { + BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_SIZE); + return -1; + } + + if (PHAL_flashErase((uint32_t *)BL_ADDRESS_BUFFER, size / 4) != FLASH_OK) + { + BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_FLASH); + return -1; + } + + buffer_index = 0; + firmware_size_total = size; + BL_sendStatusMessage(BLSTAT_VALID, firmware_size_total); + bl_unlock = true; + return 0; } -volatile uint32_t* BL_getCurrentFlashAddress(void) +static int BL_memcpy_buffer(uint32_t addr_dst, uint32_t addr_src, uint32_t size) { - return app_flash_current_address + app_flash_segment_written; + if (PHAL_flashErase((uint32_t *)addr_dst, size / 4) != FLASH_OK) + return -1; + + for (uint32_t i = 0; i < size / 4; i++) + { + uint32_t offset = i * sizeof(uint32_t); + if (PHAL_flashWriteU32(addr_dst + offset, *(__IO uint32_t*)(addr_src + offset)) != FLASH_OK) + return -1; + } + + return 0; } -void BL_timeout(void) +static int BL_setCRCConfig(uint32_t crc, uint32_t addr, uint32_t size) { + int ret; + + PHAL_flashErase((uint32_t *)BL_ADDRESS_CRC, 3); + + if (PHAL_flashWriteU32(BL_ADDRESS_CRC_CRC, crc) != FLASH_OK) + { + ret = -1; + goto erase_crc; + } + if (PHAL_flashWriteU32(BL_ADDRESS_CRC_ADDR, addr) != FLASH_OK) + { + ret = -1; + goto erase_crc; + } + if (PHAL_flashWriteU32(BL_ADDRESS_CRC_SIZE, size) != FLASH_OK) + { + ret = -1; + goto erase_crc; + } + + ret = 0; + goto exit; + +erase_crc: + // erases whole sector so size doesnt matter + PHAL_flashErase((uint32_t *)BL_ADDRESS_CRC, 3); // nothing we can do on failure +exit: bl_unlock = false; - num_msg = 0; - flash_complete = false; + return ret; } +// TODO bandwidth is halved because we send u32s with a u16 index. +// Integrate ISO-TP branch and properly buffer flash writes void bitstream_data_CALLBACK(CanParsedData_t* msg_data_a) { + uint64_t data = *((uint64_t *) msg_data_a->raw_data); + // firmware max 0x40000, so max ID is 0xffff, u16 sufficient + uint32_t index = data & 0xffff; + uint32_t payload = (data >> 16) & 0xffffffff; - #if (APP_ID == APP_L4_TESTING) - PHAL_writeGPIO(GPIOB, 7, 1); - #endif - uint64_t data; - if (bl_unlock) +#if 1 + uint32_t buffer_addr = BL_ADDRESS_BUFFER + (uint32_t)index * sizeof(uint32_t) - (0 * sizeof(buffer[0])); + if (PHAL_flashWriteU32_Buffered(buffer_addr, &payload, 1) != FLASH_OK) { - if (app_flash_written < app_flash_size) + BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_FLASH); + } +#else // flash buffering (works but kinda unsafe) + buffer[buffer_index++] = payload; + if (buffer_index == BUFFER_SIZE || index == (firmware_size_total / 4 - 1)) + { + uint32_t buffer_addr = BL_ADDRESS_BUFFER + (uint32_t)index * sizeof(uint32_t) - ((buffer_index - 1) * sizeof(buffer[0])); + if (PHAL_flashWriteU32_Buffered(buffer_addr, buffer, buffer_index) != FLASH_OK) { - num_msg++; - data = *((uint64_t *) msg_data_a->raw_data); - uint32_t curr_addr = (uint32_t) app_flash_current_address + app_flash_segment_written * sizeof(uint32_t); - - // Skip the first two words - if (!app_flash_written) - { - CRC->DR = first_word = *((uint32_t *) msg_data_a->raw_data); - CRC->DR = second_word = *((uint32_t *) msg_data_a->raw_data + 1); - } - else - { - // Address is 2-word aligned, do the actual programming now - #ifndef DEBUG - if (PHAL_flashWriteU64(curr_addr, data) != FLASH_OK) - { - BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_FLASH); - bl_unlock = false; - } - else - #endif - { - CRC->DR = *((uint32_t *)curr_addr); - CRC->DR = *((uint32_t *)(curr_addr + sizeof(uint32_t))); - } - } - *bootloader_ms = 0; // Reset timeout counter, message received! - app_flash_written += 2; // wrote 64 bits - app_flash_segment_written += 2; + BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_FLASH); } - else + buffer_index = 0; + } +#endif + + //BL_sendStatusMessage(BLSTAT_INVALID, 6); // dont send ack msg, too slow + return; +} + +static int BL_processCommand_CRC(uint32_t crc_app, uint32_t dst_addr) +{ + uint32_t size = firmware_size_total; + if (!size) + { + BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_SIZE); + return -1; + } + + uint32_t crc_flash; + crc_flash = PHAL_CRC32_Calculate((uint32_t *)BL_ADDRESS_BUFFER, size / 4); + if (crc_flash != crc_app) + { + BL_sendStatusMessage(BLSTAT_INVALID_CRC, crc_flash); + return -1; + } + +#ifdef BL_ENABLE_DOUBLE_BANK + BL_memcpy_buffer(dst_addr, BL_ADDRESS_BUFFER, size); + crc_flash = PHAL_CRC32_Calculate((uint32_t *)dst_addr, size / 4); + if (crc_flash != crc_app) + { + BL_sendStatusMessage(BLSTAT_INVALID_CRC, crc_flash); + return -1; + } +#endif // BL_ENABLE_DOUBLE_BANK + + if (BL_setCRCConfig(crc_app, dst_addr, size)) + { + BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_FLASH); + return -1; + } + + BL_sendStatusMessage(BLSTAT_VALID, crc_flash); + return 0; +} + +static void BL_processCommand_Reset(uint32_t data) +{ + Bootloader_ResetForFirmwareDownload(); // back to start of flash +} + +static void BL_processCommand_Jump(uint32_t data) +{ + bl_unlock = true; + if (data == 0xdeadbeef) // boot backup firmware + { + // TODO store backup firmware size somehow + BL_memcpy_buffer(BL_ADDRESS_APP, BL_ADDRESS_BACKUP, MAX_FIRMWARE_SIZE); + } + BL_JumptoApplication(); +} + +void BL_processCommand(BLCmd_t cmd, uint32_t data) +{ + switch (cmd) + { + case BLCMD_START: + BL_processCommand_Start(data); + break; + case BLCMD_CRC: + BL_processCommand_CRC(data, BL_ADDRESS_APP); + break; + case BLCMD_CRC_BACKUP: + BL_processCommand_CRC(data, BL_ADDRESS_BACKUP); + break; + case BLCMD_JUMP: + BL_processCommand_Jump(data); + break; + case BLCMD_RST: + BL_processCommand_Reset(data); + break; + default: { - BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_ADDR_BOUND); + BL_sendStatusMessage(BLSTAT_UNKNOWN_CMD, cmd); + break; } } +} - #if (APP_ID == APP_L4_TESTING) - PHAL_writeGPIO(GPIOB, 7, 0); - #endif +bool BL_flashStarted(void) +{ + return bl_unlock; } /* - Component specific callbacks -*/ - -// Quickly setup case statments for send function based on Node ID + * Component specific callbacks + */ #define NODE_CASE_BL_RESPONSE(app_id, resp_func) \ case app_id:\ resp_func(cmd, data);\ diff --git a/source/bootloader/bootloader/bootloader.h b/source/bootloader/bootloader/bootloader.h index fb19a929..ae3fb76b 100644 --- a/source/bootloader/bootloader/bootloader.h +++ b/source/bootloader/bootloader/bootloader.h @@ -19,15 +19,10 @@ typedef enum { - BLSTAT_INVALID = 0, /* Invalid operation */ - BLSTAT_BOOT = 1, /* Bootloader boot alert */ - BLSTAT_WAIT = 2, /* Stage 1: RST done, waiting for BLCMD */ - BLSTAT_METDATA_RX = 3, /* Stage 2: Flash erase done */ - BLSTAT_PROGRESS = 4, /* Progress update for bootloader download */ - BLSTAT_DONE = 5, /* Stage 3: Completed firmware transfer with CRC checksum */ - BLSTAT_JUMP_TO_APP = 6, /* About to jump to application */ - BLSTAT_INVAID_APP = 7, /* Did not attempt to boot because the starting address was invalid */ - BLSTAT_UNKNOWN_CMD = 8, /* Incorrect CAN command message format */ + BLSTAT_VALID = 0, + BLSTAT_INVALID = 1, + BLSTAT_INVALID_CRC = 2, + BLSTAT_UNKNOWN_CMD = 3, } BLStatus_t; typedef enum @@ -37,36 +32,15 @@ typedef enum BLERROR_LOW_ADDR = 2, BLERROR_ADDR_BOUND = 3, BLERROR_FLASH = 4, + BLERROR_SIZE = 5, } BLError_t; -void BL_init(uint32_t* app_flash_start, volatile uint32_t* bootloader_ms_ptr); +void BL_checkAndBoot(void); -/** - * @brief Process an incoming bootlaoder command - * - * @param cmd - * @param data - */ void BL_processCommand(BLCmd_t cmd, uint32_t data); -/** - * @brief The entire application has been written to flash. - * - * @return true - * @return false - */ -bool BL_flashComplete(void); - -/** - * @brief Send a Bootloader status message with the correct app ID - * - * @param cmd Command/status enum, see BLStatus_t - * @param data Status data, context specific - */ void BL_sendStatusMessage(uint8_t cmd, uint32_t data); bool BL_flashStarted(void); -void BL_timeout(void); -volatile uint32_t* BL_getCurrentFlashAddress(void); #endif diff --git a/source/bootloader/main.c b/source/bootloader/main.c index 3420de5b..227e44c2 100644 --- a/source/bootloader/main.c +++ b/source/bootloader/main.c @@ -1,25 +1,5 @@ -/* System Includes */ - -#include "inttypes.h" - -#ifdef STM32L432xx -#include "stm32l432xx.h" -#endif - -#ifdef STM32L496xx -#include "stm32l496xx.h" -#endif - -#ifdef STM32F407xx -#include "stm32f407xx.h" -#endif - -#ifdef STM32F732xx -#include "stm32f732xx.h" -#endif -// #include "system_stm32l4xx.h" +#include "common/bootloader/bootloader_common.h" -#include "can_parse.h" #if defined(STM32L496xx) || defined(STM32L432xx) #include "common/phal_L4/can/can.h" #include "common/phal_L4/gpio/gpio.h" @@ -31,36 +11,22 @@ #include "common/phal_F4_F7/rcc/rcc.h" #endif -#include "common/bootloader/bootloader_common.h" - - /* Module Includes */ +#include "can_parse.h" #include "node_defs.h" #include "bootloader.h" -#define CAN_TX_BLOCK_TIMEOUT (30 * 16000) // clock rate 16MHz, 15ms * 16000 cyc / ms /* PER HAL Initilization Structures */ GPIOInitConfig_t gpio_config[] = { CAN_RX_GPIO_CONFIG, CAN_TX_GPIO_CONFIG, - #if (APP_ID != APP_DASHBOARD) - GPIO_INIT_OUTPUT(STATUS_LED_GPIO_Port, STATUS_LED_Pin, GPIO_OUTPUT_LOW_SPEED), - #else - GPIO_INIT_OUTPUT_OPEN_DRAIN(STATUS_LED_GPIO_Port, STATUS_LED_Pin, GPIO_OUTPUT_LOW_SPEED), - #endif - - #if (APP_ID == APP_L4_TESTING) - GPIO_INIT_OUTPUT(GPIOB, 7, GPIO_OUTPUT_LOW_SPEED), - GPIO_INIT_OUTPUT(GPIOB, 6, GPIO_OUTPUT_LOW_SPEED), - GPIO_INIT_OUTPUT(GPIOB, 1, GPIO_OUTPUT_LOW_SPEED), - #endif - #if (APP_ID == APP_MAIN_MODULE) - GPIO_INIT_OUTPUT(GPIOD, 12, GPIO_OUTPUT_LOW_SPEED), - GPIO_INIT_OUTPUT(GPIOD, 14, GPIO_OUTPUT_LOW_SPEED), - #endif }; - /* TODO: remove ^ */ + +extern uint32_t APB1ClockRateHz; +extern uint32_t APB2ClockRateHz; +extern uint32_t AHBClockRateHz; +extern uint32_t PLLClockRateHz; #define TargetCoreClockrateHz 16000000 ClockRateConfig_t clock_config = { @@ -71,42 +37,25 @@ ClockRateConfig_t clock_config = { .apb2_clock_target_hz =(TargetCoreClockrateHz / (1)), }; -/* Locals for Clock Rates */ -extern uint32_t APB1ClockRateHz; -extern uint32_t APB2ClockRateHz; -extern uint32_t AHBClockRateHz; -extern uint32_t PLLClockRateHz; - -/* Function Prototypes */ void HardFault_Handler(); -extern void Default_Handler(); -void jump_to_application(void); -bool check_boot_health(void); void canTxSendToBack(CanMsgTypeDef_t *msg); static void send_pending_can(void); +static void BL_CANPoll(void); q_handle_t q_tx_can; q_handle_t q_rx_can; -extern char __isr_vector_start; /* VA of the vector table for the bootloader */ -extern char _eboot_flash; /* End of the bootlaoder flash region, same as the application start address */ -extern char _estack; /* The start location of the stack */ - -/* Bootlaoder timing control */ -static volatile uint32_t bootloader_ms = 0; -static volatile uint32_t bootloader_ms_2 = 0; -static volatile bool bootloader_timeout = false; -static volatile bool send_status_flag = true; -static bool send_flash_address = false; +#define BOOTLOADER_INITIAL_TIMEOUT 3000 // wait 3s at start +#define CAN_TX_BLOCK_TIMEOUT (30 * 16000) // clock rate 16MHz, 15ms * 16000 cyc / ms +static volatile uint32_t bootloader_ms = 0; // systick -int main (void) +int main(void) { /* Data Struct init */ qConstruct(&q_tx_can, sizeof(CanMsgTypeDef_t)); qConstruct(&q_rx_can, sizeof(CanMsgTypeDef_t)); bootloader_ms = 0; - /* HAL Initilization */ #ifdef HSI_TRIM_BL_NODE PHAL_trimHSI(HSI_TRIM_BL_NODE); #endif @@ -116,80 +65,39 @@ int main (void) if (1 != PHAL_initGPIO(gpio_config, sizeof(gpio_config)/sizeof(GPIOInitConfig_t))) HardFault_Handler(); + // Init bare minimum peripherals (systick, can1, crc) + SysTick_Config(SystemCoreClock / 1000); + NVIC_EnableIRQ(SysTick_IRQn); + if (1 != PHAL_initCAN(CAN1, false, VCAN_BPS)) HardFault_Handler(); - #if (APP_ID == APP_MAIN_MODULE) - PHAL_writeGPIO(GPIOD, 12, 0); - PHAL_writeGPIO(GPIOD, 14, 0); - #endif - - /* Module init */ initCANParse(&q_rx_can); - BL_init((uint32_t *) &_eboot_flash, &bootloader_ms); - - // Only enable application launch timeout if the device has not - // boot looped more than allowed. - bool allow_application_launch = check_boot_health(); - - SysTick_Config(SystemCoreClock / 1000); - NVIC_EnableIRQ(SysTick_IRQn); NVIC_EnableIRQ(CAN1_RX0_IRQn); - BL_sendStatusMessage(BLSTAT_BOOT, bootloader_shared_memory.reset_reason); + // BL_sendStatusMessage(BLSTAT_BOOT, 1); // TODO send initial message - /* - Main bootloader loop. - Will run until the systick timer times out or the bootloader process completes - */ - while(!bootloader_timeout || !allow_application_launch) + // bootloader can loop + while (bootloader_ms < BOOTLOADER_INITIAL_TIMEOUT || BL_flashStarted()) { - while (!qIsEmpty(&q_rx_can)) - canRxUpdate(); - - if (send_status_flag) - { - send_status_flag = false; - - if (!BL_flashStarted()) - BL_sendStatusMessage(BLSTAT_WAIT, bootloader_ms); - //else - // BL_sendStatusMessage(BLSTAT_PROGRESS, (uint32_t) BL_getCurrentFlashAddress()); - } - - // Send all pending CAN messages - send_pending_can(); + BL_CANPoll(); + } - /* - Check if firmware download is complete - Attempt to launch the app if so - */ - if (BL_flashComplete()) - { - allow_application_launch = true; - bootloader_timeout = true; - break; - } + // dont init can or systick before this + BL_checkAndBoot(); + while (1) // infinite bootloader can loop + { + BL_CANPoll(); } +} - NVIC_DisableIRQ(SysTick_IRQn); - NVIC_DisableIRQ(CAN1_RX0_IRQn); - - // Check the first word of the application, it should contain the MSP - // an address can not start with 0xFF for the MSP - BL_sendStatusMessage(BLSTAT_JUMP_TO_APP, 0); +static void BL_CANPoll(void) +{ send_pending_can(); - - - jump_to_application(); - - // Only sent if first double-word is NULL (no app exists) - BL_sendStatusMessage(BLSTAT_INVAID_APP, bootloader_shared_memory.reset_count); - bootloader_shared_memory.reset_reason = RESET_REASON_BAD_FIRMWARE; + while (!qIsEmpty(&q_rx_can)) + canRxUpdate(); send_pending_can(); - - NVIC_SystemReset(); } // Sends all pending messages in the tx queue, doesn't require systick to be active @@ -205,183 +113,13 @@ static void send_pending_can(void) } } -void SysTick_Handler(void) -{ - static uint16_t tick; - tick++; - bootloader_ms++; - - switch (bootloader_shared_memory.reset_reason) - { - case RESET_REASON_BAD_FIRMWARE: - case RESET_REASON_INVALID: - // Unknown reset cause or bad firmware - // Will infinetly wait in bootloader mode - if (tick % 100 == 0) - { - send_status_flag = true; - } - if (BL_flashStarted() && bootloader_ms >= 3000) - { - BL_timeout(); - bootloader_ms = 0; - } - break; - case RESET_REASON_BUTTON: - case RESET_REASON_DOWNLOAD_FW: - case RESET_REASON_APP_WATCHDOG: - // Watchdog reset or a bad firmware boot, - // stay in bootlaoder for 3 seconds before attempting to boot again - if (tick % 100 == 0) - { - send_status_flag = true; - } - if (bootloader_ms >= 3000) - { - send_status_flag = true; - bootloader_timeout = true; - } - break; - case RESET_REASON_POR: - if (tick % 100 == 0) - { - send_status_flag = true; - } - // Allow some time in case bootloader request present - if (bootloader_ms >= 500) - { - send_status_flag = true; - bootloader_timeout = true; - } - break; - default: - break; - } - - if ((BL_flashStarted() && tick % 50 == 0) || - !BL_flashStarted() && tick % 250 == 0) - PHAL_toggleGPIO(STATUS_LED_GPIO_Port, STATUS_LED_Pin); -} - -bool check_boot_health(void) -{ - // Initilize the shared memory block if it was corrupted or a POR - if(bootloader_shared_memory.magic_word != BOOTLOADER_SHARED_MEMORY_MAGIC) - { - bootloader_shared_memory.magic_word = BOOTLOADER_SHARED_MEMORY_MAGIC; - bootloader_shared_memory.reset_count = 0; - bootloader_shared_memory.reset_reason = RESET_REASON_POR; - } - - uint32_t reset_cause = RCC->CSR; - RCC->CSR |= RCC_CSR_RMVF; - - if (reset_cause & (RCC_CSR_BORRSTF | RCC_CSR_LPWRRSTF)) - { - // Power-on-reset, update reset count to initial value - // reset_count could have been garbage otherwise - bootloader_shared_memory.reset_reason = RESET_REASON_POR; - bootloader_shared_memory.reset_count = 0; - } - else if ((reset_cause & RCC_CSR_SFTRSTF) == RCC_CSR_SFTRSTF) - { - // Software reset - // In this case, we are assuming that the software left a reason for this reboot. - if (bootloader_shared_memory.reset_reason == RESET_REASON_DOWNLOAD_FW) - { - // We wanted to reset for a new firmware download - bootloader_shared_memory.reset_count = 0; - } - else if (bootloader_shared_memory.reset_reason == RESET_REASON_APP_WATCHDOG) - { - // Reset from software watchdog (not necessicarly IWDG, just some form of bad software reboot) - bootloader_shared_memory.reset_count++; - } - else if (bootloader_shared_memory.reset_reason == RESET_REASON_BAD_FIRMWARE) - { - // Reset from invalid app - bootloader_shared_memory.reset_count++; - } - else - { - // Debug reset event - bootloader_shared_memory.reset_reason = RESET_REASON_BUTTON; - } - } - else if ((reset_cause & RCC_CSR_IWDGRSTF) == RCC_CSR_IWDGRSTF) - { - // Application Watchdog reset from hardware watchdog - bootloader_shared_memory.reset_count++; - bootloader_shared_memory.reset_reason = RESET_REASON_APP_WATCHDOG; - } - else if ((reset_cause & RCC_CSR_PINRSTF) == RCC_CSR_PINRSTF) - { - bootloader_shared_memory.reset_reason = RESET_REASON_BUTTON; - bootloader_shared_memory.reset_count = 0; - } - else - { - bootloader_shared_memory.reset_reason = RESET_REASON_BUTTON; - } - - if (bootloader_shared_memory.reset_count >= 3) - { - // Reached the maximum number of resets - // Do not allow normal operation - return false; - } - - return true; -} - -void jump_to_application(void) -{ - uint32_t app_reset_handler_address = *(uint32_t*) (((void *) &_eboot_flash + 4)); - uint32_t msp = (uint32_t) *((uint32_t*) (((void *) &_eboot_flash))); - uint32_t estack = (uint32_t) ((uint32_t*) (((void *) &_estack))); - // Confirm app exists - if (app_reset_handler_address == 0xFFFFFFFF || - app_reset_handler_address < 0x8002000 || app_reset_handler_address > 0x807FFFF || - msp != estack) return; - - // Reset all of our used peripherals - // RCC->AHB2RSTR |= RCC_AHB2RSTR_GPIOBRST; // Must change based on status led port - RCC->AHB1RSTR |= RCC_AHB1RSTR_CRCRST; -#if defined(STM32F407xx) || defined(STM32F732xx) - RCC->APB1RSTR |= RCC_APB1RSTR_CAN1RST; - RCC->APB1RSTR &= ~(RCC_APB1RSTR_CAN1RST); -#else - RCC->APB1RSTR1 |= RCC_APB1RSTR1_CAN1RST; - RCC->APB1RSTR1 &= ~(RCC_APB1RSTR1_CAN1RST); -#endif - // RCC->AHB2RSTR &= ~(RCC_AHB2RSTR_GPIOBRST); - RCC->AHB1RSTR &= ~(RCC_AHB1RSTR_CRCRST); - SysTick->CTRL = 0; - SysTick->LOAD = 0; - SysTick->VAL = 0; - - // Make sure the interrupts are disabled before we start attempting to jump to the app - // Getting an interrupt after we set VTOR would be bad. - // Actually jump to application - __disable_irq(); - __set_MSP(msp); - SCB->VTOR = (uint32_t) (uint32_t*) (((void *) &_eboot_flash)); - __enable_irq(); - ((void(*)(void)) app_reset_handler_address)(); -} - void canTxSendToBack(CanMsgTypeDef_t *msg) { qSendToBack(&q_tx_can, msg); } -static uint32_t can_irq_hits = 0; void CAN1_RX0_IRQHandler() { - #if (APP_ID == APP_L4_TESTING) - PHAL_toggleGPIO(GPIOB, 6); - #endif - can_irq_hits ++; if (CAN1->RF0R & CAN_RF0R_FOVR0) // FIFO Overrun CAN1->RF0R &= ~(CAN_RF0R_FOVR0); @@ -420,6 +158,11 @@ void CAN1_RX0_IRQHandler() } } +void SysTick_Handler(void) +{ + bootloader_ms++; +} + void HardFault_Handler() { NVIC_SystemReset();