STM32H7使用外部flash运行程序 您所在的位置:网站首页 flash内存 STM32H7使用外部flash运行程序

STM32H7使用外部flash运行程序

2023-03-15 03:36| 来源: 网络整理| 查看: 265

STM32H7使用外部flash运行程序

在淘宝上买了一块核心板,使用的STM32H7B0VBT6。 客服很尽责,帮助了我很多。 H7系列的功能很强大,但是H7B0他有个问题,只有128k的内部flash,这么强大的芯片只有这么小的flash,想搞个RTTreadOS都不行。无奈,智能选择使用外部flash,好在核心板上有两个W25Q64,一个SPI,一个QSPI足够我们使用的。

思路

使用SPI总线的Flash模拟成U盘,然后把app的bin文件拷到模拟u盘中,通过SPI去读取SPI内保存的bin文件数据,然后写入缓存中,QSPI读取缓存数据到QSPI中,最后执行跳转程序,运行app。

细节

1,使用stm32cubemx创建一个usb模板 2,编写SPI,W25Q64驱动

void MX_SPI6_Init(void) { hspi6.Instance = SPI6; // 使用SPI6 hspi6.Init.Mode = SPI_MODE_MASTER; // 主机模式 hspi6.Init.Direction = SPI_DIRECTION_2LINES; // 双线全双工 hspi6.Init.DataSize = SPI_DATASIZE_8BIT; // 8位数据宽度 hspi6.Init.CLKPolarity = SPI_POLARITY_LOW; // CLK空闲时保持低电平 hspi6.Init.CLKPhase = SPI_PHASE_1EDGE; // 数据在CLK第一个边沿有效 hspi6.Init.NSS = SPI_NSS_HARD_OUTPUT; // 使用硬件片选 // 这里将 pll2_q_ck 设置为 100M 作为 SPI6 的内核时钟,然后再经过2分频得到 50M 的SCK驱动时钟 hspi6.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; hspi6.Init.FirstBit = SPI_FIRSTBIT_MSB; // 高位在先 hspi6.Init.TIMode = SPI_TIMODE_DISABLE; // 禁止TI模式 hspi6.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; // 禁止CRC hspi6.Init.CRCPolynomial = 0x0; // CRC校验项,这里用不到 hspi6.Init.NSSPMode = SPI_NSS_PULSE_DISABLE; // 不使用片选脉冲模式 hspi6.Init.NSSPolarity = SPI_NSS_POLARITY_LOW; // 片选低电平有效 hspi6.Init.FifoThreshold = SPI_FIFO_THRESHOLD_02DATA; // FIFO阈值 hspi6.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN; // 发送端CRC初始化模式,这里用不到 hspi6.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN; // 接收端CRC初始化模式,这里用不到 hspi6.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE; // 额外延迟周期为0 hspi6.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE; // 主机模式下,两个数据帧之间的延迟周期 hspi6.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE; // 禁止自动接收管理 hspi6.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; // 主机模式下,SPI当前引脚状态 hspi6.Init.IOSwap = SPI_IO_SWAP_DISABLE; // 不交换MOSI和MISO HAL_SPI_Init(&hspi6); }

3,编写QSPI,W25Q64驱动

void MX_OCTOSPI1_Init(void) { OSPIM_CfgTypeDef sOspiManagerCfg = {0}; HAL_OSPI_DeInit(&hospi1); // 复位OSPI hospi1.Instance = OCTOSPI1; // OSPI外设 hospi1.Init.ClockPrescaler = 2; // 时钟分频值,将OSPI内核时钟进行 2 分频得到OSPI通信驱动时钟 hospi1.Init.FifoThreshold = 8; // FIFO阈值 hospi1.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE; // 禁止双OSPI模式 hospi1.Init.MemoryType = HAL_OSPI_MEMTYPE_MICRON; // 存储器模式,只有8线模式才会用到 hospi1.Init.DeviceSize = 23; // flash大小,核心板采用是8M字节的W25Q64,这里设置为23,即2^23 hospi1.Init.ChipSelectHighTime = 1; // 片选保持高电平的时间 hospi1.Init.FreeRunningClock = HAL_OSPI_FREERUNCLK_DISABLE; // 禁止自由时钟模式 hospi1.Init.ClockMode = HAL_OSPI_CLOCK_MODE_3; // 模式3 hospi1.Init.WrapSize = HAL_OSPI_WRAP_NOT_SUPPORTED; // 不使用 wrap-size hospi1.Init.SampleShifting = HAL_OSPI_SAMPLE_SHIFTING_HALFCYCLE; // 半个CLK周期之后进行采样 hospi1.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_DISABLE; // 不使用数据保持功能 hospi1.Init.ChipSelectBoundary = 0; // 禁止片选边界功能 hospi1.Init.ClkChipSelectHighTime = 0; // 通信结束后 0 个CLK周期CS设置为高 hospi1.Init.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_BYPASSED; // 延时模块旁路 hospi1.Init.MaxTran = 0; // 禁止通信管理功能 hospi1.Init.Refresh = 0; // 禁止刷新功能 HAL_OSPI_Init(&hospi1); // 初始化 OSPI1 设置 sOspiManagerCfg.ClkPort = 1; // OSPI引脚分配管理器设置,使用 Port1 的 CLK sOspiManagerCfg.NCSPort = 1; // OSPI引脚分配管理器设置,使用 Port1 的 NCS sOspiManagerCfg.IOLowPort = HAL_OSPIM_IOPORT_1_LOW; // OSPI引脚分配管理器设置,使用 Port1 的低4位引脚,IO[3:0] HAL_OSPIM_Config(&hospi1, &sOspiManagerCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE); // 初始化OSPI引脚分配管理器设置 }

4,主函数中初始化

int main(void) { SCB_EnableICache(); // 使能ICache SCB_EnableDCache(); // 使能DCache HAL_Init(); // 初始化HAL库 SystemClock_Config(); // 配置系统时钟,主频280MHz LED_Init(); // 初始化LED引脚 KEY_Init(); // 初始化按键引脚 USART1_Init(); // USART1初始化 MX_USB_DEVICE_Init(); // 初始化USB设备,识别SPIU盘 SPI_W25Qxx_Init(); //初始化SPI OSPI_W25Qxx_Init(); // 初始化OSPI和W25Q64 Main_Menu(); //程序更新引导代码 while (1) { LED1_Toggle; HAL_Delay(100); } }

5,进入到Main_Menu(); 这个程序更新函数中后会进行选择

void Main_Menu(void) { uint8_t key = 0; uint8_t quit= 0 ; // uint8_t download_flag=0; printf("\r\n======================================================================"); printf("\r\n= (C) COPYRIGHT 2023 STMicroelectronics ="); printf("\r\n= ="); printf("\r\n= STM32H7xx In-Application Programming Application (Version 1.0.0) ="); printf("\r\n= ="); printf("\r\n= By GXY Application Team ="); printf("\r\n======================================================================"); printf("\r\n\r\n"); while (1) { printf("\r\n==================================="); printf("\r\n= 输入序号选择命令 ="); printf("\r\n= (1)SPI模拟U盘方式更新 ="); printf("\r\n= (2)SD卡方式更新 ="); printf("\r\n= (3)执行跳转 ="); printf("\r\n= (4)退出更新 ="); printf("\r\n==================================="); printf("\r\n\r\n"); /* Clean the input path */ __HAL_UART_FLUSH_DRREGISTER(&huart1); __HAL_UART_CLEAR_PEFLAG(&huart1); __HAL_UART_CLEAR_FEFLAG(&huart1); __HAL_UART_CLEAR_NEFLAG(&huart1); __HAL_UART_CLEAR_OREFLAG(&huart1); key=0; /* Receive key */ HAL_UART_Receive(&huart1, &key, 1, RX_TIMEOUT); switch (key) { case '1' : /* Download user application in the Flash */ printf ("正在更新...\r\n"); if(SpiDownload()) { printf ("更新完成,请执行跳转\r\n"); // 初始化成功 } else printf ("重新上电更新\r\n"); break; case '2' : printf ("此功能未开发,等待后续开发......\r\n"); // 初始化成功 break; case '3' : OSPI_W25Qxx_MemoryMappedMode(); // 配置QSPI为内存映射模式 SCB_DisableICache(); // 关闭ICache SCB_DisableDCache(); // 关闭Dcache SysTick->CTRL = 0; // 关闭SysTick SysTick->LOAD = 0; // 清零重载值 SysTick->VAL = 0; // 清零计数值 printf ("跳转地址设置\r\n"); JumpToApplication = (pFunction) (*(__IO uint32_t*) (W25Qxx_Mem_Addr + 4)); // 设置起始地址 __set_MSP(*(__IO uint32_t*) W25Qxx_Mem_Addr); // 设置主堆栈指针 printf("跳转到W25Q64运行用户程序>>>\r\n\r\n"); JumpToApplication(); // 执行跳转 break; case '4' : quit =1; break; default: printf("选择输入 1,2,3,4控制更新方式\r"); break; } if(quit) break; } }

6,使用串口助手输入1,进入spi模拟u盘方式更新

uint8_t SpiDownload(void) { int i; if(OSPI_W25Qxx_BlockErase_1024K(W25Qxx_TestAddr)==OSPI_W25Qxx_OK) { // printf ("擦除FLASH完成\r\n"); // 初始化成功 for(i=0;i printf ("更新进度:%d%%\r\n",i*100/31); // 初始化成功 } else { printf ("写入失败"); // 初始化成功 return 0; } } } return 1; }

7,串口打印数据

[17:41:36.483]发→◇1 □ [17:41:36.487]收←◆正在更新... [17:41:40.756]收←◆更新进度:0% [17:41:40.815]收←◆更新进度:3% 更新进度:6% 更新进度:9% 更新进度:12% [17:41:40.908]收←◆更新进度:16% 更新进度:19% [17:41:40.950]收←◆更新进度:22% 更新进度:25% 更新进度:29% 更新进度:32% 更新进度:35% [17:41:41.064]收←◆更新进度:38% 更新进度:41% 更新进度:45% 更新进度:48% [17:41:41.153]收←◆更新进度:51% 更新进度:54% 更新进度:58% 更新进度:61% 更新进度:64% 更新进度:67% 更新进度:70% [17:41:41.311]收←◆更新进度:74% 更新进度:77% 更新进度:80% 更新进度:83% 更新进度:87% [17:41:41.424]收←◆更新进度:90% 更新进度:93% [17:41:41.469]收←◆更新进度:96% 更新进度:100% 更新完成,请执行跳转

8,使用串口助手发送3,进行程序跳转

[17:42:06.050]发→◇3 □ [17:42:06.053]收←◆跳转地址设置 跳转到W25Q64运行用户程序>>> 程序运行中... [17:42:07.059]收←◆程序运行中... [17:42:08.060]收←◆程序运行中... [17:42:09.062]收←◆程序运行中... [17:42:10.063]收←◆程序运行中... [17:42:11.066]收←◆程序运行中... [17:42:12.067]收←◆程序运行中... [17:42:13.070]收←◆程序运行中.. 至此大功告成,整个工程都是例子程序改的,所以只是列出代表性的代码,大家可以下载工程代码参考,方便更新自己的程序。如有错误,多多指教。

核心板链接:https://item.taobao.com/item.htm?spm=a1z10.5-c-s.w4002-17800249301.10.75712bd3PuFnlt&id=658976139303 创建u盘模板工程参考链接:https://zhuanlan.zhihu.com/p/542651742 模拟U盘更新程序参考链接:https://blog.csdn.net/qq_44810226/article/details/127508789 整个工程代码:https://download.csdn.net/download/qq_43296570/87459589



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有