通讯协议学习之路:QSPI协议理论

通讯协议之路主要分为两部分,第一部分从理论上面讲解各类协议的通讯原理以及通讯格式,第二部分从具体运用上讲解各类通讯协议的具体应用方法。

后续文章会同时发表在个人博客(jason1016.club)、CSDN;视频会发布在bilibili(UID:399951374)

一、QSPI是什么?

SPI协议其实是包括:Standard SPI、Dual SPI和Queued SPI三种协议接口,分别对应3-wire, 4-wire, 6-wire。

(1)通常我们说的SPI就是Standard SPI,有4根信号线,分别为CLK、CS、MOSI和MISO。数据线工作在全双工。

(2)Dual SPI,它只是针对SPI Flash而言,不是针对所有SPI外设。对于SPI Flash,全双工并不常用,因此扩展了mosi和miso的用法,让它们工作在半双工,用以加倍数据传输。也就是对于Dual SPI Flash,可以发送一个命令字节进入dual mode,这样mosi变成SIO0(serial io 0),mosi变成SIO1(serial io 1),这样一个时钟周期内就能传输2个bit数据,加倍了数据传输。

(3)类似的,还可以扩展,与也是针对SPI Flash,Qual SPI Flash增加了两根I/O线(SIO2,SIO3),目的是一个时钟内传输4个bit

而QSPI就是Queued SPI的简写。

二、接口问题

上图是某SPI FLASH的引脚接口示意图,它即支持SPI通信,也可以使用DSPI通信或者QSPI通信,这块芯片一共有8个有用的管脚,其每个管脚的功能定义如下:

每个引脚的详细描述如下:

1、Chip Select(/CS)

片选信号Chip Select(/CS)的作用是使能或者不使能设备的操作,当CS为高时,表示设备未被选中,串行数据输出线(DO或IO0,IO1,IO2,IO3)均处于高阻态,当CS为低时,表示设备被选中,FPGA可以给QSPI Flash发送数据或从QSPI Flash接收数据。

2、串行数据输入信号DI以及串行输出信号DO

标准的SPI协议在串行时钟信号(SCLK)的上升沿把串行输入信号DI上的数据存入QSPI Flash中,在串行时钟信号(SCLK)的下降沿把QSPI Flash中的数据串行化通过单向的DO引脚输出。而在Dual SPI与Quad SPI中,DI与DO均为双向信号(既可以作为输入,也可以作为输出)。

3、Write Project(/WP)

写保护信号的作用是防止QSPI Flash的状态寄存器被写入错误的数据,WP信号低电平有效,但是当状态寄存器2的QE位被置1时,WP信号失去写保护功能,它变成Quad SPI的一个双向数据传输信号。

4、HOLD(/HOLD)

HOLD信号的作用是暂停QSPI Flash的操作。当HOLD信号为低,并且CS也为低时,串行输出信号DO将处于高阻态,串行输入信号DI与串行时钟信号SCLK将被QSPI Flash忽略。当HOLD拉高以后,QSPI Flash的读写操作能继续进行。当多个SPI设备共享同一组SPI总线相同的信号的时候,可以通过HOLD来切换信号的流向。和WP信号一样,当当状态寄存器2的QE位被置1时,HOLD信号失去保持功能,它也变成Quad SPI的一个双向数据传输信号。

5、串行时钟线

串行时钟线用来提供串行输入输出操作的时钟。

三、QSPI的使用

3.1 工作模式

该接口可以在以下三种模式下工作:

① 间接模式:使用 QSPI 寄存器执行全部操作

② 状态轮询模式:周期性读取外部 Flash 状态寄存器,而且标志位置 1 时会产生中断(如擦除或烧写完成,会产生中断)

③ 内存映射模式:外部 Flash 映射到微控制器地址空间,从而系统将其视作内部存储器

采用双闪存模式时,将同时访问两个 Quad-SPI Flash,吞吐量和容量均可提高二倍。

QSPI功能框图,双闪存模式禁止:

QSPI 使用 6 个信号连接Flash,分别是四个数据线BK1_IO0~BK1_IO3,一个时钟输出CLK,一个片选输出(低电平有效)BK1_nCS,它们的作用介绍如下:

  • BK1_nCS:片选输出(低电平有效),适用于 FLASH 1。如果 QSPI 始终在双闪存模式下工作,则其也可用于 FLASH 2从设备选择信号线。QSPI通讯以BK1_nCS线置低电平为开始信号,以BK1_nCS线被拉高作为结束信号。
  • CLK:时钟输出,适用于两个存储器,用于通讯数据同步。它由通讯主机产生,决定了通讯的速率,不同的设备支持的最高时钟频率不一样,如STM32的QSPI时钟频率最大为fpclk/2,两个设备之间通讯时,通讯速率受限于低速设备。
  • BK1_IO0:在双线 / 四线模式中为双向 IO,单线模式中为串行输出,适用于FLASH 1。
  • BK1_IO1:在双线 / 四线模式中为双向 IO,单线模式中为串行输入,适用于FLASH 1。
  • BK1_IO2:在四线模式中为双向 IO,适用于 FLASH 1。
  • BK1_IO3:在四线模式中为双向 IO,适用于 FLASH 1。

3.2 状态

我们可以通过配置,选择到底使用哪种方式与其进行通信传输。在进行四线读写操作(QSPI)之前一定要把寄存器中的QE(Quad Enable)位置为1,除此以外,四线读操作还需要在读数据之前等待8个dummy clock用来加快读数据的速度(详细内容请阅读芯片手册)。所以,四线操作相对于单线操作而言除了要增加四线模式读写数据的状态以外还要增加一个写状态寄存器的功能用来开启QE(Quad Enable)位以及一个dummy用来等待8个clock。

四线模式的状态为以下几个:

1、空闲状态:用来初始化各个寄存器的值

2、发送命令状态:用来发送8-bit的命令码

3、发送地址状态:用来发送24-bit的地址码

4、读等待状态(单线模式):当读数据操作正在进行的时候进入此状态等待读数据完毕

5、写数据状态(单线模式):在这个状态FPGA往QSPI Flash里面写数据

6、写状态寄存器状态:用来把状态寄存器的QE(Quad Enable)置1

7、Dummy Clock状态:四线读数据之前需要等待8个dummy clock

8、写数据状态(四线模式):在这个状态FPGA往QSPI Flash里面通过四线模式写数据

9、读等待状态(四线模式):在这个状态等待FPGA从QSPI Flash里面通过四线模式读数据完成

10、结束状态:一条指令操作结束,并给出一个结束标志

其中6-9的状态是四线模式的代码在单线模式代码的基础上增加的四个状态。

3.3 命令序列

QSPI通过命令与Flash通信,每条命令包括指令、地址、交替(复用)字节、空指令和数据共五个阶段,而这五个阶段任一阶段均可跳过,但至少要包含指令、地址、交替字节或数据阶段之一。nCS在每条指令开始前下降,在每条指令完成后再次上升。QSPI四线模式下的读命令时序如下图所示。

1)指令阶段

这一阶段,将在QSPI_CCR[7:0]寄存器的instruction字段中配置的一条8位指令发送到Flash,指定待执行操作的类型。

尽管大多数Flash从IO0/SO信号(单线SPI模式)只能以一次1位的方式接收指令,但指令阶段可选择一次发送2位(在双线SPI模式中通过IO0/IO1)或一次发送4位(在四线SPI模式中通过IO0/IO1/IO2/IO3)。这可通过QSPI_CCR[9:8]寄存器中的IMODE[1:0]字段进行配置。若IMODE = 00,则跳过指令阶段,命令序列从地址阶段(如果存在)开始。

2)地址阶段

在地址阶段,将1-4字节发送到Flash,指示操作地址。待发送的地址字节数在QSPI_CCR[13:12]寄存器的ADSIZE[1:0]字段中进行配置。在间接模式和自动轮询模式下,待发送的地址字节在QSPI_AR寄存器的ADDRESS[31:0]中指定;在内存映射模式下,则通过AHB(来自于内核或DMA)直接给出地址。地址阶段可一次发送1位(单线SPI模式通过SO)、2位(双线SPI模式中通过IO0/IO1)或4位(在四线SPI模式中通过IO0/IO1/IO2/IO3)。这可通过QUADSPI_CCR[11:10]寄存器中的ADMODE[1:0]字段进行配置。若ADMODE = 00,则跳过地址阶段,命令序列直接进入下一阶段(如果存在)。

3)交替字节阶段

在交替字节阶段,将1-4字节发送到Flash,一般用于控制操作模式。待发送的交替字节数在QSPI_CCR[17:16]寄存器的ABSIZE[1:0]字段中进行配置。待发送的字节在QSPI_ABR寄存器中指定。

交替字节阶段可一次发送1位(在单线SPI模式中通过SO)、2位(在双线SPI模式中通过IO0/IO1)或4位(在四线SPI模式中通过IO0/IO1/IO2/IO3)。这可通过QSPI_CCR[15:14]寄存器中的ABMODE[1:0]字段进行配置。若ABMODE = 00,则跳过交替字节阶段,命令序列直接进入下一阶段(如果存在)。

交替字节阶段存在仅需发送单个半字节而不是一个全字节的情况,比如采用双线模式并且仅使用两个周期发送交替字节时。在这种情况下,固件可采用四线模式(ABMODE = 11)并发送一个字节,方法是ALTERNATE的位7和3置"1"(IO3保持高电平)且位6和2置"0"(IO2线保持低电平)。此时,半字节的高2位存放在ALTERNATE的位4:3,低2位存放在位1和0中。例如,如果半字节2 (0010)通过IO0/IO1发送,则ALTERNATE应设置为0x8A (1000_1010)。

4)空指令周期阶段

在空指令周期阶段,给定的1-31个周期内不发送或接收任何数据,目的是当采用更高的时钟频率时,给Flash留出准备数据阶段的时间。这一阶段中给定的周期数在QSPI_CCR[22:18]寄存器的DCYC[4:0]字段中指定。在SDR和DDR模式下,持续时间被指定为一定个数的全时钟周期。若DCYC为零,则跳过空指令周期阶段,命令序列直接进入数据阶段(如果存在)。空指令周期阶段的操作模式由DMODE确定。为确保数据信号从输出模式转变为输入模式有足够的"周转"时间,使用双线和四线模式从Flash接收数据时,至少需要指定一个空指令周期。

5)数据阶段

在数据阶段,可从Flash接收或向其发送任意数量的字节。在间接模式和自动轮询模式下,待发送/接收的字节数在QSPI_DLR寄存器中指定。在间接写入模式下,发送到Flash的数据必须写入QSPI_DR寄存器。在间接读取模式下,通过读取QSPI_DR寄存器获得从Flash接收的数据。在内存映射模式下,读取的数据通过AHB直接发送回Cortex或DMA。数据阶段可一次发送/接收1位(在单线SPI模式中通过SO)、2位(在双线SPI模式中通过IO0/IO1)或4位(在四线SPI模式中通过IO0/IO1/IO2/IO3)。这可通过QUADSPI_CCR[15:14]寄存器中的ABMODE[1:0] 字段进行配置。若DMODE = 00,则跳过数据阶段,命令序列在拉高nCS时立即完成。这一配置仅可用于仅间接写入模式。

参考文章:https://blog.csdn.net/wangguchao/article/details/105593303

四、疑难问题

1、qspi和spi异同

QSPI(Quad SPI)和SPI(Serial Peripheral Interface)是两种串行通信协议,用于在主设备和从设备之间进行数据传输。它们有一些相似之处,但也有一些重要的区别。

相似之处:

  1. 串行通信:QSPI和SPI都是串行通信协议,通过少量的引脚进行数据传输。

  2. 主从结构:QSPI和SPI都是基于主从结构的通信协议,其中主设备控制通信的发起和时序,从设备响应主设备的指令并进行数据传输。

不同之处:

  1. 传输速率:QSPI通常支持更高的传输速率,因为它使用了四条数据线(Quad),可以同时传输四个数据位。而SPI通常只使用一条数据线,每次只能传输一个数据位。

  2. 总线模式:QSPI支持多种总线模式,如单线模式、双线模式和四线模式,可以根据需求选择不同的模式。而SPI通常只支持单线模式。

  3. 时钟频率:QSPI通常支持更高的时钟频率,可以实现更快的数据传输速度。SPI的时钟频率相对较低。

  4. 引脚数量:QSPI通常需要更多的引脚来支持四线模式的数据传输,而SPI只需要少量的引脚。

  5. 片选信号:QSPI通常使用片选信号(Chip Select)来选择要进行通信的从设备,而SPI通常使用片选信号或使能信号来选择从设备。

需要根据具体的应用需求和设备支持来选择使用QSPI还是SPI。QSPI适用于需要更高传输速率和更大带宽的应用,而SPI适用于传输速率要求不高的应用。

相关推荐
hellojackjiang201113 分钟前
开源轻量级IM框架MobileIMSDK的鸿蒙NEXT客户端库已发布
网络·即时通讯·im开发·mobileimsdk-鸿蒙端
重生之我是数学王子44 分钟前
单片机 STM32入门
stm32·单片机·嵌入式硬件
WebDeveloper20011 小时前
如何使用美国域名中心US Domain Center和WordPress创建商业网站
运维·服务器·css·网络·html
车载诊断技术2 小时前
电子电气架构 --- 什么是EPS?
网络·人工智能·安全·架构·汽车·需求分析
KevinRay_2 小时前
Python超能力:高级技巧让你的代码飞起来
网络·人工智能·python·lambda表达式·列表推导式·python高级技巧
2301_819287123 小时前
ce第六次作业
linux·运维·服务器·网络
CIb0la3 小时前
GitLab 停止为中国区用户提供 GitLab.com 账号服务
运维·网络·程序人生
Black_mario4 小时前
链原生 Web3 AI 网络 Chainbase 推出 AVS 主网, 拓展 EigenLayer AVS 应用场景
网络·人工智能·web3
eybk4 小时前
Pytorch+Mumu模拟器+萤石摄像头实现对小孩学习的监控
学习
6.944 小时前
Scala学习记录 递归调用 练习
开发语言·学习·scala