(转)Cortex-M3 (NXP LPC1788)之SDRAM操作
网上看到了一些关于1788 SDRAM的调试代码,基本上都一样,本人在调试1788 SDRAM过程中,遇到了一些大麻烦,本人使用的的SDRAM芯片为MT48LC16M162. 本人遇到的问题如下:
1: 1788芯片硬件仿真初期,调试SDRAM寄存器配置错误,导致1788芯片无法进入仿真状态,只能用Flash Magic才能擦除。
2: 1788芯片的SDRAM有一个很重要的寄存器,官方驱动为 LPC_SC->EMCDLYCTL 寄存器的设置,就算你和官方所使用芯片一样,只要电路板有差异,这个寄存器的设置将有可能导致SDRAM在使用过程中出现错误。
3: 还有对于时序的设置,这一步相对来说就比较简单了。
下面例举出我的示例代码:
说明:
1: 至于端口配置本人参考官方NXP网站,如果你的端口有充足情况下面,本人建议你不要修改。
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<j;i++)
65 pmp[i] = i;
66
67 for (k =0; k < 1; k++)
68 {
69 for(i=0;i<j;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<SDRAM_PERIOD)?0:(uint32_t)((float)Period/SDRAM_PERIOD))+1)
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 是我自己调试出来的准确的值,所以固定了。当然Segger公司有一个更好的办法计算LPC_SC->EMCDLYCTL,以下为参考Segger公司的函数。
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 //
79 if (Max != 0xFF) { // If we found a min. and max. value we use the average of the min. and max. values to get an optimal DQSIN delay
80 Delay = (Min + Max) / 2;
81 } else if (Min != 0xFF) { // If we found only a min. value we use the average of the min. value and the longest DLY value to get an optimal DQSIN delay
82 Delay = (Min + 0x1F) / 2;
83 } else { // No working max. and/or min. values found
84 while (1); // Fatal error
85 }
86 //
87 // Setup DLY value to work with
88 //
89 if (DelayType == 0) {
90 v = LPC_SC->EMCDLYCTL & ~0x001Ful;
91 LPC_SC->EMCDLYCTL = v | Delay;
92 } else {
93 v = LPC_SC->EMCDLYCTL & ~0x1F00ul;
94 LPC_SC->EMCDLYCTL = v | (Delay << 8);
95 }
96 }
97
98
99 static uint32_t _CalibrateOsc(void) {
100 uint32_t Cnt;
101 uint32_t v;
102 uint32_t i;
103
104 //
105 // Init start values
106 //
107 Cnt = 0;
108 //
109 // Calibrate osc.
110 //
111 for (i = 0; i < 10; i++) {
112 LPC_SC->EMCCAL = (1 << 14); // Start calibration
113 v = LPC_SC->EMCCAL;
114 while ((v & (1 << 15)) == 0) { // Wait for calibration done
115 v = LPC_SC->EMCCAL;
116 }
117 Cnt += (v & 0xFF);
118 }
119 return (Cnt / 10);
120 }
121
122 static void _AdjustEMCTiming(uint32_t Delay) {
123 uint32_t v;
124 uint32_t CmdDly;
125 uint32_t FBDelay;
126 uint32_t FBClkDly;
127
128 FBDelay = _CalibrateOsc();
129
130 v = LPC_SC->EMCDLYCTL;
131 CmdDly = ((v & 0x001Ful) * Delay / FBDelay) & 0x1F;
132 FBClkDly = ((v & 0x1F00ul) * Delay / FBDelay) & 0x1F00;
133 LPC_SC->EMCDLYCTL = (v & ~0x1F1Ful) | FBClkDly | CmdDly;
134 }
135
136
137 void SDRAMInit(void)
138 {
139 uint32_t i;
140 int dwtemp;
141 uint32_t uClk;
142 float SDRAM_PERIOD;
143 LPC_EMC->DynamicConfig0 = 0x00000680;
144
145 uClk = CLKPWR_GetCLK(CLKPWR_CLKTYPE_EMC);
146 uClk /= 1000000UL;
147 SDRAM_PERIOD = (float)1000/uClk;
148 LPC_EMC->DynamicRP = P2C(SDRAM_TRP);
149 LPC_EMC->DynamicRAS = P2C(SDRAM_TRAS);
150 LPC_EMC->DynamicSREX = P2C(SDRAM_TXSR);
151 LPC_EMC->DynamicAPR = SDRAM_TAPR;
152 LPC_EMC->DynamicDAL = SDRAM_TDAL+P2C(SDRAM_TRP);
153 LPC_EMC->DynamicWR = P2C(SDRAM_TWR);
154 LPC_EMC->DynamicRC = P2C(SDRAM_TRC);
155 LPC_EMC->DynamicRFC = P2C(SDRAM_TRFC);
156 LPC_EMC->DynamicXSR = P2C(SDRAM_TXSR);
157 LPC_EMC->DynamicRRD = P2C(SDRAM_TRRD);
158 LPC_EMC->DynamicMRD = SDRAM_TMRD;
159
160 LPC_EMC->DynamicConfig0 = 0x00000680;
161 LPC_EMC->DynamicRasCas0 = 0x00000303;
162 LPC_EMC->DynamicReadConfig = 0x00000001;
163
164 TIM_Waitms(100);
165 LPC_EMC->DynamicControl = 0x00000183; /* Issue NOP command */
166
167 TIM_Waitms(200);
168 LPC_EMC->DynamicControl = 0x00000103;
169 LPC_EMC->DynamicRefresh = 0x00000002;
170
171 for(i = 0; i < 0x100; i++);
172
173 LPC_EMC->DynamicRefresh = P2C(SDRAM_REFRESH)>>4;
174
175 LPC_EMC->DynamicControl = 0x00000083; /* Issue MODE command */
176
177 dwtemp = *((volatile int *)(SDRAM_BASE_ADDR | (0x33<<12)));
178
179 LPC_EMC->DynamicControl = 0x00000000;
180
181 LPC_EMC->DynamicConfig0 = 0x00080680;
182 i = _CalibrateOsc();
183 _FindDelay(0); // EMCDLY
184 _FindDelay(1); // FBCLKDLY
185
186 _AdjustEMCTiming(i);
187 }
本人因为SDRAM的问题,折腾了进半个月的时间,移植UCOSIII,YAFFS2,UCGUI , LWIP中间,程序本来是没有问题,因为SDRAM的问题,曾经好几次让我想放弃这个芯片,翻过了不知道多少遍M3的手册,看了不知道多少遍数据手册,不过最后我还是很幸运的调试出来....如果你现在的问题也出在SDRAM上面,那么希望本篇文章能给你些帮助。
posted on 2012-09-26 19:40 tdyizhen1314 阅读(9650) 评论(1) 编辑 收藏 举报