MDK+JLINK環境下LPC1857外擴SDRAM在線調試實現

        國慶快要到了,今年的中秋節剛好趕上國慶放假,在外飄着的我也要回家了。依然是一個人,依然是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

好了,也該結束了,耗時兩天,人困馬乏,祝大家國慶快樂!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章