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", 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/cmake/utils.cmake b/cmake/utils.cmake index 5d82b64b..03b95ad9 100644 --- a/cmake/utils.cmake +++ b/cmake/utils.cmake @@ -31,8 +31,8 @@ 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 - COMMENT "Generateing HEX file" + COMMAND arm-none-eabi-objcopy -S -O ihex ${TARGET_NAME} ${COMPONENT_OUTPUT_DIR}/${OUTPUT_FILE_NAME}.hex + COMMENT "Generating HEX file" ) add_custom_command(TARGET ${TARGET_NAME} POST_BUILD diff --git a/common/bootloader/bootloader_common.h b/common/bootloader/bootloader_common.h index 076b5e6d..27a1768f 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_CRC_BACKUP = 0x2, + BLCMD_JUMP = 0x4, /* Request to start firmware download */ + BLCMD_RST = 0x5, /* Request for reset */ } 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/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 diff --git a/common/phal_F4_F7/flash/flash.c b/common/phal_F4_F7/flash/flash.c index 1af47e5e..567adebc 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 */ @@ -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; @@ -85,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"); @@ -114,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 @@ -139,7 +194,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); diff --git a/common/phal_F4_F7/flash/flash.h b/common/phal_F4_F7/flash/flash.h index 413d81f9..32521214 100644 --- a/common/phal_F4_F7/flash/flash.h +++ b/common/phal_F4_F7/flash/flash.h @@ -66,7 +66,11 @@ 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_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); diff --git a/per_build.py b/per_build.py index 46c5e1b1..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" @@ -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 = [ 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 f6b76981..29dda969 100644 --- a/source/bootloader/bootloader/bootloader.c +++ b/source/bootloader/bootloader/bootloader.c @@ -1,12 +1,15 @@ /** - * @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 - * - * @copyright Copyright (c) 2022 - * + * @date 2024-11-24 + * + * @copyright Copyright (c) 2024 + * */ #include "bootloader.h" @@ -17,188 +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_end_address; /* Expected end address to stop writing */ -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_end_address = app_flash_start; - app_flash_current_address = app_flash_start; - 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: - { - app_flash_current_address = app_flash_start_address; - app_flash_end_address += data; // Number of words - *bootloader_ms = 0; - - #ifndef DEBUG - if (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); - } - num_msg = 0; - bl_unlock = true; - flash_complete = false; - first_word = second_word = 0; - CRC->CR |= CRC_CR_RESET; // Reset CRC - break; - } - case BLCMD_CRC: - { - if (bl_unlock && app_flash_current_address == app_flash_end_address) - { - 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_RST: - // Bootloader_ResetForFirmwareDownload(); - break; - default: + if (PHAL_CRC32_Calculate((uint32_t *)addr, size / 4) == crc_stored) { - 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; + 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 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) + { + 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) + { + BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_FLASH); + } + 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(); +} - #if (APP_ID == APP_L4_TESTING) - PHAL_writeGPIO(GPIOB, 7, 1); - #endif - uint64_t data; - if (bl_unlock) - { - if(app_flash_current_address >= app_flash_start_address && - app_flash_current_address < app_flash_end_address) - { - num_msg++; - data = *((uint64_t *) msg_data_a->raw_data); - - // Skip the first two words - if (app_flash_current_address == app_flash_start_address) - { - 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((uint32_t) app_flash_current_address, data) != FLASH_OK) - { - BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_FLASH); - bl_unlock = false; - } - else - #endif - { - CRC->DR = *(app_flash_current_address); - CRC->DR = *(app_flash_current_address + 1); - } - } - *bootloader_ms = 0; // Reset timeout counter, message received! - app_flash_current_address += 2; // wrote 64 bits +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_UNKNOWN_CMD, cmd); + break; } - else - BL_sendStatusMessage(BLSTAT_INVALID, BLERROR_ADDR_BOUND); } +} - #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 5b9388a3..ae3fb76b 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,12 @@ #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_PROGRESS = 4, /* Progress update for bootloader download */ - BLSTAT_DONE = 5, /* Completed the application download with CRC pass */ - 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 @@ -38,37 +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 \ No newline at end of file +#endif diff --git a/source/bootloader/main.c b/source/bootloader/main.c index f90087ab..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 = false; -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,186 +113,18 @@ 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) - { - 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) - { - 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); + 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 { @@ -418,6 +158,11 @@ void CAN1_RX0_IRQHandler() } } +void SysTick_Handler(void) +{ + bootloader_ms++; +} + void HardFault_Handler() { NVIC_SystemReset();