NXP

(转)Cortex-M3 (NXP LPC1788)之SDRAM操作

2019-07-12 12:47发布

网上看到了一些关于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上面,那么希望本篇文章能给你些帮助。