在上一篇文章中我分析了NOR Flash的手册和FlexSPI的相关配置,在这篇文章中,我将以HyperRAM为例,看看八线的HyperRAM在硬件设计和软件配置上有增加什么引脚和参数,然后以ISIS型号为IS66WVH64M8DALL/BLL
的HyperRAM为例,看看如何根据手册来配置FlexSPI的参数。
1 HyperRAM原理图
以下是官方EVKBoard中的八线Flash的原理图,由于大多数的Hyper存储器的封装都为FBGA 24-Ball 5 x 5 Array,所以可以直接进行替换。如下图所示,将R383和R400取掉,再将R401和R384焊上即可使用同封装的HyperRAM,连线非常简单,就是把一个FlexSPI的PortA和PortB都连上了,有八个数据线。
在8线的Flash/HyperRAM中会多一个DQS引脚,它用于SCLK双边沿采样,仅在存储设备发送数据给单片机时起作用,用于通知单片机数据线上的数据已经就绪。其它的注意CS引脚和RST引脚建议硬件上拉,不过忘记了硬件上拉还可以软件上拉。
2 手册解读和代码配置
在代码上和上一节的NOR Flash手册分析和参数配置详解十分相似,对于一些相同的部分,这篇文章就不再赘述。来看一下不同的地方:
2.1 DQS采样
首先,单片机的采样时钟选择DQS信号:
config.rxSampleClock = kFLEXSPI_ReadSampleClkExternalInputFromDqsPad;
...
FLEXSPI_Init(EXAMPLE_FLEXSPI, &config);
2.2 flexspi_device_config_t配置
因为不同的HyperRAM的参数肯定不一样,这一小节以IS66WVH64M8DALL/BLL
为例看看如何进行配置FlexSPI设备结构体:
typedef struct _flexspi_device_config
{
uint32_t flexspiRootClk;
bool isSck2Enabled;
uint32_t flashSize;
flexspi_cs_interval_cycle_unit_t CSIntervalUnit;
uint16_t CSInterval;
uint8_t CSHoldTime;
uint8_t CSSetupTime;
uint8_t dataValidTime;
uint8_t columnspace;
bool enableWordAddress;
uint8_t AWRSeqIndex;
uint8_t AWRSeqNumber
uint8_t ARDSeqIndex;
uint8_t ARDSeqNumber;
flexspi_ahb_write_wait_unit_t AHBWriteWaitUnit;
uint16_t AHBWriteWaitInterval;
bool enableWriteMask;
} flexspi_device_config_t;
先来看一些基本参数:
#define HYPERRAM_CMD_LUT_SEQ_IDX_READDATA 0
#define HYPERRAM_CMD_LUT_SEQ_IDX_WRITEDATA 1
.flexspiRootClk = 200000000,
.isSck2Enabled = false,
.flashSize = (0x10000U),
.enableWordAddress = true,
.AWRSeqIndex = HYPERRAM_CMD_LUT_SEQ_IDX_WRITEDATA,
.AWRSeqNumber = 1,
.ARDSeqIndex = HYPERRAM_CMD_LUT_SEQ_IDX_READDATA,
.ARDSeqNumber = 1,
.AHBWriteWaitUnit = kFLEXSPI_AhbWriteWaitUnit2AhbCycle,
.AHBWriteWaitInterval = 0,
.enableWriteMask = true,
(1)flexspiRootClk:FlexSPI的频率,这里根据手册设置为最高200MHz,8线(bit)双边沿200MHz=400MB/s的速率。
(2)isSck2Enabled:设置为false,这个是用于并行模式中,即硬件上在FlexSPI的PortA和PortB各接一个Flash,然后由FlexSPI自动组合/拆分数据的,这里没有用到。
(3)flashSize:512Mb = 64MB = 0x10000KB。
(4)enableWordAddress:手册中有提到,是word-wide address boundaries,所以这里填true,表示按字寻址。
(5)AWRSeqIndex和ARDSeqIndex:对应写和读的时序序列在LUT中的索引
(6)AWRSeqNumber和ARDSeqNumber:有的Flash需要多个Sequence完成一个操作,这里表示写和读的序列在一个LUT的Sequence(8个instruction)内就能完成。
(7)AHBWriteWaitUnit和AHBWriteWaitInterval:二者相乘为Flash写操作后需要等待的时间,在下面写时序图最后传输完数据后,CS#线马上就上拉,所以该芯片写完数据后无需等待,AHBWriteWaitInterval
填0。
(8)enableWriteMask:在向HyperRAM写入数据时,可以用DQS线控制写入时是否使用掩码,主要用于IP指令。可以指定低四位是否使用掩码,即是否忽略这四位的值,该掩码在IPCR2
寄存器中设置:
这个功能需要打开。
现在来看一下
.CSIntervalUnit = kFLEXSPI_CsIntervalUnit1SckCycle,
.CSInterval = 2,
.CSHoldTime = 1,
.CSSetupTime = 1,
.dataValidTime = 1,
.columnspace = 3,
(1)CSIntervalUnit和CSInterval:二者相乘即两次片选的间隔时间。原理图中HyperRAM的电源是1.8V,所以这里最低要为5ns,即1/200M,也就是一个时钟周期,这里将CSIntervalUnit
设置为kFLEXSPI_CsIntervalUnit1SckCycle
,然后CSInterval
就不设置地这么极端,这里就填2。
(2)CSHoldTime和CSSetupTime:数据的保持时间和建立时间,这里仅要求0.5ns,所以这两个参数都设置为1。
(3)dataValidTime:数据有效时间如下,同样,这里设置为1即可。
(4)columnspace:列地址宽度,对于这个HyperRAM来说,是用行列进行寻址的,这里列地址的宽度为3位。
2.3 LUT表格配置
这里就以读和写两个时序序列为例分析一下参数的配置,LUT表格如下:
uint32_t customLUT[20] = {
/* Read Data */
[4 * HYPERRAM_CMD_LUT_SEQ_IDX_READDATA] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
[4 * HYPERRAM_CMD_LUT_SEQ_IDX_READDATA + 1] = FLEXSPI_LUT_SEQ(
kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 6),
[4 * HYPERRAM_CMD_LUT_SEQ_IDX_READDATA + 2] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
/* Write Data */
[4 * HYPERRAM_CMD_LUT_SEQ_IDX_WRITEDATA] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
[4 * HYPERRAM_CMD_LUT_SEQ_IDX_WRITEDATA + 1] = FLEXSPI_LUT_SEQ(
kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 6),
[4 * HYPERRAM_CMD_LUT_SEQ_IDX_WRITEDATA + 2] = FLEXSPI_LUT_SEQ(
kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
};
可以看到读和写的时序序列十分类似,下面来分析一下这些opcode和operand:
(1)kFLEXSPI_Command_DDR
这里我们使用的是8线差分的HyperRAM,在时钟的双边沿都采用,所以就可以进入DDR模式进行数据的读写。对于读数据的operand
固定为0xA0,写数据的operand
固定为0x20。
- HyperRAM和HyperFlash是基于Cypress Semiconductor的HyperBus™接口规范设计的存储器产品,这个
operand
是在该规范中定义的,这里虽然是ISIS的产品,但也遵循这个规范,所以operand
固定为0xA0
(2)kFLEXSPI_Command_RADDR_DDR和kFLEXSPI_Command_CADDR_DDR:行地址和列地址的位数。来看看手册:
在CK为低电平,CK#为高电平时,FlexSPI的前三个时钟周期将传输48位的Command/Address的数据,这表示了一个时序的开始,这48位的定义如下:
由于HyperRAM连接的是8线的HyperRAM,所以一次传输的字节一定是8的倍数,所以对于FlexSPI来说,如果RADDR_DDR
或CADDR_DDR
不足8位,会自动在低位插入保留位(这个值是什么不影响)。另外,如果你传的行列地址大于特定大小的HyperRAM最大的行和列,FlexSPI会自动将高位置0。
先来看一下列地址,上表中显示低16位是列地址,有效位有3位,高13位是预留兼容的列地址位,需要置0。所以这里列地址的时序参数需要填16,即0x10。
再来看一下行地址,IS66WVH64M8DALL/BLL
有512Mbit,即
2
26
2^{26}
226Byte,而在一个时钟周期中的双边沿将采样2字节的数据,列地址还有3位,所以理论上行地址需要传输26-1-3=22位,即可寻址整个HyperRAM。然后向8位对齐,不然FlexSPI会在低位补0,就不是我们要访问的地址了。所以参数为0x18,即24位。
这里我们注意到行地址范围是bit44~16,有29位,向8位对齐为32,为什么不填32呢?
我的猜测是高3位指示传输的一些参数,也需要8位对齐,FlexSPI根据我们的kFLEXSPI_Command_DDR
传这三位的时候,肯定也是一次传8位了,所以对于1Gbit的设备,在传高三位的同时,也会根据用户提供的地址把bit44~40的位也给填充了。
(3)kFLEXSPI_Command_DUMMY_RWDS_DDR:HyperBus设备中用于数据和命令的时钟同步延时,这个值必须非常精准。。由于读写的DUMMY Cycle一般都一样,这里以IS66WVH64M8DALL/BLL
中的读时序为例,看看这个值要设置为多少:
在手册中并没有明确地标出Dummy cycle的时序图,这个图主要是为了说明一些AC参数,但从图中可以粗略地看出,当48位的CA数据发完后,再经过7个时钟周期,DQ线上就开始传输数据,但这个图仅仅是一个示意图,所以这个7并不准确。实际的值应该参考手册中Configuration Register 0
中的Initial Latency
,手册中写了默认为166MHZ,这个latency为6,所以这里填6。
(4)kFLEXSPI_Command_READ_DDR和kFLEXSPI_Command_WRITE_DDR:即读数据和写数据的命令,其参数为AHB的Burst size,即读或写数据的大小,即一次读写的最小字节数。大部分设备是4字节对齐的,这里就填0x04。
(5)kFLEXSPI_Command_STOP:停止指令。文章来源:https://www.toymoban.com/news/detail-536081.html
3 总结
本文通过分析HyperRAM的手册和FlexSPI的参数对一个8线的HyperRAM的参数配置进行了讲解,对于不同的HyperRAM来说,其寻址方式不太相同,比如有的HyperRAM列地址的高列地址和低列地址并不是连续的,这个时候设置的行地址位数的参数就不能以8位对齐了,而是要预留低位,让FlexSPI自动去填充。所以,这些存储设备的配置代码并没有一个通用的模板,对于不同的芯片,都需要阅读其手册来配置。文章来源地址https://www.toymoban.com/news/detail-536081.html
到了这里,关于I.MX RT1170之FlexSPI(4):HyperRAM手册分析和参数配置详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!