BootLoader端
BootLoader\Core\Src\stm_flash.c
c
#include "stm_flash.h"
struct stm_flash_dev Stm_Flash_Data;
// 读取指定地址的字(32位数据)
// faddr:读地址
// 返回值:对应数据.
uint32_t STMFLASH_ReadWord(uint32_t faddr)
{
return *(uint32_t *)faddr;
}
// 获取某个地址所在的flash扇区
// addr:flash地址
// 返回值:0~11,即addr所在的扇区
uint8_t STMFLASH_GetFlashSector(uint32_t addr)
{
if (addr < ADDR_FLASH_SECTOR_1)
return FLASH_SECTOR_0;
else if (addr < ADDR_FLASH_SECTOR_2)
return FLASH_SECTOR_1;
else if (addr < ADDR_FLASH_SECTOR_3)
return FLASH_SECTOR_2;
else if (addr < ADDR_FLASH_SECTOR_4)
return FLASH_SECTOR_3;
else if (addr < ADDR_FLASH_SECTOR_5)
return FLASH_SECTOR_4;
else if (addr < ADDR_FLASH_SECTOR_6)
return FLASH_SECTOR_5;
else if (addr < ADDR_FLASH_SECTOR_7)
return FLASH_SECTOR_6;
else if (addr < ADDR_FLASH_SECTOR_8)
return FLASH_SECTOR_7;
else if (addr < ADDR_FLASH_SECTOR_9)
return FLASH_SECTOR_8;
else if (addr < ADDR_FLASH_SECTOR_10)
return FLASH_SECTOR_9;
else if (addr < ADDR_FLASH_SECTOR_11)
return FLASH_SECTOR_10;
return FLASH_SECTOR_11;
}
void STMFLASH_Earse_Sector(uint32_t addr)
{
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
FLASH_EraseInitTypeDef FlashEraseInit;
uint32_t SectorError = 0;
FlashEraseInit.TypeErase = FLASH_TYPEERASE_SECTORS; // 擦除类型,扇区擦除
FlashEraseInit.Sector = STMFLASH_GetFlashSector(addr); // 要擦除的扇区
FlashEraseInit.NbSectors = 1; // 一次只擦除一个扇区
FlashEraseInit.VoltageRange = FLASH_VOLTAGE_RANGE_3; // 电压范围,VCC=2.7~3.6V之间!!
HAL_FLASHEx_Erase(&FlashEraseInit, &SectorError);
HAL_FLASH_Lock();
}
// 从指定地址开始写入指定长度的数据
// 特别注意:因为STM32F4的扇区实在太大,没办法本地保存扇区数据,所以本函数
// 写地址如果非0xFF,那么会先擦除整个扇区且不保存扇区数据.所以
// 写非0xFF的地址,将导致整个扇区数据丢失.建议写之前确保扇区里
// 没有重要数据,最好是整个扇区先擦除了,然后慢慢往后写.
// 该函数对OTP区域也有效!可以用来写OTP区!
// OTP区域地址范围:0x1FFF7800~0x1FFF7A0F(注意:最后16字节,用于OTP数据块锁定,别乱写!!)
// WriteAddr:起始地址(此地址必须为4的倍数!!)
// pBuffer:数据指针
// NumToWrite:字(32位)数(就是要写入的32位数据的个数.)
void STMFLASH_Write(uint32_t WriteAddr, uint32_t *pBuffer, uint32_t NumToWrite)
{
FLASH_EraseInitTypeDef FlashEraseInit;
HAL_StatusTypeDef FlashStatus = HAL_OK;
uint32_t SectorError = 0;
uint32_t addrx = 0;
uint32_t endaddr = 0;
if (WriteAddr < STM32_FLASH_BASE || WriteAddr % 4)
return; // 非法地址
HAL_FLASH_Unlock(); // 解锁
addrx = WriteAddr; // 写入的起始地址
endaddr = WriteAddr + NumToWrite * 4; // 写入的结束地址
if (addrx < 0x1FFF0000)
{
while (addrx < endaddr) // 扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
{
if (STMFLASH_ReadWord(addrx) != 0xFFFFFFFF) // 有非0xFFFFFFFF的地方,要擦除这个扇区
{
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
FlashEraseInit.TypeErase = FLASH_TYPEERASE_SECTORS; // 擦除类型,扇区擦除
FlashEraseInit.Sector = STMFLASH_GetFlashSector(addrx); // 要擦除的扇区
FlashEraseInit.NbSectors = 1; // 一次只擦除一个扇区
FlashEraseInit.VoltageRange = FLASH_VOLTAGE_RANGE_3; // 电压范围,VCC=2.7~3.6V之间!!
if (HAL_FLASHEx_Erase(&FlashEraseInit, &SectorError) != HAL_OK)
{
break; // 发生错误了
}
}
else
addrx += 4;
FLASH_WaitForLastOperation(FLASH_WAITETIME); // 等待上次操作完成
}
}
FlashStatus = FLASH_WaitForLastOperation(FLASH_WAITETIME); // 等待上次操作完成
if (FlashStatus == HAL_OK)
{
while (WriteAddr < endaddr) // 写数据
{
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, WriteAddr, *pBuffer) != HAL_OK) // 写入数据
{
break; // 写入异常
}
WriteAddr += 4;
pBuffer++;
}
}
HAL_FLASH_Lock(); // 上锁
}
// 从指定地址开始读出指定长度的数据
// ReadAddr:起始地址
// pBuffer:数据指针
// NumToRead:字(32位)数
void STMFLASH_Read(uint32_t ReadAddr, uint32_t *pBuffer, uint32_t NumToRead)
{
uint32_t i;
for (i = 0; i < NumToRead; i++)
{
pBuffer[i] = STMFLASH_ReadWord(ReadAddr); // 读取4个字节.
ReadAddr += 4; // 偏移4个字节.
}
}
//-------------------------------测试用-------------------------------//
// WriteAddr:起始地址
// WriteData:要写入的数据
void Test_Write(uint32_t WriteAddr, uint32_t WriteData)
{
STMFLASH_Write(WriteAddr, &WriteData, 1); // 写入一个字
}
BootLoader\Core\Inc\stm_flash.h
c
#ifndef __STM_FLASH_H__
#define __STM_FLASH_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "stm32f4xx_hal.h"
//FLASH起始地址
#define STM32_FLASH_BASE 0x08000000 //STM32 FLASH的起始地址
#define FLASH_WAITETIME 50000 //FLASH等待超时时间
//FLASH 扇区的起始地址
#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) //扇区0起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000) //扇区1起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000) //扇区2起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_3 ((uint32_t)0x0800C000) //扇区3起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_4 ((uint32_t)0x08010000) //扇区4起始地址, 64 Kbytes
#define ADDR_FLASH_SECTOR_5 ((uint32_t)0x08020000) //扇区5起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_6 ((uint32_t)0x08040000) //扇区6起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_7 ((uint32_t)0x08060000) //扇区7起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_8 ((uint32_t)0x08080000) //扇区8起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_9 ((uint32_t)0x080A0000) //扇区9起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_10 ((uint32_t)0x080C0000) //扇区10起始地址,128 Kbytes
#define ADDR_FLASH_SECTOR_11 ((uint32_t)0x080E0000) //扇区11起始地址,128 Kbytes
#define APP1_ADDRESS ADDR_FLASH_SECTOR_5
#define APP2_ADDRESS ADDR_FLASH_SECTOR_7
#define UPDATE_CODE_ADDRESS ADDR_FLASH_SECTOR_7
#define UPDATE_FLAG_ADDRESS ADDR_FLASH_SECTOR_10
struct stm_flash_dev
{
uint32_t bootloader_flag; // 值为0xA5表示进入bootloader进行代码升级
};
extern struct stm_flash_dev Stm_Flash_Data;
uint32_t STMFLASH_ReadWord(uint32_t faddr); //读出字
void STMFLASH_Write(uint32_t WriteAddr,uint32_t *pBuffer,uint32_t NumToWrite); //从指定地址开始写入指定长度的数据
void STMFLASH_Read(uint32_t ReadAddr,uint32_t *pBuffer,uint32_t NumToRead); //从指定地址开始读出指定长度的数据
void Test_Write(uint32_t WriteAddr,uint32_t WriteData); //测试写入
void STMFLASH_Earse_Sector(uint32_t addr);
#ifdef __cplusplus
}
#endif
#endif /*__STM_FLASH_H__ */
BootLoader\Core\Src\main.c
c
/* USER CODE BEGIN Header_StartDefaultTask */
/**
* @brief Function implementing the defaultTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void const * argument)
{
/* USER CODE BEGIN 5 */
// earse flash
STMFLASH_Earse_Sector(APP1_ADDRESS);
STMFLASH_Earse_Sector(APP1_ADDRESS + 0x00020000);
// 将接收到的固件写入运行区
STMFLASH_Read(APP2_ADDRESS, (uint32_t*) APP_Code, sizeof(APP_Code) / sizeof(uint32_t));
STMFLASH_Write(APP1_ADDRESS, (uint32_t*) APP_Code, sizeof(APP_Code) / sizeof(uint32_t)); // 64Kbyte code
STMFLASH_Read(APP2_ADDRESS + 1 * sizeof(APP_Code), (uint32_t*) APP_Code, sizeof(APP_Code) / sizeof(uint32_t));
STMFLASH_Write(APP1_ADDRESS + 1 * sizeof(APP_Code), (uint32_t*) APP_Code, sizeof(APP_Code) / sizeof(uint32_t)); // 64Kbyte code
STMFLASH_Read(APP2_ADDRESS + 2 * sizeof(APP_Code), (uint32_t*) APP_Code, sizeof(APP_Code) / sizeof(uint32_t));
STMFLASH_Write(APP1_ADDRESS + 2 * sizeof(APP_Code), (uint32_t*) APP_Code, sizeof(APP_Code) / sizeof(uint32_t)); // 64Kbyte code
STMFLASH_Read(APP2_ADDRESS + 3 * sizeof(APP_Code), (uint32_t*) APP_Code, sizeof(APP_Code) / sizeof(uint32_t));
STMFLASH_Write(APP1_ADDRESS + 3 * sizeof(APP_Code), (uint32_t*) APP_Code, sizeof(APP_Code) / sizeof(uint32_t)); // 64Kbyte code
// 擦除升级标志,使得MCU复位后程序运行到运行区
STMFLASH_Earse_Sector(UPDATE_FLAG_ADDRESS);
__set_FAULTMASK(1); // 关闭所有中断
HAL_NVIC_SystemReset();
/* Infinite loop */
for(;;)
{
osDelay(10);
}
/* USER CODE END 5 */
}
APP端:
\Core\Src\tasks\slave_modbus_task.c
c
void Slave_Modbus_Task(void *pvParameters)
{
uint32_t total_length = 0;
uint32_t receive_length = 0;
uint32_t length = 0;
uint16_t step = 0;
uint32_t destination_address = 0;
uint32_t check_sum = 0;
uint32_t elapse_time_start = 0;
uint32_t elapse_time = 0;
uint8_t backup_flag = 0;
uint8_t update_flag = 0;
// Slave_Data_Init();
// eMBTCPInit(502);
// eMBEnable();
xMBPortEventInit();
MX_IWDG_Init();
while (1)
{
eMBPoll();
// 固件更新升级代码
if ((Slave_station.usSRegHoldBuf[3100] == MAIN_BOARD_ID) && (Slave_station.usSRegHoldBuf[3103] == 0xAAAA))
{
if ((Slave_station.usSRegHoldBuf[3101] == 0xFFFF) && (Slave_station.usSRegHoldBuf[3102] == 0xFFFF))
{
step = 0;
}
if (step == 0)
{
{
step = 1;
Slave_station.usSRegHoldBuf[3103] = 0x5555;
}
}
else if (step == 1)
{
total_length = (uint32_t)Slave_station.usSRegHoldBuf[3101] + ((uint32_t)Slave_station.usSRegHoldBuf[3102] << 16);
receive_length = 0;
if (total_length > (256 * 1024))
{
Slave_station.usSRegHoldBuf[3103] = 0xFFFF;
step = 0;
}
else
{
vTaskSuspendAll();
// earse flash
STMFLASH_Earse_Sector(UPDATE_CODE_ADDRESS);
STMFLASH_Earse_Sector(UPDATE_CODE_ADDRESS + 0x00020000);
xTaskResumeAll();
destination_address = UPDATE_CODE_ADDRESS;
step = 2;
Slave_station.usSRegHoldBuf[3103] = 0x5555;
}
}
else if (step == 2)
{
length = total_length - receive_length;
if (length >= 128)
{
receive_length += 128;
length = 128;
}
else
{
receive_length += length;
}
vTaskSuspendAll();
// write flash
for (uint32_t i = 0; i < length / 2; i += 2)
{
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, destination_address, *(uint32_t *)&Slave_station.usSRegHoldBuf[3104 + i]);
HAL_FLASH_Lock();
destination_address += 4;
}
xTaskResumeAll();
// equ total length?
if (receive_length == total_length)
{
// judge checksum
check_sum = crc32((uint8_t *)UPDATE_CODE_ADDRESS, total_length - 4);
if (check_sum == *(uint32_t *)(UPDATE_CODE_ADDRESS + total_length - 4))
{
vTaskSuspendAll();
/* Unlock the Flash to enable the flash control register access *************/
STMFLASH_Earse_Sector(UPDATE_FLAG_ADDRESS);
HAL_FLASH_Unlock();
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, UPDATE_FLAG_ADDRESS, 0x000000A5);
/* Lock the Flash to disable the flash control register access (recommended
to protect the FLASH memory against possible unwanted operation) *********/
HAL_FLASH_Lock();
xTaskResumeAll();
// 升级成功
Slave_station.usSRegHoldBuf[3103] = 0x2222;
step = 3;
}
else
{
// 升级失败
Slave_station.usSRegHoldBuf[3103] = 0xFFFF;
step = 0;
}
}
else if (receive_length > total_length)
{
// 升级失败
Slave_station.usSRegHoldBuf[3103] = 0xFFFF;
step = 0;
}
else
{
Slave_station.usSRegHoldBuf[3103] = 0x5555;
}
}
else if (step == 3)
{
__set_FAULTMASK(1); // 关闭所有中断
HAL_NVIC_SystemReset();
step = 4;
}
}
}
}