STM32H7使用外部flash运行程序

这篇具有很好参考价值的文章主要介绍了STM32H7使用外部flash运行程序。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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<32;i++)
				{
					SPI_W25Qxx_ReadBuffer(W25Qxx_ReadBuffer,USB_FAT_Addr+W25Qxx_NumByteToTest*i,W25Qxx_NumByteToTest); // 读取数据
//					printf ("读取u盘数据进度:%d%%\r\n",i*100/31);		// 初始化成功
					
					if(OSPI_W25Qxx_OK==OSPI_W25Qxx_WriteBuffer(W25Qxx_ReadBuffer,W25Qxx_TestAddr+W25Qxx_NumByteToTest*i,W25Qxx_NumByteToTest))// 写入数据
					{
					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文章来源地址https://www.toymoban.com/news/detail-417138.html

到了这里,关于STM32H7使用外部flash运行程序的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32 CubeMX 无法将 STM32H7 的最大 CPU 频率设置为 480 MHz

    使用stm32cubemx设置时钟树为480MHz时,提示 cpu clock frequency must be =200MHZ 对于STM32H7 需要CPU修订版 为 V 才能达到 480 MHz 的最大频率。 使用STM32Programmer查看芯片修订版,确认是V版本: 在STM32CubeMX PinConfiguration 界面修改RCC选项,将Product Version设置为V: 此时时钟树界面已可以设置48

    2024年02月16日
    浏览(50)
  • STM32H7 SDMMC+FATFS+USBMSC+FREERTOS 虚拟U盘

    通过cubemx配置 实现STM32H7 SDMMC+FATFS+USBMSC+FREERTOS 虚拟U盘 1.使用FAFTS文件操作系统,实现STM32虚拟U盘,读写外部SD卡,fatfs和usb mass storage class共存。 2.请先完成上一个帖子的步骤 -- 跳转https://blog.csdn.net/hjn0618/article/details/130383593 硬件平台:正点原子阿波罗 STM32H734IIT6 开发工具:

    2024年02月10日
    浏览(40)
  • cubmx基础操作,hal库基本配置流程之使用 stm32cubmx生成HAL库进行gpio点亮led(stm32h7xx)(超详细,小白教程)

    HAL库(硬件抽象层库)是一个提供对底层硬件操作的抽象的库,它使得开发者可以使用统一的接口进行硬件操作,而不必关心底层硬件的具体实现细节。HAL库通常由硬件厂商提供,用于支持其硬件设备,并为其提供标准化的接口。 HAL库的主要目的是简化底层硬件的操作,使得

    2024年02月20日
    浏览(58)
  • STM32H7并行读取AD7606数据以及片内AD值不准解决办法

    先了解一下AD7606,16位,单电源,200k采样率,8路,除了贵没有其他缺点,数据相当的稳,一个5V供电,不用运放的情况下采集电压精度可以达到1mv,非常Nice 与单片机相连 单片机 调用代码 测试发现AD采集到的电压要远小于实际电压,H7的AD还是16位的,不能这么拉跨吧,在网上

    2024年02月11日
    浏览(49)
  • 【STM32H7 开发笔记】| 02 - 通过定时器级联方式同步启动多个定时器并输出 PWM 波形

    (STM32H723xE/G) 所有定时器包括 两个高级控制定时器、十二个通用定时器、两个基本定时器、五个低功耗定时器、两个看门狗定时器和一个SysTick定时器 。所有计时器计数器都可以在Debug模式下冻结。 本次实验主频配置的是500MHz 高级控制定时器(TIM1,TIM8)可以看作是在6通道

    2024年02月14日
    浏览(44)
  • stm32使用外部flash w25Q128实现读写操作

    数据保存是所有项目的基本功能,但是对于STM32C8T6的原flash进行操作,一方面大小有可能不够,另一方面单片机的运行程序本来就放在这个里面,所以还是外接的好。这里选用w25Q128 FLASH存储器,参考实现简单读写。 作为一个初学者,技能都是东拼西凑的,基础可能不扎实,如

    2023年04月08日
    浏览(52)
  • STM32CubeMX学习笔记(48)——USB接口使用(MSC基于外部Flash模拟U盘)

    USB(Universal Serial BUS)通用串行总线 ,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯。是应用在 PC 领域的接口技术。USB 接口支持设备的即插即用和热插拔功能。USB 是在 1994 年底由英特尔、康柏、IBM、Microsoft 等多家公司联合提出的。 USB 发展到现在已经有 US

    2024年01月16日
    浏览(50)
  • STM32使用QUADSPI读写外部Nor Flash(以W25Q64为例)

    QUADSPI 是一种专用的通信接口,连接单、双或四(条数据线) SPI Flash 存储介质。该接 口可以在以下三种模式下工作: ①间接模式:使用 QUADSPI 寄存器执行全部操作。 ②状态轮询模式:周期性读取外部 Flash 状态寄存器,而且标志位置 1 时会产生中断(如擦除或烧写完成,会

    2024年02月11日
    浏览(48)
  • stm32基于HAL库驱动外部SPI flash制作虚拟U盘

    📌参考文章: https://xiaozhuanlan.com/topic/6058234791 🎞实现效果演示: 🔖上图中的读到的 FLASH_ID 所指的是针对不同容量,所对应的ID。 🔖在电脑端,支持对虚拟出来的存储器进行读写操作。 ✨如果设计成一块PCB,可以制作成一个微小容量的移动U盘。 🌿基于STM32F103,HAL库生成

    2024年02月11日
    浏览(49)
  • 使用STM32 ST-LINK Utility 烧录程序,ST LINK烧录程序,解锁FLASH

    :ST LINK烧录程序,STLINK烧录程序,ST-LINK烧录程序,STLINK烧录程序,ST LINK解锁Flash ST-LINK Utility下载:文末附带下载地址,免费下载、免积分下载。 使用 ST-Link 连接 STM32芯片,打开STM32 ST-LINK Utility 软件, 连接芯片:Tarage  - connec t或直接点击连接快捷按钮(如下图)。

    2024年02月04日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包