STM32(H7)学习记录-11 bootloader+app使用cubeMX配置

cubemx版本6.11.1。基于U盘的bootloader

目录

一、bootloader

二、app


一、bootloader

        使用cubeMX配置(这里就不描述MPU,时钟等配置了)主要是配置USBH_MSC并使用FatFs作为文件管理系统。

并且配置了硬件CRC校验

然后进入MDK中,其中g_JumpInit变量,包括跳转函数是参考安富莱 的程序的,请参考实战技能分享,一劳永逸的解决BOOT跳转APP失败问题,含MDK AC5,AC6和IAR_哔哩哔哩_bilibili

int main(void)
{

  /* USER CODE BEGIN 1 */
if (g_JumpInit == 0xAA553344)	        /* 软件复位后再进入APP,提供一个干净的CPU环境给APP */
	{	
		JumpToApp();	                    /* 去执行APP程序 */
	}
		else
	{
		/* 用户可以自己加处理 */
	}
  /* USER CODE END 1 */

  /* MPU Configuration--------------------------------------------------------*/
  MPU_Config();

  /* Enable the CPU Cache */

  /* Enable I-Cache---------------------------------------------------------*/
  SCB_EnableICache();

  /* Enable D-Cache---------------------------------------------------------*/
  SCB_EnableDCache();

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART2_UART_Init();
  MX_FATFS_Init();
  MX_CRC_Init();
  MX_USB_HOST_Init();
  MX_TIM4_Init();
  /* USER CODE BEGIN 2 */
    bsp_InitTimer();
    bootloader_event();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    MX_USB_HOST_Process();

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

主要是增加了bsp_InitTimer() 这个函数是软件定时器初始化,方便后面做计时。

bootloader_event()是主要的函数,下面的循环while(1)执行不到。

void bootloader_event(void)
{
	printf("\nUSB enum...\n");
	bsp_StartTimer(0,4000);
	while(1)
	{
		MX_USB_HOST_Process();
		if(Appli_state == APPLICATION_READY) break;
		if(bsp_CheckTimer(0) == 1)
		{
			printf("U disk not attached");
			g_JumpInit = 0xAA553344;
			NVIC_SystemReset();	/* 复位CPU */
		}
	}
	printf("USB enum success!\n");
	
	while(1)
	{
			LoadFirmware();
			BootHexCrcVeriy();
			g_JumpInit = 0xAA553344;//此处请参考安富莱,一劳永逸bootloader跳转
			NVIC_SystemReset();	/* 复位CPU */
	}
}

bootloader_event()这个函数首先是进行usb的背景任务,如果经过4秒也没用u盘设备连接,就跳出bootloader进入app。连接之后,首先加载固件函数LoadFirmware();

static void LoadFirmware(void)
{
	FRESULT result;
	float FinishPecent;
	uint32_t bw;
//	char filepath[64];
	uint32_t SectorCount = 0;
	uint32_t SectorRemain = 0;
	
	uint32_t i = 0;
	uint8_t ucState;
    uint32_t Count = 0;
    uint32_t TotalSize = 0;
	uint32_t ver;
	
	
	/* 第1步:挂载文件系统 ***************************************************************/
	result = f_mount(&fl, path, 1);		
	if (result != FR_OK)
	{
		printf("mount fail! res: %d\n", result);
	}

	/* 第2步:打开文件 ***************************************************************/
//	sprintf(filepath, "%sapp.bin", path);
	result = f_open(&fsrc, filepath, FA_OPEN_EXISTING | FA_READ);
	if (result !=  FR_OK)
	{
		printf("Don't Find File : CL_firmware.bin\r\n");
		g_JumpInit = 0xAA553344;
		NVIC_SystemReset();	/* 复位CPU */
		return;
	}
	
	/* 第2步:获取文件大小和APP固件版本 ***********************************************/
	f_stat(filepath, &fno);

	/* 打印文件大小, 最大4G */
	printf("APP Size: %d\r\n", (int)fno.fsize);
	
	uwAppSize = fno.fsize;
	
	/* 读取固件大小 */
	f_lseek(&fsrc, 28);
	f_read(&fsrc, &ver, sizeof(ver), &bw);
	f_lseek(&fsrc, 0);
	printf("APP firmware version:V%X.%02X\r\n", ver >> 8, ver & 0xFF);
	
	/* 第4步:扇区擦除 **************************************************************/
	SectorCount = fno.fsize/(128*1024);
	SectorRemain = fno.fsize%(128*1024);	
	
	for(i = 0; i < SectorCount; i++)
	{
		//printf("go to clear sector = %08x\r\n", AppAddr + i*128*1024);
		bsp_EraseCpuFlash((uint32_t)(AppAddr + i*128*1024));
	}
	
	if(SectorRemain)
	{
		printf("App address = %08x\r\n", AppAddr + i*128*1024);
		bsp_EraseCpuFlash((uint32_t)(AppAddr + i*128*1024));
	}
	
	/* 第5步:将APP固件写入到内部Flash ********************************************/
	for(;;)
	{
		/* 读取一个扇区的数据到buf */
		result = f_read(&fsrc, &tempbuf, sizeof(tempbuf), &bw);
		
		/* 读取出错或者读取完毕,退出 */
		if ((result != FR_OK)||bw == 0)
		{
			printf("APP load firmware done\r\n");
			printf("=================================================\r\n");
			break;
		}
		
		/* 编程内部Flash */
		TotalSize += bw;
		ucState = bsp_WriteCpuFlash((uint32_t)(AppAddr + Count*sizeof(tempbuf)),  (uint8_t *)tempbuf, bw);
		
		/* 如果返回非0,表示编程失败 */
		if(ucState != 0)
		{
			printf("clear fail\r\n");
			break;
		}
		
		/* 显示复制进度 */
		Count = Count + 1;
		FinishPecent = (float)(TotalSize) / fno.fsize;
		printf("programing: %02d%%\r\n", (uint8_t)(FinishPecent*100));
	}
	/* 关闭文件*/
	f_close(&fsrc);

	/* 卸载文件系统 */
	f_mount(NULL, path, 1);

}

这里几个变量path 以及filepath是我在文件中定义好的全局变量,因为一般对于升级文件都是固定的名字比如,“0:/app.bin”。此处AppAddr是根据自己情况来,比如app开始地址是0x0804 0000,那么AppAddr就是这个值(此时偏移量就是0x0004 0000,这个值需要记住,后面还要用)。

再是校验函数BootHexCrcVeriy()

static void BootHexCrcVeriy(void)
{
	
	/* 读取bin文件的CRC */
	uwExpectedCRCValue  = *(__IO uint32_t *)(AppAddr + uwAppSize - 4);
	
	/* 计算是否与硬件CRC一致 */
	uwCRCValue = HAL_CRC_Calculate(&hcrc, (uint32_t *)(AppAddr), uwAppSize/4 - 1);
	
	printf("Actual firmware crc = 0x%x\r\n", uwExpectedCRCValue);
	printf("Calculated firmware crc = 0x%x\r\n", uwCRCValue);	
	
	if (uwCRCValue != uwExpectedCRCValue)
	{
		printf("Crc fail!\r\n");
		uint32_t SectorCount = 0;
		uint32_t SectorRemain = 0;
		SectorCount = fno.fsize/(128*1024);
		SectorRemain = fno.fsize%(128*1024);	
		int i;
		for(i = 0; i < SectorCount; i++)
		{
			//printf("go to clear sector = %08x\r\n", AppAddr + i*128*1024);
			bsp_EraseCpuFlash((uint32_t)(AppAddr + i*128*1024));
		}
		
		if(SectorRemain)
		{
			printf("App address = %08x\r\n", AppAddr + i*128*1024);
			bsp_EraseCpuFlash((uint32_t)(AppAddr + i*128*1024));
		}
		Error_Handler();		
	}
	else
	{
		FRESULT res;
		res = f_mount(&fl, path, 1);		
		if (res != FR_OK)
		{
			printf("mount fail! res: %d\n", res);
		}
		else
		{
			printf("jump to APP\r\n");
			res = f_rename(filepath,newname);
			printf("result : %d",res);
			/* 卸载文件系统 */
			f_mount(NULL, path, 1);
		}
	}
		
	printf("=================================================\r\n");
	
}

这里如果校验不通过重新擦写flash(其实这么做有点蠢。)。如果校验通过会更改文件名。

FatFs中,如果要更改文件名,该文件不可处于打开状态!

最后进行软件复位,在跳转到app。

二、app

        在已有的app程序上,

在system_stm32h7xx.c中

#define USER_VECT_TAB_ADDRESS加入这句话。

将VECT_TAB_OFFSET设置为0x0004 0000。

如果自己写了分散加载文件

就设置成这样

如果不想自己修改分散文件,就修改target这边

关于app怎么生成bin文件请参考安富莱的视频教程

BSP视频教程第18期:基于NAND,eMMC,SD卡和U盘的BootLoader实战,带CRC完整性校验_哔哩哔哩_bilibili

到这基本上就结束了。

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
USB host FATFS是指在STM32系列芯片上,通过USB主机模式使用FATFS文件系统的一种应用。引用中提到了关于在STM32F407VG芯片上使用Legacy library USB驱动的说明。在该驱动中,可以实现USB Host(全速)MSC(Mass Storage Class)和FATFS的移植。引用中提到了使用Legacy library USB库和Fatfs驱动的版本信息和一些相关的官方文档链接。引用中提到了USB OTG低级驱动程序的usb_bsp.h文件中声明的函数的实现,这些函数包括初始化GPIO、延时方法和中断启用/禁用等。引用中提到了USB库的usbh_usr.h文件中声明的处理来自用户层的库事件的函数实现,这些函数包括设备连接和断开、设备速度检测、设备描述信息获取、用户输入等。所以,USB MSC host FATFS是通过使用Legacy library USB驱动和Fatfs驱动,在STM32芯片上实现USB主机模式下使用FATFS文件系统的一种应用。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span> #### 引用[.reference_title] - *1* *2* *3* *4* [STM32 之四 标准外设版 USB 驱动 + MSC(Host) + Fatfs R0.13 移植](https://blog.csdn.net/ba_wang_mao/article/details/110402069)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值