当前位置: 首页 > news >正文

赛灵思ZYNQ官方文档UG585自学翻译笔记与代码示例:Quad-SPl Flash 闪存控制器

XILINX 四通道 SPI 闪存控制器

12.1 概述

四通道 SPI(Quad-SPI)闪存控制器是位于处理系统(PS)内的输入 / 输出外设(IOP)的一部分,用于访问多比特串行闪存设备,适用于高吞吐量、低引脚数的应用场景。

控制器可工作在三种模式之一:I/O 模式、线性寻址模式和传统 SPI 模式。在 I/O 模式下,软件与闪存设备协议紧密交互,通过四个 TXD 寄存器向控制器写入闪存命令和数据,并从 RXD 寄存器读取从闪存设备接收的数据。

线性寻址模式使用设备操作的子集,消除了 I/O 模式下读取闪存所需的软件开销。该模式通过硬件发出闪存命令,并控制数据从闪存总线到 AXI 接口的流动,控制器响应 AXI 接口上的内存请求,如同闪存是 ROM 存储器。在传统模式下,QSPI 控制器作为普通 SPI 控制器工作。

控制器可连接 1 个或 2 个闪存设备。两个设备可并行连接以实现 8 位性能,或采用堆叠式 4 位结构以减少引脚数量。两种设备组合方式如图 12-1 所示。

12.1.1 特性

  • 用于线性寻址模式传输的 32 位 AXI 接口
  • 用于 I/O 模式传输的 32 位 APB 接口
  • 支持 Micron 和 Spansion 闪存的可编程总线协议
  • 传统 SPI 及可扩展性能:1x、2x、4x、8x I/O 宽度
  • 灵活的 I/O 配置
    • 单片选 4 位 I/O 闪存接口模式
    • 双片选 8 位并行 I/O 闪存接口模式
    • 双片选 4 位堆叠 I/O 闪存接口模式
    • 单片选传统 SPI 接口
  • 每个设备支持 16MB 寻址(两个设备共 32MB)
  • I/O 模式和线性模式支持最大 128Mb 的设备密度,I/O 模式还支持大于 128Mb 的密度
  • I/O 模式(闪存命令和数据)
    • 软件发出指令并管理闪存操作
    • 用于 FIFO 控制的中断
    • 63 字的接收 FIFO(RxFIFO)和 63 字的发送 FIFO(TxFIFO)
  • 线性寻址模式(可执行读访问)
    • 控制器解析内存读写操作
    • AXI 端口可缓冲最多 4 个读请求
    • AXI 递增和 wrap 地址功能

12.1.2 系统视角

四通道 SPI 闪存控制器属于 IOP 的一部分,通过 MIO 连接到外部 SPI 闪存,如图 12-1 所示。控制器支持 1 个或 2 个存储器。

(图 12-1:四通道 SPI 控制器系统视角,此处省略图表)

线性地址模式的地址映射和设备匹配
使用单个设备时,直接内存读取的地址映射从 FC00_0000 开始,最大到 FCFF_FFFF(16MB)。双设备系统的地址映射取决于存储设备和 I/O 配置。在双设备系统中,四通道 SPI 设备需来自同一供应商,以确保协议一致。

8 位并行 I/O 配置还要求设备容量相同,其地址映射从 FC00_0000 开始,到合并内存容量的地址为止,最大为 FDFF_FFFF(32MB)。

对于 4 位堆叠 I/O 配置,设备可具有不同容量,但必须采用相同协议。若使用两个不同大小的设备,Xilinx 建议在低地址使用 128Mb 设备。在此模式下,QSPI 0 设备从 FC00_0000 开始,最大到 FCFF_FFFF(16MB);QSPI 1 设备从 FD00_0000 开始,最大到 FDFF_FFFF(另一个 16MB)。若第一个设备容量小于 16MB,两个设备之间会存在内存空间空洞。

12.1.3 框图

控制器的框图如图 12-2 所示。

(图 12-2:四通道 SPI 控制器框图,此处省略图表)

12.1.4 注意事项

操作限制
使用单个设备时,必须连接到 QSPI 0。使用两个设备时,两者必须完全相同(同一供应商且协议序列一致)。

四通道 SPI 控制器的 MIO 引脚与 SMC 控制器的 NOR 和 NAND 接口冲突,使用四通道 SPI 时,不能使用 NOR/SRAM 和 NAND 接口。有关 MIO 引脚的更多信息,请参见 2.5 节 “PS-PL MIO-EMIO 信号和接口”。

12.2 功能描述

四通道 SPI 闪存控制器可工作在 I/O 模式或线性寻址模式。对于读取操作,两种模式均支持单、双和四通道读模式;对于写入操作,I/O 模式支持单和四通道模式,线性寻址模式不支持写入。

12.2.1 操作模式

四通道 SPI 的操作模式转换如图 12-3 所示。

(图 12-3:四通道 SPI 操作模式转换,此处省略图表)

在 I/O 模式下,软件可通过设置相应的寄存器位,对读数据管理的不同方面进行不同程度的控制。在线性模式下,控制器执行所有必要的读数据管理,软件看来内存读取如同访问 ROM。

12.2.2 I/O 模式

在 I/O 模式下,软件负责根据四通道 SPI 协议准备和格式化命令及数据为指令,由 CMD 和数据组成的格式化指令序列通过重复写入 TXD 寄存器推入发送 FIFO。发送逻辑根据四通道 SPI 接口规范将 TxFIFO 的内容串行化,并发送到闪存。在发送逻辑输出 TxFIFO 内容的同时,它会同步采样原始串行数据,进行串并转换,并存储到 RxFIFO 中。

对于读命令,当命令和地址字节发送后由闪存驱动数据时,MIO 在发送逻辑的控制下适时从输出切换为输入。移入 RxFIFO 的数据反映了这种切换,使 RxFIFO 中对应条目包含有效数据。

软件需要从 RxFIFO 中过滤原始数据以获取相关内容,控制器不会修改软件写入的指令或存入 RxFIFO 的捕获数据。

控制器支持小端模式,一条 4 字节指令的最低有效字节的最高有效位首先发送。

流控制
I/O 模式在数据传输过程中有不同的流控制方式,用户可通过 config_reg.MANSTARTEN(Man_start_com)选择自动或手动模式。在手动模式下,用户可通过 Config_reg.SSFORCE(Manual_CS)进一步选择手动或自动片选。断言片选信号表示 MIO 上命令序列的开始,片选断言后,D0 上的串行数据被闪存解释为命令。

自动模式下,包括片选控制在内的整个传输序列由硬件完成,无需软件干预。向 TxFIFO 写入数据后传输立即开始,片选自动激活;TxFIFO 为空时数据传输结束,片选自动失效。在此模式下,为实现连续数据传输,软件必须以不低于 MIO 上数据移动的速率向 TxFIFO 提供数据,但由于从 RXD 读取和向 TXD 写入以 APB 时钟速率进行,这可能较难实现。

手动模式下,用户控制数据传输的开始。软件将整个传输序列写入 TxFIFO 或直到 TxFIFO 满,设置 Man_start_en 位后,控制器接管操作:断言片选,将数据从 TxFIFO 移出并移入 RxFIFO,适当控制 MIO 的输入 / 输出状态,当 TxFIFO 为空时通过撤销片选终止序列。此模式下,每个命令序列的最大字节数受限于 TxFIFO 的深度(252 字节)。

在手动模式下,用户除控制传输开始外,还可选择控制片选。软件先将传输序列(从命令开始)写入 TxFIFO 直到满,然后断言片选,接着手动启动,硬件接管操作。但 TxFIFO 为空时片选不会撤销,软件可再次填充 TxFIFO 以继续之前的命令。这种方法消除了每个命令序列的字节数限制,可有效用于大数据传输。命令序列完成后,软件通过写入 Manual_CS 位撤销片选。

12.2.3 I/O 模式发送寄存器(TXD)

软件写入特定闪存设备所需的字节序列(参考四通道 SPI 设备供应商规范)。控制器有四个只写 32 位 TXD 寄存器,供软件向闪存发送命令流以获取状态和读写数据。四通道 SPI TXD 寄存器写入格式如表 12-1 所示,访问 TXD0、TXD1、TXD2 或 TXD3 寄存器都会相应地写入 TxFIFO。

表 12-1:四通道 SPI TXD 寄存器写入格式

寄存器写入数据格式(31:24、23:16、15:8、7:0)示例用途
TXD 1保留、保留、保留、数据或命令设置写使能
TXD 2保留、保留、数据 0、数据或命令带数据写入状态
TXD 3保留、数据 1、数据 0、数据或命令带两个虚拟字节读取状态
TXD 0数据 3、数据 2、数据 1、数据或命令发送写入数据或读取用虚拟数据

连续访问以下寄存器之间时,用户必须清空 TxFIFO:

  • TXD0 到 TXD1/TXD2/TXD3
  • TXD1 到 TXD0/TXD1/TXD2/TXD3
  • TXD2 到 TXD0/TXD1/TXD2/TXD3
  • TXD3 到 TXD0/TXD1/TXD2/TXD3

TxD0 到 TXD0 的访问无需清空 FIFO。

FIFO 读写
TxFIFO 和 RxFIFO 共享同一门控时钟,因此从 TxFIFO 移出的每个字节(包括命令和地址字节),都会有一个对应字节移入 RxFIFO。

要从四通道 SPI 闪存读取数据,软件需向 TxFIFO 写入四通道 SPI 闪存所需的适当命令、地址、模式(四通道或双通道 I/O 模式时)和虚拟周期,此外还必须用额外的虚拟数据填充 TxFIFO,这些虚拟数据提供将数据移入 RxFIFO 所需的 CLK。更多编程细节参见 12.3.5 节 “Rx/Tx FIFO 对 I/O 命令序列的响应”。

12.2.4 I/O 模式注意事项

RxFIFO 中断状态位在数据实际可读取前就指示数据可用,这种延迟与时钟域交叉相关,通常会被软件处理中断的时间所覆盖。

在读取命令期间,软件必须向 TxFIFO 写入虚拟数据以接收来自设备的数据。自动模式下,若 TxFIFO 为空,四通道 SPI 控制器会撤销片选,要继续接收数据,软件必须向设备发送读命令和地址。

12.2.5 线性寻址模式

控制器具有 32 位 AXI 从接口,支持读操作的线性地址映射。当主设备通过该端口发出 AXI 读命令时,四通道 SPI 控制器生成 QSPI 命令以加载相应的内存数据,并通过 AXI 接口返回。

在线性模式下,闪存子系统如同具有 AXI 接口的典型只读存储器,支持 4 级命令流水线。与 I/O 模式相比,线性模式通过减少软件开销提高了用户友好性和整体读内存吞吐量。从软件角度看,访问线性四通道 SPI 内存子系统与访问其他 ROM 无明显差异,只是可能延迟更长。

当 qspi.LQSPI_CFG.[LQ_MODE] 位设置为 1 时,切换到 LQSPI 模式。进入线性寻址模式前,用户必须确保 TXFIFO 和 RXFIFO 均为空。设置 qspi.LQSPI_CFG.[LQ_MODE] 位后,FIFO 由 LQSPI 模块自动控制,对 TXD 和 RXD 的 I/O 访问无定义。

线性模式下,CS 引脚由 QSPI 控制器自动控制。切换到 LQSPI 模式前,用户必须确保 qspi.Config_reg [Man_start_en] 和 qspi.Config_reg [PCS] 均为 0。

控制器的简化框图(显示线性和 I/O 部分)如图 12-2 所示。

AXI 接口操作
线性寻址模式仅支持 AXI 读命令,所有有效的写地址和写数据会立即被确认但被忽略,即不会对闪存执行相应的编程(写入)操作,所有 AXI 写入会在写响应通道产生 SLVERR 错误。

支持递增或 wrap 地址突发读取,不支持固定地址突发,否则会导致 SLVERR 错误。因此,仅识别 arburst [1:0] 值为 2'b01 或 2'b10。所有读访问必须字对齐,数据宽度为 32 位(不允许窄突发传输)。

表 12-2 列出了接口忽略的主设备读地址通道信号。

表 12-2:被忽略的 AXI 读地址通道信号

信号
araddr[1:0]忽略,假设为 0(即始终假设字对齐)
arsize[2:0]忽略,始终为 32 位接口
arlock[1:0]忽略
arcache[3:0]忽略
arprot[2:0]忽略

AXI 从接口提供 4 的读接受能力,可接受最多 4 个未完成的 AXI 读命令。

AXI 读命令处理
AXI 读突发命令被转换为 SPI 闪存读指令,发送到四通道 SPI 控制器的 TxFIFO。控制器发送逻辑负责从 FIFO 检索读指令,并根据 SPI 协议传递给 SPI 闪存。

64 深度的 FIFO 用于提供读数据缓冲,可容纳最多 4 个 16 数据突发。由于 Rx FIFO 在片选信号激活后立即开始接收数据,线性地址模块会移除与指令码(如有)、地址、虚拟周期对应的输入数据,并以有效数据响应 AXI 读指令。

接口配置和读模式
AXI 读突发传输被转换为 SPI 闪存读指令,发送到控制器的 TxFIFO。发送逻辑从 TxFIFO 检索读指令,并根据 SPI 协议传递给 SPI 闪存设备。

软件通过写入 qspi.LQSPI_CFG [INST_CODE] 定义线性寻址模式中使用的 SPI 读命令。支持的读命令码和推荐的配置寄存器设置(qspi.LQSPI_CFG)如表 12-3 所示。使用 33MHz PS_CLK 时四通道 SPI 启动性能的最佳寄存器值如表 6-10 和表 12-3 所示。这些四通道 SPI 寄存器可在非安全模式下通过 BootROM 头中的寄存器初始化功能编程,以加快 FSBL / 用户代码的加载。若使用更快的 PS_CLK,需调整时钟分频器。

表 12-3:四通道 SPI 设备配置寄存器值

操作模式指令码Winbond & SpansionMicron
1 个设备2 个设备1 个设备2 个设备
读(串行位)0x030x800000030xE00000030x800000030xE0000003
快速读(串行位)0x0B0x8000010B0xE000010B0x8000010B0xE000010B
双输出快速读0x3B0x8000013B0xE000013B0x8000013B0xE000013B
四输出快速读0x6B0x8000016B0xE000016B0x8000016B0xE000016B
双 I/O 快速读0xBB0x82FF00BB0xE2FF00BB0x82FF01BB0xE2FF01BB
四 I/O 快速读0xEB0x82FF02EB0xE2FF02EB0x82FF04EB0xE2FF06EB

操作模式的选择取决于所连接设备的能力。I/O 快速读模式使用 4 位并行传输地址和数据,性能最快;输出快速读模式仅数据使用 4 位并行传输,仍比串行位模式快。

性能模式
要获得最高性能,用户应在四通道 I/O 模式下使用四通道 SPI 控制器,通过在连续读模式下使用四通道 SPI 设备可提高读性能,减少连续命令的读指令开销(详见附录 B “寄存器详情” 中的 LQSPI_CFG 寄存器)。

操作频率请参考适用的 Zynq-7000 AP SoC 数据手册。

读数据管理
63 深度的 RxFIFO 提供读数据缓冲,至少可容纳 3 个 16 字节的 AXI 突发传输长度。由于 RxFIFO 在片选信号激活后立即开始接收数据,线性地址适配器会移除与指令码(如有)、地址和虚拟周期对应的输入数据。

读数据必须与地址指定的相应字边界对齐,为实现数据对齐,控制器在将地址发送到闪存设备前可能会进行修改(如图 12-4 所示)。地址修改包括将地址减少最多 3 个字节位置,使返回数据自动按字对齐,地址变化量对 AXI 接口透明,且取决于指令。

(图 12-4:用于字对齐的自动地址偏移,此处省略图表)

例如,若 Cmd + 地址 + 模式 + 虚拟(QSPI 指令)未在 32 位边界结束,线性控制器会从地址中减去 1、2 或 3,以使数据在 32 位边界对齐。

读延迟
线性模式下,默认读模式为快速四通道 I/O。以下示例计算 100MHz 下四通道 I/O 模式(带 2 个虚拟字节)的内存延迟:对于单个设备,从 8 位指令码和 24 位地址可用到第一个 32 位数据可用的时钟周期数为:
总延迟 = 指令延迟 + 地址延迟 + 开销(模式 + 虚拟位 + 偏移)+8 个周期 = 30 周期 + 6 周期 + 8(2+4+2)周期 + 8 周期 = 30 周期
SPI 时钟为 100MHz 时,内存接口的延迟为 320ns。其他读模式的延迟更高,可按类似方式计算。

12.2.6 不支持的设备

一些设备采用自定义的 4 位宽类 SPI 接口用于闪存访问,如 SST 的 SQI 设备和 Atmel 的 Fast4 设备。其他一些四通道 SPI 设备(如某些 Micron/Numonyx 设备)通过非易失性配置位提供切换到此类自定义 4 位接口的选项。

这些接口与四通道 SPI 控制器支持的设备操作不同,它们在指令阶段以及地址和数据阶段均工作在 4 位模式,这要求四通道 SPI 闪存控制器上电后工作在 4 位模式并保持(或在有选项时可重新配置)。目前没有计划支持这些自定义接口。

12.2.7 支持的内存读写命令

支持在 SCK 上升沿每时钟传输 1 位地址,并在 SCK 上升沿每时钟返回 1、2 或 4 位数据的命令,包括 1 位数据的读或快速读、2 位数据的双输出读、4 位数据的四输出读。

支持在时钟上升沿每时钟传输 2 或 4 位地址和数据的命令,即 2 位的双 I/O 和 4 位的四 I/O。

表 12-4:内存读写命令

指令名称描述代码(十六进制)
READ读,时钟上升沿每时钟发送 1 位地址,SCLK 上升沿每时钟返回 1 位数据03
FAST_READ快速读,时钟上升沿每时钟发送 1 位地址,SCLK 上升沿每时钟返回 1 位数据0B
DOR双输出读,时钟上升沿每时钟发送 1 位地址,SCLK 上升沿每时钟返回 2 位数据3B
QOR四输出读,时钟上升沿每时钟发送 1 位地址,SCLK 上升沿每时钟返回 4 位数据6B
DIOR双 I/O 读,时钟上升沿每时钟发送 2 位地址,SCLK 上升沿每时钟返回 4 位数据BB
QIOR四 I/O 读,时钟上升沿每时钟发送 4 位地址,SCLK 上升沿每时钟返回 4 位数据EB
PP页编程,时钟上升沿每时钟发送 1 位地址,SCLK 上升沿每时钟发送 1 位数据02
QPP四页编程,时钟上升沿每时钟发送 1 位地址,SCLK 上升沿每时钟发送 4 位数据Spansion 和 Micron 设备为 32,Macronix 设备为 38

12.3 编程指南

示例:启动序列

  1. 配置时钟(参见 12.4.1 节 “时钟”)
  2. 配置 Tx/Rx 信号(参见 12.5.2 节 “MIO 编程”)
  3. 复位控制器(参见 12.4.2 节 “复位”)
  4. 配置控制器(参见 12.3.1 节 “配置”)
    之后,可将控制器配置为线性寻址模式(12.2.5 节 “线性寻址模式”)或 I/O 模式(12.3.3 节 “配置 I/O 模式” 和 12.3.4 节 “I/O 模式中断”)。

12.3.1 配置

示例:配置控制器
此示例适用于线性寻址和 I/O 模式,用于设置控制器的波特率、FIFO、闪存模式、时钟相位 / 极性,并编程回环延迟。

qspi.Config_reg 寄存器的编程值如表 12-3(344 页)所示。

  1. 配置控制器,写入 qspi.Config_reg 寄存器:
    a. 设置波特率 [BAUD_RATE_DIV]
    b. 选择主模式 [MCDE_SEL] = 1
    c. 选择闪存模式(非传统 SPI)[LEG_FLSH] = 1
    d. 选择小端模式 [endian] = 0
    e. 设置 FIFO 宽度为 32 位 [FIFO_WIDTH]
    f. 设置时钟相位 [CLK_PH] 和极性 [CLK_POL]
  2. 若波特率分频器为 2,需修改默认设置。若 qspi.Config_reg [BAUD_RATE_DIV] 设置为 0b00,按以下设置配置 qspi.LPBK_DLY_ADJ(回环延迟调整)寄存器:
    a. 选择内部时钟 qspi.LPBK_DLY_ADJ [USE_LPBK] = 1
    b. 设置时钟延迟 0 qspi.LPBK_DLY_ADJ [DLY0] = 0b00
    c. 设置时钟延迟 1 qspi.LPBK_DLY_ADJ [DLY1] = 0b00

12.3.2 线性寻址模式

示例:线性寻址模式(内存读取)
线性寻址模式下数据读取的操作序列如下:

  1. 设置手动启动使能为自动模式 qspi.Config_reg [Man_start_en] = 0
  2. 断言片选 qspi.Config_reg [PCS] = 0
  3. 编程线性寻址模式的配置寄存器(示例值如表 12-3(344 页)所示)
  4. 使能控制器 qspi.En_REG [SPI_EN] = 1
  5. 从线性地址内存区域读取数据,内存范围取决于设备数量和大小,范围从 0xFC00_0000 到 0xFDFF_FFFF
  6. 禁用控制器 qspi.En_REG [SPI_EN] = 0
  7. 撤销片选 qspi.Config_reg [PCS] = 1

12.3.3 配置 I/O 模式

示例:I/O 模式(内存读写)
使用 I/O 模式进行读写的操作序列:

  1. 使能手动模式,写入 1 到 qspi.Config_reg [Man_start_en, Manual_CS] = 1
  2. 配置闪存设备(参见 355 页图 12-6),单个闪存设备使用 qspi.LQSPI_CFG 寄存器的复位值,并行双闪存设备时,向 TWO_MEM、SEP_BUS 位域写入 1
  3. 断言片选 qspi.Config_reg [PCS] = 0
  4. 使能控制器 qspi.En_REG [SPI_EN] = 1
  5. 向闪存写入字节序列,使用 TXD 寄存器向 TxFIFO 写入 1 到 4 字节(参见 12.2.3 节 “I/O 模式发送寄存器(TXD)”)
  6. 避免 TxFIFO 溢出,TxFIFO 为空时可写入 252 字节,之后软件可通过读取 qspi.Intr_status_REG [TX_FIFO_full],等待其为 0 后再写入 TXD 寄存器
  7. 使能中断,写入 qspi.Intrpt_en_REG(中断处理程序参见中断处理程序部分)
  8. 开始数据传输 qspi.Config_reg [Man_start_com] = 1
  9. 中断处理程序:在四通道 SPI 闪存的编程 / 读取操作期间,将所有所需数据传输到 QSPI 闪存(参见 349 页 “示例:I/O 模式中断服务程序”)
  10. 若执行读取操作:重新排列读取数据,消除虚拟周期导致的读取数据
  11. 禁用控制器 qspi.En_REG [SPI_EN] = 0
  12. 撤销片选 QSPI.Config_reg [PCS] = 1

注意,TxFIFO 宽度必须编程为 32 位:qspi.Config_reg [FIFO_WIDTH] = 0b11,软件需处理 “连续非字对齐” 传输。

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

  1. 根据四通道 SPI 设备类型配置 ISR 以处理中断条件。要从四通道 SPI 设备读取,最简单的 ISR 从 RxFIFO 读取数据并写入 TxFIFO。系统中断控制器(GIC)在第 7 章 “中断” 中描述,控制器生成系统外设中断(SPI),IRQ ID#51。四通道 SPI 控制器的中断机制参见 12.3.4 节 “I/O 模式中断”。
    a. 读传输中断:RxFIFO 非空中断
    b. 写传输中断:TxFIFO 非满中断

12.3.4 I/O 模式中断

中断仅用于 I/O 模式,任何中断条件满足时,控制器都会断言中断。四通道 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
  3. 清空 RxFIFO,检查 RxFIFO 非空中断是否断言。若 qspi.Intr_status_REG [RX_FIFO_not_empty] = 1,则 RxFIFO 中有数据:
    a. 若状态断言,从 RxFIFO 读取数据,使用 qspi.RX_data_REG 寄存器
    b. 从 RxFIFO 读取数据并轮询中断状态,直到 RxFIFO 为空(qspi.Intr_status_REG [RX_FIFO_not_empty] = 0)
  4. 填充 TxFIFO,检查 TxFIFO 非满状态是否断言。若 qspi.Intr_status_REG [TX_FIFO_not_Full] = 1,则有数据要发送到闪存设备(编程和 / 或读取操作):
    a. 向 qspi.TXD0 寄存器写入数据
    b. 轮询 qspi.Intr_status_REG [TX_FIFO_full] = 1,指示 TX FIFO 已满
    c. 重复步骤 a 和 b,直到所有数据写入 TxFIFO 或 qspi.Intr_status_REG [TX_FIFO_full] = 1
  5. 使能中断,设置 qspi.Intrpt_en_REG [TX_FIFO_not_full, RX_FIFO_full] 均 = 1
  6. 开始数据传输,设置 qspi.Config_reg [MANSTRTEN] = 1

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

示例命令和序列

  • 写使能命令
  • 读状态命令
  • 读数据序列

示例中,YY 可为任意值,每个 YY 对可不同。

在串行传统模式下接收数据时,从 MISO/DQ1 线采样的值同步于时钟存入 RxFIFO,而命令和地址事务在 MOSI/DQ0 上进行。

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

  1. 发送写使能命令(WREN),向 qspi.TXD1 寄存器写入 0xYYYY_YY06:
    a. WREN 命令 = 0×06
    b. YY=0
    c. 控制器从 TxFIFO 向设备移出 1 个字节,并在 RxFIFO 接收 1 个字节
  2. 读状态,读取 qspi.RXD 寄存器接收 0xYYPP_PPPP:
    a. 当 YY=0×0(状态)且 PP_PPPP=0×0(位的先前状态)时,值为 0x0000_0000
    b. 软件记录写使能命令产生 1 个字节,并向调用函数返回 0xYY

发送 WREN 命令后 RxFIFO 的内容如下(“先前” 表示寄存器值未从之前的值改变):

RxFIFO 条目MSBLSB
1无效无效无效无效
000先前先前先前

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

  1. 发送读状态命令(RDSR),向 qspi.TXD2 寄存器写入 0xYYYY_DD05:
    a. 命令为 0x05,DD = 虚拟数据,YY=0
    b. 控制器从 TxFIFO 向闪存移出 2 个字节,并在 RxFIFO 接收 2 个字节
  2. 读状态值,从 qspi.RXD 寄存器读取 0xZZYY_PPPP:
    a. 当 ZZ=0×03、YY=0×0 且 PPPP=0x0 时,值为 0x0300_0000
    b. 软件记录 2 个字节有效,并向调用函数返回 0x00、0x03

发送 RDSR 命令后 RxFIFO 的内容如下(“先前” 表示寄存器值未从之前的值改变):

TxFIFO 条目MSBLSB
1无效无效无效无效
00x30x00先前先前

示例:读数据序列
此示例向调用函数返回地址 0 处的 4 个字节数据。

  1. 发送数据读取指令,向 qspi.TXD0 寄存器写入 0xA2A1_A003:
    a. 指令包括命令(0x03)和地址(A0、A1 和 A2)
  2. 发送虚拟数据,向 qspi.TXD0 寄存器(第二个 TxFIFO 条目)写入 0xD0D1_D2D3(虚拟数据):
    a. 控制器从 TxFIFO 向闪存移出 8 个字节,并在 RxFIFO 接收 8 个字节

本示例的 TxFIFO 内容如下,从控制器到设备的字节序列为:0x03、Y0、Y1、Y2、D0、D1、D2 和 D3。

TxFIFO 条目MSBLSB
1D3D2D1D0
0A2A1A00x03

  1. 读取指令字之后的内容,读取 qspi.RXD 寄存器接收 0xYYYY_YYYY:
    a. YY=0
  2. 读取闪存数据,再次读取 RXD 寄存器接收 0xD3D2_D1D0:
    a. 对于第二次读取,软件记录 4 个字节有效
    b. 示例数据:0x2468ACEF
    c. 软件总共读取这些字节:0x00、0x00、0x00、0x00、0x24、0x68、0xAC、0xEF,并向调用函数返回 4 个字节数据

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

RxFIFO 条目MSBLSB
10x240x680xAC0xEF
0YYYYYYYY

12.3.6 寄存器概述

寄存器概述如表 12-5 所示。

表 12-5:四通道 SPI 寄存器概述

地址偏移软件助记符名称描述
0x00Config_reg配置
0x04Intr_status_REG中断状态
0x08Intrpt_en_REG中断使能
0x0CIntrpt_dis_REG中断禁用
0x10Intrpt_mask_REG中断掩码
0x14En_REG控制器使能
0x18Delay_REG延迟
0x1CTXD0传输 1 字节命令和 3 字节数据或 4 字节数据
0x20Rx_data_REG接收数据(RxFIFO)
0x24Slave_Idle_count_REG从机空闲计数
0x28TX_thres_REGTxFIFO 阈值水平(4 字节字)
0x2CRX_thres_REGRxFIFO 阈值水平(4 字节字)
0x30GPIO通用输入输出
0x38LPBK_DLY_ADJ回环主时钟延迟调整
0x80TXD1传输 1 字节命令
0x84TXD2传输 1 字节命令和 1 字节数据
0x88TXD3传输 1 字节命令和 2 字节数据
0xA0LQSPI_CFG线性模式配置
0xA4LQSPI_STS线性模式状态
0xFCMOD_ID模块 ID

12.4 系统功能

12.4.1 时钟

控制器和 I/O 接口由参考时钟(QSPI_REF_CLK)驱动,控制器的互连还需要 APB 接口 CPU_1x 时钟,这些时钟由 PS 时钟子系统生成。

CPU_1x 时钟
通用时钟编程信息参见 25.2 节 “CPU 时钟”,CPU_1x 时钟与四通道 SPI 参考时钟异步运行。

QSPI_REF_CLK 和四通道 SPI 接口时钟
QSPI_REF_CLK 是主控制器时钟,源自 PS 时钟子系统。时钟使能、PLL 选择和分频器设置通过 slcr.LQSPI_CLK_CTRL 寄存器编程,四通道 SPI 参考时钟频率的编程参见 25.6.3 节 “SDIO、SMC、SPI、四通道 SPI 和 UART 时钟”。

四通道 SPI 接口时钟由 QSPI_REF_CLK 通过 qspi.Config_reg [BAUD_RATE_DIV] 位域分频得到,分频系数为 2、4、8、16、32、64、128 或 256。

为进行电源管理,可使用 slcr 寄存器中的时钟使能关闭时钟,参考时钟的工作频率在数据手册中定义。

手动模式下的时钟比率限制
手动模式下,为保证控制器可靠运行,QSPI_REF_CLK 频率必须大于或等于 CPU_1x 时钟频率。

自动模式下无此限制,参考时钟通过 qspi.Config_reg [baud_rate_divisor] 分频生成闪存的 SCLK 时钟。

示例:设置参考时钟
假设所选 PLL(ARM、DDR 或 IO)工作在 1000MHz,期望的四通道 SPI 参考时钟频率为 200MHz。

  1. 选择 PLL 源、分频器并使能,向 slcr.QSPI_CLK_CTRL 寄存器写入 0x0000_0501:
    a. 使能参考时钟
    b. 将 I/O PLL 时钟分频 5:DIVISOR=0×05
    c. 选择 I/O PLL 作为时钟源

四通道 SPI 反馈时钟
四通道 SPI 接口支持名为 qspi_sclk_fb_out 的可选反馈时钟引脚,用于高速四通道 SPI 时序模式(内存接口时钟需大于 40MHz)。反馈信号来自 I/O 内部输入,因此需要编程 MIO 引脚 8 并允许其自由切换。编程 MIO_PIN_08 寄存器的可选编程示例参见 12.5.2 节 “MIO 编程”。

使用四通道 SPI 反馈模式时,qspi_sclk_fb_out 引脚应仅连接到上拉或下拉电阻,以设置 MIO 电压模式(vmode)。

当四通道 SPI 时钟频率大于 FQSPICLK2 时,必须将 MIO 8 引脚编程为反馈输出时钟,且 MIO 8 引脚在 PCB 上仅连接到用于引导的上拉 / 下拉电阻。

12.4.2 复位

控制器有两个复位域:APB 接口和控制器本身,可一起或独立控制。每种复位类型的影响总结如表 12-6 所示。

表 12-6:四通道 SPI 复位影响

名称APB 接口TxFIFO 和 RxFIFO协议引擎寄存器
ABP 接口复位 slcr.LQSPI_RST_CTRL [LQSPI_CPU1X_RST]
PS 复位子系统 slcr.LQSPI_RST_CTRL [QSPI_REF_RST]

示例:复位 APB 接口和四通道 SPI 控制器

  1. 设置控制器复位,向 slcr.LQSPI_RST_CTRL [QSPI_REF_RST 和 LQSPI_CPU1X_RST] 位域写入 1
  2. 清除控制器复位,向 slcr.LQSPI_RST_CTRL [QSPI_REF_RST 和 LQSPI_CPU1X_RST] 位域写入 0

12.5 I/O 接口

12.5.1 接线连接

I/O 信号通过 MIO 引脚可用,四通道 SPI 控制器支持最多两个 SPI 闪存,采用共享或独立总线配置,支持多种配置:

  • 四通道 SPI 单 SS,4 位 I/O
  • 四通道 SPI 双 SS,8 位并行 I/O
  • 四通道 SPI 双 SS,4 位堆叠 I/O
  • 四通道 SPI 单 SS,传统 I/O

重要提示:若要使用 QSPI 内存子系统,QSPI 0 必须存在;QSPI 1 为可选,仅在双内存配置时需要,因此不能单独使用 QSPI_1。

单 SS,4 位 I/O
4 位闪存接口连接到控制器配置的框图如图 12-5 所示。

(图 12-5:四通道 SPI 单 SS 4 位 I/O,此处省略图表)

双 SS,8 位并行
控制器支持最多两个 SPI 闪存并行工作,如图 12-6 所示。此配置将最大可寻址 SPI 闪存从 16MB(24 位寻址)增加到 32MB(25 位寻址)。

(图 12-6:四通道 SPI 双 SS,8 位并行 I/O,此处省略图表)

对于 8 位并行配置,数据字的偶数位位于低内存,奇数位位于高内存,控制器在 I/O 和线性模式下均处理数据管理。四通道 SPI 控制器从两个四通道 SPI 设备读取数据,并在将状态数据写入 RXFIFO 之前对两个设备的状态信息执行 OR 操作。表 12-7 显示 8 位并行配置下 32 位数据字的数据位排列,表 12-8 显示双四通道 SPI 并行模式下的四通道 SPI CMD 行为。

表 12-7:四通道 SPI 双 SS,8 位并行 I/O 数据管理

(此处省略复杂表格结构,保留原数据逻辑)

表 12-8:双四通道 SPI 并行模式下的四通道 SPI CMD 行为

命令双并行四通道 SPI 控制器行为
扇区擦除四通道 SPI 控制器向两个芯片发送擦除命令,每个部分执行 64KB 擦除操作,实际从两个存储器共擦除 128KB
读 ID仅从低闪存总线接收数据并放入 RXD,因此无需组合数据,使用并行闪存模式时,上下闪存必须为相同部件
页编程分离偶数和奇数位并在两个存储器中编程,详见表 12-7
从两个设备读取偶数和奇数数据位,并按表 12-7 所示交织
RDSR两个部分的 WIP 位相或形成读取数据的 LSB,其他 7 位仅来自低总线

8 位并行配置下,总可寻址内存大小为 32MB,需要 25 位地址。所有内存访问必须字对齐并具有双字节分辨率。线性模式下,四通道 SPI 控制器将 AXI 地址除以 2,并将得到的地址发送到四通道 SPI 设备;I/O 模式下,软件负责执行地址转换以支持 SPI 24 位地址。

双 SS,4 位堆叠 I/O
为减少 I/O 引脚数,控制器还支持最多两个 SPI 闪存采用共享总线配置,如图 12-7 所示。此配置将最大可寻址 SPI 闪存从 16MB(24 位寻址)增加到 32MB(25 位寻址),但吞吐量与单内存模式相同。注意,此配置不支持设备级 XIP 模式(读指令码 0xbb 和 0xeb)。

(图 12-7:四通道 SPI 双 SS 4 位堆叠 I/O,此处省略图表)

若使用线性四通道 SPI 内存子系统,低 SPI 闪存必须连接,高闪存为可选。总地址空间为 32MB,采用 25 位地址。I/O 模式下,地址的 MSB 由位于寄存器 0xA0 的位 28 的 U_PAGE 定义;线性地址模式下,AXI 地址位 24 决定高或低内存页。所有命令由 I/O 模式下 U_PAGE 选择的设备和线性模式下地址位 24 选择的设备执行。

单 SS,传统 I/O
四通道 SPI 控制器可工作在传统单比特串行接口模式,支持 1x、2x 和 4x I/O 模式,如图 12-8 所示。

(图 12-8:四通道 SPI 单 SS,传统 I/O,此处省略图表)

12.5.2 MIO 编程

四通道 SPI 信号可路由到特定 MIO 引脚,参见表 12-9 “四通道 SPI 接口信号”,接线图如图 12-5 至图 12-8 所示。通用路由概念和 MIO I/O 缓冲器配置在 2.4 节 “PS–PL 电压电平转换器使能” 中说明。

若使用 4 位 I/O 总线,使用四通道 SPI 0;若总线频率大于 40MHz,必须将四通道 SPI 反馈时钟路由到 MIO 引脚 8。

示例:为单个设备编程 I/O
以下步骤适用于上述所有四通道 SPI I/O 接口连接:

  1. 配置 MIO 引脚 1 为片选 0 输出,向 slcr.MIO_PIN_01 寄存器写入 0x0000_1202:
    a. 将四通道 SPI 0 片选路由到引脚 1
    b. 三态由四通道 SPI 控制(TRI_ENABLE = 0)
    c. LVCMOS18(其他电压选项参见寄存器定义)
    d. 慢 CMOS 边沿(温和设置)
    e. 使能内部上拉电阻
    f. 禁用 HSTL 接收器(因选择 LVCMOS)
  2. 配置 MIO 引脚 2 至 5 为 I/O,向每个 slcr.MIO_PIN_{02:05} 寄存器写入 0x0000_0302:
    a. 将四通道 SPI 0 I/O 引脚路由到引脚 2 至 5
    b. 三态由四通道 SPI 控制(TRI_ENABLE = 0)
    c. LVCMOS18(其他电压选项参见寄存器定义)
    d. 慢 CMOS 驱动边沿
    e. 禁用内部上拉电阻
    f. 禁用 HSTL 接收器
  3. 配置 MIO 引脚 6 为串行时钟 0 输出,向 slcr.MIO_PIN_06 寄存器写入 0x0000_0302:
    a. 将四通道 SPI 0 串行时钟路由到引脚 6
    b. 三态由四通道 SPI 控制(TRI_ENABLE = 0)
    c. LVCMOS18(其他电压选项参见寄存器定义)
    d. 慢 CMOS 边沿(温和设置)
    e. 禁用内部上拉电阻
    f. 禁用 HSTL 接收器

选项:添加第二个设备片选
以下 I/O 连接需要此步骤:

  • 双选择,共享 4 位数据内存接口
  • 双选择,独立 4 位数据内存接口

  1. 配置 MIO 引脚 0 为片选 1 输出,向 slcr.MIO_PIN_00 寄存器写入 0x0000_1302:
    a. 将四通道 SPI 1 片选路由到引脚 0
    b. 三态由四通道 SPI 控制(TRI_ENABLE = 0)
    c. LVCMOS18(其他电压选项参见寄存器定义)
    d. 慢 CMOS 边沿(温和设置)
    e. 使能内部上拉电阻
    f. 禁用 HSTL 接收器

选项:添加第二个串行时钟
双选择、独立 4 位数据内存接口需要此步骤:
5. 配置 MIO 引脚 9 为串行时钟 1 输出,向 slcr.MIO_PIN_09 寄存器写入 0x0000_0302:
a. 将四通道 SPI 1 串行时钟路由到引脚 9
b. 三态由四通道 SPI 控制(TRI_ENABLE = 0)
c. LVCMOS18(其他电压选项参见寄存器定义)
d. 慢 CMOS 边沿(温和设置)
e. 禁用内部上拉电阻
f. 禁用 HSTL 接收器

选项:添加 4 位数据
双选择、独立 4 位数据内存接口需要以下步骤:
6. 配置 MIO 引脚 10 至 13 为 I/O,向每个 slcr.MIO_PIN_{10:13} 寄存器写入 0x0000_0302:
a. 将四通道 SPI 1 I/O 引脚路由到引脚 9 至 13
b. 三态由四通道 SPI 控制(TRI_ENABLE = 0)
c. LVCMOS18(其他电压选项参见寄存器定义)
d. 慢 CMOS 驱动边沿
e. 禁用内部上拉电阻
f. 禁用 HSTL 接收器

选项:添加反馈输出时钟
I/O 接口工作在 40MHz 以上时使用可选反馈时钟,为设置 MIO 电压模式(vmode),它应仅连接到上拉或下拉电阻,还必须使能反馈时钟。
7. 配置 MIO 引脚 8 为反馈时钟,向 slcr.MIO_PIN_08 寄存器写入 0x0000_0302:
a. 将四通道 SPI 反馈时钟输出路由到引脚 8
b. 三态由四通道 SPI 控制(TRI_ENABLE = 0)
c. LVCMOS18(其他电压选项参见寄存器定义)
d. 慢 CMOS 边沿(温和设置)
e. 禁用内部上拉电阻
f. 禁用 HSTL 接收器

12.5.3 MIO 信号

四通道 SPI 闪存信号通过 MIO 多路复用器路由到 MIO 设备引脚,双控制器端口的每一侧可单独使能,或一起作为 8 位 I/O 接口工作。

四通道 SPI 闪存信号路由到 MIO 引脚如表 12-9 所示。

表 12-9:四通道 SPI 接口信号

四通道 SPI 闪存接口数据 I/O 模式MIO 引脚控制器默认输入值
信号1 位数据2 位数据4 位数据四通道 SPI 0四通道 SPI 1I/O名称
闪存片选~~~10OQSPI{1,0}_SS_B~
串行时钟~~~69OQSPI{1,0}_SCLK~
输出反馈时钟~~~8OQSPI_SCLK_FB_OUT~
I/O 0主输出I/O 0I/O 0210IOQSPI{1,0}_IO_00
I/O 1主输入I/O 1I/O 1311IOQSPI{1,0}_IO_10
I/O 2写保护写保护I/O 2412IOQSPI{1,0}_IO_20
I/O 3保持保持I/O 3513IOQSPI{1,0}_IO_30

你可以将以上内容复制到 Word 文档中,Word 会自动识别部分格式,若有表格错乱等情况,可手动调整表格边框和行列对齐方式以确保格式正确。

示例 1:启动序列(适用于所有模式初始化)

  1. 配置时钟:参考 12.4.1 节 “Clocks” 配置 QSPI_REF_CLK 和 CPU_1x 时钟。
  2. 配置 Tx/Rx 信号:参考 12.5.2 节 “MIO Programming” 设置 MIO 引脚(如片选、时钟、I/O 引脚)。
  3. 复位控制器:通过 slcr.LQSPI_RST_CTRL 寄存器设置并清除复位(先写 1 再写 0 到 [QSPI_REF_RST] 和 [LQSPI_CPU1X_RST] 位域)。
  4. 配置控制器:参考 12.3.1 节设置波特率、FIFO 宽度、时钟相位等(见示例 2)。
  5. 选择工作模式:后续可配置为线性寻址模式或 I/O 模式。

示例 2:配置控制器(适用于线性和 I/O 模式)

  1. 配置qspi.Config_reg寄存器:
    • 设置波特率分频:[BAUD_RATE_DIV](如分频系数 2、4 等)。
    • 选择主模式:[MCDE_SEL] = 1
    • 选择闪存模式(非传统 SPI):[LEG_FLSH] = 1
    • 选择小端模式:[endian] = 0
    • 设置 FIFO 宽度为 32 位:[FIFO_WIDTH](具体值参考寄存器定义)。
    • 设置时钟相位和极性:[CLK_PH][CLK_POL]
  2. 若波特率分频器为 2([BAUD_RATE_DIV] = 0b00),配置qspi.LPBK_DLY_ADJ寄存器:
    • 选择内部时钟:[USE_LPBK] = 1
    • 设置时钟延迟:[DLY0] = 0b00[DLY1] = 0b00

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

  1. 设置手动启动使能为自动模式:qspi.Config_reg[Man_start_en] = 0
  2. 断言片选:qspi.Config_reg[PCS] = 0
  3. 编程线性模式配置寄存器:参考表 12-3 设置qspi.LQSPI_CFG(如四 I/O 快速读指令 0xEB 对应的值)。
  4. 使能控制器:qspi.En_REG[SPI_EN] = 1
  5. 读取数据:从线性地址区域(0xFC00_0000 至 0xFDFF_FFFF)读取数据。
  6. 禁用控制器:qspi.En_REG[SPI_EN] = 0
  7. 撤销片选:qspi.Config_reg[PCS] = 1

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

  1. 启用手动模式:qspi.Config_reg[Man_start_en, Manual_CS] = 1
  2. 配置闪存设备:单设备用qspi.LQSPI_CFG复位值;双设备并行时,设置TWO_MEMSEP_BUS位。
  3. 断言片选:qspi.Config_reg[PCS] = 0
  4. 使能控制器:qspi.En_REG[SPI_EN] = 1
  5. 写入数据:通过 TXD0-TXD3 寄存器向 TxFIFO 写入 1-4 字节(如命令、地址、数据)。
  6. 避免 FIFO 溢出:通过qspi.Intr_status_REG[TX_FIFO_full]判断 TxFIFO 状态,为空时再写入。
  7. 使能中断:写入qspi.Intrpt_en_REG使能 TxFIFO 非满和 RxFIFO 非空中断。
  8. 开始传输:qspi.Config_reg[Man_start_com] = 1
  9. 处理数据:读操作需过滤 RxFIFO 中的虚拟数据;写操作等待传输完成。
  10. 禁用控制器并撤销片选:qspi.En_REG[SPI_EN] = 0qspi.Config_reg[PCS] = 1

示例 5:I/O 模式中断服务程序(处理 Rx/Tx)

  1. 禁用中断:qspi.Intrpt_dis_REG[TX_FIFO_not_full, RX_FIFO_full] = 1
  2. 清除中断:读取qspi.Intr_status_REG
  3. 清空 RxFIFO:若qspi.Intr_status_REG[RX_FIFO_not_empty] = 1,通过qspi.RX_data_REG读取数据,直到 FIFO 为空。
  4. 填充 TxFIFO:若qspi.Intr_status_REG[TX_FIFO_not_full] = 1,通过qspi.TXD0写入数据,直到 FIFO 满或数据写完。
  5. 使能中断:qspi.Intrpt_en_REG[TX_FIFO_not_full, RX_FIFO_full] = 1
  6. 启动传输:qspi.Config_reg[MANSTRTEN] = 1

示例 6:FIFO 响应命令序列(以读数据为例)

  1. 发送读指令:向qspi.TXD0写入0xA2A1_A003(含命令 0x03 和地址 A0-A2)。
  2. 发送虚拟数据:向qspi.TXD0写入0xD0D1_D2D3(提供时钟用于接收数据)。
  3. 读取无效数据:第一次读qspi.RXD获取0xYYYY_YYYY(虚拟数据对应的接收值)。
  4. 读取有效数据:第二次读qspi.RXD获取实际闪存数据(如0x2468ACEF)。

以下是基于文档内容整理的完整编程实例(含伪代码及注释),涵盖初始化、线性寻址模式、I/O 模式及中断处理等场景:

一、启动序列初始化(适用于所有模式)

c

运行

/* 参考文档12.3节启动序列:1-179至1-184 */
void qspi_init() {// 1. 配置时钟(参考12.4.1节时钟配置:1-322至1-347)// 示例:设置QSPI_REF_CLK为200MHz(源I/O PLL 1000MHz,分频5)slcr.LQSPI_CLK_CTRL = 0x00000501;  // 使能时钟,选择I/O PLL,分频5 // 2. 配置MIO引脚(参考12.5.2节MIO编程:1-419至1-496)// 配置片选0(MIO1)、I/O引脚(MIO2-5)、时钟0(MIO6)slcr.MIO_PIN_01 = 0x00001202;  // 片选0输出,LVCMOS18,上拉 slcr.MIO_PIN_02 = 0x00000302;  // I/O0,LVCMOS18 slcr.MIO_PIN_03 = 0x00000302;  // I/O1,LVCMOS18slcr.MIO_PIN_04 = 0x00000302;  // I/O2,LVCMOS18slcr.MIO_PIN_05 = 0x00000302;  // I/O3,LVCMOS18slcr.MIO_PIN_06 = 0x00000302;  // 串行时钟0输出 // 3. 复位控制器(参考12.4.2节复位:1-355至1-361)slcr.LQSPI_RST_CTRL = (1 << QSPI_REF_RST) | (1 << LQSPI_CPU1X_RST);  // 置位复位slcr.LQSPI_RST_CTRL = 0;  // 清除复位 // 4. 配置控制器核心参数(参考12.3.1节配置:1-185至1-200)qspi.Config_reg = 0x00000000;qspi.Config_reg |= (0x02 << BAUD_RATE_DIV);  // 波特率分频(示例:4分频)qspi.Config_reg |= (1 << MCDE_SEL);  // 主模式qspi.Config_reg |= (1 << LEG_FLSH);  // 闪存模式(非传统SPI)qspi.Config_reg &= ~(1 << endian);  // 小端模式qspi.Config_reg |= (0b11 << FIFO_WIDTH);  // 32位FIFO宽度 qspi.Config_reg |= (0 << CLK_PH) | (0 << CLK_POL);  // 时钟相位/极性// 若波特率分频为2,配置回环延迟(示例:分频为2时)if ((qspi.Config_reg & (0b11 << BAUD_RATE_DIV)) == 0) {qspi.LPBK_DLY_ADJ = (1 << USE_LPBK) | (0 << DLY0) | (0 << DLY1); }
}

二、线性寻址模式(内存读取)

c

运行

/* 参考12.3.2节线性模式:1-206至1-215 */
void qspi_linear_read(uint32_t addr, uint32_t *buf, uint32_t len) {// 1. 配置自动模式及片选qspi.Config_reg &= ~(1 << Man_start_en);  // 自动启动 qspi.Config_reg &= ~(1 << PCS);  // 断言片选 // 2. 配置线性模式指令(示例:四I/O快速读0xEB,单设备)qspi.LQSPI_CFG = 0x82FF02EB;  // 参考表12-3 // 3. 使能控制器qspi.En_REG |= (1 << SPI_EN);  // 使能QSPI // 4. 从线性地址区域读取数据(0xFC000000至0xFDFFFFFF)uint32_t *qspi_addr = (uint32_t *)(0xFC000000 + addr); for (uint32_t i = 0; i < len; i++) {buf[i] = qspi_addr[i];  // 像访问普通内存一样读取}// 5. 禁用控制器及片选qspi.En_REG &= ~(1 << SPI_EN);  // 禁用QSPI qspi.Config_reg |= (1 << PCS);  // 撤销片选 
}

三、I/O 模式(读写操作)

3.1 I/O 模式初始化及写操作

c

运行

/* 参考12.3.3节I/O模式:1-216至1-230 */
void qspi_io_write(uint8_t *cmd, uint32_t cmd_len, uint8_t *data, uint32_t data_len) {// 1. 配置手动模式qspi.Config_reg |= (1 << Man_start_en) | (1 << Manual_CS);  // 手动启动+片选 // 2. 配置双设备(若需):单设备无需此步// qspi.LQSPI_CFG |= (1 << TWO_MEM) | (1 << SEP_BUS); // 3. 断言片选qspi.Config_reg &= ~(1 << PCS);  // 片选使能 // 4. 使能控制器qspi.En_REG |= (1 << SPI_EN); // 5. 写入命令(通过TXD寄存器,参考12.2.3节TXD:1-92至102)for (uint32_t i = 0; i < cmd_len; i += 4) {uint32_t txd_data = 0;// 填充4字节数据(不足补0)for (int j = 0; j < 4 && (i + j) < cmd_len; j++) {txd_data |= (cmd[i + j] << (8 * j));}qspi.TXD0 = txd_data;  // 使用TXD0发送命令 }// 6. 写入数据(避免FIFO溢出)for (uint32_t i = 0; i < data_len; i += 4) {// 等待TxFIFO非满while (qspi.Intr_status_REG & (1 << TX_FIFO_full)); uint32_t txd_data = 0;for (int j = 0; j < 4 && (i + j) < data_len; j++) {txd_data |= (data[i + j] << (8 * j));}qspi.TXD0 = txd_data;}// 7. 使能中断(用于后续传输完成通知)qspi.Intrpt_en_REG |= (1 << TX_FIFO_not_full) | (1 << RX_FIFO_not_empty); // 8. 启动传输qspi.Config_reg |= (1 << Man_start_com); // 9. 等待传输完成(通过中断或轮询)while (qspi.Intr_status_REG & (1 << TX_FIFO_not_empty));  // 示例:轮询// 10. 禁用控制器及片选qspi.En_REG &= ~(1 << SPI_EN); qspi.Config_reg |= (1 << PCS); 
}
3.2 I/O 模式读操作(含 FIFO 处理)

c

运行

/* 参考12.3.5节读数据序列:1-296至310 */
void qspi_io_read(uint8_t *cmd, uint32_t cmd_len, uint8_t *buf, uint32_t data_len) {// 1. 同写操作步骤1-4:配置手动模式、片选、使能控制器// ...(省略重复代码)// 2. 写入读命令和地址(示例:命令0x03 + 地址A0-A2)qspi.TXD0 = (0x03) | (A2 << 24) | (A1 << 16) | (A0 << 8); // 3. 写入虚拟数据(用于接收闪存数据,长度=数据长度)for (uint32_t i = 0; i < data_len; i += 4) {while (qspi.Intr_status_REG & (1 << TX_FIFO_full));qspi.TXD0 = 0xDDDDDDDD;  // 虚拟数据 }// 4. 启动传输qspi.Config_reg |= (1 << Man_start_com);// 5. 读取RxFIFO(过滤虚拟数据对应的无效值)uint32_t rx_idx = 0;while (rx_idx < data_len) {while (!(qspi.Intr_status_REG & (1 << RX_FIFO_not_empty)));  // 等待接收数据uint32_t rxd_data = qspi.RX_data_REG;  // 读取FIFO // 提取有效字节(忽略前4字节无效值,参考1-304至308)for (int j = 0; j < 4 && rx_idx < data_len; j++) {buf[rx_idx++] = (rxd_data >> (8 * j)) & 0xFF;}}// 6. 禁用控制器及片选(同写操作步骤10)// ...
}

四、I/O 模式中断服务程序(ISR)

c

运行

/* 参考12.3.4节中断处理:1-238至1-256 */
void qspi_isr() {// 1. 禁用中断qspi.Intrpt_dis_REG |= (1 << TX_FIFO_not_full) | (1 << RX_FIFO_not_empty); // 2. 清除中断状态uint32_t intr_status = qspi.Intr_status_REG;  // 读状态自动清除 // 3. 处理接收数据if (intr_status & (1 << RX_FIFO_not_empty)) {while (qspi.Intr_status_REG & (1 << RX_FIFO_not_empty)) {uint32_t data = qspi.RX_data_REG;  // 读取RxFIFO // 存储数据到缓冲区...}}// 4. 处理发送数据if (intr_status & (1 << TX_FIFO_not_full)) {while ((qspi.Intr_status_REG & (1 << TX_FIFO_full)) == 0 && has_more_data()) {qspi.TXD0 = get_next_tx_data();  // 填充TxFIFO }}// 5. 重新使能中断qspi.Intrpt_en_REG |= (1 << TX_FIFO_not_full) | (1 << RX_FIFO_not_empty); // 6. 启动传输(若需)qspi.Config_reg |= (1 << MANSTRTEN); 
}

五、常用命令序列示例(写使能、读状态)

5.1 写使能命令(WREN, 0x06)

c

运行

/* 参考12.3.5节写使能:1-270至279 */
void qspi_write_enable() {// 配置I/O模式(同前)// ...// 发送写使能命令(使用TXD1寄存器,1字节命令)qspi.TXD1 = 0x00000006;  // TXD1格式:仅最低字节有效 // 启动传输并等待完成qspi.Config_reg |= (1 << Man_start_com);while (qspi.Intr_status_REG & (1 << TX_FIFO_not_empty));
}
5.2 读状态命令(RDSR, 0x05)

c

运行

/* 参考12.3.5节读状态:1-280至295 */
uint8_t qspi_read_status() {// 配置I/O模式(同前)// ...// 发送读状态命令(TXD2:1字节命令+1字节虚拟数据)qspi.TXD2 = 0x0000DD05;  // DD为虚拟数据 // 启动传输qspi.Config_reg |= (1 << Man_start_com);// 读取状态(RxFIFO中第二字节有效)while (!(qspi.Intr_status_REG & (1 << RX_FIFO_not_empty)));uint32_t status = qspi.RX_data_REG;return (status >> 8) & 0xFF;  // 有效状态在次低字节 
}

说明

  1. 代码中寄存器名称(如qspi.Config_regslcr.LQSPI_CLK_CTRL)及位域(如BAUD_RATE_DIV)均来自文档 12.3.6 节寄存器概述(1-317 至 320)及对应配置说明。
  2. 数值配置(如0x82FF02EB)参考文档表 12-3(1-138)及示例步骤。
  3. 实际使用时需根据硬件环境调整地址、数据长度等参数,中断处理需结合系统中断控制器(如 GIC,IRQ ID#51)。
http://www.dtcms.com/a/343191.html

相关文章:

  • 深度剖析字节跳动VeOmni框架
  • MySQL索引优化之索引条件字段类型不同
  • POI读和写
  • C2ComponentStore
  • CMOS知识点 MOS管线性区电流公式
  • Linux 网络命令大全
  • 在VSCode中配置.NET项目的tasks.json以实现清理、构建、热重载和发布等操作
  • vue2 watch 用法
  • K8s安全管理与持久化存储实战指南
  • Seaborn数据可视化实战:Seaborn入门-环境搭建与基础操作
  • Seaborn数据可视化实战
  • AI对口型唱演:科技赋能,开启虚拟歌者新篇章
  • 刷机维修进阶教程-----如何清除云账号 修复wifi 指南针 相机 指纹等刷机故障
  • 自然处理语言NLP:One-Hot编码、TF-IDF、词向量、NLP特征输入、EmbeddingLayer实现、word2vec
  • Linux 802.11协议栈深度分析与实践指南
  • 车机两分屏运行Unity制作的效果
  • OpenAI重新开源!gpt-oss-20b适配昇腾并上线魔乐社区
  • WebSocket连接的例子
  • 链游开发新篇章:融合区块链技术的游戏创新与探索
  • 什么是撮合引擎
  • 模型的量化-nf4和pf4
  • 基于STM32F103单片机智能门禁热释人体感应报警设计
  • C#串口单例 + 端口复用
  • LCD DMA day59
  • 为何vivo做了头显,小米却选择AI眼镜
  • 【GNSS基带算法】Chapter.2 相干积分与非相干积分
  • 基于 .NET Core Web API 请求 Nacos 配置中心的最佳实践
  • 微服务01-微服务架构:Java中的最佳实践
  • 业务扩展字段系统设计理念与流程图
  • LeetCode_动态规划