UKSVEP_23550.2/Core/Bootloader/bootloader.c

306 lines
8.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "bootloader.h"
#include "boot_flash.h"
#include "boot_uart.h"
#include "boot_can.h"
CAN_TxHeaderTypeDef TxHeader;
CAN_RxHeaderTypeDef RxHeader;
uint32_t TxMailBox = 0; // num of used mail
void SetKey(void);
uint32_t ReadKey(void);
void ResetKey(void);
void Boot_SystemClock_Config(void);
void JumpToApplocation(void);
void Bootloader_UART_Receive_Page(Bootloader_t *bl);
void Bootloader_CAN_Receive_Page(Bootloader_t *bl);
void Bootloader_Init(void)
{
HAL_Init();
Boot_SystemClock_Config();
MX_BOOT_UART_Init();
MX_BOOT_CAN_Init();
}
HAL_StatusTypeDef res_hal;
void Bootloader_Task(Bootloader_t *bl)
{
switch (bl->state)
{
case BL_STATE_INIT:
// Проверяем ключ, чтобы понять запускать приложение или программирование
if (ReadKey() == BL_KEY_APP_WRITTEN)
{
bl->state = BL_STATE_JUMP_TO_APP;
break; // не инициализируем, а сразу прыгаем в приложение
}
else
{
bl->state = BL_STATE_IDLE;
}
// Инициализация периферии
Bootloader_Init();
bl->huart = &huart_boot;
bl->hcan = &hcan_boot;
bl->addr = MAIN_APP_START_ADR;
break;
case BL_STATE_IDLE:
// Ждем команды по UART или CAN
if(bl->state != bl->prev_state)
{
static uint8_t Data[8] = {0};
static uint32_t TxMail = {0};
Data[0] = 0xFA;
HAL_CAN_AddTxMessage(bl->hcan, &bl->TxHeader, Data, &TxMail);
HAL_UART_Transmit()
}
if (Receive_FW_Command(bl) == 0xFF) // функция обработки команд, возвращает 1 если ошибка
{
bl->state = BL_STATE_ERROR;
}
break;
case BL_STATE_ERASE:
ResetKey();
if (FLASH_Erase_App() == HAL_OK) // твоя функция стирания MAIN_APP_PAGE..NUM
{
bl->state = BL_STATE_IDLE;
}
else
{
bl->state = BL_STATE_ERROR;
}
break;
case BL_STATE_RECEIVE_UART:
// В этом состоянии мы просто принимаем страницу + CRC
Bootloader_UART_Receive_Page(bl);
break;
case BL_STATE_RECEIVE_CAN:
Bootloader_CAN_Receive_Page(bl);
break;
case BL_STATE_WRITE:
if (FLASH_Write_Page(&bl->addr, bl->fw_buffer, bl->fw_len) == HAL_OK) // запись блока во Flash
{
bl->state = BL_STATE_IDLE; // ждём следующего блока
}
else
{
bl->state = BL_STATE_ERROR;
}
break;
case BL_STATE_VERIFY:
if (/*Verify_Flash_CRC(bl->fw_crc)*/0 == HAL_OK)
{
ResetKey();
SetKey(); // отметка, что прошивка записана
bl->state = BL_STATE_IDLE;
}
else
{
bl->state = BL_STATE_ERROR;
}
break;
case BL_STATE_JUMP_TO_APP:
JumpToApplocation();
break;
case BL_STATE_ERROR:
// обработка ошибок (можно светодиод, повторная инициализация, лог по UART)
Error_Handler();
break;
default:
bl->state = BL_STATE_ERROR;
break;
}
bl->prev_state = bl->state;
}
/**
* @brief Обработка команд прошивки по UART или CAN
* @param bl: указатель на структуру бутлоадера
* @retval 0x00 - команда принята и обработана, 0xFF - ошибка
*/
uint8_t Receive_FW_Command(Bootloader_t *bl)
{
BootloaderCommand_t cmd = 0;
HAL_StatusTypeDef res = HAL_ERROR;
// ---------------------------
// Чтение команды по UART
// ---------------------------
res = HAL_UART_Receive(bl->huart, &cmd, 1, 10); // таймаут 10 ms
if (res == HAL_OK)
{
switch(cmd)
{
case CMD_ERASE: // команда: стереть Flash
bl->state = BL_STATE_ERASE;
return 0x00;
case CMD_START_RECEIVE: // команда: принять блок
bl->state = BL_STATE_RECEIVE_UART;
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;
return 0x00;
default:
return 0xFF; // неизвестная команда
}
}
// ---------------------------
// Чтение команды по CAN
// ---------------------------
CAN_RxHeaderTypeDef canHeader;
uint8_t canData[8];
if (HAL_CAN_GetRxFifoFillLevel(bl->hcan, CAN_RX_FIFO0) > 0)
{
if (HAL_CAN_GetRxMessage(bl->hcan, CAN_RX_FIFO0, &canHeader, canData) == HAL_OK)
{
cmd = canData[0]; // предполагаем, что команда в первом байте
switch(cmd)
{
case CMD_ERASE:
bl->state = BL_STATE_ERASE;
return 0x00;
case CMD_START_RECEIVE:
// запускаем прием первой страницы + crc, затем после приема всего массива ждем следующей комманды
bl->state = BL_STATE_RECEIVE_CAN;
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;
return 0x00;
default:
return 0xFF;
}
}
}
#ifdef TEST_CAN
TxHeader.StdId = 0x200; // ID OF MESSAGE
TxHeader.ExtId = 0; // STANDART FRAME (NOT EXTENTED)
TxHeader.RTR = CAN_RTR_DATA; // TRANSMIT DATA OR
TxHeader.IDE = CAN_ID_STD; // STANDART FRAME
TxHeader.DLC = 8; // DATA SIZE
TxHeader.TransmitGlobalTime = DISABLE; //THIS MODE IS NOT USED, SO DISABLE
uint8_t asd[8] = "ABCDEFGL";
res_hal = HAL_CAN_AddTxMessage(&hcan_boot, &TxHeader, asd, &TxMailBox); // add to mail for transmit
HAL_Delay(1000);
#endif
return 0x00; // если команды нет, ничего не делаем, остаёмся в BL_STATE_IDLE
}
// reset/set key function
void SetKey(void)
{
HAL_FLASH_Unlock();
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, BOOTLOADER_KEY_ADR, BL_KEY_APP_WRITTEN);
HAL_FLASH_Lock();
}
uint32_t ReadKey(void)
{
return (*(__IO uint32_t*)BOOTLOADER_KEY_ADR);
}
void ResetKey(void)
{
FLASH_EraseInitTypeDef EraseInitStruct;
HAL_FLASH_Unlock();
uint32_t PageError = 0x00;
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;// erase pages
EraseInitStruct.PageAddress = BOOTLOADER_KEY_ADR; //address
EraseInitStruct.NbPages = 0x01;// num of erased pages
HAL_FLASHEx_Erase(&EraseInitStruct, &PageError);
HAL_FLASH_Lock();
}
void JumpToApplocation(void)
{
// jump to main app
//Задаётся адрес программы со смещением от начала вектора прерываний
uint32_t app_jump_adr;
app_jump_adr=*((volatile uint32_t*)(MAIN_APP_START_ADR+4));
void(*GoToApp)(void);
//Деинициализация HAL
HAL_DeInit();
GoToApp = (void (*) (void)) app_jump_adr;
//Перенос вектора прерываний на начало зашитой программы
__disable_irq();
__set_MSP(*((volatile uint32_t*)MAIN_APP_START_ADR));
__enable_irq();
//Переход к выполнению зашитой программы
GoToApp();
}
void Boot_SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/* Включаем внутренний генератор HSI */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_OFF; // без PLL
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/* Настройка шин AHB/APB */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; // HSI = 8 MHz
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // HCLK = 8 MHz
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; // PCLK1 = 8 MHz
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // PCLK2 = 8 MHz
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
void Error_Handler(void)
{
NVIC_SystemReset();
}