#include "stm32f4xx.h" #include "common_config.h" #include "conf.h" #include "main.h" #include "led.h" #include "systick.h" #include "usart.h" #include "httpserver.h" #include "flash_if.h" #include "settings_api.h" #include "gpio_io.h" #include "gpio.h" #include "crc.h" #include "wdg.h" #include "tinystdio.h" #include "time.h" #include "string.h" #include "stm32f4x7_eth.h" #include "netconf.h" #include "rng.h" #ifdef SD_ENABLE #include "SD_Card/sdio_sd.h" #include "FATFS/ff.h" #include "FATFS/diskio.h" #endif #ifdef LCD_ENABLE #include "lcd.h" #endif #ifdef SLAVEBRD_ENABLE #include "stm32sprog.h" #endif #ifdef FTP_ENABLE #include "spi_flash.h" #endif /* Секция размещения СRC прошивки */ #if defined ( __GNUC__ ) uint32_t crc __attribute__ ((section (".crc"))) = 0xAABBCCDD; #endif #define FW_FILE_NAME MAIN_FW_NAME /* * Bootloader verification key section. * Use "openssl rand -hex 8" to generate new key. * */ uint64_t bootkey __attribute__ ((section (".bootkey"))) = 0x92dc73b8fef3b041; bool IAPviaETH = false; bool fDoneReset = false; bool fUpload = false; bool fInvalidFw = false; bool fBootFailed = false; volatile uint32_t resetCounter = 0; bool UpdateTimeoutFlag = false; #ifdef SD_ENABLE extern FATFS fs; extern FIL fil_obj; #endif /* this variable is used to create a time reference incremented by 10ms */ __IO uint32_t LocalTime = 0; pFunction Jump_To_App; uint32_t JumpAdd; /** * @brief Общая структура настроек */ extern SETTINGS_t sSettings; void UpdateTimeout_Handler(void); #ifdef SD_ENABLE bool mmc_mount(void) { if (disk_initialize(0) != RES_OK) return false; if (f_mount(&fs, "0:", 1) != FR_OK) return false; return true; } #endif bool CheckFWIsValid(void) { if (((*(__IO uint32_t *)USER_FLASH_FIRST_PAGE_ADDRESS) & 0x2FFE0000 ) == 0x20000000 && *(__IO uint32_t *)USER_FLASH_CRC_ADDRESS != 0xFFFFFFFF) { return true; } printf("\r\nFW empty. Started bootloader\r\n"); return false; } #ifdef FTP_ENABLE void spi_flash_update(void) { printf("ftp: trying to update the firmware from the SPI flash\r\n"); const uint32_t spif_firmware_offset = SPI_FLASH_SECTOR_SIZE * FIRMWARE_UPDATE_SECTOR_OFFSET; uint32_t fw_begin; spi_flash_init(); spi_flash_read(spif_firmware_offset, &fw_begin, 4, 0); const uint32_t crc_offset = USER_FLASH_CRC_ADDRESS - USER_FLASH_FIRST_PAGE_ADDRESS; uint32_t expected_crc; spi_flash_read(spif_firmware_offset + crc_offset, &expected_crc, 4, 0); bool present_firmware = (fw_begin != 0xFFFFFFFF) || (expected_crc != 0xFFFFFFFF); if (!present_firmware) { printf("ftp: no firmware-like data is present on the SPI flash\r\n"); return; } // check CRC CRC->CR = 1; for (uint32_t offset = 0; offset < crc_offset; offset += 4) { uint32_t data; spi_flash_read(spif_firmware_offset + offset, &data, sizeof(data), 0); CRC->DR = data; } uint32_t calculated_crc = CRC->DR; if (expected_crc != calculated_crc) { printf("ftp: calculated CRC (%lx) doesn't match the expected CRC (%lx)!\r\n", calculated_crc, expected_crc); return; } printf("ftp: writing the stm32 flash\r\n"); FLASH_If_Erase(USER_FLASH_FIRST_PAGE_ADDRESS); FLASH_If_Init(); // unlock it again uint8_t buf[1024]; for (uint32_t offset = 0; offset < MAIN_FW_SIZE; offset += sizeof(buf)) { spi_flash_read(spif_firmware_offset + offset, buf, sizeof(buf), 0); uint8_t *addr = USER_FLASH_FIRST_PAGE_ADDRESS + offset; FLASH_If_Write(&addr, buf, sizeof(buf) / 4); } printf("ftp: erasing the SPI flash\r\n"); for (int sec = 0; sec < FIRMWARE_UPDATE_SECTOR_COUNT; ++sec) { spi_flash_erase_sector(SPI_FLASH_SECTOR_SIZE * (FIRMWARE_UPDATE_SECTOR_OFFSET + sec), 0); } printf("ftp: update successful, rebooting...\r\n"); SET_FWUPDATED_FLAG(); CLEAR_FWINVALID_FLAG(); RTC_WriteBackupRegister(RTC_BKP_DR1, 0); // loadMode NVIC_SystemReset(); } #endif // FTP_ENABLE void main(void) { uint8_t bootTry; uint8_t loadMode; gpio_init(); WDG_Init(); InitUSART(); #ifdef PRINTF_STDLIB setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); #endif /* Enable PWR peripheral clock */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); /* Allow access to BKP Domain */ PWR_BackupAccessCmd(ENABLE); /* Включаем тактирование модуля CRC */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE); /* Проверка флага, определяющего состояние устройства. */ /* Флаг установлен - работает Bootloader */ /* Флаг сброшен - запускается основная программа */ SETTINGS_Load(); /* Проверка флага bootTry. Если флаг установлен, значит произошел сбой в основной прошивке. Нужно загружать bootloader и ждать обновления ПО */ loadMode = RTC_ReadBackupRegister(RTC_BKP_DR1); bootTry = RTC_ReadBackupRegister(RTC_BKP_DR2); fInvalidFw = RTC_ReadBackupRegister(RTC_BKP_DR7); printf("\r\nloadMode: %d\r\nbootTry: %d\r\n", loadMode, bootTry); printf("fInvalidFw: %s\r\n", fInvalidFw ? "true" : "false"); if (bootTry > 1) { bootTry--; RTC_WriteBackupRegister(RTC_BKP_DR2, bootTry); /* Check if valid stack address (RAM address) then jump to user application */ if (CheckFWIsValid()) { CLEAR_FWINVALID_FLAG(); /* Jump to user application */ JumpAdd = *(__IO uint32_t *) (USER_FLASH_FIRST_PAGE_ADDRESS + 4); Jump_To_App = (pFunction) JumpAdd; /* Initialize user application's Stack Pointer */ __set_MSP(*(__IO uint32_t *) USER_FLASH_FIRST_PAGE_ADDRESS); Jump_To_App(); } else { /* Флеш пустая, нечего загружать, висим в аварийном режиме */ SET_FWINVALID_FLAG(); } } else if (bootTry == 1) { fBootFailed = 1; printf("\r\nFW boot failed. Started bootloader\r\n"); bootTry = 0; loadMode = 1; RTC_WriteBackupRegister(RTC_BKP_DR2, bootTry); RTC_WriteBackupRegister(RTC_BKP_DR1, loadMode); } /* Флаг не установлен прыгаем на основную программу */ if (loadMode == 0) { printf("Run main FW\r\n"); //printf("*(__IO uint32_t*)(USER_FLASH_FIRST_PAGE_ADDRESS) = 0x%X\r\n", *(__IO uint32_t*)USER_FLASH_FIRST_PAGE_ADDRESS); //printf("*(__IO uint32_t*)(USER_FLASH_FIRST_PAGE_ADDRESS + 4) = 0x%X\r\n", *(__IO uint32_t*)(USER_FLASH_FIRST_PAGE_ADDRESS + 4)); /* Set bootTry flag every time to ensure that * IAP will starts again if FW is corrupted */ bootTry = BOOT_TRY; RTC_WriteBackupRegister(RTC_BKP_DR2, bootTry); /* Check if valid stack address (RAM address) then jump to user application */ if (CheckFWIsValid()) { CLEAR_FWINVALID_FLAG(); /* Jump to user application */ JumpAdd = *(__IO uint32_t *) (USER_FLASH_FIRST_PAGE_ADDRESS + 4); Jump_To_App = (pFunction) JumpAdd; /* Initialize user application's Stack Pointer */ __set_MSP(*(__IO uint32_t *) USER_FLASH_FIRST_PAGE_ADDRESS); Jump_To_App(); } } /* Загружается Bootloader... */ SysTick_Config(168000);//120000 LED_Init(); LED_On(LED_INIT_ERR); PRINT_USART("\n\rBootloader starting... \n\r"); #ifdef LCD_ENABLE LCD_Init(); LCD_PrintAligned(1, alignCENTER, "Обновление ПО"); #endif /* Random number generator */ RNG_Init(); ETH_BSP_Config(); LwIP_Init(); IAP_httpd_init(); CRC_Init(); //Если нажата DEF начинаем обновление с sd if (IO_BtnDefaultPressed()) { #ifdef SD_ENABLE IAPviaETH = false; timer_AddFunction(500, &LED_Blinky_Red); SD_NVIC_Init(); #endif } else { IAPviaETH = true; timer_AddFunction(500, &LED_Blinky_Red); } /* Check if valid stack address (RAM address) */ if (((*(__IO uint32_t *)USER_FLASH_FIRST_PAGE_ADDRESS) & 0x2FFE0000 ) == 0x20000000 && !fInvalidFw) { #if UPDATE_TIMEOUT != 0 timer_AddFunction(1000, &UpdateTimeout_Handler); #endif } else { update_timeout = 0; /* Флеш пустая, нечего загружать, висим в аварийном режиме */ SET_FWINVALID_FLAG(); #ifdef LCD_ENABLE LCD_PrintAligned(5, alignCENTER, "Аварийный режим"); LCD_PrintAligned(7, alignCENTER, "Ошибка ПО"); #endif } if (fBootFailed) { #ifdef LCD_ENABLE LCD_PrintAligned(5, alignCENTER, "Аварийный режим"); LCD_ClearRow(7); #endif } #ifdef FTP_ENABLE spi_flash_update(); #endif // FTP_ENABLE while (1) { timer_Main(); if (IAPviaETH) { // Обновление по ETH /* Handle received packets and periodic timers for LwIP */ LwIP_Periodic_Handle(0); if (fDoneReset) { resetCounter++; if (resetCounter > 400000) { loadMode = 0; bootTry = BOOT_TRY; RTC_WriteBackupRegister(RTC_BKP_DR1, loadMode); RTC_WriteBackupRegister(RTC_BKP_DR2, bootTry); SET_FWUPDATED_FLAG(); CLEAR_FWINVALID_FLAG(); #ifdef SLAVEBRD_ENABLE /* Reboot daughter board */ stmReboot(); #endif /* Self reboot */ NVIC_SystemReset(); } } } else { #ifdef SD_ENABLE // Обновление с SD // Пробуем смонтировать SD if (mmc_mount()) { // Пробуем открыть файл с именем FW_FILE_NAME timer_Stop(&LED_Blinky_Yellow); LED_Off(RED1_INT); LED_Off(GREEN_INT); if (f_open(&fil_obj, FW_FILE_NAME, FA_READ | FA_OPEN_EXISTING) == FR_OK) { // открываем файл LED_On(GREEN_INT); if (startFlashing() < 0) { Error_Handler(); } f_close(&fil_obj); // CRC посчитанная при сборке и записанная в последине 4 байта прошивки // Должна сойтись с CRC посчитанной на контроллере if (CRC_Read() == CRC_Calculate()) { loadMode = 0; bootTry = BOOT_TRY; RTC_WriteBackupRegister(RTC_BKP_DR1, loadMode); RTC_WriteBackupRegister(RTC_BKP_DR2, bootTry); #ifdef SLAVEBRD_ENABLE /* Reboot daughter board */ stmReboot(); #endif /* Self reboot */ NVIC_SystemReset(); } else { Error_Handler(); } } else { // Файл не найден LED_On(RED1_INT); } } #endif } //Если нажата DEF переходим в основную прошивку if (IO_BtnDefaultPressed() || UpdateTimeoutFlag) { if (!fUpload && ((*(__IO uint32_t *)USER_FLASH_FIRST_PAGE_ADDRESS) != 0xFFFFFFFF)) { printf("\r\nUpdate timeout... Return to main FW\r\n"); loadMode = 0; bootTry = BOOT_TRY; RTC_WriteBackupRegister(RTC_BKP_DR1, loadMode); RTC_WriteBackupRegister(RTC_BKP_DR2, bootTry); #ifdef SLAVEBRD_ENABLE /* Reboot daughter board */ stmReboot(); #endif /* Self reboot */ NVIC_SystemReset(); } } } } /** * @brief Updates the system local time * @param None * @retval None */ void Time_Update(void) { LocalTime += SYSTEMTICK_PERIOD_MS; } /** * @brief */ u32_t sys_now(void) { return LocalTime; } /** * @brief Error handler * @param None * @retval None */ void Error_Handler(void) { LED_Off(LED_INIT_ERR); LED_Off(LED_INIT_OK); timer_AddFunction(500, &LED_Blinky_Red); while (1) { timer_Main(); } } /** * @brief */ void UpdateTimeout_Handler(void) { if ((fUpload) || (fInvalidFw) || (fDoneReset)) { return; } if (update_timeout == 0) { UpdateTimeoutFlag = true; } else { #ifdef LCD_ENABLE static char lcdbuf[32] = {0}; sprintf(lcdbuf, "Ожидание (%d) ", update_timeout); LCD_ClearRow(7); LCD_PrintAligned(7, alignCENTER, lcdbuf); #endif update_timeout--; } }