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。

- 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)
}
}

1462

被折叠的 条评论
为什么被折叠?



