STM32H743-ARM例程40-U_DISK_IAP

目录

实验平台

硬件:银杏科技GT7000双核心开发板-ARM-STM32H743XIH6,银杏科技iToolXE仿真器

软件:最新版本STM32CubeH7固件库STM32CubeMX v6.10.0,开发板环境MDK v5.35TCP&UDP测试工具,串口工具putty

网盘资料包:链接: https://pan.baidu.com/s/1Y3nwaY4SMxfoUsdqPm2R3w?pwd=inba 提取码: inba

IAP(U盘存储介质)

前面章节我们介绍了IAP相关知识,并且利用UART串口和SD卡传输APP文件,本章我们采用U盘来传输APP文件。

U盘相关知识可以参考文章STM32H743-ARM例程24-USB_MSC

STM32CubeMX生成工程

我们参考前面章节STM32H743-结合CubeMX新建HAL库MDK工程,打开CubeMX软件,重复步骤不再展示,我们来看配置USB部分如下图所示:
配置USB

配置FATFAS

实验代码

本章实验包含两个程序,APP和bootloader,APP程序可以参考STM32H743-ARM例程34-BootROM,把启动地址修改为0x8040000

bootloader程序

1. 主函数

c 复制代码
int main(void)
{
  /* USER CODE BEGIN 1 */
    
  /* Enable the CPU Cache */
    CPU_CACHE_Enable();
  /* USER CODE END 1 */

  /* 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_USART6_UART_Init();
  MX_FATFS_Init();
  MX_USB_HOST_Init();
  /* USER CODE BEGIN 2 */
    uart6.initialize(115200);
    uart6.printf("\x0c");
    uart6.printf("\033[1;32;40m");
    uart6.printf("Hello,I am GT7000!\r\n\r\n"); 
    LED_ON;
  /* USER CODE END 2 */
    if(ARM_KEY4_STATE == KEY_UP){                //按键松开状态直接跳向应用程序
        goto start;
    }
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    MX_USB_HOST_Process();

    /* USER CODE BEGIN 3 */
  }
   start:
    
        if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x24000000){ 
            
            //跳转至用户程序
            JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
            JumpToApplication = (pFunction) JumpAddress;
            
            //初始化用户程序的堆栈指针
            __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
            
            //跳转至应用程序
            JumpToApplication();
        }
        else{               
            led_trade();
        }
  /* USER CODE END 3 */
}

2. USBH_UserProcess 函数

c 复制代码
static void USBH_UserProcess  (USBH_HandleTypeDef *phost, uint8_t id)
{
  /* USER CODE BEGIN CALL_BACK_1 */
    static FRESULT res;
    unsigned char buffer[6144];
    unsigned char * p;
    unsigned long int ncounter = 0;
    unsigned int counter;
    switch(id)
      {
      case HOST_USER_SELECT_CONFIGURATION:
      break;

      case HOST_USER_DISCONNECTION:
      Appli_state = APPLICATION_DISCONNECT;
      break;

      case HOST_USER_CLASS_ACTIVE:
      Appli_state = APPLICATION_READY;
      //f_mount
        res = f_mount(&fatfs,"0:",0);
        
        if(res != RES_OK){
            USBH_UsrLog("\r\nf_mount error!");
            led_trade();
        }else{
            USBH_UsrLog("\r\nf_mount successful!");
        }
        
        res = f_open(&fil,"0:/app.bin",FA_READ);               //打开app.bin文件

        if(res != RES_OK){
            USBH_UsrLog("\r\nf_open error!");
            led_trade();
        }else{
            USBH_UsrLog("\r\nf_open successful!");
        }
        
        //f_lseek
        res = f_lseek(&fil,0);
        if(res != RES_OK){
            USBH_UsrLog("\r\nf_lseek error!");
            led_trade();
        }else{
            USBH_UsrLog("\r\nf_lseek successful!");
        }
        
        //获取文件信息
        f_stat("0:/app.bin",&finfo);
        while(ncounter < finfo.fsize)
        {
            //读取6144Byte数据
            res = f_read(&fil,buffer,6144,&counter);             //读文件
            if(res != RES_OK){
                led_trade();
            }
            //写入EXT FLASH中
            p =(unsigned char*)buffer;  
            USBH_UsrLog("Read APP ...!\r\n");   
            iap_write_appbin(APPLICATION_ADDRESS,p ,6144);
            ncounter = ncounter + 6144;
        }   
        USBH_UsrLog("Load APP finish!\r\n");
      break;

      case HOST_USER_CONNECTION:
      Appli_state = APPLICATION_START;
      break;

      default:
      break;
  }
  /* USER CODE END CALL_BACK_1 */
}

3.flash相关操作函数

c 复制代码
#include "stmflash.h"
#include "uart6.h"
//读取指定地址的字(32位数据) 
//faddr:读地址 
//返回值:对应数据.
uint32_t STMFLASH_ReadWord(uint32_t faddr)
{
	return *(__IO uint32_t *)faddr; 
}

//获取某个地址所在的flash扇区,仅用于BANK1!!
//addr:flash地址
//返回值:0~11,即addr所在的扇区
uint16_t STMFLASH_GetFlashSector(uint32_t addr)
{
	if(addr >= FLASH_BANK2_ADDR) //BANK2
	{
		if(addr<ADDR_FLASH_SECTOR_1_BANK2)return FLASH_SECTOR_0;
		else if(addr<ADDR_FLASH_SECTOR_2_BANK2)return FLASH_SECTOR_1;
		else if(addr<ADDR_FLASH_SECTOR_3_BANK2)return FLASH_SECTOR_2;
		else if(addr<ADDR_FLASH_SECTOR_4_BANK2)return FLASH_SECTOR_3;
		else if(addr<ADDR_FLASH_SECTOR_5_BANK2)return FLASH_SECTOR_4;
		else if(addr<ADDR_FLASH_SECTOR_6_BANK2)return FLASH_SECTOR_5;
		else if(addr<ADDR_FLASH_SECTOR_7_BANK2)return FLASH_SECTOR_6;
	}
	else	//BANK1
	{	
		if(addr<ADDR_FLASH_SECTOR_1_BANK1)return FLASH_SECTOR_0;
		else if(addr<ADDR_FLASH_SECTOR_2_BANK1)return FLASH_SECTOR_1;
		else if(addr<ADDR_FLASH_SECTOR_3_BANK1)return FLASH_SECTOR_2;
		else if(addr<ADDR_FLASH_SECTOR_4_BANK1)return FLASH_SECTOR_3;
		else if(addr<ADDR_FLASH_SECTOR_5_BANK1)return FLASH_SECTOR_4;
		else if(addr<ADDR_FLASH_SECTOR_6_BANK1)return FLASH_SECTOR_5;
		else if(addr<ADDR_FLASH_SECTOR_7_BANK1)return FLASH_SECTOR_6;

	}
	return FLASH_SECTOR_7;	

}

//从指定地址开始写入指定长度的数据
//特别注意:因为STM32H7的扇区实在太大,没办法本地保存扇区数据,所以本函数
//         写地址如果非0XFF,那么会先擦除整个扇区且不保存扇区数据.所以
//         写非0XFF的地址,将导致整个扇区数据丢失.建议写之前确保扇区里
//         没有重要数据,最好是整个扇区先擦除了,然后慢慢往后写. 
//该函数对OTP区域也有效!可以用来写OTP区!
//OTP区域地址范围:0X1FF0F000~0X1FF0F41F
//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;	
	uint32_t bankFlag = 1;
    if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)return;	//非法地址
//	bankFlag = WriteAddr >= FLASH_BANK2_ADDR ? FLASH_BANK_2:FLASH_BANK_1;
	
 	HAL_FLASH_Unlock();             //解锁	
	addrx=WriteAddr;				//写入的起始地址
	endaddr=WriteAddr+NumToWrite*4;	//写入的结束地址
    
    if(addrx<0X1FF00000)
    {
        while(addrx<endaddr)		//扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
		{
			if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)//有非0XFFFFFFFF的地方,要擦除这个扇区
			{   
				FlashEraseInit.Banks=bankFlag;							//操作BANK1或者2
                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) 
                {
					uart6.printf("flash set operation err...\r\n");
                    break;//发生错误了	
                }
                SCB_CleanInvalidateDCache();                            //清除无效的D-Cache
			}else addrx+=4;
            FLASH_WaitForLastOperation(FLASH_WAITETIME,bankFlag);    //等待上次操作完成
        }
    }
    FlashStatus=FLASH_WaitForLastOperation(FLASH_WAITETIME,bankFlag);       //等待上次操作完成
	if(FlashStatus==HAL_OK)
	{
		while(WriteAddr<endaddr)//写数据
		{
            if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD,WriteAddr,(uint64_t)pBuffer)!=HAL_OK)//写入数据
			{ 
				uart6.printf("flash write operation err...\r\n");
				break;	//写入异常
			}
			WriteAddr+=32;
			pBuffer+=8;
			
		}
	}
	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个字节.	
	}
}


#define FLASH_SECTOR	256*128   //256*4 就是1KB,*128就是128K
uint32_t iapbuf[FLASH_SECTOR]; 	//1K*128字节缓存 
uint8_t binBuf[1024*200];
//appxaddr:应用程序的起始地址
//appbuf:应用程序CODE.
//appsize:应用程序大小(字节).
void iap_write_appbin(uint32_t appxaddr,uint8_t *appbuf,uint32_t appsize)
{
	uint32_t t;
	uint16_t i=0;
	uint32_t temp;
	uint32_t fwaddr=appxaddr;//当前写入的地址
	uint8_t *dfu=appbuf;
	for(t=0;t<appsize;t+=4)
	{						   
		temp=(uint32_t)dfu[3]<<24;   
		temp|=(uint32_t)dfu[2]<<16;    
		temp|=(uint32_t)dfu[1]<<8;
		temp|=(uint32_t)dfu[0];	  
		dfu+=4;//偏移4个字节
		iapbuf[i++]=temp;	    
		if(i==FLASH_SECTOR)
		{
			i=0; 
			STMFLASH_Write(fwaddr,iapbuf,FLASH_SECTOR);
			fwaddr+=FLASH_SECTOR*4;//偏移2048  512*4=2048
						
		}
	} 
	if(i){
		STMFLASH_Write(fwaddr,iapbuf,i);//将最后的一些内容字节写进去.  
	}
	
}

实验现象

我们将app.bin 文件拷贝到U盘中,运行程序,按下 ARM-KEY 将烧写 Bootloader(IAP)程序烧写程序到GT7000上,通过读取U盘中的app.bin文件,重新上电 ARM-LED 灯闪烁,即 ARM 更新升级成功。

注:GT7000上需要用tpye-c转接器连接U盘和USB-Hs接口。

相关推荐
No0d1es2 小时前
电子学会青少年软件编程(C/C++)1级等级考试真题试卷(2025年9月)
java·c语言·c++·青少年编程·电子学会·真题·一级
小龙报3 小时前
《算法通关指南数据结构和算法篇(4)--- 队列和queue》
c语言·开发语言·数据结构·c++·创业创新·学习方法·visual studio
hazy1k4 小时前
51单片机基础-GPIO结构详解
stm32·单片机·嵌入式硬件·51单片机
集和诚JHCTECH4 小时前
专为严苛环境而生:高防护等级工业防水平板WPPC-H1520T(P)
人工智能·嵌入式硬件·平板
m0_748248024 小时前
C++与C#布尔类型深度解析:从语言设计到跨平台互操作
c++·stm32·c#
云山工作室4 小时前
基于协同过滤算法的话剧购票系统(论文+源码)
单片机·物联网·毕业设计·课程设计·毕设
辰哥单片机设计6 小时前
STM32项目分享:智能水产养殖系统
stm32·单片机·嵌入式硬件
一枝小雨6 小时前
【OTA专题】2 初级bootloader架构和基础工程移植
stm32·单片机·嵌入式·ota·bootloader·固件升级·加密升级
序属秋秋秋6 小时前
《Linux系统编程之开发工具》【实战:倒计时 + 进度条】
linux·运维·服务器·c语言·c++·ubuntu·系统编程