CAN_Request-Response_protocol/Core/Src/bootloader.c

614 lines
17 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 "custom_receive_and_write.h"
extern FLASH_EraseInitTypeDef EraseInitStruct;
struct flag FLAGS;
struct Bootloader_Errors_Counters BOOTLOADER_ERRORS_COUNTERS;
struct Bootloader_Errors BOOTLOADER_ERRORS;
uint32_t app_current_add; // address for writing pages
int cnt_tim_reset = 0; // WD Tim counter
uint8_t ReceiveDataUART[4]; // buffer for CMD
uint8_t Data2Write[PAGE_SIZE*2]; // DMA buffer for application
uint8_t CAN_Data[8];
CAN_TxHeaderTypeDef TxHeader;
CAN_RxHeaderTypeDef RxHeader;
uint32_t TxMailBox = 0; // num of used mail
extern UART_HandleTypeDef huart_boot; // uart handler for boot uart
extern DMA_HandleTypeDef hdma_usart_boot_rx; // dma handler for boot uart
struct UARTSettings UARTSet; // settings for uart
void Bootloader_Init(void)
{
HAL_Init();
Boot_SystemClock_Config();
MX_DMA_Init();
//Если используется ЮСАРТ - инициализация
#ifdef __USART_H__
UARTSet.UARTx = UART_BOOT;
UARTSet.UART_Speed = UART_SPEED;
UARTSet.GPIOx = UART_PORT;
UARTSet.GPIO_PIN_RX = UART_PIN_RX;
UARTSet.GPIO_PIN_TX = UART_PIN_TX;
UARTSet.DMAChannel = DMA_UART_Channel;
User_UART_Init(&huart_boot, &hdma_usart_boot_rx, &UARTSet);
#endif
//Если используется SD-карта - инициализация
#ifdef __SDIO_H__
BSP_SD_ITConfig();
#endif
#ifdef __CAN_H__
MX_CAN_Init();
#endif
//Инициализация светодиодов
MX_GPIO_Init();
MX_TIM7_Init();
}
HAL_StatusTypeDef res_hal;
void Bootloader_main(void) // main function, that defines bootloader behaviour
{
/*
// Настройка доступной переферии с помощью define
Bootloader_Init();
*/
/* START APPLICATION */
if (ReadKey() == BL_KEY_APP_WRITTEN)
{
// 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();
}
else /* START PROGRAMMING MCU */
{
/* MCU Configuration for bootloader-------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash BootloaderCMD and the Systick. */
Bootloader_Init();
FLAGS.InitOrWait = 0;
// waif for commant for programming
do{
res_hal=HAL_UART_Receive_IT(&huart_boot, ReceiveDataUART, sizeof(ReceiveDataUART));
if(res_hal!=HAL_OK){
BOOTLOADER_ERRORS_COUNTERS.USART_RECEIVE++;
BOOTLOADER_ERRORS.USART_RECEIVE=1;
}
}while(res_hal!=HAL_OK); // if usart err - try start receive again
HAL_CAN_Start(&hcan);
HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
CAN_FilterTypeDef canFilterConfig;
canFilterConfig.FilterBank = 0;
canFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
canFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
canFilterConfig.FilterIdHigh = 0x0000;
canFilterConfig.FilterIdLow = 0x0000;
canFilterConfig.FilterMaskIdHigh = 0x0000;
canFilterConfig.FilterMaskIdLow = 0x0000;
canFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
canFilterConfig.FilterActivation = ENABLE;
canFilterConfig.SlaveStartFilterBank = 14;
HAL_CAN_ConfigFilter(&hcan, &canFilterConfig);
// FLAGS.StartInit=1;
// FLAGS.reInitMCU=1;
// FLAGS.BootloaderCMD = 2;
app_current_add = MAIN_APP_START_ADR;
// HAL_CAN_Start(&hcan);
/* Infinite loop */
while (1)
{
// HAL_Delay(10);
// HAL_UART_Transmit(&huart_boot, (uint8_t *)"000000", 6, HAL_MAX_DELAY);
// choose interface for programming
if (FLAGS.StartInit)
{
if (FLAGS.reInitMCU) // if its reInit request - erase outdate app
{
GPIOB->ODR^=0x2000;
res_hal=FLASH_Erase_App();
if(res_hal!=HAL_OK)
{
FLAGS.StartInit=1;
BOOTLOADER_ERRORS.FLASH_ERASE = 1;
continue;
}
BOOTLOADER_ERRORS.FLASH_ERASE = 0;
GPIOB->ODR^=0x2000;
FLAGS.reInitMCU = 0;
}
FLAGS.StartInit = 0;
HAL_UART_AbortReceive_IT(&huart_boot);
HAL_CAN_Stop(&hcan);
HAL_CAN_DeactivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
switch ((int)FLAGS.BootloaderCMD)
{
// UART
#ifdef __USART_H__
case 1:/* UART */
FLAGS.InitBootPeriph = 1;
// start receiving app.bin
res_hal = HAL_UART_Receive_DMA(&huart_boot, Data2Write, PAGE_SIZE*2);
if(res_hal!=HAL_OK)
{
FLAGS.StartInit=1;
BOOTLOADER_ERRORS_COUNTERS.USART_RECEIVE++;
BOOTLOADER_ERRORS.USART_RECEIVE = 1;
break;
}
// code of writing app in flash in callbacks functions:
// HAL_UART_RxHalfCpltCallback and HAL_UART_RxCpltCallback
break;
#endif
#ifdef __CAN_H__
// CAN
case 2: /* CAN */
// activate can and start receiving app.bin
FLAGS.InitOrWait=1;
res_hal = HAL_CAN_Start(&hcan);
res_hal = HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_ERROR | CAN_IT_BUSOFF | CAN_IT_LAST_ERROR_CODE);
// code of writing app in flash in callback functions:
// HAL_CAN_RxFifo0MsgPendingCallback
break;
#endif
// SD
#ifdef __SDIO_H__
case 3: /* SD */
if (FLAGS.SDCardIn==0) // wait for sd-card
{
FLAGS.StartInit=1; // if there is no card, exit programmator and go in again
BOOTLOADER_ERRORS.SD_CARD_NOT_INSERTED = 1;
//Ошибка SD карты. Начать приём новой cmd
break;
}
HAL_Delay(100); // wait for inputting SD Card
if (FLAGS.SDCardIn==0)
{
FLAGS.StartInit=1;
BOOTLOADER_ERRORS.SD_CARD_NOT_INSERTED = 1;
break;
}
FRESULT res_fresult;
SD_Programming(&res_fresult, &res_hal); // programming from sd card
// res_fresual - status for sd card read // res_hal - status for flash write
//Если всё удачно - выполнить код ниже. Если нет - StartInit = 1, break
if(res_fresult!=FR_OK || res_hal!=HAL_OK)
{
FLAGS.StartInit=1;
if(res_fresult!=FR_OK){
BOOTLOADER_ERRORS_COUNTERS.SD_CARD_READ++;
BOOTLOADER_ERRORS.SD_CARD_READ = 1;
}
if(res_hal!=HAL_OK){
BOOTLOADER_ERRORS_COUNTERS.FLASH_WRITE++;
BOOTLOADER_ERRORS.FLASH_WRITE = 1;
}
break;
}
// write Key: application in Flash, and reset MCU
{
ResetKey();
SetKey();
NVIC_SystemReset();
}// reset mcu
break;
#endif
default: // if command is incorrect - wait CMD
BOOTLOADER_ERRORS_COUNTERS.CMD_INVALID++; // uncorrect command
BOOTLOADER_ERRORS.CMD_INVALID=1;
do
{
res_hal=HAL_UART_Receive_IT(&huart_boot, ReceiveDataUART, sizeof(ReceiveDataUART));
if(res_hal!=HAL_OK){
BOOTLOADER_ERRORS_COUNTERS.USART_RECEIVE++; // err when initialize uart
BOOTLOADER_ERRORS.USART_RECEIVE=1;}
}while(res_hal!=HAL_OK);
HAL_CAN_Start(&hcan);
HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
}
}
// 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";
// while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan) == 0); // wait for free mail box
// res_hal = HAL_CAN_AddTxMessage(&hcan, &TxHeader, asd, &TxMailBox); // add to mail for transmit
// HAL_Delay(1000);
}
}
}
void SD_Programming(FRESULT *res_fresult, HAL_StatusTypeDef *res_hal)
{
// init peripth
MX_FATFS_Init();
MX_SDIO_SD_Init();
FIL MFile;
int SizeApp;
int AppCount;
// mount disk
uint8_t MOUNT=1;
*res_fresult = f_mount(&SDFatFS, (TCHAR const*)SDPath, 1);
if(*res_fresult != FR_OK) return;
// name of the application file
static char path[8] = "app.bin";
path[7] = '\0';
// OPEN AND READ
*res_fresult = f_open(&MFile, (const TCHAR*)path, FA_READ);
if (*res_fresult == FR_OK)
{
SizeApp = MFile.fsize;
AppCount = 0; // counter of written bytes
unsigned int bytesRead;
// reading and writing two pages
while(SizeApp - AppCount >= PAGE_SIZE*2) // read while count of rest bytes more than size of two pages
{
*res_fresult = f_read(&MFile, Data2Write, PAGE_SIZE*2, &bytesRead);
if(*res_fresult != FR_OK) return;
AppCount += PAGE_SIZE*2;
*res_hal = FLASH_Write_Page(&app_current_add, Data2Write, PAGE_SIZE*2);
if(*res_hal != HAL_OK) return;
GPIOB->ODR^=0x2000; // indicate written two pages
}
// reading and writing rest bytes (less than two pages)
if(SizeApp != AppCount)
{
int NumOfLastBytes = SizeApp - AppCount;
*res_fresult = f_read(&MFile, Data2Write, NumOfLastBytes, &bytesRead);
if(*res_fresult != FR_OK) return;
AppCount += PAGE_SIZE*2;
*res_hal = FLASH_Write_Page(&app_current_add, Data2Write, NumOfLastBytes);
if(*res_hal != HAL_OK) return;
GPIOB->ODR^=0x2000;
}
*res_fresult = f_close(&MFile); // indicate written two pages
}
}
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart) // writing first half of dma buffer (1 page)
{
if (huart->Instance == UART_BOOT)
{
if (FLAGS.InitOrWait)
{
HAL_StatusTypeDef res_hal;
if (FLAGS.InitBootPeriph) // if its first received page
{
//HAL_TIM_Base_Start_IT(&htim_boot); // start "wd" timer
FLAGS.InitBootPeriph = 0; // 5 sec silent on RX - mcu reset
}
res_hal = FLASH_Write_Page(&app_current_add, Data2Write, PAGE_SIZE);
if (res_hal != HAL_OK)
{
BOOTLOADER_ERRORS_COUNTERS.FLASH_WRITE++; // err when initialize uart
BOOTLOADER_ERRORS.FLASH_WRITE=1;
}
// HAL_UART_DMAStop(&huart_boot);
// HAL_UART_AbortReceive_IT(&huart_boot);
// HAL_UART_AbortReceive(&huart_boot);
FLAGS.HalfOfWrite = 1; // switch unwritten half of DMA buffer
cnt_tim_reset = 0; // upd WD Tim
GPIOB->ODR^=0x2000; // indicate written page
}
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) // writing second half of dma buffer (1 page)
{
if (huart->Instance == UART_BOOT)
{
if (FLAGS.InitOrWait == 0) // if its wait mode (not writting app)
{
// set Init mode, start WDTim after receiving first page
Check_CMD_USART(ReceiveDataUART); // check received uart data
FLAGS.InitOrWait = 1;
FLAGS.StartInit = 1;
FLAGS.InitBootPeriph = 1;
app_current_add = MAIN_APP_START_ADR; // set adress for app
}
else
{
HAL_StatusTypeDef res_hal;
res_hal = FLASH_Write_Page(&app_current_add, Data2Write+PAGE_SIZE, PAGE_SIZE);
if (res_hal != HAL_OK)
{
BOOTLOADER_ERRORS_COUNTERS.FLASH_WRITE++; // err when initialize uart
BOOTLOADER_ERRORS.FLASH_WRITE=1;
}
FLAGS.HalfOfWrite = 0; // switch unwritten half of DMA buffer
cnt_tim_reset = 0; // upd WD Tim
GPIOB->ODR^=0x2000; // indicate written page
}
}
}
uint32_t temp_app_cur_add;
int app_size;
/*void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
if(HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, CAN_Data) == HAL_OK)
{
#ifdef _CAN_PUSH_ID_TO_ADDR_
if(FLAGS.InitOrWait)
{ // if its 1 - Init: writting app.bin in flash
temp_app_cur_add = app_current_add+(RxHeader.ExtId&(0x0000FFFF));
FLASH_Write_Page(&temp_app_cur_add, CAN_Data, 8);
app_size-=8; // decrease app_size
if (app_size<=0) // when its gone - reset system and go to the app
{
__ASM("");
NVIC_SystemReset();
}
}
else
{ // if its 0 - Wait: parsing address to writting and size of app.bin
app_current_add = Data2Write[0]<<24 | Data2Write[1]<<16 | Data2Write[2]<<8 | Data2Write[3];
app_size = Data2Write[4]<<24 | Data2Write[5]<<16 | Data2Write[6]<<8 | Data2Write[7];
FLAGS.InitOrWait = 1; // switch to firmware (init)
}
#endif
if(FLAGS.InitOrWait)
{
if (FLAGS.InitBootPeriph) // if its first received page
{
HAL_TIM_Base_Start_IT(&htim_boot); // start "wd" timer
FLAGS.InitBootPeriph = 0; // 5 sec silent on RX - mcu reset
}
FLASH_Write_Page(&app_current_add, CAN_Data, 8);
cnt_tim_reset=0;
}
else
{
app_current_add = MAIN_APP_START_ADR; // set adress for app
Check_CMD_USART(CAN_Data);
FLAGS.InitBootPeriph=1;
FLAGS.InitOrWait = 1;
FLAGS.StartInit = 1;
}
}
}
*/
void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan)
{
uint32_t er;
er = HAL_CAN_GetError(hcan);
__ASM("");
}
void Bootloader_TIM_Handler(void) // reset mcu after writing application is done
{ // add this to the TIM handler that is used (TIMx is seting up in project_setup.h)
HAL_StatusTypeDef res_fresult;
cnt_tim_reset++;
if (cnt_tim_reset > 5) // writing is done if there is silence on Rx for 5 second
{
if(FLAGS.BootloaderCMD==1)
{
FLAGS.InitMCUReady = 1;
ResetKey();
SetKey(); // write key for going to application
int NumOfLastBytes = (PAGE_SIZE - DMA1_Channel3->CNDTR%PAGE_SIZE); // read size of new data in dma buffer
if (NumOfLastBytes != 0)
{
res_fresult = FLASH_Write_Page(&app_current_add, Data2Write+PAGE_SIZE*FLAGS.HalfOfWrite, NumOfLastBytes); // writing last data
}
NVIC_SystemReset(); // reset mcu
}
else if(FLAGS.BootloaderCMD==2)
{
FLAGS.InitMCUReady = 1;
ResetKey();
SetKey();
NVIC_SystemReset();
}
}
}
void Check_CMD_USART(uint8_t *DataUART) // choose CMD (interface)
{ // 4 byte: 0xFF - erase app, else - just write app
//USART
if ((DataUART[0]|
DataUART[1]<<8|
DataUART[2]<<16) == 0xFFFFFF)
{
FLAGS.BootloaderCMD = 1;
}
//CAN
else if ((DataUART[0]|
DataUART[1]<<8|
DataUART[2]<<16) == 0xAAAFFF)
{
FLAGS.BootloaderCMD = 2;
}
//SDIO
else if ((DataUART[0]|
DataUART[1]<<8|
DataUART[2]<<16) == 0xAAFAFF)
{
FLAGS.BootloaderCMD = 3;
BSP_SD_DetectIT();
}
if (DataUART[3]== 0xFF)
{
FLAGS.reInitMCU = 1;
}
else
{
FLAGS.reInitMCU = 0;
}
}
// 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)
{
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();
}
HAL_StatusTypeDef BSP_SD_ITConfig(void)
{
/* Code to be updated by the user or replaced by one from the FW pack (in a stmxxxx_sd.c file) */
GPIO_InitTypeDef gpio_init_structure;
/* Configure Interrupt mode for SD detection pin */
gpio_init_structure.Pin = SDIO_SDCard_In_PIN;
gpio_init_structure.Pull = GPIO_PULLUP;
gpio_init_structure.Speed = GPIO_SPEED_HIGH;
gpio_init_structure.Mode = GPIO_MODE_IT_RISING_FALLING;
HAL_GPIO_Init(SDIO_SDCard_In_PORT, &gpio_init_structure);
/* Enable and set SD detect EXTI Interrupt to the lowest priority */
HAL_NVIC_SetPriority((SDIO_SDCard_In_IRQn), 0x00, 0x00);
HAL_NVIC_EnableIRQ((SDIO_SDCard_In_IRQn));
return HAL_OK;
// return (uint8_t)0;
}
void BSP_SD_DetectIT(void)
{ // add this to the EXTI handler that is used (EXTIx (GPIO_PIN_x) is seting up in project_setup.h)
if(SDIO_SDCard_In_PORT->IDR&SDIO_SDCard_In_PIN)
FLAGS.SDCardIn = 0;
else
FLAGS.SDCardIn = 1;
}
void Boot_SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
HAL_RCC_MCOConfig(RCC_MCO, RCC_MCO1SOURCE_PLLCLK, RCC_MCODIV_1);
}