×
单片机 > 单片机程序设计 > 详情

Cortex-M3 (NXP LPC1788)之SDRAM操作

发布时间:2020-06-04 发布时间:
|

网上看到了一些关于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

 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 是我自己调试出来的准确的值,所以固定了。当然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上面,那么希望本篇文章能给你些帮助。



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
ARM 汇编的必知必会