(轉)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