#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); }