本文主要是通过迁移的思维,记录本人初次使用NXP MCUXpresso SDK API进行BSP开发
MCUXpresso SDK SEMC API 接口链接
在MCUXpresso SDK 框架下提供了对SEMC DDR进行操作的接口。
学习链接:https://community.nxp.com/t5/MCUXpresso-Community-Articles/i-MX-RT-memory-validation/ba-p/1130828
1. 首先阅读原理图
DDR芯处使用IS42S32800J-6BLA1从手册上可以看得出来该芯片支持的最大工作时钟为166Mhz.
但是从MCU的手册上可以看出其支持的最大速率为200Mhz.
2. SDK api 应用
2.1 引脚配置
引脚复用配置
2.2 时钟配置
从上图可以看到时钟源从SYM_PLL2_528Mhz至SYS_PLL2_PFD1(594Mhz)再通过4分频获取148.5MHz的时钟。
相关的配置代码如下所示:
2.3 外设配置
对DDR的初始化,还是需要有前置知识的,了解DDR的工作时钟、时序相关知识,以及初始化的状态机。
进入SEMC DDR的配置界面,如下所示:
第一,需要选择DDR的时钟源及其频率
第二,需要DDR的数据锁存模式,我们选择DQS模式。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
第三、需要配置片选信号,这个和硬件设计相关
第四、需要配置内存的物理起始位置,这个和MCU的地址分配相关。
第五、需要配置内存的容量,和所选的SDRAM芯片容量保持一致。
第六、配置SDRAM数据线的宽度及突发长度,数据宽度从原理图上可以看出来。突发长度可以从SDRAM手册上找到。
第七、配置列地址线的个数及CAS。列地址线的个数可以从手册上找出来,CAS可以选择2或者3也是在手册上的。
第八、预充电(Precharge)至有效(active)的等待时间tRP,在166MHz,从手册上查得该数值>=18
第九、Active Command To Read / Write Command Delay Time (tRCD)
第十、刷新恢复时间 取tRFC/tXSR当中的最大值。
第十一、写恢复(write recovery)时间 tWR
第十二、CKE off minimun time, 一般取tRAS
第十三、active to precharge, 取tRAS
第十四、self refresh reovery time 自刷新恢复时间,取tXSR
第十五、refresh to refresh wait time 刷新至刷新的等待时间,取tRC.
第十六、active to active wait time 有效至有效的等待时间, 取tRC = tRAS + tRP = tRCD + tWR + tRP
第十七、prescaler timer period, 取160个tCLK时钟周期
160 * 1000000000 / semc_clk = 160 * 1000000000 / 148500000
第十八、sdram idle time 必须小于 tRAS, 而tRAS的最大值为100000ns
且有一个限制条件:
周期为 tPrescalePeriod_Ns = 160*100000000/semc_clk
ITO* 160 * 1000000000 / 148500000 < 100000,
ITO < 92.812
ITO取值意义如下,所以我们取[1,92]
第十九:refresh timer period /refresh upgent period, 从手册上可以看到刷新4096次,总用耗时64ms,每次的刷新时间为 64*1000000/4096,两者相同值。
2.4 验证测试
SDRAM 时钟配置成148.5Mhz:
Index: D:/svn/SDK_2.8.0_MIMXRT1170-EAR3/boards/easyarm-rt1170-revb/driver_examples/semc/sdram/cm7/clock_config.c
===================================================================
--- D:/svn/SDK_2.8.0_MIMXRT1170-EAR3/boards/easyarm-rt1170-revb/driver_examples/semc/sdram/cm7/clock_config.c (revision 7)
+++ D:/svn/SDK_2.8.0_MIMXRT1170-EAR3/boards/easyarm-rt1170-revb/driver_examples/semc/sdram/cm7/clock_config.c (working copy)
@@ -136,7 +136,7 @@
CLOCK_InitPfd(kCLOCK_PllSys2, kCLOCK_Pfd1, 16);
/* Configure Semc using SysPll2Pfd1 divided by 3 */
rootCfg.mux = kCLOCK_SEMC_ClockRoot_MuxSysPll2Pfd1;
- rootCfg.div = 3;
+ rootCfg.div = 4;
CLOCK_SetRootClock(kCLOCK_Root_Semc, &rootCfg);
#endif
最终针对148.5Mhz时钟的SDRAM配置代码如下所示:
status_t BOARD_InitSEMC(void)
{
semc_config_t config;
semc_sdram_config_t sdramconfig;
uint32_t clockFrq = EXAMPLE_SEMC_CLK_FREQ;
/* Initializes the MAC configure structure to zero. */
memset(&config, 0, sizeof(semc_config_t));
memset(&sdramconfig, 0, sizeof(semc_sdram_config_t));
/* Initialize SEMC. */
SEMC_GetDefaultConfig(&config);
config.dqsMode = kSEMC_Loopbackdqspad; /* For more accurate timing. */
SEMC_Init(SEMC, &config);
/* Configure SDRAM. */
sdramconfig.csxPinMux = kSEMC_MUXCSX0;
sdramconfig.address = 0x80000000;
sdramconfig.memsize_kbytes = 32 * 1024; /* 32MB = 32*1024*1KBytes*/
sdramconfig.portSize = kSEMC_PortSize32Bit;
sdramconfig.burstLen = kSEMC_Sdram_BurstLen8;
sdramconfig.columnAddrBitNum = kSEMC_SdramColunm_9bit;
sdramconfig.casLatency = kSEMC_LatencyThree;
sdramconfig.tPrecharge2Act_Ns = 18; /* Trp 18ns */
sdramconfig.tAct2ReadWrite_Ns = 18; /* Trcd 18ns */
sdramconfig.tRefreshRecovery_Ns = 70; /* Use the maximum of the (Trfc , Txsr). */
sdramconfig.tWriteRecovery_Ns = 12; /* 12ns */
sdramconfig.tCkeOff_Ns =
42; /* The minimum cycle of SDRAM CLK off state. CKE is off in self refresh at a minimum period tRAS.*/
sdramconfig.tAct2Prechage_Ns = 42; /* Tras 42ns */
sdramconfig.tSelfRefRecovery_Ns = 70;
sdramconfig.tRefresh2Refresh_Ns = 60;
sdramconfig.tAct2Act_Ns = 60;
sdramconfig.tPrescalePeriod_Ns = 160 * (1000000000 / clockFrq);
sdramconfig.refreshPeriod_nsPerRow = 64 * 1000000 / 4096; /* 64ms/8192 */
sdramconfig.refreshUrgThreshold = sdramconfig.refreshPeriod_nsPerRow;
sdramconfig.refreshBurstLen = 1;
sdramconfig.delayChain = 2;
sdramconfig.tIdleTimeout_Ns = 92;
return SEMC_ConfigureSDRAM(SEMC, kSEMC_SDRAM_CS0, &sdramconfig, clockFrq);
}
测试结果如下所示:
SEMC SDRAM Example Start!
EXAMPLE_SEMC_CLK_FREQ: 148500000
SEMC SDRAM Write 32 bit Start, Start Address 0x80000000, Data Length 8388607 !
SEMC SDRAM Read 32 bit Data Start, Start Address 0x80000000, Data Length 8388607 !
SEMC SDRAM Write 32 bit Start, Start Address 0x80000001, Data Length 8388607 !
SEMC SDRAM Read 32 bit Data Start, Start Address 0x80000001, Data Length 8388607 !
SEMC SDRAM Write 32 bit Start, Start Address 0x80000002, Data Length 8388607 !
SEMC SDRAM Read 32 bit Data Start, Start Address 0x80000002, Data Length 8388607 !
SEMC SDRAM Write 32 bit Start, Start Address 0x80000003, Data Length 8388607 !
SEMC SDRAM Read 32 bit Data Start, Start Address 0x80000003, Data Length 8388607 !
SEMC SDRAM 32 bit Data Write and Read Compare Succeed!
SEMC SDRAM Write 16 bit Start, Start Address 0x80000000, Data Length 16777215 !
SEMC SDRAM Read 16 bit Data Start, Start Address 0x80000000, Data Length 16777215 !
SEMC SDRAM Write 16 bit Start, Start Address 0x80000001, Data Length 16777215 !
SEMC SDRAM Read 16 bit Data Start, Start Address 0x80000001, Data Length 16777215 !
SEMC SDRAM 16 bit Data Write and Read Compare Succeed!
SEMC SDRAM Memory 8 bit Write Start, Start Address 0x80000000, Data Length 33554432 !
SEMC SDRAM Read 8 bit Data Start, Start Address 0x80000000, Data Length 33554432 !
SEMC SDRAM 8 bit Data Write and Read Compare Succeed!
SEMC SDRAM Example End.
4. 总结
默认DDR工作时钟为198Mhz,本文将其修改为148.5Mz.主要是针对SDRAM各参数如何从芯片中获取,取值的约束条件做了详细说明,至于各参数的具体含义可以从DDR的协议规范当中找到,或者芯片手册当中学到。