HAL STM32H750驱动W25Qxx移植参考说明

HAL STM32H750驱动W25Qxx移植参考说明


  • STM32H7有关SPI外设介绍文章内容《STM32H7的SPI总线基础知识和HAL库API
  • 📑基于安富莱BSP驱动移植,将W25Q64挂载到STM32H750的SPI2上,板子采用自制的。
  • 🔖驱动Nor flash型号:GD25q64/W25Q64(两者在SPI驱动模式下,几乎通用)
  • 🎉BSP驱动包资料:
https://pan.baidu.com/s/1Lum1i0K157Dv3z9annKiYw 
提取码:0eqi

移植到个人自制板子上使用,相比于使用QSPI方式,在使用spi方式驱动时,使用硬件SPI +DMA遇到了一些问题,一直没有解决。使用SPI查询方式和中断方式测试没有问题。

⏰时钟配置

  • STM32H7的SPI支持4到32bit数据传输,而STM32F1和F4系列仅支持8bit或者16bit。
    STM32H7的主频400MHz时,SPI1, 2, 3最高通信时钟是100MHz,而SPI4, 5, 6是50MHz
  • 🌿以 SPI2为例,SPI时钟源选择:(可以来源于4个地方)
    在这里插入图片描述

  • 🌿个人硬件实际测试,只能设置到3.15MHz,这个可能和硬件SPI实际走线有关(双层板,走的线比较长)。再高不是不能运行,只是在读取大量数据做测试时,发现,前面一段的数据总会有错误。在主频时钟400MHz情况下,SPI2时钟源:200MHz,PLLQ,经过64分频得到。(这个速度不代表SPI理论的最高速度)

  • 🍁个人使用SPI2连接的W25Q64,接线方式:
    在这里插入图片描述
    在这里插入图片描述

  • 🌼测试效果:
    在这里插入图片描述

在这里插入图片描述

📒STM32H750 SPI 接口的区别和时钟源(SPI1 到 SPI6)

  • 🔰SPI1 到 SPI6 的区别
    • SPI1,SPI2 和 SPI3 支持 4 到 32bit 数据传输,SPI4,SPI5 和 SPI6 是 4 到 16bit 数据传输。
    • SPI1,SPI2 和 SPI3 的 FIFO 大小是 16x8bit,而 SPI4,SPI5 和 SPI6 的 FIFO 大小是 8x8bit。
      在这里插入图片描述

🔖使用SPI4,SPI5,那么最大值就是8字节,这点要特别注意,然后配置如下两个参数时:

hspi5.Init.DataSize = SPI_DATASIZE_16BIT;
hspi5.Init.FifoThreshold = SPI_FIFO_THRESHOLD_04DATA;

16bit配4个FIFO,正好是8字节,

  • fifo配置参考说明:https://www.armbbs.cn/forum.php?mod=viewthread&tid=102944&highlight=SPI%2BDMA
  • 🌿SPI1 到 SPI6 的所在的总线(对应 SPI 框图的 SPI_CLK 时钟域)
    SPI1,SPI4 和 SPI5 在 APB2 总线,SPI2,SPI3 在 APB1 总线,SPI6 在 APB4 总线。注意,SPI 的最高时钟不是由这些总线决定的。
  • 🌿SPI1 到 SPI6 的支持的最高时钟(对应 SPI 框图的 SPI_KER_CK)
    STM32H7 主频在 400MHz 下,SPI1,SPI2 和 SPI3 的最高时钟是 200MHz,而 SPI4,5,6 是 100MHz, 以 SPI1 为例,可以选择的时钟源如下:
    在这里插入图片描述
  • ✨这里特别注意一点,SPI 工作时最少选择二分频,也就是说 SPI1,2,3 实际通信时钟是 100MHz,而 SPI4,5,6是 50MHz。

📒移植方法

  • 🌿通过STM32CubeMX创建自己的工程,选择对应的SPI组。

在这里插入图片描述

  • 📑生成的代码配置信息参考:
void MX_SPI2_Init(void)
{

  /* USER CODE BEGIN SPI2_Init 0 */

  /* USER CODE END SPI2_Init 0 */

  /* USER CODE BEGIN SPI2_Init 1 */

  /* USER CODE END SPI2_Init 1 */
  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_MASTER;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi2.Init.NSS = SPI_NSS_SOFT;
  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 0x0;
  hspi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  hspi2.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
  hspi2.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
  hspi2.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  hspi2.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  hspi2.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
  hspi2.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
  hspi2.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
  hspi2.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
  hspi2.Init.IOSwap = SPI_IO_SWAP_DISABLE;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI2_Init 2 */

  /* USER CODE END SPI2_Init 2 */

}
  • 🌿如果SPI使用DMA或中断方式,,那么取消勾选生成中断函数:
    在这里插入图片描述

在原工程中已经包含中断相关函数定义。

  • 个人在配置使用中,需要调整相关SPIx引脚宏以及DMA通道的地方。(选择不同的SPI线路DMA通道不同)
/* 串行Flash的片选GPIO端口, PB12  */
#define SF_CS_CLK_ENABLE() 			__HAL_RCC_GPIOB_CLK_ENABLE()
#define SF_CS_GPIO					GPIOB
#define SF_CS_PIN					GPIO_PIN_12

#define SF_CS_0()					SF_CS_GPIO->BSRR = ((uint32_t)SF_CS_PIN << 16U) 
#define SF_CS_1()					SF_CS_GPIO->BSRR = SF_CS_PIN

/*
*********************************************************************************************************
*	                            时钟,引脚,DMA,中断等宏定义
*********************************************************************************************************
*/
#define SPIx							SPI2
#define SPIx_CLK_ENABLE()				__HAL_RCC_SPI2_CLK_ENABLE()
#define DMAx_CLK_ENABLE()				__HAL_RCC_DMA1_CLK_ENABLE()

#define SPIx_FORCE_RESET()				__HAL_RCC_SPI2_FORCE_RESET()
#define SPIx_RELEASE_RESET()			__HAL_RCC_SPI2_RELEASE_RESET()

#define SPIx_SCK_CLK_ENABLE()			__HAL_RCC_GPIOB_CLK_ENABLE()
#define SPIx_SCK_GPIO					GPIOB
#define SPIx_SCK_PIN					GPIO_PIN_13
#define SPIx_SCK_AF						GPIO_AF5_SPI2

#define SPIx_MISO_CLK_ENABLE()			__HAL_RCC_GPIOB_CLK_ENABLE()
#define SPIx_MISO_GPIO					GPIOB
#define SPIx_MISO_PIN 					GPIO_PIN_14
#define SPIx_MISO_AF					GPIO_AF5_SPI2

#define SPIx_MOSI_CLK_ENABLE()			__HAL_RCC_GPIOB_CLK_ENABLE()
#define SPIx_MOSI_GPIO					GPIOB
#define SPIx_MOSI_PIN 					GPIO_PIN_15
#define SPIx_MOSI_AF					GPIO_AF5_SPI2

#define SPIx_TX_DMA_STREAM               DMA1_Stream0
#define SPIx_RX_DMA_STREAM               DMA1_Stream1

#define SPIx_TX_DMA_REQUEST              DMA_REQUEST_SPI2_TX
#define SPIx_RX_DMA_REQUEST              DMA_REQUEST_SPI2_RX

#define SPIx_DMA_TX_IRQn                 DMA1_Stream0_IRQn
#define SPIx_DMA_RX_IRQn                 DMA1_Stream1_IRQn

#define SPIx_DMA_TX_IRQHandler           DMA1_Stream0_IRQHandler
#define SPIx_DMA_RX_IRQHandler           DMA1_Stream1_IRQHandler

#define SPIx_IRQn                        SPI2_IRQn
#define SPIx_IRQHandler                  SPI2_IRQHandler
  • 🌿接下来就是,根据个人硬件配置进行调整修改即可。
void sf_SetCS(uint8_t _Level)
{
	if (_Level == 0)
	{
		bsp_SpiBusEnter();	
		bsp_InitSPIParam(SPI_BAUDRATEPRESCALER_64, SPI_PHASE_1EDGE, SPI_POLARITY_LOW);		
		SF_CS_0();
	}
	else
	{		
		SF_CS_1();	
		bsp_SpiBusExit();		
	}
}
📗个人移植工程(查询方式和中断方式可用,DMA不可用)
通过网盘分享的文件:STM32H7_RTC_SPI2.rar
链接: https://pan.baidu.com/s/100jceM7dWQ4rLB8xDJNAIw?pwd=rtiq 提取码: rtiq

📘DMA方式实现注意事项

  • 👉使用SPI DMA 读写前,必须先禁用SCB_DisableICache(),否则读写数据会有问题。个人所使用的板子芯片没有使用外部扩展SDRAM。。

  • 🌿禁用此函数,不要放到SPI WRITE函数里面执行。

  • 🌿禁用SCB_DisableDCache()时,顺便清除缓存数据SCB_CleanDCache ()

		 printf("Write. \r\n");
#ifdef	USE_SPI_DMA
  			SCB_DisableICache();	//禁用DCACHE缓存,影响DMA接收
				SCB_DisableDCache();
				SCB_CleanDCache (); //数据Cache清除
#endif									
			sfWriteTest();//写操作
  • 📜GD25Q64测试:
    在这里插入图片描述
    在这里插入图片描述
  • W25Q64测试效果
    在这里插入图片描述

和上面的工程有差异,不兼容。

通过网盘分享的文件:STM32H7_RTC_SPI2_DMA.rar
链接: https://pan.baidu.com/s/1nrRXpjnlTeHUcfRoxweIwA?pwd=g35t 提取码: g35t
  • DMA方式如果将接收和发送数组定义到指定的SRAM空间,需要做如下定义使用:
    在这里插入图片描述
  • 🔖这样可以不用,在读取前后分别作禁用和启用缓存操作:
    在这里插入图片描述
//__ARMCC_VERSION >= 6010050
        __attribute__((section (".RAM_D3"))) uint8_t g_spiTxBuf[SPI_BUFFER_SIZE];   
        __attribute__((section (".RAM_D3"))) uint8_t g_spiRxBuf[SPI_BUFFER_SIZE];

  • 片内启动(Start addr:0x08000000)
LR_IROM1 0x08000000 0x00200000 { ; load region size_region
 ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
 *.o (RESET, +First)
 *(InRoot$$Sections)
 .ANY (+RO)
 }
 
 ; RW data - 128KB DTCM
 RW_IRAM1 0x20000000 0x00020000 { 
 .ANY (+RW +ZI)
 }
 
 ; RW data - 512KB AXI SRAM
 RW_IRAM2 0x24000000 0x00080000 { 
 *(.RAM_D1) 
 }
 
 ; RW data - 128KB SRAM1(0x30000000) + 128KB SRAM2(0x3002 0000) + 32KB SRAM3(0x30040000)
 RW_IRAM3 0x30000000 0x00048000 { 
 *(.RAM_D2)
 }
 
 ; RW data - 64KB SRAM4(0x38000000)
 RW_IRAM4 0x38000000 0x00010000 { 
 *(.RAM_D3)
 }

  • 片外启动(Start addr:0x90000000)
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x90000000 0x20000000  {    ; load region size_region
  ER_IROM1 0x90000000 0x20000000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data - 128KB DTCM
   .ANY (+RW +ZI)
  }
  RW_IRAM2 0x24000000 0x00080000  {   ; RW data - 512KB AXI SRAM
   .ANY (+RW +ZI)
  }
  ; RW data - 128KB SRAM1(0x30000000) + 128KB SRAM2(0x3002 0000) + 32KB SRAM3(0x30040000)
 RW_IRAM3 0x30000000 0x00048000 { 
 *(.RAM_D2)
 }
 
 ; RW data - 64KB SRAM4(0x38000000)
 RW_IRAM4 0x38000000 0x00010000 { 
 *(.RAM_D3)
 }
}

根据引用和引用的内容,可以总结出STM32h750 QSPI W25Q64驱动的一些关键信息。 首先,W25Q64是一种SPI NOR Flash芯片,它被连接到STM32h750的QSPI(Quad SPI)接口上。W25Q64的引脚连接为PB2、PB6、PF6、PF7、PF8和PF9。 在设置QSPI时,一些关键的配置参数需要注意。首先是时钟预分频器(clock prescaler),根据W25Q256的最高时钟频率为104MHz,因此需要将分频设置为2。其次是闪存大小(FLASH SIZE),W25Q64的大小为8MB,所以需要将设置为2的(22-1)次方。时钟模式(Clock Mode)应设置为Low,表示CLK空闲时为低电平。芯片选择(Chip Select)需要设置为High Time为5,以确保高电平持续时间大于50ns。 另外,为了保证正常的工作,所有的QSPI引脚都应该设置为very high,而NCS脚(PB6)必须设置为PULL-UP。关于为什么要设置为PULL-UP,具体原因在引用中没有提及。 最后,需要注意W25Q64与W25Q256之间的一些区别。首先是地址位数,W25Q64只支持24位地址,而W25Q256支持24位和32位地址。其次是读写状态寄存器的不同,W25Q64的读状态寄存器为05h和35h,而W25Q256的为05h、35h和15h。写状态寄存器也有所不同,W25Q64的为01h,而W25Q256的为01h、31h和11h。 综上所述,STM32h750的QSPI可以通过相应的配置来驱动W25Q64芯片。需要注意的是,具体的配置参数和引脚连接可能还取决于具体的硬件设计和应用需求。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [STM32H750 QSPI间接模式 W25Q64](https://blog.csdn.net/smallerlang/article/details/127921384)[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_2"}}] [.reference_item style="max-width: 50%"] - *2* [STM32H753 STM32H743 STM32H750 QSPI W25Q256 下载算法](https://blog.csdn.net/c101028/article/details/132073746)[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_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值