Cortex-M3 (NXP LPC1788)之SDRAM操作
網(wǎng)上看到了一些關(guān)于1788 SDRAM的調(diào)試代碼,基本上都一樣,本人在調(diào)試1788 SDRAM過程中,遇到了一些大麻煩,本人使用的的SDRAM芯片為MT48LC16M162. 本人遇到的問題如下:
1:1788芯片硬件仿真初期,調(diào)試SDRAM寄存器配置錯誤,導(dǎo)致1788芯片無法進(jìn)入仿真狀態(tài),只能用Flash Magic才能擦除。
2:1788芯片的SDRAM有一個很重要的寄存器,官方驅(qū)動為 LPC_SC->EMCDLYCTL 寄存器的設(shè)置,就算你和官方所使用芯片一樣,只要電路板有差異,這個寄存器的設(shè)置將有可能導(dǎo)致SDRAM在使用過程中出現(xiàn)錯誤。
3:還有對于時序的設(shè)置,這一步相對來說就比較簡單了。
下面例舉出我的示例代碼:
說明:
1:至于端口配置本人參考官方NXP網(wǎng)站,如果你的端口有充足情況下面,本人建議你不要修改。
2:本人的CPU主頻為108M,不是120M,因為我的電路板的原因,在120M的時候,偶爾會有無法啟動SDRAM的情況,所以為了安全本人使用了108M的主頻。
1 #define SDRAM_REFRESH 7513
2 #define SDRAM_TRP 24
3 #define SDRAM_TRAS 40
4 #define SDRAM_TAPR 2
5 #define SDRAM_TDAL 2
6 #define SDRAM_TWR 18
7 #define SDRAM_TRC 70
8 #define SDRAM_TRFC 70
9 #define SDRAM_TXSR 78
10 #define SDRAM_TRRD 18
11 #define SDRAM_TMRD 2
12
13
14
15 void EMC_Init(void)
16 {
17 uint8_t i;
18
19
20 CLKPWR_ConfigPPWR(CLKPWR_PCONP_PCEMC, ENABLE);
21 LPC_SC->EMCDLYCTL = (0x10 << 8) | (0 << 16) | (0 << 24) | 4;
22
23 LPC_EMC->Control = 0x00000001;
24 LPC_EMC->Config = 0x00000000;
25
26
27 PINSEL_ConfigPin(2,14,1);
28 PINSEL_ConfigPin(2,15,1);
29 PINSEL_ConfigPin(2,16,1);
30 PINSEL_ConfigPin(2,17,1);
31 PINSEL_ConfigPin(2,18,1);
32 PINSEL_ConfigPin(2,19,1);
33 PINSEL_ConfigPin(2,20,1);
34 PINSEL_ConfigPin(2,21,1);
35 PINSEL_ConfigPin(2,22,1);
36 PINSEL_ConfigPin(2,23,1);
37 PINSEL_ConfigPin(2,24,1);
38 PINSEL_ConfigPin(2,25,1);
39 PINSEL_ConfigPin(2,26,1);
40 PINSEL_ConfigPin(2,27,1);
41 PINSEL_ConfigPin(2,28,1);
42 PINSEL_ConfigPin(2,29,1);
43 PINSEL_ConfigPin(2,30,1);
44 PINSEL_ConfigPin(2,31,1);
45
46 for(i = 0; i < 32; i++)
47 {
48 PINSEL_ConfigPin(3,i,1);
49 PINSEL_ConfigPin(4,i,1);
50 }
51
52 }
53
54
55
56 int Sdram_Debug(void)
57 {
58 INT32U i=0,j,k;
59 volatile INT32U *pmp;
60
61
62 pmp = (volatile INT32U *)BASE_SDRAMADDR;
63 j = SDRAM_SIZE/sizeof(*pmp);
64 for(i=0;i 65 pmp[i] = i; 66 67 for (k =0; k < 1; k++) 68 { 69 for(i=0;i 70 { 71 if(pmp[i] != i) 72 { 73 while(1); 74 return FALSE; 75 } 76 } 77 } 78 return TRUE; 79 } 80 81 82 83 #define P2C(Period) (((Period 84 85 void SDRAMInit(void) 86 { 87 uint32_t i; 88 int dwtemp; 89 uint32_t uClk; 90 float SDRAM_PERIOD; 91 LPC_EMC->DynamicConfig0 = 0x00000680; 92 93 uClk = CLKPWR_GetCLK(CLKPWR_CLKTYPE_EMC); 94 uClk /= 1000000UL; 95 SDRAM_PERIOD = (float)1000/uClk; 96 97 LPC_EMC->DynamicRP = P2C(SDRAM_TRP); 98 LPC_EMC->DynamicRAS = P2C(SDRAM_TRAS); 99 LPC_EMC->DynamicSREX = P2C(SDRAM_TXSR); 100 LPC_EMC->DynamicAPR = SDRAM_TAPR; 101 LPC_EMC->DynamicDAL = SDRAM_TDAL+P2C(SDRAM_TRP); 102 LPC_EMC->DynamicWR = P2C(SDRAM_TWR); 103 LPC_EMC->DynamicRC = P2C(SDRAM_TRC); 104 LPC_EMC->DynamicRFC = P2C(SDRAM_TRFC); 105 LPC_EMC->DynamicXSR = P2C(SDRAM_TXSR); 106 LPC_EMC->DynamicRRD = P2C(SDRAM_TRRD); 107 LPC_EMC->DynamicMRD = SDRAM_TMRD; 108 109 LPC_EMC->DynamicConfig0 = 0x00000680; 110 LPC_EMC->DynamicRasCas0 = 0x00000303; 111 LPC_EMC->DynamicReadConfig = 0x00000001; 112 113 TIM_Waitms(100); 114 LPC_EMC->DynamicControl = 0x00000183; /* Issue NOP command */ 115 116 TIM_Waitms(200); 117 LPC_EMC->DynamicControl = 0x00000103; 118 LPC_EMC->DynamicRefresh = 0x00000002; 119 120 for(i = 0; i < 0x100; i++); 121 122 LPC_EMC->DynamicRefresh = P2C(SDRAM_REFRESH)>>4; 123 124 LPC_EMC->DynamicControl = 0x00000083; /* Issue MODE command */ 125 126 dwtemp = *((volatile int *)(SDRAM_BASE_ADDR | (0x33<<12))); 127 128 LPC_EMC->DynamicControl = 0x00000000; 129 130 LPC_EMC->DynamicConfig0 = 0x00080680; 131 for(i = 0; i < 20000; i++); 132 Sdram_Debug(); 133 } 上面的LPC_SC->EMCDLYCTL 是我自己調(diào)試出來的準(zhǔn)確的值,所以固定了。當(dāng)然Segger公司有一個更好的辦法計算LPC_SC->EMCDLYCTL,以下為參考Segger公司的函數(shù)。 1 static int _TestSDRAM(void) { 2 volatile uint32_t * pWriteLong; 3 volatile uint16_t * pWriteShort; 4 uint32_t Data; 5 uint32_t i; 6 uint32_t j; 7 8 pWriteLong = (uint32_t*)SDRAM_BASE_ADDR; 9 pWriteShort = (uint16_t*)SDRAM_BASE_ADDR; 10 // 11 // Fill 16 bit wise 12 // 13 for (i = 0; i < (SDRAM_SIZE / 0x40000); i++) { 14 for (j = 0; j < 0x100; j++) { 15 *pWriteShort++ = (i + j); 16 *pWriteShort++ = (i + j) + 1; 17 } 18 } 19 // 20 // Verifying 21 // 22 pWriteLong = (uint32_t*)SDRAM_BASE_ADDR; 23 for (i = 0; i < (SDRAM_SIZE / 0x40000); i++) { 24 for (j = 0; j < 0x100; j++) { 25 Data = *pWriteLong++; 26 if (Data != (((((i + j) + 1) & 0xFFFF) << 16) | ((i + j) & 0xFFFF))) { 27 return 1; // Error 28 } 29 } 30 } 31 return 0; // O.K. 32 } 33 34 static void _FindDelay(int DelayType) { 35 uint32_t Delay; 36 uint32_t Min; 37 uint32_t Max; 38 uint32_t v; 39 Delay = 0x00; 40 Min = 0xFF; 41 Max = 0xFF; 42 // 43 // Test for DLY min./max. values 44 // 45 while (Delay < 32) { 46 // 47 // Setup new DLY value to test 48 // 49 if (DelayType == 0) { 50 v = LPC_SC->EMCDLYCTL & ~0x001Ful; 51 LPC_SC->EMCDLYCTL = v | Delay; 52 } else { 53 v = LPC_SC->EMCDLYCTL & ~0x1F00ul; 54 LPC_SC->EMCDLYCTL = v | (Delay << 8); 55 } 56 // 57 // Test configured DLY value and find out min./max. values that will work 58 // 59 if (_TestSDRAM() == 0) { 60 // 61 // Test passed, remember min. DLY value if not done yet 62 // 63 if (Min == 0xFF) { 64 Min = Delay; 65 } 66 } else { 67 // 68 // Test failed, if a min. value has been found before, remember the current value for max. 69 // 70 if (Min != 0xFF) { 71 Max = Delay; 72 } 73 } 74 Delay++; 75 } 76 // 77 // Calc DLY value 78 // 7