小猫爪:i.MX RT1050学习笔记12-FlexSPI简介
1 前言
接下来我们学习一下RT1050一个最重要的外部存储器接口FlexSPI,因为其对于RT的启动,XIP以及外部存储器的拓展都息息相关,实打实的核心。
2 扩展SPI
相信大家对于传统SPI并不陌生,四个信号线,四种工作模式,同步全双工通讯,在这里我就不多做介绍了,接下来让我们了解一下SPI的扩展协议(Dual/Quad/Octal SPI)。下表列出了这四种SPI之间的对比。
类型 | 数据线 | 通讯方式 |
---|---|---|
Single SPI(标准SPI) | 1 根发送,1 根接收 | 同步全双工 |
Dual SPI(双线SPI) | 收发共用2 根数据线 | 同步半双工 |
Quad SPI(四线SPI) | 收发共用4 根数据线 | 同步半双工 |
Octal SPI(八线SPI) | 收发共用8 根数据线 | 同步半双工 |
除了以上的区别,扩展SPI还增加了SDR(Single Data Rate)和DDR(Double Data Rate)两种模式。在标准SPI 协议的SDR 模式下,只在SCK 的单边沿进行数据传输,即一个SCK 时钟只传输一位数据;而在DDR 模式下,会在SCK 的上升沿和下降沿都进行数据传输,即一个SCK 时钟能传输两位数据,传输速率提高一倍,这个就跟SDRAM的DDR原理是差不多的。
3 FlexSPI
RT1050的FlexSPI就是针对SPI协议设计的一个超级灵活SPI外设,下面是它的一些特性:
- Single/Dual/Quad/Octal 模式的传输(即1/2/4/8 根数据线的传输)。
- 支持SDR/DDR通讯模式,在SDR模式下,它仅支持SPI 中的模式0(CPOL=0, CPHA=0),即SCK 空闲时为低电平,采样时刻为奇数边沿的模式。
- 支持控制SPI接口的串行NOR/NAND Flash 设备、HyperBus 协议设备以及FPGA 设备。 支持读写单个串行FLASH以及读写多个并联的串行FLASH 的模式(Individual Mode 及Parallel Mode)。
- 支持IP操作,支持把存储器地址映射至通过AHB总线读写。 支持使用DMA进行访问,从而减少CPU 的介入。
- 支持以下多种模式以适配不同的功耗状态:模块关闭模式(Module Disable mode)、打盹儿模式(Dozemode)、停止模式(Stop mode)以及正常模式 (Normal mode)。
- 最多支持4个存储设备,每个存储设备最大容量为4GB,不过要注意如果同时使用FlexSPI外接多个存储设备,那么这些存储设备容量的总和也不能超过4GB。
下图为FlexSPI的结构图:
3.1 IO_CTL
FlexSPI 外设包含有A/B 两组SPI 通讯接口,即图 22-5 中第①部分IO_CTL(IO 控制逻辑)引出的“SPI Bus FA port”和“SPI Bus FB port”。每组接口最多可外接2 个设备,即A1、A2、B1 和B2,下面列出第一组接口定义(两组一样):
引脚简称 | 方向 | 功能 | 引脚名 | 引脚号 |
---|---|---|---|---|
PCSA1 | 输出 | A1设备的SPI 片选信号 | FLEXSPI_A_SS0_B | GPIO_AD_B1_15 GPIO_SD_B1_06 |
PCSA2 | 输出 | A2 设备的SPI片选信号 | FLEXSPI_A_SS1_B | GPIO_AD_B1_08 GPIO_SD_B0_00 GPIO_SD_B1_04 |
SCKA | 输出 | A1/A2 设备共用的时钟信号 | FLEXSPI_A_SCLK | GPIO_AD_B1_14 GPIO_SD_B1_07 |
SIOA[0] | 输入/输出 | A1/A2 设备共用的数据信号0 | FLEXSPI_A_DATA0 | GPIO_AD_B1_13 GPIO_SD_B1_08 |
SIOA[1] | 输入/输出 | A1/A2 设备共用的数据信号1 | FLEXSPI_A_DATA1 | GPIO_AD_B1_12 GPIO_SD_B1_09 |
SIOA[2] | 输入/输出 | A1/A2 设备共用的数据信号2 | FLEXSPI_A_DATA2 | GPIO_AD_B1_11 GPIO_SD_B1_10 |
SIOA[3] | 输入/输出 | A1/A2 设备共用的数据信号3 | FLEXSPI_A_DATA3 | GPIO_AD_B1_10 GPIO_SD_B1_11 |
DQSA | 输入/输出 | A1/A2 使用的数据选通信号,它有如下功能: ①部分Flash 通过本引脚提供读选通信号。②一些HyperRAM/HyperFlash 设备使用本引脚提供需要延迟的通知信号。③FlexSPI 自身使用本引脚提供回环的dummy 读选通信号,以获得更高的读取频率。 | FLEXSPI_A_DQS | GPIO_AD_B1_09 GPIO_SD_B1_05 |
当工作在Octal 模式下,也就是八数据线模式下,它会以SIOB[3:0]数据信号线作为高4位的数据线,此时仅A 组可以工作,B 组不能使用。如下图所示:
3.2 SEQ_CTL
这一部分为序列控制模块,主要负责具体命令时序的组合,其中有一个非常重要的部分叫做LUT表(Look Up Table),它是一个寄存器组,我们可以在这组寄存器中存储命令序列,之后我们可以通过调用索引来直接调用LUT中存储的命令序列,它是为了让通过IP命令操作更加方便快捷服务的。
LUT寄存器组一共有64个寄存器(LUT0~LUT64),每个寄存器可以存储2个指令,8个指令组成一个指令序列,所以一个支持16个指令序列。接下来让我们看看一个指令中包含了哪些信息,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 决定。 |
其中OPERAND参数是跟着OPCODE指令编码来决定的。
①对于CMD_SDR 指令,它的功能是向FLASH 发送命令,此时要发送的FLASH命令代码就是CMD_SDR 指令的参数,即由OPERAND 域指定。例如W25Q256 型号的FLASH 的读取ID 命令代码为0xAB,当RT1052 要读取FLASH 的ID 时,利用CMD_SDR指令同时把命令代码0xAB 赋予到OPERAND 域,这样FlexSPI 控制的时候就会通过SPI 接口把FLASH 命令0xAB 发送出去了。
②对于RADDR_SDR 指令,它的功能是向FLASH 发送要读写的存储单元地址,该地址由IPCR0 寄存器指定,同时OPERAND 域用于指定地址的长度。例如部分FLASH 的空间比较小,只使用16 位来表示地址,那么该命令的OPERAND 域的值就应为16,对于W25Q256 这种地址为24 或32 位的存储器,OPERAND 域的值就应设置为24 或32。
③对于DUMMY_SDR 指令,它的功能是释放FlexSPI 对数据线的控制,而时钟正常运行,该指令是针对FLASH 存储器的部分时序要求,这时FLASH 存储器会忽略数据线上的内容,实质它是要求主机进行等待,在这种情况下可通过OPERAND 指定该过程要占多少个SCK 的周期数。
一些常见的LUT指令大家可以参考官方指南中的Table 27-7. Instruction set,在这里就不一 一列举了,我截图截一部分。
所以我们只需要提前将一些常见的FLASH操作命令写入LUT寄存器组中,我们就可以通过将指令序列索引和指令序列数量写入IPCR1中,就可以调用我们预先设置的LUT表指令。
(注意:在使用LUT表过程中,我们需要了解和注意一下几点:
①对于指令编码01和21,它们的作用都是发送FLASH命令,唯一的区别就是实现方式的不同,01为通过SDR模式发送,21为通过DDR模式发送。
②在前面说到我们可以通过改变指令中NUM_PADS参数来确定使用几根信号线发送数据,1/2/4/8,但是不是所有的指令编码都可以改变NUM_PADS,对于STOP指令和大多数FLASH的CMD指令来说,只能使用single模式,也是使用一根线来传输。
③每一个指令通常不会单独执行,而是组成一个指令序列,一般的FLASH操作通常使用序列并配合STOP 指令(停止指令)使用,所有对于指令数不满8 个的序列,需要使用STOP 指令表示结束,其中STOP命令的LUT参数全部为0,所以在设计LUT表时,不加也是可以的。)
注:关于LUT表的相关使用在我的三篇FlexSPI使用文章中也有详细的解释。
3.3 ARB_CTL
ARB_CTL(仲裁器逻辑),它主要用来决定执行哪一套命令。在其前面有一个AHB_CTL(AHB 命令控制逻辑)和IP_CTL(IP 命令控制逻辑),它们分别代表了内核对FlexSPI 的两种控制方式 ,该仲裁器逻辑就是决定它们谁拥有对前面逻辑单元(SEQ_CTL 和IO_CTL)的控制权。
3.4 IP_CTL
这一部分决定了我们可以通过访问寄存器的形式完成对FlexSPI外设的操作。IP_RX_FIFO 和IP_TX_FIFO用来缓冲收发的数据,它们均为16*64Bits 大小。。IP_CTL 连接至32 位的ARM IP 总线,通过它可以向ARB_CTL(仲裁器逻辑)发送控制命令,从而利用FlexSPI 访问外部SPI 设备。
IP操作具体流程如下:
- 往IP_TX_FIFO 填充要传输的数据;
- 通过IPCR0 寄存器和IPCR1寄存器设置要写入的FLASH 内部存储单元的首地址,要传输的数据大小以及要执行的LUT 命令序列的编号;
- 对寄存器IPCMD 的TRG 位置1 触发FlexSPI 访问;
- 检查寄存器INTR 的IPCMDDONE 位以等待至FlexSPI 外设执行完该指令;
- 若执行的命令序列有会接收数据,那么接收到的数据会被缓存至IP_RX_FIFO 中。
3.5 AHB_CTL
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 控制时序。
以上对FlexSPI的结构进行了一个简单的介绍,接下来我们会对其一些日常的使用做一些简单的介绍。
END