1. 程式人生 > >MDK+JLINK環境下LPC1857外擴SDRAM線上除錯實現

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

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