(转)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编辑  收藏  举报

导航