Hi,
I've designed a custom board with LPC54608J512BD208 and IS42S16160J-7TLI following the OM13098 schematics (RevF) as a reference. Here's my current SDRAM connection
Everything goes well with the board... except the SDRAM test. I've run the lpcxpresso54608_emc_sdram example provided by the SDK (v2.7.0) and the test fails at line 24 of the next of SDRAM_AddressBusCheck function.
status_t SDRAM_AddressBusCheck(volatile uint32_t *address, uint32_t bytes)
{
uint32_t pattern = 0x55555555;
uint32_t size = bytes / 4;
uint32_t offset;
uint32_t checkOffset;
/* write the pattern to the power-of-two address. */
for (offset = 1; offset < size; offset <<= 1)
{
address[offset] = pattern;
}
address[0] = ~pattern;
/* Read and check. */
for (offset = 1; offset < size; offset <<= 1)
{
if (address[offset] != pattern)
{
return kStatus_Fail;
}
}
if (address[0] != ~pattern)
{
return kStatus_Fail;
}
/* Change the data to the revert one address each time
* and check there is no effect to other address. */
for (offset = 1; offset < size; offset <<= 1)
{
address[offset] = ~pattern;
for (checkOffset = 1; checkOffset < size; checkOffset <<= 1)
{
if ((checkOffset != offset) && (address[checkOffset] != pattern))
{
return kStatus_Fail;
}
}
address[offset] = pattern;
}
return kStatus_Success;
}
In this case, address[0] = 0xaa2aaa2a so it does not match with the expected result (0x55555555). Previous loop (line 16) is terminated successfully.
On the other hand, here's is the IS42S16160J-7TLI SDRAM initialization
uint32_t dwtemp = dwtemp;
uint32_t emcFreq;
emc_basic_config_t basicConfig;
emcFreq = CLOCK_GetEmcClkFreq();
assert(emcFreq != 0); // Check the clock of emc
// Basic configuration.
basicConfig.endian = kEMC_LittleEndian;
basicConfig.fbClkSrc = kEMC_IntloopbackEmcclk;
// EMC Clock = CPU FREQ/2 here can fit CPU freq from 12M ~ 180M.
// If you change the divide to 0 and EMC clock is larger than 100M
// please take refer to emc.dox to adjust EMC clock delay.
//
basicConfig.emcClkDiv = 1;
EMC_Init(EMC, &basicConfig);
EMC->CONTROL = 1; // EMC controller active
EMC->CONFIG = 0; // EMC configuration register to 0 according to the DATASHEET
SYSCON->EMCDLYCTRL = 0x00001010;
// EMC Memory map selection: 4M x 16bits x 4 banks (banks = 4; row = 13; column = 9):
EMC->DYNAMIC[0].DYNAMICCONFIG = 0x00001680;
// EMC Delays configuration selection
EMC->DYNAMIC[0].DYNAMICRASCAS = 0x00000202; // 2 RAS, 2 CAS latency
EMC->DYNAMICREADCONFIG = 0x00000001; // Command delayed strategy, using EMCCLKDELAY
EMC->DYNAMICRP = 0x00000001; // ( n + 1 ) -> 2 clock cycles - Precharge to activate delay min 20nS --> 2 clock at 60Mhz
EMC->DYNAMICRAS = 0x00000002; // ( n + 1 ) -> 3 clock cycles - Activate to precharge delay min 45ns --> 3 clock at 60Mhz
EMC->DYNAMICSREX = 0x00000004; // ( n + 1 ) -> 5 clock cycles - SelfRegister exit time delay min 70nS --> 5 clock at 60Mhz
EMC->DYNAMICAPR = 0x00000002; // ( n + 1 ) -> 3 clock cycles //??????????
EMC->DYNAMICDAL = 0x00000004; // ( n + 0 ) -> 3 clock cycles - Data-in to activate delay 3.2 clocks at rounded to 4
EMC->DYNAMICWR = 0x00000001; // ( n + 1 ) -> 2 clock cycles - Write recovery time 2 clock cycles
EMC->DYNAMICRC = 0x00000003; // ( n + 1 ) -> 4 clock cycles - Active to active command period delay min 54ns --> 3.2 clock at 60Mhz
EMC->DYNAMICRFC = 0x00000003; // ( n + 1 ) -> 4 clock cycles - Autorefresh to active comand period delay 54ns --> 3.2 clock at 60Mhz
EMC->DYNAMICXSR = 0x00000003; // ( n + 1 ) -> 4 clock cycles - Exit self-refresh to active mode delay min 60ns --> 3.6 clock at 60Mhz
EMC->DYNAMICRRD = 0x00000000; // ( n + 1 ) -> 1 clock cycles - Activate A to activate B delay 14nS --> 1 clock at 60Mhz
EMC->DYNAMICMRD = 0x00000001; // ( n + 1 ) -> 2 clock cycles - Mode register to any command delay 2 clock cycles
// SDRAM initialization
SDK_DelayAtLeastUs(100000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);// wait 100ms to have the supply stable
EMC->DYNAMICCONTROL = 0x00000183; // Issue NOP command
SDK_DelayAtLeastUs(1000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);// Wait for some time to stabilization
EMC->DYNAMICCONTROL = 0x00000103; // Issue PALL command to precharge the SDRAM
EMC->DYNAMICREFRESH = 0x00000001; // Autorefresh must be as short as possible to precharge quickly the SDRAM !!!!!OJO habia 2
SDK_DelayAtLeastUs(100000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);// Wait for autorefresh command to execute at least two times
EMC->DYNAMICREFRESH = 0x0000003A; //Configure the right autorefresh cycle to th SDRAM
EMC->DYNAMICCONTROL = 0x00000083; // Mode command for the SDRAM to configure the mode of operation
dwtemp = *((volatile uint32_t *)(0xA0000000 | (0x23<<(10)))); // Force a command with the command in the address contents 8 burst, 2 CAS latency
EMC->DYNAMICCONTROL = 0x00000000; // Normal command to SDRAM to operate
EMC->DYNAMIC[0].DYNAMICCONFIG = 0x00081680; // Enable the buffers
Please could anyone help me with this issue? I also attach the mcuxpresso ide project.
regards,
gaston
已解决! 转到解答。
Higher values for CMD_DELAY and FBCLK_DELAY ?
I use 0x1010 on 54608 running at 180 MHz and EMC at 90 MHz. I use the same value on projects with the 54628 running at 200 MHz and EMC at 100 MHz. This does not mean that it is a "universal value" that works for all. I could also be something else with the design/setup.
Have you tried all kinds of bit patterns to see if they work ?
Gaston,
in all my designs with 54608, 54628 and SDRAM (and also on the NXP eval board!) I need to add:
SYSCON->EMCDLYCTRL = 0x1010; // Handles EMC clock=90 MHz !!!
to get the SDRAM to work properly.
Higher values for CMD_DELAY and FBCLK_DELAY ?
I use 0x1010 on 54608 running at 180 MHz and EMC at 90 MHz. I use the same value on projects with the 54628 running at 200 MHz and EMC at 100 MHz. This does not mean that it is a "universal value" that works for all. I could also be something else with the design/setup.
Have you tried all kinds of bit patterns to see if they work ?
At the end I have come to the conclusion that the PCB design (routing, stack-up) is not very suitable for the required SDRAM speeds. I will have to redo the design prioritizing this point.
Xiangjun & Carsten, thank you both for the given support.
regards,
gaston
Hi, Gaston,
From your description, I see that you use the similar SDRAM chip as the that of LPC54608 evaluation board and the example code in SDK package. I think the code is okay, because most of reading data are correct.
Regarding the issue that you write address[0]=0xaaaaaaaa, but you read as 0xaa2aaa2a, obviously, the D7 is read as 0 which should have been 1. I think it is a hardware issue, for high speed SDRAM access, you have to consider the signal integrity, in other words, 4 layers board, all data bus pins should connect to a serial resistor which locates as close as possible to the SDRAM data bus. BTW, if you decrease the SDRAM clock frequency, what is the result?
BR
Xiangjun Rong
Hi Xiangjun, I'm not sure is a Harware issue.The design includes a 4-layer PCB (one internal layer as solid GND) and the distribution is close enough (I hope) with the 22R resistors connected to the data bus.
Indeed the sdram test fails at the mentioned line. However if I write (outside from the test routine) ~0x55555555 at 0xA0000000 and read back from the same address I get 0xAAAAAAAA as expected.
In fact, there is no problem if I write/read back a 32-bit word to/from any SDRAM address in this way:
*(uint32_t *)(sdram) = ~0x55555555;
readData = *(uint32_t *)(sdram);
Why can't I pass the full test?
It's really puzzled me.
I've also tested it with lower EMC clks for example:
basicConfig.emcClkDiv = 1, 2, 3, 4, 5 and even 6 without success...
gaston