国庆快要到了,今年的中秋节刚好赶上国庆放假,在外飘着的我也要回家了。依然是一个人,依然是20个小时的站票,依然是在底层摸爬滚打的白领。站在家门口就能看到飞机场,依然还是拿着站票,想想都觉得心情很复杂,什么时候能觉得买一张机票和买一个面包的感觉是一样的呢?相信低谷终会过去,触底总会反弹,人生依然会灿烂。伟人说,不以结婚为目的的谈恋爱都是耍流氓。这里是技术区,不以技术为目的的写博客都是扯淡。当然,也不能偏激嘛,还是要有点文艺气息的。要不然遇到喜欢的姑娘,见面不跟人谈人生谈理想,一直跟人谈电磁抗干扰,姑娘绝对不会再出现。扯点儿无关紧要的东西,毕竟博客不是论文,不需要文绉绉的,下面开始技术交流,有理解不对的地方,欢迎各位技术大神批评指正。
LPC1857是M3内核的单片机,和我们使用广泛的STM32系列单片机有一些不同的地方,比如外扩SDRAM功能。普通的STM32没有SDRAM扩展接口,而LPC18系列具有这个功能。对于普通的单片机开发,平时很少需要外扩SDRAM,所以网上也很难找到关于单片机外扩SDRAM的相关技术文档。根据网上搜到的零散资料,在LPC1857开发板上不断的实验,理论和实践相互印证,才有了今天的这篇博文,希望能给正在苦苦寻找相关资料的广大程序猿提供参考。
既然是谈技术,我们就要谈的深入,谈的彻底,一些重要的基础知识这里也会介绍。习惯了散文的形式谈论技术,所以还是按照SDRAM的配置步骤说,中间穿插一些用到的理论基础知识。
一、SDRAM驱动
SDRAM在用作内存之前,是要先进行初始化操作的,要不然无法向里面写入数据,当然也就不能当内存使用了。LPC1857提供SDRAM总线接口,所以只需要设置总线频率和数据刷新频率就可以了。关于SDRAM的实现原理,网上有许多介绍,这里不再啰嗦,直接贴出LPC1857驱动SDRAM的关键代码供大家参考。
#define SCU_PIN_CONFIG(port, pin, mode, func) \
(*((volatile uint32_t*)(LPC_SCU_BASE+(PORT_OFFSET*(port)+PIN_OFFSET*(pin)))) = ((mode)+(func)))
//Ö±½Ó¼Ä´æÆ÷²Ù×÷£¬²»Ê¹ÓÃÕ»
void SdramInit(void)
{
register uint32_t i;
/* Shared signals : EXTBUS_A[23:0], EXTBUS_D[31:0], EXTBUS_WE*/
SCU_PIN_CONFIG( 2 , 9 , MD_PLN_FAST , 3 ); // EXTBUS_A0
SCU_PIN_CONFIG( 2 , 10 , MD_PLN_FAST , 3 ); // EXTBUS_A1
SCU_PIN_CONFIG( 2 , 11 , MD_PLN_FAST , 3 ); // EXTBUS_A2
SCU_PIN_CONFIG( 2 , 12 , MD_PLN_FAST , 3 ); // EXTBUS_A3
SCU_PIN_CONFIG( 2 , 13 , MD_PLN_FAST , 3 ); // EXTBUS_A4
SCU_PIN_CONFIG( 1 , 0 , MD_PLN_FAST , 2 ); // EXTBUS_A5
SCU_PIN_CONFIG( 1 , 1 , MD_PLN_FAST , 2 ); // EXTBUS_A6
SCU_PIN_CONFIG( 1 , 2 , MD_PLN_FAST , 2 ); // EXTBUS_A7
SCU_PIN_CONFIG( 2 , 8 , MD_PLN_FAST , 3 ); // EXTBUS_A8
SCU_PIN_CONFIG( 2 , 7 , MD_PLN_FAST , 3 ); // EXTBUS_A9
SCU_PIN_CONFIG( 2 , 6 , MD_PLN_FAST , 2 ); // EXTBUS_A10
SCU_PIN_CONFIG( 2 , 2 , MD_PLN_FAST , 2 ); // EXTBUS_A11
SCU_PIN_CONFIG( 2 , 1 , MD_PLN_FAST , 2 ); // EXTBUS_A12
SCU_PIN_CONFIG( 2 , 0 , MD_PLN_FAST , 2 ); // EXTBUS_A13
SCU_PIN_CONFIG( 6 , 8 , MD_PLN_FAST , 1 ); // EXTBUS_A14
#if 1
SCU_PIN_CONFIG( 6 , 7 , MD_PLN_FAST , 1 ); // EXTBUS_A15
SCU_PIN_CONFIG( 0xD , 16 , MD_PLN_FAST , 2 ); // EXTBUS_A16
SCU_PIN_CONFIG( 0xD , 15 , MD_PLN_FAST , 2 ); // EXTBUS_A17
SCU_PIN_CONFIG( 0xE , 0 , MD_PLN_FAST , 3 ); // EXTBUS_A18
SCU_PIN_CONFIG( 0xE , 1 , MD_PLN_FAST , 3 ); // EXTBUS_A19
SCU_PIN_CONFIG( 0xE , 2 , MD_PLN_FAST , 3 ); // EXTBUS_A20
SCU_PIN_CONFIG( 0xE , 3 , MD_PLN_FAST , 3 ); // EXTBUS_A21
SCU_PIN_CONFIG( 0xE , 4 , MD_PLN_FAST , 3 ); // EXTBUS_A22
SCU_PIN_CONFIG( 0xA , 4 , MD_PLN_FAST , 3 ); // EXTBUS_A23
#endif
SCU_PIN_CONFIG( 1 , 7 , MD_PLN_FAST , 3 ); // EXTBUS_D0
SCU_PIN_CONFIG( 1 , 8 , MD_PLN_FAST , 3 ); // EXTBUS_D1
SCU_PIN_CONFIG( 1 , 9 , MD_PLN_FAST , 3 ); // EXTBUS_D2
SCU_PIN_CONFIG( 1 , 10 , MD_PLN_FAST , 3 ); // EXTBUS_D3
SCU_PIN_CONFIG( 1 , 11 , MD_PLN_FAST , 3 ); // EXTBUS_D4
SCU_PIN_CONFIG( 1 , 12 , MD_PLN_FAST , 3 ); // EXTBUS_D5
SCU_PIN_CONFIG( 1 , 13 , MD_PLN_FAST , 3 ); // EXTBUS_D6
SCU_PIN_CONFIG( 1 , 14 , MD_PLN_FAST , 3 ); // EXTBUS_D7
SCU_PIN_CONFIG( 5 , 4 , MD_PLN_FAST , 2 ); // EXTBUS_D8
SCU_PIN_CONFIG( 5 , 5 , MD_PLN_FAST , 2 ); // EXTBUS_D9
SCU_PIN_CONFIG( 5 , 6 , MD_PLN_FAST , 2 ); // EXTBUS_D10
SCU_PIN_CONFIG( 5 , 7 , MD_PLN_FAST , 2 ); // EXTBUS_D11
SCU_PIN_CONFIG( 5 , 0 , MD_PLN_FAST , 2 ); // EXTBUS_D12
SCU_PIN_CONFIG( 5 , 1 , MD_PLN_FAST , 2 ); // EXTBUS_D13
SCU_PIN_CONFIG( 5 , 2 , MD_PLN_FAST , 2 ); // EXTBUS_D14
SCU_PIN_CONFIG( 5 , 3 , MD_PLN_FAST , 2 ); // EXTBUS_D15
#if 1
SCU_PIN_CONFIG( 0xD , 2 , MD_PLN_FAST , 2 ); // EXTBUS_D16
SCU_PIN_CONFIG( 0xD , 3 , MD_PLN_FAST , 2 ); // EXTBUS_D17
SCU_PIN_CONFIG( 0xD , 4 , MD_PLN_FAST , 2 ); // EXTBUS_D18
SCU_PIN_CONFIG( 0xD , 5 , MD_PLN_FAST , 2 ); // EXTBUS_D19
SCU_PIN_CONFIG( 0xD , 6 , MD_PLN_FAST , 2 ); // EXTBUS_D20
SCU_PIN_CONFIG( 0xD , 7 , MD_PLN_FAST , 2 ); // EXTBUS_D21
SCU_PIN_CONFIG( 0xD , 8 , MD_PLN_FAST , 2 ); // EXTBUS_D22
SCU_PIN_CONFIG( 0xD , 9 , MD_PLN_FAST , 2 ); // EXTBUS_D23
SCU_PIN_CONFIG( 0xE , 5 , MD_PLN_FAST , 3 ); // EXTBUS_D24
SCU_PIN_CONFIG( 0xE , 6 , MD_PLN_FAST , 3 ); // EXTBUS_D25
SCU_PIN_CONFIG( 0xE , 7 , MD_PLN_FAST , 3 ); // EXTBUS_D26
SCU_PIN_CONFIG( 0xE , 8 , MD_PLN_FAST , 3 ); // EXTBUS_D27
SCU_PIN_CONFIG( 0xE , 9 , MD_PLN_FAST , 3 ); // EXTBUS_D28
SCU_PIN_CONFIG( 0xE , 10 , MD_PLN_FAST , 3 ); // EXTBUS_D29
SCU_PIN_CONFIG( 0xE , 11 , MD_PLN_FAST , 3 ); // EXTBUS_D30
SCU_PIN_CONFIG( 0xE , 12 , MD_PLN_FAST , 3 ); // EXTBUS_D31
#endif
SCU_PIN_CONFIG( 1 , 6 , MD_PLN_FAST , 3 ); // EXTBUS_WE
/* Static memory signals : EXTBUS_OE, EXTBUS_BLS[3:0], EXTBUS_CS[3:0] */
SCU_PIN_CONFIG( 1 , 3 , MD_PLN_FAST , 3 ); // EXTBUS_OE
SCU_PIN_CONFIG( 1 , 4 , MD_PLN_FAST , 3 ); // EXTBUS_BLS0
SCU_PIN_CONFIG( 6 , 6 , MD_PLN_FAST , 1 ); // EXTBUS_BLS1
SCU_PIN_CONFIG( 0xD , 13 , MD_PLN_FAST , 2 ); // EXTBUS_BLS2
SCU_PIN_CONFIG( 0xD , 10 , MD_PLN_FAST , 2 ); // EXTBUS_BLS3
SCU_PIN_CONFIG( 1 , 5 , MD_PLN_FAST , 3 ); // EXTBUS_CS0
SCU_PIN_CONFIG( 6 , 3 , MD_PLN_FAST , 3 ); // EXTBUS_CS1
SCU_PIN_CONFIG( 0xD , 12 , MD_PLN_FAST , 2 ); // EXTBUS_CS2
SCU_PIN_CONFIG( 0xD , 11 , MD_PLN_FAST , 2 ); // EXTBUS_CS3
/* Dynamic memory signals : EXTBUS_DYCS[3:0], EXTBUS_CAS, EXTBUS_RAS, EXTBUS_CLK[3:0], EXTBUS_CLKOUT[3:0], EXTBUS_DQMOUT[3:0]*/
SCU_PIN_CONFIG( 6 , 9 , MD_PLN_FAST , 3 ); // EXTBUS_DYCS0
// SCU_PIN_CONFIG( 6 , 1 , MD_PLN_FAST , 1 ); // EXTBUS_DYCS1
// SCU_PIN_CONFIG( 0xD , 14 , MD_PLN_FAST , 2 ); // EXTBUS_DYCS2
// SCU_PIN_CONFIG( 0xE , 14 , MD_PLN_FAST , 3 ); // EXTBUS_DYCS3
SCU_PIN_CONFIG( 6 , 4 , MD_PLN_FAST , 3 ); // EXTBUS_CAS
SCU_PIN_CONFIG( 6 , 5 , MD_PLN_FAST , 3 ); // EXTBUS_RAS
LPC_SCU_CLK(0) = 0 + (MD_PLN_FAST); // EXTBUS_CLK0
LPC_SCU_CLK(1) = 0 + (MD_PLN_FAST); // EXTBUS_CLK1
LPC_SCU_CLK(2) = 0 + (MD_PLN_FAST); // EXTBUS_CLK2
LPC_SCU_CLK(3) = 0 + (MD_PLN_FAST); // EXTBUS_CLK3
SCU_PIN_CONFIG( 6 , 11 , MD_PLN_FAST , 3 ); // EXTBUS_CKEOUT0
//SCU_PIN_CONFIG( 6 , 2 , MD_PLN_FAST , 1 ); // EXTBUS_CKEOUT1
//SCU_PIN_CONFIG( 0xD , 1 , MD_PLN_FAST , 2 ); // EXTBUS_CKEOUT2
//SCU_PIN_CONFIG( 0xE , 15 , MD_PLN_FAST , 3 ); // EXTBUS_CKEOUT3
SCU_PIN_CONFIG( 6 , 12 , MD_PLN_FAST , 3 ); // EXTBUS_DQMOUT0
SCU_PIN_CONFIG( 6 , 10 , MD_PLN_FAST , 3 ); // EXTBUS_DQMOUT1
SCU_PIN_CONFIG( 0xD , 0 , MD_PLN_FAST , 2 ); // EXTBUS_DQMOUT2
SCU_PIN_CONFIG( 0xE , 13 , MD_PLN_FAST , 3 ); // EXTBUS_DQMOUT3
/* The EMC clock is half of the core clock */
LPC_CCU1->CLK_M3_EMCDIV_CFG = 0x01 | (1 << 5);
LPC_CREG->CREG6 |= (1 << 16);
//EMC½Ó¿ÚÅäÖÃ
LPC_SCU->EMCDELAYCLK = 0x7777;
LPC_EMC->CONTROL =1; /* Disable Address mirror */
#if 1
//MCX514?2¨¬?SRAM?????¡Â3?¨º??¡¥
LPC_EMC->STATICCONFIG3 = 0x81;
LPC_EMC->STATICWAITWEN3=0x0;/* ¨¦¨¨??¡ä¨®????¦Ì?D¡ä¨º1?¨¹¦Ì??¨®¨º¡À¡ê?¦Ì¨ª????¨®DD¡ì*/
LPC_EMC->STATICWAITOEN3 = 0x0; /* ¨¦¨¨??¡ä¨®?????¨°¦Ì??¡¤¡À??¡¥¡ê¡§¨¢????D??¨ª¨ª¦Ì?¡ê?¦Ì?¨º?3?¨º1?¨¹¦Ì??¨®¨º¡À¡ê?¦Ì¨ª????¨®DD¡ì*/
//LPC_EMC->STATICEXTENDEDWAIT =0x6;
LPC_EMC->STATICWAITWR3=0x2;/* ¨¦¨¨??¡ä¨®????¦Ì?D¡ä¨¨?¦Ì??¨®¨º¡À¡ê?¨®?EMCStaticConfig?¨®3¡è¦Ì¨¨¡äy??¨®D1??¦Ì,¦Ì¨ª????¨®DD¡ì*/
LPC_EMC->STATICWAITRD3 = 0x2;/* ¨¦¨¨??¡ä¨®????¦Ì??¨¢¨¨?¦Ì??¨®¨º¡À¡ê?¨®?EMCStaticConfig?¨®3¡è¦Ì¨¨¡äy??¨®D1??¦Ì¡ê?¦Ì¨ª????¨®DD¡ì*/
LPC_EMC->STATICWAITTURN3=0x0;/* ¨¦¨¨??¡Á¨¹??¦Ì??¨¹¡Áa?¨¹?¨²¨ºy¡ê?????¡Á??2¨¬?¡ä?¡ä¡é?¡Â?¨¢¡ê?D¡ä2¨´¡Á¡Â???????¨®¦Ì?¡Á¨¹???¨¹¡Áa?¨¹?¨²¨ºy¡ê?¦Ì¨ª????¨®DD¡ì*/
#endif
LPC_EMC->DYNAMICRP = P2C(SDRAM_TRP) - 1; /* Precharge command period -- Trp */
LPC_EMC->DYNAMICRAS = P2C(SDRAM_TRAS) - 1; /* Active to precharge command period -- Tras */
LPC_EMC->DYNAMICSREX = P2C(SDRAM_TXSR) - 1; /* Self-refresh exit time -- Txsr */
LPC_EMC->DYNAMICRC = P2C(SDRAM_TRC) - 1; /* Active to active command period -- Trc */
LPC_EMC->DYNAMICRFC = P2C(SDRAM_TRFC) - 1; /* Auto-refresh period and auto-refresh to active command period -- Trfc */
LPC_EMC->DYNAMICXSR = P2C(SDRAM_TXSR) - 1; /* Exit self-refresh to active command time -- Txsr */
LPC_EMC->DYNAMICRRD = SDRAM_TRRD; /* Active bank A to active bank B latency -- Trrd */
LPC_EMC->DYNAMICAPR = SDRAM_TAPR; /* Last-data-out to active command time -- Tapr */
LPC_EMC->DYNAMICDAL = SDRAM_TDAL+P2C(SDRAM_TRP) - 1; /* Data-in to active command -- Tdal */
LPC_EMC->DYNAMICWR = SDRAM_TWR; /* Write recovery time -- Twr*/
LPC_EMC->DYNAMICMRD = SDRAM_TMRD; /* Load mode register to active command time -- Tmrd */
LPC_EMC->DYNAMICREADCONFIG = 1; /* Command delayed strategy */
LPC_EMC->DYNAMICRASCAS0 = (3 << 0) |(3 << 8); /* RAS latency 3 CCLKs, CAS latenty 3 CCLKs. */
// LPC_EMC->DYNAMICCONFIG0 = 0<<14 | 3<<9 | 1<<7;
LPC_EMC->DYNAMICCONFIG0 = 1<<14 | 3<<9 | 1<<7; /* 256MB, 16Mx16, 4 banks, row=13, column=9 */
LPC_EMC->DYNAMICCONTROL = 0x0183; /* Mem clock enable, CLKOUT runs, send command: NOP */
for(i= 200*30; i;i--);
LPC_EMC->DYNAMICCONTROL = 0x0103; /* PRECHARGE-ALL, shortest possible refresh period */
LPC_EMC->DYNAMICREFRESH = 2; /* set 32 CCLKs between SDRAM refresh cycles */
for(i= 256; i; --i); /* wait 128 AHB clock cycles */
LPC_EMC->DYNAMICREFRESH = P2C(SDRAM_REFRESH) >> 4; /* 7.813us between SDRAM refresh cycles */
LPC_EMC->DYNAMICCONTROL = 0x00000083; /* Mem clock enable, CLKOUT runs, send command: MODE */
i = *((volatile uint32_t *)(SDRAM_ADDR_BASE | (0x32<<13))); /* Set Mode regitster */
// Dummy = *((volatile uint32_t *)(SDRAM_ADDR_BASE | (0x33<<12)));
LPC_EMC->DYNAMICCONTROL = 0x0000; /* Issue NORMAL command */
LPC_EMC->DYNAMICCONFIG0 |=(1<<19); /* Enable buffer */
for(i = 100000; i;i--);
}
二、SDRAM配置作内存
在讲SDRAM作内存配置方法之前,先说点ARM架构中编译链接生成的可执行文件的组成,以及ARM架构中加载域和执行域的概念。
(1)ARM架构中生成的可执行文件一般有三个段组成:RO、RW和ZI段。
RO段:存储程序中的指令和常量;RW段:存储程序中初始化值不为零的变量;ZI段:存储程序中没有初始化和初始化为零的变量。至于这些概念中的指令、常量、变量是什么,网上有很多详细的资料,对于一个嵌入式程序猿,这些应该很容易理解,不再啰嗦。
(2)ARM架构中加载域和执行域
加载域:可执行文件存储的地址区域。一般情况下代码会存储在单片机的内部falsh中,当然也可以存储在SDRAM中。可执行文件的三个段,只有RO和RW段需要存储,ZI段的值全部为零,所以只需要存储ZI段的空间大小信息就可以了。
执行域:可执行文件在运行时的地址区域。ARM架构中要求RW段存储的变量必须拷贝到可读写的RAM中,这样CPU才能方便的修改变量的值。对于ZI段,ARM架构中,也需要在RAM中为其分配指定的内存空间用于存储变量。
在MDK环境中,我们可以通过可视化界面去配置加载域和执行域,配置如下图所示:
为了更灵活的配置加载域和执行域,我们可以直接使用分散加载脚本,当然上面使用可视化界面配置的值最终也是翻译成了分散加载脚本的,分散加载脚本如下图所示,里面的语法结构,网上有很多详细的资料,这里不啰嗦:
通常,LPC1857的代码加载域和执行域都在内部flash中,flash起始地址为0x1a000000。单片机运行时,从0x1a000000处开始读取指令执行,根据LPC1857的代码分析,最开始的flash地址里存放的是中断向量表(这是M3架构的知识,不明白的自己查看M3内核使用指南)。这里我们要分析下单片机启动时都在干啥,因为这对于我们理解何时初始化SDRAM很有帮助,也就是说一定要在单片机用到SDRAM之前进行初始化,否则SDRAM肯定不能当内存使用。下面看最开始的启动代码:
单片机启动后,执行复位操作,在复位操作之后,我们调用了一些函数,这里我们先跳过,待会再返回来解释。先看__main函数,它究竟干了啥,在MDK的官方文档中有详细的说明,里面的东西又多又难理解,这里我直接说它重点做了啥。它主要是分配C语言运行必须的堆栈空间,把RW段的数据拷贝到内存中,为ZI段分配指定的内存空间,最后调用main函数开始执行程序。
从上面的解释可知,在__main函数调用之前,一定要做好内存的初始化工作,否则__main函数中无法正常使用内存。这里我们使用SDRAM作内存,所以我们必须在__main函数之前初始化SDRAM。现在我们回到之前跳过的地方,调用SdramInit函数的目的就是要在__main之前做好SDRAM的初始化工作。在这之前我们还调用了SystemInit函数,这是因为SDRAM初始化之前需要配置内核总线时钟,这个函数就是用来配置内核总线时钟的。当然,还有一点要注意,在__main函数分配好内存空间之前,所有的指令都不能使用内存,即不能在__main函数之前的函数中使用全局变量和局部变量,只能使用直接操作单片机的寄出器方式。有一点除外,就是可以使用register修饰的变量,因为被register修饰的变量是放在单片机的特殊寄出器组里的,不是放在内存中的,不过还是要尽量少用几个这样的变量,因为单片机里的特殊寄出器组也是有限的。
(三)使用JLINK把程序加载到SDRAM中调试
在第二节中,我们讲到加载域可以是内部flash,也可以是SDRAM。一般情况,我们把程序加载到内部flash中运行就可以了,但是有时候我们必须把代码加载到SDRAM中调试。有两种情况需要这样做:
(1)代码在内部flash存储时,每次调试烧录都很慢,为了加快调试效率,需要把程序加载到SDRAM中调试;
(2)当我们的程序大小超过了内部flash存储空间时,我们必须把代码放到eMMC等外部存储介质里,单片机启动时我们使用bootloader程序把外部存储介质里的程序拷贝到SDRAM中执行。如果使用这种方式,在调试的时候,我们就必须把程序加载到SDRAM里了。
单片机在线调试,我们一般都会使用MDK+JLINK的方式,JLINK根据分散加载脚本中的加载地址,把代码烧录到指定地址,然后开始进入调试状态。当加载地址是内部flash地址空间时,由于内部flash不需要初始化就可以直接使用,JLINK直接访问内部flash空间是没有问题的;当加载地址是SDRAM时,JLINK在访问SDRAM之前,必须先要初始化SDRAM才行。JLINK工具支持脚本的方式直接读写总线地址,这样我们就可以在JLINK的脚本中操作用于配置SDRAM的寄出器了,也就是说我们可以用JLINK脚本的方式初始化SDRAM。至于脚本的语法,这里不介绍,不明白的自己网上找相关资料,只给出脚本的源码和MDK中添加JLINK脚本的方法:
在画红框的地方的文件即为JLINK脚本,在MDK可视化界面中按上述方法添加脚本,就可以初始化SDRAM,同时把程序烧录到SDRAM中调试。注意,这种方法只能用于调试模式,不能用于下载模式,即只能点
图标,不能点
图标,因为下载模式下,加载完程序后,单片机会复位,SDRAM自然也被复位,这样加载到SDRAM中的程序也会被擦掉。下面是JLINK脚本的源码,贴出了供大家参考:
//¸ÃÎļþÓÃÓÚJLINKÅäÖÃLPC1857µÄϵͳʱÖÓºÍÍⲿSDRAM
//CPUϵͳʱÖÓ³õʼ»¯
FUNC void SysClockInit (void)
{
_WDWORD(0x40050018, 0x00000001);
_WDWORD(0x40050018, 0x00000000);
_WDWORD(0x40050044, 0x06171880);
_WDWORD(0x40050044, 0x06000800);
_WDWORD(0x40050044, 0x060e09c0);
_WDWORD(0x40050044, 0x060e09c0);
_sleep_(10);
_WDWORD(0x4005006c, 0x09000800);
}
//¹Ü½Å²Ù×÷
FUNC void GPIOInit(int port, int pin, int mod, int fun)
{
_WDWORD(0x40086000+(0x80*(port)+0x04*(pin)),(mod)+(fun));
}
//SDRAM¹Ü½Å³õʼ»¯
FUNC void SdramGpioInit (void)
{
/* Shared signals : EXTBUS_A[23:0], EXTBUS_D[31:0], EXTBUS_WE*/
GPIOInit( 2 , 9 , 0xf0 , 3 ); // EXTBUS_A0
GPIOInit( 2 , 10 , 0xf0 , 3 ); // EXTBUS_A1
GPIOInit( 2 , 11 , 0xf0 , 3 ); // EXTBUS_A2
GPIOInit( 2 , 12 , 0xf0 , 3 ); // EXTBUS_A3
GPIOInit( 2 , 13 , 0xf0 , 3 ); // EXTBUS_A4
GPIOInit( 1 , 0 , 0xf0 , 2 ); // EXTBUS_A5
GPIOInit( 1 , 1 , 0xf0 , 2 ); // EXTBUS_A6
GPIOInit( 1 , 2 , 0xf0 , 2 ); // EXTBUS_A7
GPIOInit( 2 , 8 , 0xf0 , 3 ); // EXTBUS_A8
GPIOInit( 2 , 7 , 0xf0 , 3 ); // EXTBUS_A9
GPIOInit( 2 , 6 , 0xf0 , 2 ); // EXTBUS_A10
GPIOInit( 2 , 2 , 0xf0 , 2 ); // EXTBUS_A11
GPIOInit( 2 , 1 , 0xf0 , 2 ); // EXTBUS_A12
GPIOInit( 2 , 0 , 0xf0 , 2 ); // EXTBUS_A13
GPIOInit( 6 , 8 , 0xf0 , 1 ); // EXTBUS_A14
GPIOInit( 6 , 7 , 0xf0 , 1 ); // EXTBUS_A15
GPIOInit( 0xD , 16 , 0xf0 , 2 ); // EXTBUS_A16
GPIOInit( 0xD , 15 , 0xf0 , 2 ); // EXTBUS_A17
GPIOInit( 0xE , 0 , 0xf0 , 3 ); // EXTBUS_A18
GPIOInit( 0xE , 1 , 0xf0 , 3 ); // EXTBUS_A19
GPIOInit( 0xE , 2 , 0xf0 , 3 ); // EXTBUS_A20
GPIOInit( 0xE , 3 , 0xf0 , 3 ); // EXTBUS_A21
GPIOInit( 0xE , 4 , 0xf0 , 3 ); // EXTBUS_A22
GPIOInit( 0xA , 4 , 0xf0 , 3 ); // EXTBUS_A23
GPIOInit( 1 , 7 , 0xf0 , 3 ); // EXTBUS_D0
GPIOInit( 1 , 8 , 0xf0 , 3 ); // EXTBUS_D1
GPIOInit( 1 , 9 , 0xf0 , 3 ); // EXTBUS_D2
GPIOInit( 1 , 10 , 0xf0 , 3 ); // EXTBUS_D3
GPIOInit( 1 , 11 , 0xf0 , 3 ); // EXTBUS_D4
GPIOInit( 1 , 12 , 0xf0 , 3 ); // EXTBUS_D5
GPIOInit( 1 , 13 , 0xf0 , 3 ); // EXTBUS_D6
GPIOInit( 1 , 14 , 0xf0 , 3 ); // EXTBUS_D7
GPIOInit( 5 , 4 , 0xf0 , 2 ); // EXTBUS_D8
GPIOInit( 5 , 5 , 0xf0 , 2 ); // EXTBUS_D9
GPIOInit( 5 , 6 , 0xf0 , 2 ); // EXTBUS_D10
GPIOInit( 5 , 7 , 0xf0 , 2 ); // EXTBUS_D11
GPIOInit( 5 , 0 , 0xf0 , 2 ); // EXTBUS_D12
GPIOInit( 5 , 1 , 0xf0 , 2 ); // EXTBUS_D13
GPIOInit( 5 , 2 , 0xf0 , 2 ); // EXTBUS_D14
GPIOInit( 5 , 3 , 0xf0 , 2 ); // EXTBUS_D15
GPIOInit( 0xD , 2 , 0xf0 , 2 ); // EXTBUS_D16
GPIOInit( 0xD , 3 , 0xf0 , 2 ); // EXTBUS_D17
GPIOInit( 0xD , 4 , 0xf0 , 2 ); // EXTBUS_D18
GPIOInit( 0xD , 5 , 0xf0 , 2 ); // EXTBUS_D19
GPIOInit( 0xD , 6 , 0xf0 , 2 ); // EXTBUS_D20
GPIOInit( 0xD , 7 , 0xf0 , 2 ); // EXTBUS_D21
GPIOInit( 0xD , 8 , 0xf0 , 2 ); // EXTBUS_D22
GPIOInit( 0xD , 9 , 0xf0 , 2 ); // EXTBUS_D23
GPIOInit( 0xE , 5 , 0xf0 , 3 ); // EXTBUS_D24
GPIOInit( 0xE , 6 , 0xf0 , 3 ); // EXTBUS_D25
GPIOInit( 0xE , 7 , 0xf0 , 3 ); // EXTBUS_D26
GPIOInit( 0xE , 8 , 0xf0 , 3 ); // EXTBUS_D27
GPIOInit( 0xE , 9 , 0xf0 , 3 ); // EXTBUS_D28
GPIOInit( 0xE , 10 , 0xf0 , 3 ); // EXTBUS_D29
GPIOInit( 0xE , 11 , 0xf0 , 3 ); // EXTBUS_D30
GPIOInit( 0xE , 12 , 0xf0 , 3 ); // EXTBUS_D31
GPIOInit( 1 , 6 , 0xf0 , 3 ); // EXTBUS_WE
/* Static memory signals : EXTBUS_OE, EXTBUS_BLS[3:0], EXTBUS_CS[3:0] */
GPIOInit( 1 , 3 , 0xf0 , 3 ); // EXTBUS_OE
GPIOInit( 1 , 4 , 0xf0 , 3 ); // EXTBUS_BLS0
GPIOInit( 6 , 6 , 0xf0 , 1 ); // EXTBUS_BLS1
GPIOInit( 0xD , 13 , 0xf0 , 2 ); // EXTBUS_BLS2
GPIOInit( 0xD , 10 , 0xf0 , 2 ); // EXTBUS_BLS3
GPIOInit( 1 , 5 , 0xf0 , 3 ); // EXTBUS_CS0
GPIOInit( 6 , 3 , 0xf0 , 3 ); // EXTBUS_CS1
GPIOInit( 0xD , 12 , 0xf0 , 2 ); // EXTBUS_CS2
GPIOInit( 0xD , 11 , 0xf0 , 2 ); // EXTBUS_CS3
/* Dynamic memory signals : EXTBUS_DYCS[3:0], EXTBUS_CAS, EXTBUS_RAS, EXTBUS_CLK[3:0], EXTBUS_CLKOUT[3:0], EXTBUS_DQMOUT[3:0]*/
GPIOInit( 6 , 9 , 0xf0 , 3 ); // EXTBUS_DYCS0
//GPIOInit( 6 , 1 , 0xf0 , 1 ); // EXTBUS_DYCS1
//GPIOInit( 0xD , 14 , 0xf0 , 2 ); // EXTBUS_DYCS2
//GPIOInit( 0xE , 14 , 0xf0 , 3 ); // EXTBUS_DYCS3
GPIOInit( 6 , 4 , 0xf0 , 3 ); // EXTBUS_CAS
GPIOInit( 6 , 5 , 0xf0 , 3 ); // EXTBUS_RAS
_WDWORD(0x40086000+0xC00+((0) * 0x4),0xf0); // EXTBUS_CLK0
_WDWORD(0x40086000+0xC00+((1) * 0x4),0xf0); // EXTBUS_CLK1
_WDWORD(0x40086000+0xC00+((2) * 0x4),0xf0); // EXTBUS_CLK2
_WDWORD(0x40086000+0xC00+((3) * 0x4),0xf0); // EXTBUS_CLK3
GPIOInit( 6 , 11 , 0xf0 , 3 ); // EXTBUS_CKEOUT0
//GPIOInit( 6 , 2 , 0xf0 , 1 ); // EXTBUS_CKEOUT1
//GPIOInit( 0xD , 1 , 0xf0 , 2 ); // EXTBUS_CKEOUT2
//GPIOInit( 0xE , 15 , 0xf0 , 3 ); // EXTBUS_CKEOUT3
GPIOInit( 6 , 12 , 0xf0 , 3 ); // EXTBUS_DQMOUT0
GPIOInit( 6 , 10 , 0xf0 , 3 ); // EXTBUS_DQMOUT1
GPIOInit( 0xD , 0 , 0xf0 , 2 ); // EXTBUS_DQMOUT2
GPIOInit( 0xE , 13 , 0xf0 , 3 ); // EXTBUS_DQMOUT3
}
//SDRAM×ÜÏß³õʼ»¯
FUNC void SdramPeriInit (void)
{
unsigned int i;
_WDWORD(0x40051478, 0x00000021);
_WDWORD(0x4004312C, 0x00010000);
//EMC½Ó¿ÚÅäÖÃ
_WDWORD(0x40086D00, 0x00007777);
/* Disable Address mirror */
_WDWORD(0x40005000, 0x00000001);
//MCX514 sram½Ó¿Ú³õʼ»¯
_WDWORD(0x40005260, 0x00000081);
_WDWORD(0x40005264, 0x00000000);
_WDWORD(0x40005268, 0x00000000);
_WDWORD(0x40005274, 0x00000002);
_WDWORD(0x4000526c, 0x00000002);
_WDWORD(0x40005278, 0x00000000);
/* Precharge command period -- Trp */
_WDWORD(0x40005030, 0x00000001);
/* Active to precharge command period -- Tras */
_WDWORD(0x40005034, 0x00000004);
/* Self-refresh exit time -- Txsr */
_WDWORD(0x40005038, 0x00000006);
/* Active to active command period -- Trc */
_WDWORD(0x40005048, 0x00000005);
/* Auto-refresh period and auto-refresh to active command period -- Trfc */
_WDWORD(0x4000504c, 0x00000005);
/* Exit self-refresh to active command time -- Txsr */
_WDWORD(0x40005050, 0x00000006);
/* Active bank A to active bank B latency -- Trrd */
_WDWORD(0x40005054, 0x00000001);
/* Last-data-out to active command time -- Tapr */
_WDWORD(0x4000503c, 0x00000001);
/* Data-in to active command -- Tdal */
_WDWORD(0x40005040, 0x00000004);
/* Write recovery time -- Twr*/
_WDWORD(0x40005044, 0x00000001);
/* Load mode register to active command time -- Tmrd */
_WDWORD(0x40005058, 0x00000001);
/* Command delayed strategy */
_WDWORD(0x40005028, 0x00000001);
/* RAS latency 3 CCLKs, CAS latenty 3 CCLKs. */
_WDWORD(0x40005124, 0x00000303);
/* 256MB, 16Mx16, 4 banks, row=13, column=9 */
_WDWORD(0x40005100, 0x00004680);
/* Mem clock enable, CLKOUT runs, send command: NOP */
_WDWORD(0x40005020, 0x00000183);
_sleep_(50);
/* PRECHARGE-ALL, shortest possible refresh period */
_WDWORD(0x40005020, 0x00000103);
/* set 32 CCLKs between SDRAM refresh cycles */
_WDWORD(0x40005024, 0x00000002);
/* wait 128 AHB clock cycles */
_sleep_(10);
/* 7.813us between SDRAM refresh cycles */
_WDWORD(0x40005024, 0x0000002c);
/* Mem clock enable, CLKOUT runs, send command: MODE */
_WDWORD(0x40005020, 0x00000083);
/* Set Mode regitster */
i = _RDWORD(0x28000000+(0x32<<13));
/* Issue NORMAL command */
_WDWORD(0x40005020, 0x00000000);
/* Enable buffer */
_WDWORD(0x40005100, 0x00084680);
_sleep_(50);
}
//CPUÌøµ½Ö¸¶¨µÄµØÖ·Ö´ÐгÌÐò
FUNC void Setup (unsigned int region)
{
region &= 0xFFFF0000;
SP = _RDWORD(region); // Setup Stack Pointer
PC = _RDWORD(region + 4); // Setup Program Counter
}
SysClockInit();
SdramGpioInit();
SdramPeriInit();
LOAD "obj\\app_code.axf" INCREMENTAL // Download program
Setup(0x28000000); // Setup for Running
go main
好了,也该结束了,耗时两天,人困马乏,祝大家国庆快乐!