работает но не стабильно
This commit is contained in:
@@ -119,6 +119,7 @@ void Bootloader_CAN_Receive_Page(Bootloader_t *bl)
|
||||
}
|
||||
}
|
||||
|
||||
// Таймаут
|
||||
if(HAL_GetTick() - start_tick >= FW_RECEIVE_TIMEOUT_MS)
|
||||
{
|
||||
bl->error.bit.timeout_receive = 1;
|
||||
|
||||
@@ -6,11 +6,7 @@ int main()
|
||||
__disable_irq();
|
||||
SCB->VTOR = 0x08000000;
|
||||
__enable_irq();
|
||||
|
||||
/* Включаем тактирование PWR и BKP (APB1) и разрешаем доступ к BKP domain */
|
||||
/* Записываем напрямую в регистры RCC/APB1ENR и PWR->CR */
|
||||
RCC->APB1ENR |= (RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN);
|
||||
|
||||
|
||||
boot.state = BL_STATE_INIT;
|
||||
while (1)
|
||||
{
|
||||
@@ -88,6 +84,9 @@ void HardFault_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN HardFault_IRQn 0 */
|
||||
|
||||
/* Включаем тактирование PWR и BKP (APB1) и разрешаем доступ к BKP domain */
|
||||
/* Записываем напрямую в регистры RCC/APB1ENR и PWR->CR */
|
||||
RCC->APB1ENR |= (RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN);
|
||||
PWR->CR |= PWR_CR_DBP;
|
||||
BKP->DR1 = 0xDEAD; // записываем код ошибки
|
||||
BKP->DR2 = BKP->DR2 + 1; // счётчик ошибок
|
||||
@@ -106,6 +105,9 @@ void HardFault_Handler(void)
|
||||
void MemManage_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN MemoryManagement_IRQn 0 */
|
||||
/* Включаем тактирование PWR и BKP (APB1) и разрешаем доступ к BKP domain */
|
||||
/* Записываем напрямую в регистры RCC/APB1ENR и PWR->CR */
|
||||
RCC->APB1ENR |= (RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN);
|
||||
PWR->CR |= PWR_CR_DBP;
|
||||
BKP->DR1 = 0xBEEF; // записываем код ошибки
|
||||
BKP->DR2 = BKP->DR2 + 1; // счётчик ошибок
|
||||
|
||||
@@ -5,14 +5,38 @@
|
||||
|
||||
// === BOOTLOADER defines ===
|
||||
// KEY defines
|
||||
#define BOOTLOADER_KEY_ADR (uint32_t)0x08009800
|
||||
#define BOOTLOADER_KEY_ADR (uint32_t)0x08009800UL
|
||||
#define BOOTLOADER_KEY_PAGE 20
|
||||
|
||||
// MAIN APP defines
|
||||
#define MAIN_APP_START_ADR (uint32_t)0x0800C000
|
||||
#define MAIN_APP_START_ADR (uint32_t)0x0800C000UL
|
||||
#define MAIN_APP_PAGE 21
|
||||
#define MAIN_APP_NUM_OF_PAGE 250-MAIN_APP_PAGE
|
||||
|
||||
|
||||
|
||||
/* Flash boundaries: подставьте реальные границы флеш-памяти вашего MCU */
|
||||
#ifndef FLASH_START_ADR
|
||||
#define FLASH_START_ADR 0x08000000UL
|
||||
#endif
|
||||
#ifndef FLASH_END_ADR
|
||||
/* пример: 512KB flash -> 0x08080000. Поменяйте под ваш MCU */
|
||||
#define FLASH_END_ADR 0x080FFFFFUL
|
||||
#endif
|
||||
|
||||
/* SRAM boundaries: подставьте реальные адреса SRAM вашей MCU */
|
||||
#ifndef SRAM_START_ADR
|
||||
#define SRAM_START_ADR 0x20000000UL
|
||||
#endif
|
||||
#ifndef SRAM_END_ADR
|
||||
/* пример: 128KB SRAM -> 0x2001FFFF. Поменяйте под ваш MCU */
|
||||
#define SRAM_END_ADR 0x2003FFFFUL
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// RECEIVE defines
|
||||
#define FW_RECEIVE_TIMEOUT_MS 5000 // таймаут приёма страницы
|
||||
#define PAGE_SIZE 2048 // страницы принимаются размером с page_size (размер страниц флеш должен быть кратен PAGE_SIZE)
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
#define __BOOT_UART_H
|
||||
|
||||
#include "bootloader.h"
|
||||
|
||||
extern UART_HandleTypeDef huart_boot;
|
||||
|
||||
void MX_BOOT_UART_Init(void);
|
||||
void Bootloader_UART_Receive_Page(Bootloader_t *bl);
|
||||
|
||||
#endif //__BOOT_UART_H
|
||||
@@ -8,18 +8,18 @@ CAN_TxHeaderTypeDef TxHeaderBoot;
|
||||
CAN_RxHeaderTypeDef RxHeaderBoot;
|
||||
uint32_t TxMailBoxBoot = 0;
|
||||
uint8_t TXDataBoot[8] = {0};
|
||||
int receive_uart_flag = 0;
|
||||
|
||||
void SetKey(void);
|
||||
uint32_t ReadKey(void);
|
||||
void EraseKey(void);
|
||||
uint32_t ErrCodeBoot = 0;
|
||||
uint32_t ErrCntBoot = 0;
|
||||
|
||||
static uint8_t Receive_FW_Command(Bootloader_t *bl);
|
||||
static void SetKey(void);
|
||||
static uint32_t ReadKey(void);
|
||||
static void EraseKey(void);
|
||||
static void JumpToApplocation(void);
|
||||
static uint32_t CRC32_Compute(const uint8_t* data, uint32_t length);
|
||||
void Boot_SystemClock_Config(void);
|
||||
void JumpToApplocation(void);
|
||||
|
||||
void Bootloader_UART_Receive_Page(Bootloader_t *bl);
|
||||
void Bootloader_CAN_Receive_Page(Bootloader_t *bl);
|
||||
|
||||
uint32_t CRC32_Compute(const uint8_t* data, uint32_t length);
|
||||
static HAL_StatusTypeDef Verify_Firmware(void);
|
||||
|
||||
void Bootloader_Init(Bootloader_t *bl)
|
||||
{
|
||||
@@ -31,24 +31,62 @@ void Bootloader_Init(Bootloader_t *bl)
|
||||
|
||||
}
|
||||
|
||||
void App_Init(void)
|
||||
{
|
||||
__disable_irq();
|
||||
SCB->VTOR = 0x0800C000;
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Bootloader_StartCheck(Bootloader_t *bl)
|
||||
{
|
||||
|
||||
// Проверка watchdog reset (IWDGRSTF или WWDGRSTF в RCC->CSR)
|
||||
if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) || __HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST))
|
||||
{
|
||||
//SaveErrorCode(0x0D0D);
|
||||
__HAL_RCC_CLEAR_RESET_FLAGS(); // Очистить флаги сброса, чтобы не повторялось
|
||||
}
|
||||
|
||||
ErrCodeBoot = GetErrorCode();
|
||||
ErrCntBoot = GetErrorCnt();
|
||||
if(ErrCntBoot > 5)
|
||||
{
|
||||
ClearErrorCode();
|
||||
if(ErrCodeBoot == 0xDEAD) // HardFault
|
||||
{
|
||||
ResetKey();
|
||||
bl->error.bit.hardfault_cycle = 1;
|
||||
bl->state = BL_STATE_ERROR;
|
||||
}
|
||||
else if(ErrCodeBoot == 0xBEEF) // MemManage
|
||||
{
|
||||
ResetKey();
|
||||
bl->error.bit.memmanage_cycle = 1;
|
||||
bl->state = BL_STATE_ERROR;
|
||||
}
|
||||
/*else if(ErrCodeBoot == 0x0D0D) пока хз надо ли
|
||||
{
|
||||
ResetKey();
|
||||
bl->error.bit.watchdog_reset = 1; // Добавь бит в структуру BootloaderError_
|
||||
bl->state = BL_STATE_ERROR;
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t code = 0;
|
||||
uint32_t cnt = 0;
|
||||
void Bootloader_Task(Bootloader_t *bl)
|
||||
{
|
||||
|
||||
int receive_uart_flag;
|
||||
switch (bl->state)
|
||||
{
|
||||
case BL_STATE_INIT:
|
||||
code = LoadErrorCode();
|
||||
cnt = LoadErrorCnt();
|
||||
|
||||
bl->prev_state = bl->state;
|
||||
Bootloader_StartCheck(bl);
|
||||
// Проверяем ключ, чтобы понять запускать приложение или программирование
|
||||
if ((ReadKey() == BL_KEY_APP_WRITTEN) && (cnt <= 5))
|
||||
if ((ReadKey() == BL_KEY_APP_WRITTEN))
|
||||
{
|
||||
bl->state = BL_STATE_JUMP_TO_APP;
|
||||
break; // не инициализируем, а сразу прыгаем в приложение
|
||||
@@ -65,35 +103,15 @@ void Bootloader_Task(Bootloader_t *bl)
|
||||
bl->TxHeader.DLC = 8;
|
||||
bl->TxHeader.StdId = 123;
|
||||
bl->addr = MAIN_APP_START_ADR;
|
||||
|
||||
if(cnt > 5)
|
||||
{
|
||||
ClearErrorCode();
|
||||
if(code == 0xDEAD) // HardFault
|
||||
{
|
||||
ResetKey();
|
||||
bl->error.bit.hardfault_cycle = 1;
|
||||
TXDataBoot[0] = 0xAA;
|
||||
TXDataBoot[1] = (bl->error.all >> 8) & 0xFF;
|
||||
TXDataBoot[2] = bl->error.all & 0xFF;
|
||||
res_hal = HAL_CAN_AddTxMessage(bl->hcan, &bl->TxHeader, TXDataBoot, &TxMailBoxBoot);
|
||||
res_hal = HAL_UART_Transmit(bl->huart, TXDataBoot, 1, 100);
|
||||
}
|
||||
else if(code == 0xBEEF) // MemManage
|
||||
{
|
||||
ResetKey();
|
||||
bl->error.bit.memmanage_cycle = 1;
|
||||
TXDataBoot[0] = 0x55;
|
||||
TXDataBoot[1] = (bl->error.all >> 8) & 0xFF;
|
||||
TXDataBoot[2] = bl->error.all & 0xFF;
|
||||
res_hal = HAL_CAN_AddTxMessage(bl->hcan, &bl->TxHeader, TXDataBoot, &TxMailBoxBoot);
|
||||
res_hal = HAL_UART_Transmit(bl->huart, TXDataBoot, 1, 100);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BL_STATE_IDLE:
|
||||
if(bl->error.all)
|
||||
{
|
||||
bl->prev_state = bl->state;
|
||||
bl->state = BL_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
if((bl->state != bl->prev_state) && (bl->prev_state != BL_STATE_ERROR))
|
||||
{
|
||||
TXDataBoot[0] = 0x00;
|
||||
@@ -118,6 +136,7 @@ void Bootloader_Task(Bootloader_t *bl)
|
||||
EraseKey();
|
||||
if (FLASH_Erase_App() == HAL_OK) // твоя функция стирания MAIN_APP_PAGE..NUM
|
||||
{
|
||||
HAL_Delay(50);
|
||||
bl->state = BL_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
@@ -168,23 +187,19 @@ void Bootloader_Task(Bootloader_t *bl)
|
||||
}
|
||||
break;
|
||||
|
||||
case BL_STATE_VERIFY:
|
||||
case BL_STATE_JUMP_TO_APP:
|
||||
bl->prev_state = bl->state;
|
||||
if (/*Verify_Flash_CRC(bl->fw_crc)*/0 == HAL_OK)
|
||||
if (Verify_Firmware() == HAL_OK)
|
||||
{
|
||||
EraseKey();
|
||||
SetKey(); // отметка, что прошивка записана
|
||||
bl->state = BL_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
bl->error.bit.verify_err = 1;
|
||||
bl->state = BL_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case BL_STATE_JUMP_TO_APP:
|
||||
bl->prev_state = bl->state;
|
||||
JumpToApplocation();
|
||||
break;
|
||||
|
||||
@@ -221,7 +236,7 @@ void Bootloader_Task(Bootloader_t *bl)
|
||||
}
|
||||
|
||||
|
||||
uint8_t SetBootState(Bootloader_t *bl, BootloaderCommand_t cmd, uint8_t uart_flag)
|
||||
static uint8_t SetBootState(Bootloader_t *bl, BootloaderCommand_t cmd, uint8_t uart_flag)
|
||||
{
|
||||
switch(cmd)
|
||||
{
|
||||
@@ -236,9 +251,6 @@ uint8_t SetBootState(Bootloader_t *bl, BootloaderCommand_t cmd, uint8_t uart_fla
|
||||
return 0x00;
|
||||
case CMD_WRITE: // команда: записать блок
|
||||
bl->state = BL_STATE_WRITE;
|
||||
return 0x00;
|
||||
case CMD_VERIFY: // команда: проверка прошивки
|
||||
bl->state = BL_STATE_VERIFY;
|
||||
return 0x00;
|
||||
case CMD_GOTOAPP: // команда: прыжок в приложение
|
||||
bl->state = BL_STATE_JUMP_TO_APP;
|
||||
@@ -260,7 +272,7 @@ uint8_t SetBootState(Bootloader_t *bl, BootloaderCommand_t cmd, uint8_t uart_fla
|
||||
* @param bl: указатель на структуру бутлоадера
|
||||
* @retval 0x00 - команда принята и обработана, 0xFF - ошибка
|
||||
*/
|
||||
uint8_t Receive_FW_Command(Bootloader_t *bl)
|
||||
static uint8_t Receive_FW_Command(Bootloader_t *bl)
|
||||
{
|
||||
BootloaderCommand_t cmd = 0;
|
||||
HAL_StatusTypeDef res = HAL_ERROR;
|
||||
@@ -303,7 +315,7 @@ uint8_t Receive_FW_Command(Bootloader_t *bl)
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
uint32_t CRC32_Compute(const uint8_t* data, uint32_t length)
|
||||
static uint32_t CRC32_Compute(const uint8_t* data, uint32_t length)
|
||||
{
|
||||
const uint32_t polynomial = 0x04C11DB7;
|
||||
uint32_t crc = 0xFFFFFFFF;
|
||||
@@ -323,6 +335,36 @@ uint32_t CRC32_Compute(const uint8_t* data, uint32_t length)
|
||||
return crc ^ 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
static HAL_StatusTypeDef Verify_Firmware(void)
|
||||
{
|
||||
uint32_t msp = *((volatile uint32_t*)(MAIN_APP_START_ADR));
|
||||
uint32_t reset = *((volatile uint32_t*)(MAIN_APP_START_ADR + 4));
|
||||
|
||||
/* 1) Проверка MSP: должен быть указателем в SRAM */
|
||||
if ((msp < SRAM_START_ADR) || (msp > SRAM_END_ADR))
|
||||
{
|
||||
/* Некорректный стек — прошивка невалидна */
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
/* 2) Проверка reset handler:
|
||||
- бит0 должен быть 1 (Thumb)
|
||||
- адрес без бита0 должен лежать в пределах flash (MAIN_APP_START_ADR .. FLASH_END_ADR)
|
||||
*/
|
||||
if ((reset & 0x1) == 0)
|
||||
{
|
||||
/* Не Thumb-при-старте — подозрительно */
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
uint32_t reset_addr = (reset & (~1U)); /* выравненный адрес */
|
||||
if ((reset_addr < FLASH_START_ADR) || (reset_addr > FLASH_END_ADR))
|
||||
{
|
||||
/* Reset handler вне flash */
|
||||
return HAL_ERROR;
|
||||
}
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
// key functions
|
||||
void ResetKey(void)
|
||||
@@ -334,7 +376,15 @@ void ResetKey(void)
|
||||
HAL_FLASH_Lock();
|
||||
}
|
||||
|
||||
void SetKey(void)
|
||||
void JumpToBootloader(void)
|
||||
{
|
||||
// jump to boot
|
||||
ResetKey(); // сброс ключа (не erase, просто битый ключ
|
||||
NVIC_SystemReset(); // сброс и переход в бутлоадер (т.к. нет ключа)
|
||||
}
|
||||
|
||||
|
||||
static void SetKey(void)
|
||||
{
|
||||
HAL_FLASH_Unlock();
|
||||
|
||||
@@ -343,12 +393,12 @@ void SetKey(void)
|
||||
HAL_FLASH_Lock();
|
||||
}
|
||||
|
||||
uint32_t ReadKey(void)
|
||||
static uint32_t ReadKey(void)
|
||||
{
|
||||
return (*(__IO uint32_t*)BOOTLOADER_KEY_ADR);
|
||||
}
|
||||
|
||||
void EraseKey(void)
|
||||
static void EraseKey(void)
|
||||
{
|
||||
FLASH_EraseInitTypeDef EraseInitStruct;
|
||||
HAL_FLASH_Unlock();
|
||||
@@ -364,7 +414,7 @@ void EraseKey(void)
|
||||
|
||||
|
||||
|
||||
void JumpToApplocation(void)
|
||||
static void JumpToApplocation(void)
|
||||
{
|
||||
//Деинициализация HAL
|
||||
HAL_DeInit();
|
||||
@@ -387,33 +437,6 @@ void JumpToApplocation(void)
|
||||
}
|
||||
|
||||
|
||||
void JumpToBootloader(void)
|
||||
{
|
||||
// jump to boot
|
||||
ResetKey(); // сброс ключа (не erase, просто битый ключ
|
||||
NVIC_SystemReset(); // сброс и переход в бутлоадер (т.к. нет ключа)
|
||||
}
|
||||
|
||||
|
||||
// Сохранение кода ошибки
|
||||
// Чтение после ресета
|
||||
uint32_t LoadErrorCode(void)
|
||||
{
|
||||
return BKP->DR1;
|
||||
}
|
||||
|
||||
uint32_t LoadErrorCnt(void)
|
||||
{
|
||||
return BKP->DR2;
|
||||
}
|
||||
|
||||
void ClearErrorCode(void)
|
||||
{
|
||||
PWR->CR |= PWR_CR_DBP;
|
||||
BKP->DR1 = 0;
|
||||
BKP->DR2 = 0;
|
||||
}
|
||||
|
||||
|
||||
__WEAK void Boot_SystemClock_Config(void)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,35 @@
|
||||
|
||||
|
||||
#define BL_KEY_APP_WRITTEN 0xAAAA5555
|
||||
/* --- Настройка: подставьте значения для вашей MCU --- */
|
||||
/* Адрес начала приложения (используется в вашем коде) */
|
||||
#ifndef MAIN_APP_START_ADR
|
||||
#error "MAIN_APP_START_ADR must be defined"
|
||||
#endif
|
||||
|
||||
/* Если нужен другой полином/поведение CRC, используйте вашу функцию CRC32_Compute.
|
||||
В вашем коде уже есть CRC32_Compute, поэтому будем её использовать. */
|
||||
|
||||
|
||||
|
||||
#define GetErrorCode() BKP->DR1
|
||||
#define GetErrorCnt() BKP->DR2
|
||||
|
||||
|
||||
#define SaveErrorCode(code) do{ \
|
||||
RCC->APB1ENR |= (RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN); \
|
||||
PWR->CR |= PWR_CR_DBP; \
|
||||
GetErrorCode() = code; \
|
||||
GetErrorCnt() = GetErrorCnt() + 1; \
|
||||
}while(0u);
|
||||
|
||||
#define ClearErrorCode(code) do{ \
|
||||
RCC->APB1ENR |= (RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN); \
|
||||
PWR->CR |= PWR_CR_DBP; \
|
||||
GetErrorCode() = 0; \
|
||||
GetErrorCnt() = 0; \
|
||||
}while(0u);
|
||||
|
||||
|
||||
// ERROR DEFINES
|
||||
/**
|
||||
@@ -15,7 +44,6 @@ typedef enum {
|
||||
CMD_ERASE = 0x01, ///< Команда на стирание прошивки
|
||||
CMD_START_RECEIVE, ///< Команда на старт приема прошивки
|
||||
CMD_WRITE, ///< Команда на запись блока прошивки
|
||||
CMD_VERIFY, ///< Команда на проверку прошивки
|
||||
CMD_GOTOAPP, ///< Команда на переход в приложение
|
||||
CMD_RESET, ///< Команда на переход в приложение
|
||||
CMD_GOTOBOOT, ///< Команда на переход в приложение
|
||||
@@ -32,7 +60,6 @@ typedef enum {
|
||||
BL_STATE_RECEIVE_UART, ///< Состояние: прием прошивки по UART
|
||||
BL_STATE_RECEIVE_CAN, ///< Состояние: прием прошивки по CAN
|
||||
BL_STATE_WRITE, ///< Состояние: запись данных
|
||||
BL_STATE_VERIFY, ///< Состояние: проверка прошивки
|
||||
BL_STATE_ERROR, ///< Состояние: ошибка
|
||||
BL_STATE_RESET, ///< Состояние: сброс контролллера
|
||||
BL_STATE_JUMP_TO_BOOT, ///< Состояние: запуск приложения
|
||||
@@ -44,14 +71,15 @@ typedef enum {
|
||||
typedef union {
|
||||
uint16_t all;
|
||||
struct {
|
||||
unsigned hardfault_cycle:1;
|
||||
unsigned memmanage_cycle:1;
|
||||
unsigned watchdog_reset:1;
|
||||
unsigned unknown_cmd:1;
|
||||
unsigned erase_err:1;
|
||||
unsigned write_err:1;
|
||||
unsigned verify_err:1;
|
||||
unsigned timeout_receive:1;
|
||||
unsigned crc_err:1;
|
||||
unsigned hardfault_cycle:1;
|
||||
unsigned memmanage_cycle:1;
|
||||
}bit;
|
||||
} BootloaderError_t;
|
||||
|
||||
@@ -79,15 +107,8 @@ extern uint8_t TXDataBoot[8];
|
||||
void ResetKey(void);
|
||||
void JumpToBootloader(void);
|
||||
|
||||
|
||||
void SaveErrorCode(uint32_t code);
|
||||
uint32_t LoadErrorCode(void);
|
||||
uint32_t LoadErrorCnt(void);
|
||||
void ClearErrorCode(void);
|
||||
|
||||
void Boot_SystemClock_Config(void);
|
||||
void App_Init(void);
|
||||
void Bootloader_Task(Bootloader_t *bl);
|
||||
uint8_t Receive_FW_Command(Bootloader_t *bl);
|
||||
|
||||
void Error_Handler(void);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user