Zynq7000系列中的Quad-SPI(四线制串行外设接口)Flash控制器编程指南

Zynq7000系列中的Quad-SPI(四线制串行外设接口)Flash控制器是一个功能强大的组件,它支持高速数据传输和多种配置模式。以下是基于Zynq7000系列的Quad-SPI Flash控制器编程指南,旨在帮助开发者了解如何配置和使用该控制器。

编程指南:启动序列示例

这个序列包括配置时钟、配置传输/接收信号、重置控制器、配置控制器以及选择线性寻址模式或I/O模式。

  1. 配置时钟:根据设备的规格和需求,配置适当的时钟源和时钟频率。
  2. 配置Tx/Rx信号:配置传输(Tx)和接收(Rx)信号。这通常涉及选择正确的物理引脚、设置信号的方向(输入/输出)以及可能的信号特性(如电平、速率等)。
  3. 重置控制器:对控制器进行硬件或软件重置。重置操作将控制器恢复到初始状态,确保后续的配置操作在一个干净的环境中进行。
  4. 配置控制器:这可能包括设置工作模式、数据格式、波特率、超时等参数。

接下来,根据应用需求,您可以选择配置控制器为线性寻址模式或I/O模式。

配置

示例:配置控制器

此配置示例适用于线性寻址模式和I/O模式。它准备了控制器的波特率、FIFO、闪存模式、时钟相位/极性,并设置了回环延迟。需要编程到qspi.Config_reg寄存器的值如表12-3所示。

  1. 配置控制器:qspi.Config_reg寄存器写入配置值。

        a. 通过[BAUD_RATE_DIV]字段来设置波特率。
        b. 将[MODE_SEL]设置为1来选择主模式。
        c. 将[LEG_FLSH]设置为1来选择闪存模式(非传统SPI)。
        d .将[endian]设置为0 来选择小端模式。
        e. 通过[FIFO_WIDTH]字段来设置FIFO宽度为32位。
        f.  通过[CLK_PH][CLK_POL]字段来设置时钟相位和极性。

     2. 启用回环时钟

      如果使用回环时钟,请确保qspi.Config_reg[BAUD_RATE_DIV]被设置为0b00,并配置qspi.LPBK_DLY_ADJ(回环延迟调整)寄存器,设置如下:
     a. 将qspi.LPBK_DLY_ADJ[USE_LPBK]设置为1来选择内部时钟。
     b. 将qspi.LPBK_DLY_ADJ[DLY0]设置为0b00来设置时钟延迟0。
     c. 将qspi.LPBK_DLY_ADJ[DLY1]设置为0b00来设置时钟延迟1。

线性寻址模式

示例:线性寻址模式(内存读取)

在线性寻址模式下进行数据读取的操作序列如下:

  1. 设置手动启动为自动模式:将qspi.Config_reg[Man_start_en]设置为0,以启用自动模式。这允许控制器在接收到指令后自动开始数据传输,而无需手动触发。
  2. 激活芯片选择:将qspi.Config_reg[PCS]设置为0,以选择目标SPI设备。
  3. 为线性寻址模式配置配置寄存器:根据表12-3中的示例值,对配置寄存器进行编程。
  4. 启用控制器:将qspi.En_REG[SPI_EN]设置为1,以启用QSPI控制器。这将使控制器开始工作,并准备接收和发送数据。
  5. 从线性地址内存区域读取数据:数据读取的范围取决于连接的设备的大小和数量。在线性寻址模式下,内存地址范围可能是从0xFC00_00000xFDFF_FFFF。您需要通过向控制器发送读取指令和指定地址来从该范围内读取数据。
  6. 禁用控制器:在完成数据读取后,将qspi.En_REG[SPI_EN]设置为0,以禁用QSPI控制器。
  7. 取消激活芯片选择:将qspi.Config_reg[PCS]设置为1,以取消选择SPI设备。

配置I/O模式

示例:I/O模式(内存读写)

以下操作序列使用I/O模式进行读写操作:

  1. 启用手动模式:将qspi.Config_reg[Man_start_en, Manual_CS]的相应位设置为1,以启用手动模式。
  2. 配置闪存设备:参考图12-6。对于单个闪存设备,请使用qspi.LQSPI_CFG寄存器的复位值。如果是并行双闪存设备,请将TWO_MEMSEP_BUS位字段设置为1。

     3. 激活芯片选择:将qspi.Config_reg[PCS]设置为0,以选择目标SPI闪存设备。

     4. 启用控制器:将qspi.En_REG[SPI_EN]设置为1。

     5. 向闪存写入字节序列:使用TXD寄存器向TxFIFO写入1到4个字节。

     6. 避免TxFIFO溢出:当TxFIFO为空时,可以写入252个字节。之后,软件可以通过读取qspi.Intr_status_REG[TX_FIFO_full]并等待其值变为0来避免TxFIFO溢出,然后再向TXD寄存器写入数据。

     7. 启用中断:向qspi.Intrpt_en_REG写入值。

     8. 启动数据传输:将qspi.Config_reg[Man_start_com]设置为1,以手动启动数据传输。

     9. 中断处理程序:在程序/读取操作期间,中断处理程序负责将所需的所有数据传输到Quad-SPI闪存。

     10. 当执行读取操作时:由于存在虚拟(dummy)周期,读取的数据中会包含一些不需要的部分。为了消除这些数据,需要对读取的数据进行重新排列。

     11. 取消激活芯片选择QSPI.Config_reg[PCS]设置为1。

     12. 禁用控制器:将qspi.En_REG[SPI_EN]设置为0。

请注意,TxFIFO的宽度必须被编程为32位,即将qspi.Config_reg[FIFO_WIDTH]设置为0b11。如果传输的数据不是字对齐的(即不是32位的倍数),软件需要处理这种“连续非字对齐”的传输。

I/O模式中断服务例程示例

以下是一个I/O模式中断服务例程(ISR)的示例,该例程基于Quad-SPI设备类型处理中断条件:

  1. 配置ISR:根据Quad-SPI设备类型配置ISR。对于从Quad-SPI设备读取数据,最简单的ISR会从RxFIFO读取数据并将其内容写入TxFIFO(尽管在读取操作中,这通常不是必需的,除非有特定的数据回环或测试需求)。控制器生成系统外设中断(SPI),IRQ ID为#51。
         a. 读取传输中断:RxFIFO非空中断
  • 当RxFIFO中有数据时,此中断会被触发。
  • ISR应该读取RxFIFO中的数据,并根据需要处理这些数据(例如,将其存储到内存中)。

        b. 写入传输中断:TxFIFO非满中断

  • 当TxFIFO中有空间可以写入更多数据时,此中断会被触发。
  • 在写入操作中,ISR可能会准备更多的数据并将其写入TxFIFO中。然而,在读取操作中,这个中断可能不是必需的,除非有特定的数据传输需求。

I/O模式中断

在I/O模式下,当中断条件满足时,会触发控制器中断。Quad-SPI中断处理程序会检查中断的原因,并且一个单独的中断服务例程可以管理所有的中断条件。

中断服务例程示例:Rx和Tx

此中断服务例程由IRQ ID #51触发。它会一直读取RxFIFO直到其为空,然后填充TxFIFO。使用RxFIFO非空中断状态来确定是否可以从RxFIFO中读取内容,而TxFIFO非满中断则指示TxFIFO中是否有空间容纳更多内容。

中断处理步骤
  1. 禁用控制器中的所有中断:将qspi.Intrpt_dis_REG[TX_FIFO_not_full, RX_FIFO_full]都设置为1。
  2. 清除中断:向中断状态寄存器qspi.Intr_status_REG写入1,以清除当前的中断状态。
  3. 清空RxFIFO:检查RxFIFO非空中断是否被触发。如果qspi.Intr_status_REG[RX_FIFO_not_empty] = 1,则表示RxFIFO中有数据。
    • 继续从RxFIFO中读取数据并轮询中断状态,直到RxFIFO为空(即qspi.Intr_status_REG[RX_FIFO_not_empty] = 0)。
    • 如果状态被触发,则从RxFIFO中读取数据,使用qspi.RX_data_REG寄存器。
  4. 填充TxFIFO:检查TxFIFO非满状态是否被触发。如果qspi.Intr_status_REG[TX_FIFO_not_Full] = 1,则表示有数据需要发送到闪存设备(进行编程和/或读取操作)。
    • 重复上述步骤,直到所有数据都写入TxFIFO或qspi.Intr_status_REG[TX_FIFO_full] = 1
    • 轮询qspi.Intr_status_REG[TX_FIFO_full],直到其变为1,表示TxFIFO已满。
    • qspi.TXD0寄存器写入数据。
  5. 启用中断:将qspi.Intrpt_en_REG[TX_FIFO_not_full, RX_FIFO_full]都设置为1。
  6. 启动数据传输:将qspi.Config_reg[MANSTRTEN]设置为1,以手动启动数据传输。

注意

  • QSPI的Intr_status_reg.RX_FIFO_not_empty位更新存在延迟。这可能导致轮询软件错误地认为RxFIFO中仍有数据,而实际上已经没有数据了,从而导致RxFIFO下溢并读取到无效数据。为了避免这种情况,软件可以两次读取Intr_status_reg.RX_FIFO_not_empty位,以确保控制器有足够的时间更新状态位。
  • 非空阈值事件是在FIFO水平跨越阈值时检测到的变化,但是将阈值寄存器更改为小于当前水平的值不会生成中断。

Rx/Tx FIFO 对 I/O 命令序列的响应

以下是一些示例命令和序列,包括写使能命令、读状态命令和读数据序列。在这些示例中,YY 可以是任意值,每对 YY 可能具有不同的值。

在串行传统模式下接收数据时,数据会从 MISO/DQ1 线同步于时钟采样到 RxFIFO 中,而命令和地址事务则在 MOSI/DQ0 上发生。

示例:写使能命令(代码 0x06)

  1. 发送写使能命令(WREN):将 0xYYYY_YY06 写入 qspi.TXD1 寄存器。
    • 控制器将 TxFIFO 中的一个字节移出到设备,并在 RxFIFO 中接收一个字节。
    • YY = 0(在这个例子中,我们假设 YY 为 0,但 YY 可以是任意值)。
    • WREN 命令 = 0x06。
  2. 读状态:读取 qspi.RXD 寄存器,并接收 0xYYPP_PPPP。
    • 软件记住写使能命令产生的一个字节,并将 0xYY 返回给调用函数。这里的 0xYY 实际上是命令执行后的状态字节的前缀,但由于 YY 在这个例子中为 0,且状态没有改变,所以返回的是 0x00。
    • 当 YY = 0x0 时(表示状态),值为 0x0000_0000,PP_PPPP = 0x0 表示位的前一个状态(即状态寄存器中的值没有改变)。

发送WREN命令后RxFIFO中的内容如下。(Previous表示该值与寄存器的先前值没有变化。)

示例:读状态命令(代码 0x05)

  1. 发送读状态命令(RDSR)
    • qspi.TXD2寄存器写入0xYYYY_DD05。这里,05是读状态命令的代码,DD是虚拟数据(dummy data,即在这个命令中不重要的数据,通常用于填充传输的空闲时间或满足特定的数据长度要求),而YY是任意值,但在这个例子中假设为0
    • 控制器从TxFIFO中移出两个字节到闪存设备(因为QSPI通常使用至少两个字节(16位)的传输单位,即使命令本身只有一个字节)。同时,控制器从闪存设备接收两个字节到RxFIFO中。
  2. 读取状态值
    • qspi.RXD寄存器读取0xZZYY_PPPP。这里,ZZYYPPPP是接收到的数据的各个部分。
    • ZZ = 0x03(这通常表示状态寄存器的地址或某种特定的响应格式,但具体含义取决于设备和其文档),YY = 0x0(在这个例子中,由于我们发送的是0x00作为YY,所以接收到的YY通常也会是0x00,除非设备修改了这部分),PPPP = 0x0时,整个接收到的值为0x0300_0000
    • 软件记住这两个字节是有效的,并将0x00, 0x03(注意字节顺序,通常低位字节先发送/接收)返回给调用函数。这表示状态寄存器的值(或设备返回的特定响应)已被成功读取。

发送RDSR命令后RxFIFO中的内容如表所示(previous 表示该值与寄存器的先前值没有变化):

示例:读数据序列

这个示例的目的是从地址0读取四个字节的数据,并将这些数据返回给调用函数。

  1. 发送数据读取指令:向qspi.TXD0寄存器写入0xA2A1_A003。这里,03是读取数据的命令代码(具体代码取决于设备和其文档),而A2A1A0是地址的高位、中位和低位字节。
  2. 发送虚拟数据:向qspi.TXD0寄存器(或可能是另一个用于后续传输的TxFIFO条目)写入0xD0D1_D2D3作为虚拟数据。虚拟数据通常用于填充传输的空闲时间,以满足设备对数据传输长度的要求。控制器从TxFIFO中移出8个字节(包括命令、地址和虚拟数据)到闪存设备,并接收8个字节到RxFIFO中。

本例中TxFIFO的内容如下。从控制器到设备的字节序列为:0x03、A0、A1、A2、D0、D1、D2和D3。

      3. 读取指令字后的数据:读取qspi.RXD寄存器。接收到的数据为0xYYYY_YYYY,其中YY = 0。这一步通常是为了确认指令已经被正确发送,并且设备已经准备好返回数据。

     4. 读取闪存内存数据:再次读取qspi.RXD寄存器。接收到的数据为0xD3D2_D1D0

  • a. 第二次读取时,软件记住四个字节是有效的:这意味着从这次读取中,软件期望并接收到了四个字节的数据。这些数据是闪存设备从指定地址返回的实际数据。
  • b. 示例数据:0x2468ACEF:这是一个假设的数据值,用于说明接收到的数据可能是什么样子的。在实际操作中,这个值将由闪存设备的内容决定。
  • c. 软件读取的字节总体:根据前面的步骤和这次读取,软件实际上读取了以下字节序列:0x00, 0x00, 0x00, 0x000x24, 0x68, 0xAC, 0xEF。然后,软件将这四个数据字节(0x24, 0x68, 0xAC, 0xEF)返回给调用函数。

本例中RxFIFO的内容如下。从设备到控制器的字节序列为:YY、YY、YY,YY、0xEF、0xAC、0x68和0x24。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值