【转】16.HAL库之SPI和QSPI

1.SPI协议(以RN8302为例)

SPI是串行外设接口(Serial Peripheral Interface)的缩写。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线(SCSN,SCLK,SDI,SDO).

 

总结传输流程:

a.写时序

 

 

SCSN拉低,开启通讯。主机依次写入地址,命令,数据(高位在前,低位在后),CS校验。主机在SCLK下降沿将数据通过SDI写入从机。最后SCSN拉高结束通讯。

b.读时序

 

 

SCSN拉低开启通讯,主机先写入地址+命令共两个字节,随后在SCLK下降沿读取从机从SDO输出的数据(高位在前,低位在后)。最后SCSN拉高结束通讯。

驱动程序编写:头文件中需定义管脚控制命令,寄存器地址,芯片命令。c文件中依次编写读写字节,读写帧数据,读写寄存器,芯片初始化等函数。

RN8302具体驱动程序见: https://download.csdn.net/download/weixin_42480952/10772976

主机(STM32F746)只需配置SPI接口即可,具体流程为:开启时钟,GPIO管脚配置,SPI配置。

2.QSPI

QSPI是Queued SPI的简写,是Motorola公司推出的SPI接口的扩展,比SPI应用更加广泛。在SPI协议的基础上,Motorola公司对其功能进行了增强,增加了队列传输机制,推出了队列串行外围接口协议(即QSPI协议)。QSPI 是一种专用的通信接口,连接单、双或四(条数据线) SPI Flash 存储介质。共有SNCS,SCLK,BK0,BK1,BK2,BK3共6根接线,可以实现多种通信模式。

 

 

主机需进行QSPI接口的配置,QSPI协议主要通过发送命令来进行通讯,因此主机的配置包括管脚配置,QSPI初始化。

QUADSPI通过命令和FLASH通讯,命令包括:指令+地址+交替字节+空周期+数据五个阶段,并且各阶段可省略。

 

单线SPI模式:BK_IO0即SO,BK_IO1即SI,加上NCS和SCLK,类似于SPI模式。

 

 

 

 

双线SPI模式:BK_IO0和BK_IO1实现数据的双入双出。

 

 

 

 

四线SPI模式:BK_IO0,BK_IO1,BK_IO2,BK_IO3四根线实现数据的传输。

 

 

 

 

SDR模式:QSPI驱动IO0~IO3在SCLK的下降沿进行数据变化。

DDR模式:在该模式下,指令阶段在SCLK下降沿发送数据,而在地址,交替字节,数据阶段在SCLK上升沿和下降沿均发送数据。

 

 

 

 

双闪存模式:使用两个外部SPI四线,可将flash扩大一倍。

QSPI配置:

时钟使能,管脚定义,QSPI配置,flash初始化,QSPI读/写函数定义。

void Qspi_Config()
{
  __HAL_RCC_QSPI_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOF_CLK_ENABLE();

Flash_GPIO.Pin=GPIO_PIN_2;
Flash_GPIO.Mode=GPIO_MODE_AF_PP;
Flash_GPIO.Speed=GPIO_SPEED_FREQ_MEDIUM;
Flash_GPIO.Pull=GPIO_NOPULL;
Flash_GPIO.Alternate=GPIO_AF9_QUADSPI;
HAL_GPIO_Init(GPIOB,&Flash_GPIO); //QSPI_CLK, PB2

Flash_GPIO.Pin=GPIO_PIN_6;
Flash_GPIO.Mode=GPIO_MODE_AF_PP;
Flash_GPIO.Speed=GPIO_SPEED_FREQ_MEDIUM;
Flash_GPIO.Pull=GPIO_PULLUP;
Flash_GPIO.Alternate=GPIO_AF10_QUADSPI;
HAL_GPIO_Init(GPIOB,&Flash_GPIO); //QSPI_NCS, PB6

Flash_GPIO.Pin=GPIO_PIN_8;
Flash_GPIO.Mode=GPIO_MODE_AF_PP;
Flash_GPIO.Speed=GPIO_SPEED_FREQ_MEDIUM;
Flash_GPIO.Pull=GPIO_NOPULL;
Flash_GPIO.Alternate=GPIO_AF10_QUADSPI;
HAL_GPIO_Init(GPIOF,&Flash_GPIO); //QSPI_IO0, PF8

Flash_GPIO.Pin=GPIO_PIN_9;
Flash_GPIO.Mode=GPIO_MODE_AF_PP;
Flash_GPIO.Speed=GPIO_SPEED_FREQ_MEDIUM;
Flash_GPIO.Pull=GPIO_NOPULL;
Flash_GPIO.Alternate=GPIO_AF10_QUADSPI;
HAL_GPIO_Init(GPIOF,&Flash_GPIO); //QSPI_IO1, PF9

Flash_GPIO.Pin=GPIO_PIN_7;
Flash_GPIO.Mode=GPIO_MODE_AF_PP;
Flash_GPIO.Speed=GPIO_SPEED_FREQ_MEDIUM;
Flash_GPIO.Pull=GPIO_NOPULL;
Flash_GPIO.Alternate=GPIO_AF9_QUADSPI;
HAL_GPIO_Init(GPIOF,&Flash_GPIO); //QSPI_IO2, PF7

Flash_GPIO.Pin=GPIO_PIN_6;
Flash_GPIO.Mode=GPIO_MODE_AF_PP;
Flash_GPIO.Speed=GPIO_SPEED_FREQ_MEDIUM;
Flash_GPIO.Pull=GPIO_NOPULL;
Flash_GPIO.Alternate=GPIO_AF9_QUADSPI;
HAL_GPIO_Init(GPIOF,&Flash_GPIO); //QSPI_IO3, PF6

QSPI_Flash.Instance=QUADSPI;
QSPI_Flash.Init.ClockPrescaler=2;
QSPI_Flash.Init.FifoThreshold=4;
QSPI_Flash.Init.SampleShifting=QSPI_SAMPLE_SHIFTING_HALFCYCLE;
QSPI_Flash.Init.FlashSize=25;
QSPI_Flash.Init.ChipSelectHighTime=QSPI_CS_HIGH_TIME_8_CYCLE;
QSPI_Flash.Init.ClockMode=QSPI_CLOCK_MODE_0;
HAL_QSPI_Init(&QSPI_Flash);
}

void QSPI_Read(uint8_t *data,uint32_t addr, uint32_t size)
{
QSPI_CommandTypeDef flash_command;
flash_command.InstructionMode=QSPI_INSTRUCTION_1_LINE;
flash_command.Instruction=0x13;
flash_command.Address=addr;
flash_command.AddressMode=QSPI_ADDRESS_1_LINE;
flash_command.AddressSize=QSPI_ADDRESS_32_BITS;
flash_command.AlternateByteMode=QSPI_ALTERNATE_BYTES_NONE;
flash_command.DataMode=QSPI_DATA_1_LINE;
flash_command.DummyCycles=0;
flash_command.NbData=size;
flash_command.DdrMode=QSPI_DDR_MODE_DISABLE;
flash_command.DdrHoldHalfCycle=QSPI_DDR_HHC_ANALOG_DELAY;
flash_command.SIOOMode=QSPI_SIOO_INST_EVERY_CMD;
HAL_QSPI_Command(&QSPI_Flash,&flash_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
HAL_QSPI_Receive(&QSPI_Flash,data,1000); //读取的数据放入*data中,共size个字节
QSPI_AutoPollingMemReady();
}

void QSPI_WritePage(uint8_t *pData,uint32_t WriteAddr, uint32_t Size)
{
QSPI_CommandTypeDef flash_command;
QSPI_WriteEnable();

flash_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
flash_command.Instruction = 0x12;
flash_command.AddressMode = QSPI_ADDRESS_1_LINE;
flash_command.AddressSize = QSPI_ADDRESS_32_BITS;
flash_command.Address = WriteAddr;
flash_command.NbData = Size;
flash_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
flash_command.DataMode = QSPI_DATA_1_LINE;
flash_command.DummyCycles = 0;
flash_command.DdrMode = QSPI_DDR_MODE_DISABLE;
flash_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
flash_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;

HAL_QSPI_Command(&QSPI_Flash, &flash_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
HAL_QSPI_Transmit(&QSPI_Flash, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
QSPI_AutoPollingMemReady();
}


————————————————
版权声明:本文为CSDN博主「南国枫火」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42480952/article/details/83863176

posted @   r_jw  阅读(729)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示