文章目录
- 22.1 SPI 协议简介
- 22.1.1 SPI物理层
- 22.1.2 协议
- 22.1.3 CPOL/CPHA 及通讯模式
- 22.1.4 扩展 SPI 协议
- 22.1.5 SDR 和 DDR 模式
- 22.2 RT1052 的 FlexSPI 特性及架构
- 22.2.1 RT1052 的 FlexSPI 外设简介
- 22.2.2 RT1052 的 FlexSPI 架构剖析
- 22.2.2.1 通讯引脚
- 22.2.2.2 指令查找表 LUT
- 22.2.2.3 命令仲裁器
- 22.2.2.4 IP 命令控制逻辑
- 22.2.2.5 AHB 命令控制逻辑
- 22.2.2.6 驱动时钟
- 22.3 FlexSPI 初始化配置结构体
22.1 SPI 协议简介
22.1.1 SPI物理层
SPI 通讯使用 3 条总线及片选线,3 条总线分别为 SCK、MOSI、MISO。
SS( Slave Select)片选信号线,也称为 NSS、CS
- 每个从设备都有独立的这一条 NSS 信号线
- 当主机要选择从设备时,把该从设备的 NSS 信号线设置为低电平
SCK (Serial Clock):时钟信号线,用于通讯数据同步。
- 它由通讯主机产生,决定了通讯的速率,不同的设备支持的最高时钟频率不一样
22.1.2 协议
SPI 使用 MOSI 及 MISO 信号线来传输数据,使用 SCK 信号线进行数据同步。
- MOSI 及 MISO 数据线在 SCK 的每个时钟周期传输一位数据,且数据输入输出是同时进行的。
- 一般都会采用MSB 先行模式。
- 数据在 SCK 的上升沿期间变化输出,在 SCK 的下降沿时被采样。
- SPI 每次数据传输可以 8 位或 16 位为单位,每次传输的单位数不受限制。
22.1.3 CPOL/CPHA 及通讯模式
SPI 一共有四种通讯模式,它们的主要区别是总线空闲时 SCK 的时钟状态以及数据采样时刻。
- 时钟极性 CPOL 是指 SPI 通讯设备处于空闲状态时,SCK 信号线的电平信号。CPOL=0 时,SCK 在空闲状态时为低电平,CPOL=1 时,则相反。
- 时钟相位 CPHA 是指数据的采样的时刻
- 当 CPHA=0 时,MOSI 或 MISO 数据线上的信号将会在SCK 时钟线的“奇数边沿”被采样。
- 当 CPHA=1 时,数据线在 SCK 的“偶数边沿”采样。
由 CPOL 及 CPHA 的不同状态,SPI 分成了四种模式。实际中采用较多的是“模式 0”与“模式 3”。
22.1.4 扩展 SPI 协议
为了适应更高速率的通讯需求,半导体厂商扩展 SPI 协议,主要发展出了 Dual/Quad/Octal SPI 协议,加上标准 SPI 协议(Single SPI),这四种协议的主要区别是数据线的数量及通讯方式
扩展的三种 SPI 协议都是半双工的通讯方式,也就是说它们的数据线是分时进行收发数据的。
- 双线 SPI(Dual SPI)的两根线都具有收发功能,但在同一时刻只能是发送或者是接收
- 四线 SPI(Quad SPI)和八线 SPI(Octal SPI)与双线 SPI(Dual SPI)类似,只是数据线量的区别。
22.1.5 SDR 和 DDR 模式
SDR 模式(单倍速率 Single Data Rate)和 DDR 模式(双倍速率 DoubleData Rate)。
- 在标准 SPI 协议的 SDR 模式下,只在 SCK 的单边沿进行数据传输,即一个 SCK时钟只传输一位数据
- 在它 DDR 模式下,会在 SCK 的上升沿和下降沿都进行数据传输,即一个 SCK 时钟能传输两位数据,传输速率提高一倍。
22.2 RT1052 的 FlexSPI 特性及架构
RT1052 芯片也集成了专门用于 SPI 协议通讯的外设 FlexSPI、LPSPI
- LPSPI 主要定位于通用的 SPI 通讯
- FlexSPI 外设除了支持 SPI 通讯外还提供了很多与存储器相关的特性,所以 FlexSPI 外设通常用于与使用 SPI 协议的存储设备进行通讯。
22.2.1 RT1052 的 FlexSPI 外设简介
NXP 以 Flex 形容它的 SPI 外设是因为它使用起来非常灵活
- Single/Dual/Quad/Octal 模式的传输(即 1/2/4/8 根数据线的传输)
- 支持 SDR/DDR 通讯模式
- 在 SDR 模式下,它仅支持 SPI 中的模式 0(CPOL=0,CPHA=0)
- 支持控制 SPI 接口的串行 NOR/NAND Flash 设备、HyperBus 协议设备以及 FPGA 设备。
- 支持读写单个串行 FLASH 以及读写多个并联的串行 FLASH 的模式
- 支持把存储器地址映射至通过 AHB 总线读写,即后面说明的 AHB 命令模式。
- 支持使用 DMA 进行访问,从而减少 CPU 的介入。
- 支持以下多种模式以适配不同的功耗状态:模块关闭模式(Module Disable mode)、打盹儿模式(Doze mode)、停止模式(Stop mode)以及正常模式(Normal mode)。
- 最多支持 4 个存储设备,每个存储设备最大容量为 4GB,连接多个存储设备时容量的总和也不能超过 4GB。
22.2.2 RT1052 的 FlexSPI 架构剖析
22.2.2.1 通讯引脚
FlexSPI 外设包含有 A/B 两组 SPI 通讯接口,每组接口最多可外接 2 个设备,即 A1、A2、B1 和 B2。
RT1052 的 FlexSPI A 组引脚:
这些引脚与外部 SPI Flash 设备的连接的方式
当 FlexSPI 工作于 Octal 模式(八线 SPI)时,它会以 SIOB[3:0] 数据信号线作为高 4 位的数据线,此时仅 A 组可以工作,B 组不能使用。
22.2.2.2 指令查找表 LUT
FlexSPI 外设中包含有一个指令查找表 LUT(Look Up Table),上图第 ② 部分 SEQ_CTL(序列控制逻辑)的主要内容
- 用来预存储访问外部设备时可能使用到的指令
- 对 FLASH 进行访问时,FlexSPI 会从查找表 LUT 中获取相应的指令然后通过 SPI 接口对 FLASH 发起通讯。
查找表 LUT 的构成:
- 第 ① 部分是查找表 LUT 视图,它表示查找表 LUT 有 0~N 个序列;
- 第 ② 部分是序列视图,它表示 1 个序列中包含有 8 个指令
- 第 ③ 部分是指令视图,表示指令由 opcode(指令编码)、num_pads(数据线的数目)、operand(指令参数) 三个寄存器域构成。
这些指令的存储位置是 FlexSPI 外设中的寄存器 LUT0~LUT63
- 每个 LUT 寄存器可以缓存 2 个指令
- 1 个指令序列(8 个指令)由 4 个寄存器构成
- 这些寄存器构成了一个完整的 LUT 表
LUT寄存器
OPCODE:指令编码
- 由 FlexSPI 定义的一些基本指令码
- 向 FLASH 发送控制命令的 CMD_SDR 指令 OPCODE 为 0x01;
- 发送行地址到 FLASH 的指令 OPCODE 为 0x02等
NUM_PADS:进行 SPI 通讯时使用的数据线的数目
-
- 0x0:Single 模式
-
- 0x1:Dual 模式
-
- 0x2:Quad 模式
-
- 0x3:Octal 模式
OPERAND:指令参数
- 部分 OPCODE 指令包含参数,这些参数就由 OPERAND 设定
- 参数的具体作用由相应的 OPCODE 决定。
查找表 LUT 的常用指令
查找表支持两套有同功能不同模式的指令
- 如 CMD_SDR 和 CMD_DDR 的 OPCODE 为0x01 和 0x21,它们分别表示使用 SDR 模式和 DDR 模式的 CMD 指令,它们的功能一样,都是向 FLASH 发送命令代码。
- 其它指令类似,大都有 SDR 和 DDR 模式。
数据线的数目由 NUM_PADS 指定。
- 不同指令可以使用不同的数据线数目。
- 一些 FLASH 存储器的命令只使用一根数据线(Single 模式)
- 快速读写的命令则可支持 Dual、Quad 模式
OPERAND 参数在不同指令下作用不同:
-
对于 CMD_SDR 指令,此时要发送的 FLASH 命令代码就是 CMD_SDR 指令的参数
- 例如 W25Q256 型号的 FLASH 的读取 ID 命令代码为 0xAB,当 RT1052 要读取FLASH 的 ID 时,利用 CMD_SDR 指令同时把命令代码 0xAB 赋予到 OPERAND
-
对于 RADDR_SDR 指令,功能是向 FLASH 发送要读写的存储单元地址,该地址由IPCR0 寄存器指定,同时 OPERAND 域用于指定地址的长度。
- 例如部分 FLASH 的空间比较小,只使用 16 位来表示地址,那么该命令的 OPERAND 域的值就应为 16,对于 W25Q256这种地址为 24 或 32 位的存储器,OPERAND 域的值就应设置为 24 或 32。
-
对于 DUMMY_SDR 指令,它的功能是释放 FlexSPI 对数据线的控制,在这种情况下可通过 OPERAND 指定该过程要占多少个 SCK的周期数。
数据传输指令的数据缓冲区位置分两种情况。WRITE_SDR 和 READ_SDR 指令分别用于向FLASH 写入和读取数据
- 在 AHB 命令模式下:数据缓存在 AHB_TX_BUF(发送缓冲区)以及AHB_RX_BUF(接收缓冲区)中,此时要传输的字节数由 AHB 突发传输的大小和类型决定。
- 在 IP 命令模式下:数据缓存在 IP_TX_FIFO(发送缓冲区)以及 IP_RX_FIFO(接收缓冲区)中,此时要传输的字节数可通过寄存器 IPCR1 的 DATSZ 域指定。
操作通常使用序列的形式并配合 STOP 指令(停止指令)使用
- 以上说明的各个指令通常不会单独执行,而是组成一个指令序列,对于指令数不满 8 个的序列,需要使用 STOP 指令表示结束。
如一个使用 IP 命令模式的读取操作:
-
- 使用 CMD_SDR 指令向发送 FLASH 的读取命令,如 W25Q256 的 Quad 模式读取命令编码为 0x6B,此时 CMD_SDR 指令的 OPERAND 域为 0x6B;
-
- 使用 RADDR_SDR 指令发送要读取的 FLASH 存储单元地址,OPERAND 域的值为 24 表示使用 24 位的地址,而地址具体的值由寄存器 IPCR0 设定;
-
- 按照 FLASH 的 Quad 模式读取命令的要求发送占 8 个 SCK 时钟的 DUMMY 操作,此时使用 DUMMY_SDR 指令且 OPERAND 域的值设置为 8;
-
- 使用 READ_SDR 指令,开始接收 FLASH 的数据到 IP_RX_FIFO 中,要读取的字节数由寄存器 IPCR1 的 DATSZ 域指定;
-
- 由于使用的指令不足 8 个字节,在该序列的最后使用 STOP 指令表示停止,当 FlexSPI 执行到 STOP 指令时,会释放 SPI 的片选信号 CS,结束通讯。
22.2.2.3 命令仲裁器
上图第 ③ 部分是 ARB_CTL(仲裁器逻辑),它主要用来决定执行哪一套命令。
- 其后有一个AHB_CTL(AHB 命令控制逻辑)和 IP_CTL(IP 命令控制逻辑),它们分别代表了内核对 FlexSPI的两种控制方式。
- 仲裁器逻辑就是决定它们谁拥有对前面逻辑单元(SEQ_CTL 和 IO_CTL)的控制权。
22.2.2.4 IP 命令控制逻辑
第 ④ 部分 IP_CTL 是 IP 命令控制逻辑,它包含 IP_RX_FIFO 和 IP_TX_FIFO 用来缓冲收发的数据,它们均为 16*64Bits 大小。
- IP_CTL 连接至 32 位的 ARM IP 总线,通过它可以向ARB_CTL(仲裁器逻辑)发送控制命令,从而利用 FlexSPI 访问外部 SPI 设备
IP 命令的控制流程如下:
- (1) 往 IP_TX_FIFO 填充要传输的数据;
- (2) 通过 IPCR0 寄存器设置要写入的 FLASH 内部存储单元的首地址,要传输的数据大小以及要执行的 LUT 命令序列的编号;
- (3) 对寄存器 IPCMD 的 TRG 位置 1 触发 FlexSPI 访问;
- (4) 检查寄存器 INTR 的 IPCMDDONE 位以等待至 FlexSPI 外设执行完该指令;
- (5) 若执行的命令序列有会接收数据,那么接收到的数据会被缓存至 IP_RX_FIFO 中
22.2.2.5 AHB 命令控制逻辑
第⑤部分AHB_CTL是AHB命令控制逻辑
- 它包含有128×64Bits大小的AHB_RX_BUF和 8×64Bits 大小的 AHB_TX_BUF 用来缓冲收发的数据
- AHB_CTL 连接至 64 位的 AHBP 总线,通过它可以向 ARB_CTL(仲裁器逻辑)发送控制命令,从而 FlexSPI 访问外部 SPI 设备。
使用 AHB 命令的方式是直接访问 RT1052 内部的 0x600 0000-0x1000 0000 地址
- 这些地址的读写访问会触发 FlexSPI 产生 SPI 控制时序,然后对连接的 FLASH 内部存储单元进行读写,这种功能称为地址映射。
例如
- 把外部 NOR Flash 存储器的内部地址 0x0 映射到 RT1052 的 0x60000000 地址
- 初始化好FlexSPI 后,我们直接使用指针读取 RT1052 的 0x60000000 地址
- 自动触发 FlexSPI外设访问外部的 NOR Flash 存储器的 0x0 地址获得数据
- 访问时它会自动使用 AHB_RX_BUF 及AHB_TX_BUF 缓冲数据。
AHB 命令仅支持对 FLASH 存储单元的读写访问,对 FLASH 存储器的工作模式或状态寄存器的读取需要使用 IP 命令实现。
22.2.2.6 驱动时钟
FlexSPI 外设的驱动时钟,它的 SCK 线的时钟信号是由 ipg_clk_sfck 提供的,即 FlexSPI 根时钟 FLEXSPI_CLK_ROOT
FlexSPI 根时钟有 4 个可选输入来源:
- semc_clk_root_pre:这是未经过 SEMC“时钟门”的 SEMC 根时钟 SEMC_CLK_ROOT
- 如果选择本输入源的话,不打开 SEMC 的时钟门它也是可以正常输入到 FlexSPI 的。
- pll3_sw_clk:该时钟来源即为 PLL3,常规配置为 480MHz。
- PLL2 PFD2:该时钟常规配置为 396MHz。
- PLL3 PFD0:该时钟常规配置为 720MHz。
选择的时钟源经过 FlexSPI 的时钟门之后,还有一个 3 位的分频器,它可对时钟源进行 1~8 分频,分频后得到 FlexSPI 根时钟 FLEXSPI_CLK_ROOT。
22.3 FlexSPI 初始化配置结构体
FlexSPI 的初始化结构体及函数定义在库文件“fsl_flexspi.h”及“fsl_flexspi.c”中
/*! @brief FLEXSPI 初始化配置结构体 */typedef struct _flexspi_config {/*!< 选择读取 FLASH 使用的采样时钟源 */flexspi_read_sample_clock_t rxSampleClock;/*!< 是否使能 SCK 自由运行输出 */bool enableSckFreeRunning;/*!< 是否使能 PORT A 和 PORT B 的数据引脚组合 (SIOA[3:0] 和 SIOB[3:0]) 以支持FLASH 的 8 位模式 */bool enableCombination;/*!< 是否使能 doze 模式 */bool enableDoze;/*!< 是否使能 为半速率命令而对时钟 2 分频 的功能 */bool enableHalfSpeedAccess;/*!< 是否使能 SCKB 用作 SCKA 的差分时钟,当使能时, PORT B 的 FLASH 无法访问 */bool enableSckBDiffOpt;/*!< 是否使能对所有连接的设备使用同样的配置,当使能时,FLSHA1CRx 寄存器的配置会应用到所有设备 */bool enableSameConfigForAll;/*!< 命令序列执行的等待超时周期, ahbGrantTimeoutCyle*1024 个串行根时钟周期后超时 */uint16_t seqTimeoutCycle;/*!< IP 命令授予等待超时周期, ipGrantTimeoutCycle*1024 个 AHB 时钟周期后超时 */uint8_t ipGrantTimeoutCycle;/*!< FLEXSPI IP 发送水印值 */uint8_t txWatermark;/*!< FLEXSPI 接收水印值 */uint8_t rxWatermark;struct {/*!< 使能 AHB 总线对 IP TX FIFO 的写访问 */bool enableAHBWriteIpTxFifo;/*!< 使能 AHB 总线对 IP RX FIFO 的写访问 */bool enableAHBWriteIpRxFifo;/*!< AHB 命令授予等待超时周期,在 ahbGrantTimeoutCyle*1024 个 AHB 时钟周期后超时 */uint8_t ahbGrantTimeoutCycle;/*!< AHB 读写访问超时周期, ahbBusTimeoutCycle*1024 个 AHB 时钟后超时 */uint16_t ahbBusTimeoutCycle;/*!< 在暂停命令序列恢复之前空闲状态的等待周期, ahbBusTimeoutCycle 个 AHB时钟后超时 */uint8_t resumeWaitCycle;/*!< AHB 缓冲区信息 */flexspi_ahbBuffer_config_t buffer[FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT];/*!< 是否使能当 FLEXSPI 返回停止模式响应时自动清除 AHB RX 和 TX 缓冲 */bool enableClearAHBBufferOpt;/*!< 是否使能 AHB 预读取特性,当使能时, FLEXSPI 会读取比当前 AHB 突发读取更多的数据 */bool enableAHBPrefetch;/*!< 是否使能 AHB 缓冲写访问的功能,当使能时, FLEXSPI 会在等待命令执行完成前就返回 */bool enableAHBBufferable;/*!< 是否使能 AHB 总线缓冲读访问的功能 */bool enableAHBCachable;} ahbConfig;} flexspi_config_t;
rxSampleClock
- 寄存器位 MCR0[RXCLKSRC],本成员用于配置读取 FLASH 使用的采样时钟源,它是一个枚举类型变量
/*! @brief 选择给读取 FLASH 使用的 FlexSPI 采样时钟源 */typedef enum _flexspi_read_sample_clock {/*!< 伪读选通脉冲由 FlexSPI 控制器产生并在内部回环 */kFLEXSPI_ReadSampleClkLoopbackInternally = 0x0U,/*!< 伪读选通脉冲由 FlexSPI 控制器产生并从 DQS 引脚回环 */kFLEXSPI_ReadSampleClkLoopbackFromDqsPad = 0x1U,/*!< 使用 SCK 输出时钟以并从 SCK 引脚回环 */kFLEXSPI_ReadSampleClkLoopbackFromSckPad = 0x2U,/*!< Flash 提供读选通脉冲并从 DQS 引脚输入 */kFLEXSPI_ReadSampleClkExternalInputFromDqsPad = 0x3U,} flexspi_read_sample_clock_t;
enableSckFreeRunning
- 寄存器位 MCR0[SCKFREERUNEN],本成员用于配置是否使能 SCK 的输出自由运行(free-running)的功能
- 该功能通常应用在与 FPGA 设备相关的应用中,它会以 SCK 作为参考时钟自己内部 PLL 的输入。
enableCombination
- 寄存器位 MCR0[COMBINATIONEN],本成员用于配置是否使能图 22‑11 中的PORT A 和 PORT B 组合模式
- 在组合模式中会同时使用 PORTA[3:0] 及 PORTB[3:0] 的数据线,通过这种方式,可以对有 8 根数据信号线的 FLASH 进行读写。
enableDoze
- 寄存器位 MCR0[DOZEEN],本成员配置是否使能 Doze 模式
- 使能了 doze 模式后,即使 RT1052 芯片处于低功耗 stop 运行状态时 FlexSPI 也能正常工作。
enableHalfSpeedAccess
- 寄存器位 MCR0[HSEN],本成员配置是否使能对 SCK 时钟进行 2 分频以降低访问速率。
enableSckBDiffOpt
- 寄存器位 MCR2[SCKBDIFFOPT],本成员配置是否把 SCKB 用作 SCKA 的差分时钟,使用 2 线差分的形式可以提高抗干扰的能力。
- 不过此时 PORT B 就不能再用于 FLASH 的时钟信号,也就是无法使用了。
enableSameConfigForAll
- 寄存器位 MCR2[SAMEDEVICEEN],本成员配置是否使能所有连接的设备都用同样的配置
- 如果使能的话,FLASHA1CRx 寄存器的配置会被应用到所有的设备。
seqTimeoutCycle
- 寄存器位 MCR1[SEQWAIT],本成员设置命令序列执行的等待超时周期
- 设置结果为 seqTimeoutCycle*1024 个 FlexSPI 根时钟周期后超时,超时后可产生中断且会忽略 AHB 命令。若本成员设置为 0 则不使用本功能。
ipGrantTimeoutCycle
- 寄存器位 MCR0 [IPGRANTWAIT],本成员配置 IP 命令授予等待超时周期
- 触发 IP 命令后,若命令仲裁器在 ipGrantTimeoutCycle*1024 个 AHB 时钟周期后还不允许执行该命令,则可触发中断。
- 本功能仅支持调试模式,使用时直接设置为默认值即可,且不能设置为 0!
txWatermark
- 寄存器位 IPTXFCR [TXWMRK],本成员配置 IP 发送的水印值,单位为字节。
- 当IP_TX_FIFO 的空余的程度大于或等于该水印值时,可触发 IPTXWE 中断
- 同时也可触发 DMA 请求从而往 IP_TX_FIFO 填充要传输的数据。
rxWatermark
- 寄存器位 IPRXFCR [RXWMRK],本成员配置接收的水印值,单位为字节。
- 当IP_RX_FIFO 接收的数据超过该水印值时,可触发 IPRXWA 中断
- 同时也可触发DMA 请求把数据从 IP_RX_FIFO 转移出去
在 flexspi_config_t 中的一个 ahbConfig 结构体类型的成员,它主要用于配置 AHB 总线的各项参数:
enableAHBWriteIpTxFifo
- 寄存器位 MCR0 [ATDFEN],配置是否使能 AHB 总线通过映射地址对 IP_TX_FIFO 的写访问。
- 0x7F800000-0x11000400
- 使能后,可通过 AHB 总线映射的地址向 IP_TX_FIFO 写入内容,此时通过 IP 总线写入 IP_TX_FIFO 的操作会被忽略,但不会出现错误标志
- 若不使能,可通过 IP 总线写入 IP_TX_FIFO,此时通过 AHB 总线的写入操作会被忽略,且会产生错误标志。
enableAHBWriteIpRxFifo
- 寄存器位 MCR0 [ARDFEN],配置是否使能 AHB 总线通过映射地址对 IP_RX_FIFO 的读访问。
- 0x7FC00000-0x10000200
- 与 enableAHBWriteIpTxFifo 的类似,用于控制使用 AHB 还是 IP 进行读操作。
ahbGrantTimeoutCycle
- 寄存器位MCR0[AHBGRANTWAIT],与ipGrantTimeoutCycle成员类似,ahbGrantTimeoutCycle 用于配置 AHB 命令授予等待超时周期
- 触发 AHB 命令后,若命令仲裁器在在 ahbGrantTimeoutCyle*1024 个 AHB 时钟周期后还不允许执行该命令,会触发中断。
- 注意本功能同样仅支持调试模式,使用时直接设置为默认值即可,且不能设置为 0
ahbBusTimeoutCycle
- 寄存器位 MCR1 [AHBBUSWAIT],配置 AHB 读写访问超时周期
- 在超过 ahbBus-TimeoutCycle*1024 个 AHB 时钟周期后,仍没接收到数据或没发送出数据则表示访问超时,触发时可产生 AHBBUSTIMEOUT 中断。
resumeWaitCycle
- 寄存器位 MCR2[RESUMEWAIT],配置在暂停命令序列恢复之前,等待空闲状态的周期
- 等待超过 resumeWaitCycle 个 AHB 时钟后超时。