(转)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上面,那么希望本篇文章能给你些帮助。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM