本帖最后由 小恩GG 于 2024-7-17 15:52 编辑
MCX N947:FlexSPI接HyperRAM分析和配置 一、概述 MCXN947芯片是一款高度集成的微控制器,具有强大的处理能力、丰富的外设支持和高级安全特性,适用于多种复杂应用。其中有个非常重要的外设为FlexSPI。 FlexSPI是一种可扩展的串行外设接口,主要用于连接固态存储设备,如QuadSPI NOR Flash、QuadSPI NAND Flash、HyperRAM等。FlexSPI是一种全面的、灵活的、高性能的解决方案,可以配置成不同的模式以适应不同的存储设备。 NXP FRDM-MCXN947板是一款基于MCXN947设备的低成本设计与评估板。NXP为MCXN947设备提供了包括硬件评估板、软件开发集成开发环境(IDE)、示例应用程序和驱动程序在内的工具和软件支持。该板FlexSPI接口默认接了一块MT35XU512 NOR Flash。 在本文中,我们将探讨如何在MCXN947板的FlexSPI接口接HyperRAM。 硬件环境: l 开发板:FRDM-MCXN947 l HyperRAM:W956D8MBYA 软件环境: l IDE:MCUXpresso IDE v11.9.0 二、 HyperRAM原理图 以下是官方FRDM-MCXN947中的八线Flash的原理图,由于W956D8MBYA的HyperRAM的封装都为TFBGA 24-Ball 5 x 5 Array,所以可以直接进行替换。 根据以上原理图,总结出HyperRAM存储器的信号连接方式见表。
三、 HyperRAM配置流程 3.1 时钟配置 FlexSPI的时钟需要正确配置。 我们在调程序的阶段还是保险地选择低一点的频率,这里选择75MHz。 3.2 FlexSPI初始化配置结构体详解 接下来是FlexSPI相关配置,我们可以调用FLEXSPI_GetDefaultConfig获取一些针对FlexSPI特性结构体flexspi_config_t的一些默认配置,这个默认配置具有一定的普遍性,能兼容大部分的FlexSPI设备,对于该W956D8MBYA的HyperRAM,在默认配置的基础上,增加如下几个参数: - config.ahbConfig.enableAHBPrefetch = true;
- config.ahbConfig.enableAHBBufferable = true;
- config.ahbConfig.enableReadAddressOpt = true;
- config.ahbConfig.enableAHBCachable = true;
- config.rxSampleClock = kFLEXSPI_ReadSampleClkLoopbackFromDqsPad;
复制代码(1)enableAHBPrefetch:是否使能AHB预读取特性,当使能时,FlexSPI会读取比当前AHB突发读取更多的数据。 (2)enableAHBBufferable :是否使能AHB写缓冲访问,在执行写命令后,不等待其执行完毕就返回,允许后续指令继续执行,提高系统的并发性。 (3)enableReadAddressOpt:控制是否移除AHB读取突发起始地址对齐限制,若使能,突发读取地址没有字节对齐限制。 (4)enableAHBCachable:使能AHB总线缓存读取,若命中则从缓存中读取,但要确保数据的一致性。 (5)rxSampleClock:读数据使用的时钟源,对于HyperRAM来说,HyperRAM提供读选通脉冲并从DQS引脚输入。 3.3 FlexSPI外部设备配置结构体详解
FlexSPI与外部设备通讯时常常需要与设备协调通讯的时序,如时钟频率、数据有效时间等内容,NXP软件库提供了结构体类型flexspi_device_config_t专门用于配置这些参数。 - 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;
复制代码(1)flexspiRootClk = 75000000,此参数与前面设置的FlexSPI的时钟频率一致。 (2)flashSize = 0x2000, Flash的大小,以KB为单位。对于W956D8MBYA,64Mb = 8MB = 8 *1024KB。 (3)CSIntervalUnit = kFLEXSPI_CsIntervalUnit1SckCycle,此参数用于配置CS信号线间隔的时间单位。 (4)CSInterval = 2,此参数用于配置CS信号线有效与无效切换的最小时间间隔,单位为上面CSIntervalUnit成员的配置。 (5)CSHoldTime = 3,此参数用于设定CS信号线的保持时间,单位为FlexSPI根时钟周期。 (6)CSSetupTime=3,此参数用于设定CS信号线的建立时间,单位为FlexSPI根时钟周期。 根据MCXNx4x datasheet,
= 6ns,最小的
= 8.3ns,最小的
= 9.8ns。时钟为75M的周期时间大约是13.3纳秒。故CSHoldTime和CSSetupTime大于等于1即可,均配置成3。 (7)dataValidTime=2,寄存器DLLACR和DLLBCR,本成员用于配置通讯中的数据有效时间,单位为纳秒。 (8)columnspace = 3,低位列地址宽度,对于这个HyperRAM来说,是用行列进行寻址的,这里列地址的宽度为3位。 (9)enableWordAddress = true,配置是否使能2字节可寻址功能,使能后会以16位的数据格式对HyperRAM进行访问。 (10)AWRSeqIndex = 1,对应写的时序序列在LUT中的索引。 (11)AWRSeqNumber =1,此参数配置AHB写命令的序列数目。 (12)ARDSeqIndex = 0,对应读的时序序列在LUT中的索引。 (13)ARDSeqNumber =1,此参数配置AHB读命令的序列数目。 (14)enableWriteMask = true,此参数用于设置FlexSPI写外部设备时是否使能驱动DQS位作为掩码,这种功能在访问数据宽度为16位时用于地址对齐。 3.4 LUT表格配置 下面是HyperRAM 读和写的时序LUT表格的代码示例, - const uint32_t customLUT[CUSTOM_LUT_LENGTH] = {
- /* Read Data */
- [4 * PSRAM_CMD_LUT_SEQ_IDX_READDATA] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
- [4 * PSRAM_CMD_LUT_SEQ_IDX_READDATA + 1] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x07),
- [4 * PSRAM_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 * PSRAM_CMD_LUT_SEQ_IDX_WRITEDATA] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
- [4 * PSRAM_CMD_LUT_SEQ_IDX_WRITEDATA + 1] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x07),
- [4 * PSRAM_CMD_LUT_SEQ_IDX_WRITEDATA + 2] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
- };
复制代码(1)我们使用的是8线差分的HyperRAM,在时钟的双边沿都采用,所以与外部存储器通信时用的数据线的个数均为kFLEXSPI_8PAD。 (2)HyperRAM和HyperFlash是基于Cypress Semiconductor的HyperBus™接口规范设计的存储器产品,这个operand是在该规范中定义的,所以读操作operand固定为0xA0,写数据的operand固定为0x20。 (3)CADDR_DDR列地址,由于一次传输的字节一定是8的倍数,如果你传的行列地址大于特定大小的HyperRAM最大的行和列,FlexSPI会自动将高位置0。 上表中显示低16位是列地址,有效位有3位,高13位是预留兼容的列地址位,需要置0。所以这里列地址的时序参数需要填16,即0x10。 (4)RADDR_DDR行地址,如图所示,如果 FLSHxxCR1[CAS] 位不为 0 ,那么 FlexSPI 外设在传输时序里会拆分实际映射 Flash Address (即存储器自身偏移地址) 为行地址 FA[31:CAS] 和列地址 [CAS-1:0] 来分别传输。对于字可寻址闪存设备,不需要地址的最后一位,因为闪存是按照两个字节读取和编程的。Flexspi 一个字为两个字节,所有需要如果2个字节对齐,就需要少一位地址。行列地址加一起少一位。W956D8MBYA有64Mbit,即
,列地址还有3位,所以理论上行地址需要传输26-1-3=22位,即可寻址整个HyperRAM。然后向8位对齐,不然FlexSPI会在低位补0,就不是我们要访问的地址了。所以参数为0x18,即24位。 四、实验验证 我们可以利用简单的AHB读写来验证此HyperRAM是否可以工作,代码如下: - for (i = 0; i < sizeof(s_psram_write_buffer); i++)
- {
- s_psram_write_buffer[i] = i;
- }
- memcpy((uint32_t*)(EXAMPLE_FLEXSPI_AMBA_BASE), s_psram_write_buffer, sizeof(s_psram_write_buffer));
- memcpy(s_psram_read_buffer,(uint32_t*)(EXAMPLE_FLEXSPI_AMBA_BASE) , sizeof(s_psram_read_buffer));
- if (memcmp(s_psram_read_buffer, s_psram_write_buffer, sizeof(s_psram_write_buffer)) == 0)
- {
- PRINTF("AHB Command Read/Write data successfully !\r\n");
- }
复制代码当你的串口打印出“AHB Command Read/Write data successfully !”证明你的FlexSPI接HyperRAM可以正常工作。
|