一、测试平台:
MCU:STM32F407VET6
固件库:CUBEMX
IDE:MDK
二、实验目的:
将U盘里面的bin文件插入要升级的设备,通过BootLoader来进行升级
在这是用板载的LED灯来显示升级情况:
不进行升级:LED灯是灭的状态
升级成功:LED灯以100ms在闪烁
接下来先进行BootLoader的配置以及程序编写,再配置APP
三、BootLoader:
1 下载器配置
2 时钟源配置
3 LED配置
4 串口配置 开启全局中断
5 USB_OTG_FS配置
6 USB_HOST配置
7 FATFS配置
8 时钟树配置 48M是用来操作U盘的,所以必须要有
9 工程配置
10 生成工程
11 创建两个空白文件文件
BootLoader.h
#ifndef __BOOTLOADER_H
#define __BOOTLOADER_H
#include "stm32f4xx_hal.h"
#include "usb_host.h"
#include "fatfs.h"
#include "usart.h"
#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* Base @ of Sector 0, 16 Kbytes */
#define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000) /* Base @ of Sector 1, 16 Kbytes */
#define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000) /* Base @ of Sector 2, 16 Kbytes */
#define ADDR_FLASH_SECTOR_3 ((uint32_t)0x0800C000) /* Base @ of Sector 3, 16 Kbytes */
#define ADDR_FLASH_SECTOR_4 ((uint32_t)0x08010000) /* Base @ of Sector 4, 64 Kbytes */
#define ADDR_FLASH_SECTOR_5 ((uint32_t)0x08020000) /* Base @ of Sector 5, 128 Kbytes */
#define ADDR_FLASH_SECTOR_6 ((uint32_t)0x08040000) /* Base @ of Sector 6, 128 Kbytes */
#define ADDR_FLASH_SECTOR_7 ((uint32_t)0x08060000) /* Base @ of Sector 7, 128 Kbytes */
#define ADDR_FLASH_SECTOR_8 ((uint32_t)0x08080000) /* Base @ of Sector 8, 128 Kbytes */
#define ADDR_FLASH_SECTOR_9 ((uint32_t)0x080A0000) /* Base @ of Sector 9, 128 Kbytes */
#define ADDR_FLASH_SECTOR_10 ((uint32_t)0x080C0000) /* Base @ of Sector 10, 128 Kbytes */
#define ADDR_FLASH_SECTOR_11 ((uint32_t)0x080E0000) /* Base @ of Sector 11, 128 Kbytes */
#define RAM_BUFFER_SIZE ((uint32_t)30*1024) /*KBytes*/
#define filename "LED.bin"
#define FLASH_USER_START_ADDR ADDR_FLASH_SECTOR_4 /* Start @ of user Flash area */
#define FLASH_USER_END_ADDR ADDR_FLASH_SECTOR_4 + 0x10000
uint32_t FLASH_Erase_Write(void);
static uint32_t GetSector(uint32_t Address);
void jumpToApp(void);
void UP_Data(void);
#endif
BootLoader.c
#include "BootLoader.h"
extern ApplicationTypeDef Appli_state;
FRESULT res;
static FLASH_EraseInitTypeDef EraseInitStruct;
uint8_t RAM_Buffer[RAM_BUFFER_SIZE];
uint32_t APP_Size;
uint32_t FirstSector = 0, NbOfSectors = 0, Address = 0;
uint32_t SectorError = 0;
__IO uint32_t data32 = 0 , MemoryProgramStatus = 0;
uint8_t errorcode;
uint32_t *p;
uint8_t SystemUpdateFlag = 0, state = 0;
uint16_t t = 0;
typedef void (*pFunction)(void);
pFunction Jump_To_Application;
uint32_t JumpAddress;
int fputc(int ch, FILE *f) //用来打印信息的 便于观察
{
HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 100);
return ch;
}
uint32_t FLASH_Erase_Write(void) //FLASH擦写
{
uint32_t i = 0;
HAL_FLASH_Unlock();
FirstSector = GetSector(FLASH_USER_START_ADDR);
NbOfSectors = GetSector(FLASH_USER_END_ADDR) - FirstSector + 1;
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
EraseInitStruct.Sector = FirstSector;
EraseInitStruct.NbSectors = NbOfSectors;
if(HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK)
{
errorcode = HAL_FLASH_GetError(); //擦除失败的扇区
printf("errorcode %d", errorcode);
Error_Handler();
}
__HAL_FLASH_DATA_CACHE_DISABLE();
__HAL_FLASH_INSTRUCTION_CACHE_DISABLE();
__HAL_FLASH_DATA_CACHE_RESET();
__HAL_FLASH_INSTRUCTION_CACHE_RESET();
__HAL_FLASH_INSTRUCTION_CACHE_ENABLE();
__HAL_FLASH_DATA_CACHE_ENABLE();
printf("HAL_OK\r\n");
Address = FLASH_USER_START_ADDR;
while (Address < FLASH_USER_END_ADDR)
{
p = (uint32_t *)&RAM_Buffer[i];
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, *p) == HAL_OK) //FLASH写入
{
Address = Address + 4;
i = i + 4;
}
else
{
printf("Address-error\r\n");
Error_Handler();
}
}
HAL_FLASH_Lock();
Address = FLASH_USER_START_ADDR; //校验
MemoryProgramStatus = 0x0;
printf("CHEAK\r\n");
while (Address < FLASH_USER_END_ADDR)
{
data32 = *(__IO uint32_t*)Address;
if (data32 != *(uint32_t*)RAM_Buffer)
{
MemoryProgramStatus++;
}
Address = Address + 4;
}
printf("CHEAK-finish\r\n");
return HAL_OK;
}
static uint32_t GetSector(uint32_t Address) //获取扇区
{
uint32_t sector = 0;
if((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0))
{
sector = FLASH_SECTOR_0;
}
else if((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1))
{
sector = FLASH_SECTOR_1;
}
else if((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2))
{
sector = FLASH_SECTOR_2;
}
else if((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3))
{
sector = FLASH_SECTOR_3;
}
else if((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4))
{
sector = FLASH_SECTOR_4;
}
else if((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5))
{
sector = FLASH_SECTOR_5;
}
else if((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6))
{
sector = FLASH_SECTOR_6;
}
else if((Address < ADDR_FLASH_SECTOR_8) && (Address >= ADDR_FLASH_SECTOR_7))
{
sector = FLASH_SECTOR_7;
}
else if((Address < ADDR_FLASH_SECTOR_9) && (Address >= ADDR_FLASH_SECTOR_8))
{
sector = FLASH_SECTOR_8;
}
else if((Address < ADDR_FLASH_SECTOR_10) && (Address >= ADDR_FLASH_SECTOR_9))
{
sector = FLASH_SECTOR_9;
}
else if((Address < ADDR_FLASH_SECTOR_11) && (Address >= ADDR_FLASH_SECTOR_10))
{
sector = FLASH_SECTOR_10;
}
else /* (Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_11) */
{
sector = FLASH_SECTOR_11;
}
return sector;
}
void jumpToApp()
{
if (((*(__IO uint32_t*)FLASH_USER_START_ADDR) & 0x2FFE0000 ) == 0x20000000)
{
printf("ADDR == 0x20000000\r\n");
JumpAddress = *(__IO uint32_t*) (FLASH_USER_START_ADDR + 4);
Jump_To_Application = (pFunction) JumpAddress;
__set_MSP(*(__IO uint32_t*) FLASH_USER_START_ADDR);
__HAL_UART_DISABLE(&huart3); //关闭相应中断
__HAL_RCC_USB_OTG_FS_CLK_DISABLE();
__HAL_UART_CLEAR_FLAG(&huart3, UART_FLAG_TC);
__HAL_UART_DISABLE_IT(&huart3, UART_IT_RXNE);
Jump_To_Application();
}
printf("ADDR != 0x20000000\r\n");
}
void UP_Data(void)
{
if(state == 0)
{
if(t < 2010)
{
if(SystemUpdateFlag == 0 && Appli_state == APPLICATION_READY)
{
printf("APPLICATION_READY\r\n");
SystemUpdateFlag = 1;
t = 2000;
state = 1;
res = f_mount(&USBHFatFS, (TCHAR const*)USBHPath, 0);
if(res != FR_OK)
{
printf("U盘挂载失败 %d\r\n", res);
Error_Handler();
}
else
{
printf("U盘挂载成功\r\n");
}
res = f_open(&USBHFile, filename, FA_READ);
if(res != FR_OK)
{
printf("打开U盘文件失败 %d\r\n", res);
Error_Handler();
}
else
{
printf("打开U盘文件成功\r\n");
}
res = f_read(&USBHFile, RAM_Buffer, sizeof(RAM_Buffer), (void *)&APP_Size);
if(res != FR_OK)
{
printf("读取U盘文件失败 %d\r\n", res);
Error_Handler();
}
else
{
printf("读取U盘文件成功\r\n");
}
if((0<APP_Size) && (APP_Size<FLASH_USER_END_ADDR))
{
printf("FLASH_Erase\r\n");
FLASH_Erase_Write();
jumpToApp();
}
else
{
printf("APP_Size错误\r\n");
}
f_close(&USBHFile);
// FATFS_UnLinkDriver(USBHPath);
}
else
{
printf("%d\r\n", t);
t++;
HAL_Delay(1);
}
if(state == 0 && t > 2000) //超过2s 读取U盘失败
{
state = 1;
printf("DISCONNECT\r\n");
jumpToApp();
}
}
}
}
四、APP:
1 APP程序只进行LED闪烁,只配置这三个功能就够了
2 时钟树配置
3 工程配置
4 接下来是APP程序
(1)main.c 只放LED闪烁的功能
(2)中断偏移地址 这个地址要和BootLoader程序里面flash的起始地址要一样
(3)魔术棒配置
D:\software\keil5\path \ARM\ARMCLANG\bin\fromelf.exe --bin --output ./APP/LED.bin ./APP/APP.axf
详细说明
D:\software\keil5\path \ARM\ARMCLANG\bin\fromelf.exe
formelf.exe是Keil自带的格式工具软件,其路径在你电脑的Keil安装盘的对应位置;
不要以为这里啥也没有,这里是有一个空格的;
--bin
输出bin文件的命令语句;
空格;
--output
输出文件的命令语句,也可以写成简写的形式:-o;
空格;
./APP/LED.bin
APP是我用于存放输出bin文件的文件夹(系统默认此路径从工程文件开始算起),LED.bin是我生成的bin文件;
空格;
./APP/APP.axf
APP是用于存放axf输入文件的文件夹,生成bin文件前,要先生成axf输入文件;
配置好后点击OK,编译一下工程,bin文件就生成了
添加全局变量 USER_VECT_TAB_ADDRESS
,USER_VECT_TAB_ADDRESS
变量前面有个逗号 英文的
将生成的bin文件放到U盘里
五、实验现象:
BootLoader第一次下载是最好是进行一下全片擦除,之后使用扇区擦除
(1)没有检测到U盘现象
蓝色是电源指示灯,红框才是实验灯(红色的)
串口打印信息
两秒没有检测到U盘打印的信息
没有检测到U盘
(2)检测到U盘现象
红色LED以100ms的时间在闪烁
升级成功现象
串口打印信息
检测到U盘