Hi there,
I have a custom pcb mounted with an LPC4367 and interfaced with EMC an external sdram IS42S16320D of 512Mbit.
I have followed AN11508 and set up emc and sdram timings.
I have ported from lpcopen 3.01 for keil the process of initialization of EMC and sdram. I have also ported and run the memtest that lpcopen 3.01 provides (periph_memtest) and sdram works fine.
After setting up the emc and sdram i am kind of confused how to use the external sdram.
I have some questions.
1.
What is the suggested procedure to correclty use external sdram?
Sdram is interfaced with microcontroller through emc
Do i have to go to Project-Settings-MCU and add the new sdram?
Do i have to manually modify the linker script?
Both?
I have only found scattered information and not a complete guide of how to use external sdram
2.
In lpcopen 3.01 for keil 4357 (which i follow and port various things from there to my custom pcb)
in periph_lcd example the only thing i see regarding sdram is the below line:
static uint16_t *framebuffer = (uint16_t *) FRAMEBUFFER_ADDR;
where FRAMEBUFFER_ADDR is 0x28000000 which is the memory emc puts external sdram. I also configured emc for my custom pcb the same way. 0x28000000 is my base sdram address.
I see nowhere in project setting of adding a new ram block or any mention to that address in linker script or any use of cr_section_macros.h.
Is just declaring a pointer or a variable like the
static uint16_t *framebuffer = (uint16_t *) FRAMEBUFFER_ADDR
enough for using sdram?
NXP, I need some help and explanation.
Please don't post the obvious answers and links without any explanation like
Placing data into different RAM blocks
Allocating dynamic memory in External SDRAM
and links that google search returns.
I have read those and weren't concrete enough to get the whole picture.
Thanks a lot in advance!
1) Do I have to manually modify the linker script?
It's up to you, for instance, after initialize the EMC module, you choose a area of external RAM to store the data, you can write or read the external RAM as the memtest demo illustrates.
It's not necessary to modify the linker file manually.
However, in the case, you want to declare a array which locates in the external RAM, it'd better to modify the linker file to fit for this implementation.
Placing data into different RAM blocks
Allocating dynamic memory in External SDRAM
These above thread are about the LPCXpressor IDE, of course, they're not fit for the other IDE.
Have a great day,
TIC
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi,
Thanks for replying!
I have edited the memory configuration and added my external sdram at address 0x28000000 as EMC indicates.
I have this small testing code with linker option -print-memory-usage enabled.
#include <cr_section_macros.h>
#include "board.h"
__DATA(RAM6) char data_buffer[1024] ;
int main(void)
{
SystemCoreClockUpdate();
Board_Init();
for (int i = 0; i < sizeof(data_buffer); i++)
{
data_buffer[i] = 0xF;
}
}
Memory usage of the above example is:
Memory region Used Size Region Size %age Used
MFlashA512: 10868 B 512 KB 2.07%
MFlashB512: 0 GB 512 KB 0.00%
RamLoc32: 348 B 32 KB 1.06%
RamLoc40: 0 GB 40 KB 0.00%
RamAHB32: 0 GB 32 KB 0.00%
RamAHB16: 0 GB 16 KB 0.00%
RamAHB_ETB16: 0 GB 16 KB 0.00%
External_SDRAM: 1 KB 64 MB 0.00%
So far everything seems ok.
Then i want to make a larger buffer half the size the whole external sdram:
#include <cr_section_macros.h>
#include "board.h"
__DATA(RAM6) char data_buffer[32 * 1024 * 1024] ;
int main(void)
{
SystemCoreClockUpdate();
Board_Init();
for (int i = 0; i < sizeof(data_buffer); i++)
{
data_buffer[i] = 0xF;
}
}
This is the outcome:
Memory region Used Size Region Size %age Used
MFlashA512: 33564276 B 512 KB 6401.88%
MFlashB512: 0 GB 512 KB 0.00%
RamLoc32: 348 B 32 KB 1.06%
RamLoc40: 0 GB 40 KB 0.00%
RamAHB32: 0 GB 32 KB 0.00%
RamAHB16: 0 GB 16 KB 0.00%
c:/nxp/lpcxpresso_8.2.0_647/lpcxpresso/tools/bin/../lib/gcc/arm-none-eabi/5.3.1/../../../../arm-none-eabi/bin/ld.exe: periph_sdram_test.axf section `.data_RAM6' will not fit in region `MFlashA512'
RamAHB_ETB16: 0 GB 16 KB 0.00%
c:/nxp/lpcxpresso_8.2.0_647/lpcxpresso/tools/bin/../lib/gcc/arm-none-eabi/5.3.1/../../../../arm-none-eabi/bin/ld.exe: region `MFlashA512' overflowed by 33039988 bytes
External_SDRAM: 32 MB 64 MB 50.00%
Sdram seems to have 32MB occupied as expected but flash A overflows.
This is because .text section of program goes to flash i suppose.
So how can avoid this from happening?
I want to use Sdram to store large arrays and if possible store .text section also in external sdram if flash A does not have the capacity.
Can i do this?
Any suggestion?
Thanks a lot!
Hi Dimitris Sideris,
Please referring to the the method as the following thread illustrates, and after testing, it definitely occupies any space of the flash.
Fig 1
Fig 2
Have a great day,
TIC
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi
Thanks a lot.
After your suggestion i used the __NOINIT(bank) macro and it worked the same as your example.
The issue is that sdram is not consistent.
When i write to the buffer that is located in sdram from 10 to 50 values everything seems ok.
When the array is kind of larger 1024 (not to mention even larger like 32*1024*1024) values in sdram are not the values i assigned.
Actually all values are 255.
example code:
#include <cr_section_macros.h>
#include "board.h"
#define BUF_SIZE 1024
__NOINIT(RAM6) uint8_t data_buffer[BUF_SIZE];
void fill_data_buffer() {
for (int i = 0; i < BUF_SIZE; i++)
{
if (i<BUF_SIZE/2) {
data_buffer[i] = 0x0A;
}
else {
data_buffer[i] = 0x0B;
}
}
}
int main(void)
{
SystemCoreClockUpdate();
Board_Init();
fill_data_buffer();
}
Any clue or idea why is this happening?
Thanks a lot in advance
Any help?
I am really stuck here.
My initialization code is taken from lpcopen for keil and it is modified for my needs.
void Board_SystemInit(void)
{
/* Setup system clocking and memory. This is done early to allow the
application and tools to clear memory and use scatter loading to
external memory. */
Board_SetupMuxing();
Board_SetupClocking();
Board_SetupExtMemory();
}
void Board_SetupMuxing(void)
{
int i;
/* Setup system level pin muxing */
Chip_SCU_SetPinMuxing(pinmuxing, sizeof(pinmuxing) / sizeof(PINMUX_GRP_T));
/* Clock pins only, group field not used */
for (i = 0; i < (sizeof(pinclockmuxing) / sizeof(pinclockmuxing[0])); i++) {
Chip_SCU_ClockPinMuxSet(pinclockmuxing[i].pinnum, pinclockmuxing[i].modefunc);
}
}
STATIC const PINMUX_GRP_T pinmuxing[] = {
/* External data lines D0 .. D15 */
{0x1, 7,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
{0x1, 8,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
{0x1, 9,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
{0x1, 10,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
{0x1, 11,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
{0x1, 12,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
{0x1, 13,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
{0x1, 14,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
{0x5, 4,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC2)},
{0x5, 5,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC2)},
{0x5, 6,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC2)},
{0x5, 7,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC2)},
{0x5, 0,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC2)},
{0x5, 1,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC2)},
{0x5, 2,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC2)},
{0x5, 3,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC2)},
/* Address lines A0 .. A23 */
{0x2, 9,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
{0x2, 10,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
{0x2, 11,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
{0x2, 12,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
{0x2, 13,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
{0x1, 0,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC2)},
{0x1, 1,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC2)},
{0x1, 2,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC2)},
{0x2, 8,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
{0x2, 7,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
{0x2, 6,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC2)},
{0x2, 2,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC2)},
{0x2, 1,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC2)},
{0x2, 0,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC2)},
{0x6, 8,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC1)},
//DYCS0
{0x6, 9,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
//WE
{0x1, 6,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
//CAS
{0x6, 4,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
//RAS
{0x6, 5,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
//CKEOUT0
{0x6, 11,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
//DQMOUT0
{0x6, 12,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
//DQMOUT1
{0x6, 10,
(SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC3)},
};
STATIC const PINMUX_GRP_T pinclockmuxing[] = {
{0, 0, (SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC0)},
{0, 1, (SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC0)},
{0, 2, (SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC0)},
{0, 3, (SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_FUNC0)},
};
void Board_SetupClocking(void)
{
int i;
Chip_Clock_SetBaseClock(CLK_BASE_SPIFI, CLKIN_IRC, true, false); // change SPIFI to IRC during clock programming
LPC_SPIFI->CTRL |= SPIFI_CTRL_FBCLK(1); // and set FBCLK in SPIFI controller
/* Enable Flash acceleration and setup wait states */
Chip_CREG_SetFlashAcceleration(MAX_CLOCK_FREQ);
/* Setup System core frequency to MAX_CLOCK_FREQ */
Chip_SetupCoreClock(CLKIN_CRYSTAL, MAX_CLOCK_FREQ, true);
/* Setup system base clocks and initial states. This won't enable and
disable individual clocks, but sets up the base clock sources for
each individual peripheral clock. */
for (i = 0; i < (sizeof(InitClkStates) / sizeof(InitClkStates[0])); i++) {
Chip_Clock_SetBaseClock(InitClkStates[i].clk, InitClkStates[i].clkin,
InitClkStates[i].autoblock_enab, InitClkStates[i].powerdn);
}
/* Reset and enable 32Khz oscillator */
LPC_CREG->CREG0 &= ~((1 << 3) | (1 << 2));
LPC_CREG->CREG0 |= (1 << 1) | (1 << 0);
}
void Board_SetupExtMemory(void)
{
/* Setup EMC Delays */
/* Move all clock delays together */
LPC_SCU->EMCDELAYCLK = ((CLK0_DELAY) | (CLK0_DELAY << 4) | (CLK0_DELAY << 8) | (CLK0_DELAY << 12));
/* Setup EMC Clock Divider for divide by 2 - this is done in both the CCU (clocking)
and CREG. For frequencies over 120MHz, a divider of 2 must be used. For frequencies
less than 120MHz, a divider of 1 or 2 is ok. */
Chip_Clock_EnableOpts(CLK_MX_EMC_DIV, true, true, 2);
LPC_CREG->CREG6 |= (1 << 16);
/* Enable EMC clock */
Chip_Clock_Enable(CLK_MX_EMC);
/* Init EMC Controller -Enable-LE mode */
Chip_EMC_Init(1, 0, 0);
/* Init EMC Dynamic Controller */
Chip_EMC_Dynamic_Init((IP_EMC_DYN_CONFIG_T *) &IS4245S16320D_config);
/* Enable Buffer for External Flash */
LPC_EMC->STATICCONFIG0 |= 1 << 19;
}
STATIC const IP_EMC_DYN_CONFIG_T IS4245S16320D_config = {
EMC_NANOSECOND(64000000 / 8192), /* Row refresh time */
0x01, /* Command Delayed */
EMC_NANOSECOND(18),
EMC_NANOSECOND(42),
EMC_NANOSECOND(70),
EMC_CLOCK(0x03),
EMC_CLOCK(0x05),
EMC_NANOSECOND(18),
EMC_NANOSECOND(60),
EMC_NANOSECOND(60),
EMC_NANOSECOND(70),
EMC_NANOSECOND(12),
EMC_CLOCK(0x02),
{
{
EMC_ADDRESS_DYCS0, /* Keil Board uses DYCS0 for SDRAM */
6, /* RAS */
EMC_DYN_MODE_WBMODE_PROGRAMMED |
EMC_DYN_MODE_OPMODE_STANDARD |
EMC_DYN_MODE_CAS_2 |
EMC_DYN_MODE_BURST_TYPE_SEQUENTIAL |
EMC_DYN_MODE_BURST_LEN_8,
EMC_DYN_CONFIG_DATA_BUS_16 |
EMC_DYN_CONFIG_LPSDRAM |
EMC_DYN_CONFIG_32Mx16_4BANKS_13ROWS_10COLS |
EMC_DYN_CONFIG_MD_SDRAM
},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0}
}
};
void Chip_EMC_Dynamic_Init(IP_EMC_DYN_CONFIG_T *Dynamic_Config)
{
uint32_t ClkFreq;
/* Note clocks must be enabled prior to this call */
ClkFreq = Chip_Clock_GetEMCRate();
initDynMem(LPC_EMC, Dynamic_Config, ClkFreq);
}
void initDynMem(LPC_EMC_T *pEMC, IP_EMC_DYN_CONFIG_T *Dynamic_Config, uint32_t EMC_Clock)
{
uint32_t ChipSelect, tmpclk;
volatile int i;
for (ChipSelect = 0; ChipSelect < 4; ChipSelect++) {
LPC_EMC_T *EMC_Reg_add = (LPC_EMC_T *) ((uint32_t) pEMC + (ChipSelect << 5));
EMC_Reg_add->DYNAMICRASCAS0 = Dynamic_Config->DevConfig[ChipSelect].RAS |
((Dynamic_Config->DevConfig[ChipSelect].ModeRegister <<
(8 - EMC_DYN_MODE_CAS_BIT)) & 0xF00);
EMC_Reg_add->DYNAMICCONFIG0 = Dynamic_Config->DevConfig[ChipSelect].DynConfig;
}
pEMC->DYNAMICREADCONFIG = Dynamic_Config->ReadConfig; /* Read strategy */
pEMC->DYNAMICRP = convertTimmingParam(EMC_Clock, Dynamic_Config->tRP, 1);
pEMC->DYNAMICRAS = convertTimmingParam(EMC_Clock, Dynamic_Config->tRAS, 1);
pEMC->DYNAMICSREX = convertTimmingParam(EMC_Clock, Dynamic_Config->tSREX, 1);
pEMC->DYNAMICAPR = convertTimmingParam(EMC_Clock, Dynamic_Config->tAPR, 1);
pEMC->DYNAMICDAL = convertTimmingParam(EMC_Clock, Dynamic_Config->tDAL, 0);
pEMC->DYNAMICWR = convertTimmingParam(EMC_Clock, Dynamic_Config->tWR, 1);
pEMC->DYNAMICRC = convertTimmingParam(EMC_Clock, Dynamic_Config->tRC, 1);
pEMC->DYNAMICRFC = convertTimmingParam(EMC_Clock, Dynamic_Config->tRFC, 1);
pEMC->DYNAMICXSR = convertTimmingParam(EMC_Clock, Dynamic_Config->tXSR, 1);
pEMC->DYNAMICRRD = convertTimmingParam(EMC_Clock, Dynamic_Config->tRRD, 1);
pEMC->DYNAMICMRD = convertTimmingParam(EMC_Clock, Dynamic_Config->tMRD, 1);
for (i = 0; i < 1000; i++) { /* wait 100us */
}
pEMC->DYNAMICCONTROL = 0x00000183; /* Issue NOP command */
for (i = 0; i < 1000; i++) {}
pEMC->DYNAMICCONTROL = 0x00000103; /* Issue PALL command */
pEMC->DYNAMICREFRESH = 3; /* ( 2 * 16 ) -> 32 clock cycles */
for (i = 0; i < 80; i++) {}
tmpclk = EMC_DIV_ROUND_UP(convertTimmingParam(EMC_Clock, Dynamic_Config->RefreshPeriod, 0), 16);
pEMC->DYNAMICREFRESH = tmpclk;
pEMC->DYNAMICCONTROL = 0x00000083; /* Issue MODE command */
for (ChipSelect = 0; ChipSelect < 4; ChipSelect++) {
/*uint32_t burst_length;*/
uint32_t DynAddr;
uint8_t Col_len;
Col_len = getColsLen(Dynamic_Config->DevConfig[ChipSelect].DynConfig);
/* get bus wide: if 32bit, len is 4 else if 16bit len is 2 */
/* burst_length = 1 << ((((Dynamic_Config->DynConfig[ChipSelect] >> 14) & 1)^1) +1); */
if (Dynamic_Config->DevConfig[ChipSelect].DynConfig & (1 << EMC_DYN_CONFIG_DATA_BUS_WIDTH_BIT)) {
/*32bit bus */
/*burst_length = 2;*/
Col_len += 2;
}
else {
/*burst_length = 4;*/
Col_len += 1;
}
/* Check for RBC mode */
if (!(Dynamic_Config->DevConfig[ChipSelect].DynConfig & EMC_DYN_CONFIG_LPSDRAM)) {
if (!(Dynamic_Config->DevConfig[ChipSelect].DynConfig & (0x7 << EMC_DYN_CONFIG_DEV_SIZE_BIT))) {
/* 2 banks => 1 bank select bit */
Col_len += 1;
}
else {
/* 4 banks => 2 bank select bits */
Col_len += 2;
}
}
DynAddr = Dynamic_Config->DevConfig[ChipSelect].BaseAddr;
if (DynAddr != 0) {
uint32_t temp;
uint32_t ModeRegister;
ModeRegister = Dynamic_Config->DevConfig[ChipSelect].ModeRegister;
temp = *((volatile uint32_t *) (DynAddr | (ModeRegister << Col_len)));
temp = temp;
}
}
pEMC->DYNAMICCONTROL = 0x00000000; /* Issue NORMAL command */
/* enable buffers */
pEMC->DYNAMICCONFIG0 |= 1 << 19;
pEMC->DYNAMICCONFIG1 |= 1 << 19;
pEMC->DYNAMICCONFIG2 |= 1 << 19;
pEMC->DYNAMICCONFIG3 |= 1 << 19;
}
The part that i am completely lost is a few lines above when mode register is to be calculated and is never used.
temp = temp; ??????
if (DynAddr != 0) {
uint32_t temp;
uint32_t ModeRegister;
ModeRegister = Dynamic_Config->DevConfig[ChipSelect].ModeRegister;
temp = *((volatile uint32_t *) (DynAddr | (ModeRegister << Col_len)));
temp = temp;
}
The question for mode register after calculating the "OFFSET" can also be found here without any clear answer.
Homemade config to SDRAM, Wait states and READ strategy. Need advice.
Inside UM10503 page 623
23.5.8.2 and 23.5.8.2.1
Example for setting the SDRAM mode register
For a 16-bit external SDRAM chip, select latency mode = 2 and burst size = 8. The mode
register value is MODE = 0x23.
Using a 128 Mb (8Mx16) SDRAM chip with address mapping of 4 banks, row length = 12,
column length = 9 (see Table 434), OFFSET = 9 + 1 + 2.
Using DYCS0, the SDRAM address is 0x2800 0000.
The SDRAM read command address becomes 0x2802 3000.
What is the read command address and how to use it?
In the above lpcopen example this address is calculated and is never used. temp = temp;
if (DynAddr != 0) {
uint32_t temp;
uint32_t ModeRegister;
ModeRegister = Dynamic_Config->DevConfig[ChipSelect].ModeRegister;
temp = *((volatile uint32_t *) (DynAddr | (ModeRegister << Col_len)));
temp = temp;
}
I really need some help NXP!
Hi Dimitris Sideris,
Thanks for you reply.
As mentioned before, the following structure includes the several parameters which are used to initialize the MT48LC4M32B2P-6, you can adapt some parameters, such as TRP, TRAS, TAPR,etc, to suit for the IS42S16320D by referring to the electrical specifications in its datasheet.
/* Keil SDRAM timing and chip Config */
STATIC const IP_EMC_DYN_CONFIG_T MT48LC4M32_config = {
EMC_NANOSECOND(64000000 / 4096), /* Row refresh time */
0x01, /* Command Delayed */
EMC_NANOSECOND(18),
EMC_NANOSECOND(42),
EMC_NANOSECOND(70),
EMC_CLOCK(0x01),
EMC_CLOCK(0x05),
EMC_NANOSECOND(12),
EMC_NANOSECOND(60),
EMC_NANOSECOND(60),
EMC_NANOSECOND(70),
EMC_NANOSECOND(12),
EMC_CLOCK(0x02),
{
{
EMC_ADDRESS_DYCS0, /* Keil Board uses DYCS0 for SDRAM */
3, /* RAS */
EMC_DYN_MODE_WBMODE_PROGRAMMED |
EMC_DYN_MODE_OPMODE_STANDARD |
EMC_DYN_MODE_CAS_3 |
EMC_DYN_MODE_BURST_TYPE_SEQUENTIAL |
EMC_DYN_MODE_BURST_LEN_4,
EMC_DYN_CONFIG_DATA_BUS_32 |
EMC_DYN_CONFIG_LPSDRAM |
EMC_DYN_CONFIG_4Mx32_4BANKS_12ROWS_8COLS |
EMC_DYN_CONFIG_MD_SDRAM
},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0}
}
};
The following is used to execute the LOAD MODE REGISTER command, the mode register is programmed via the LOAD MODE REGISTER command and retains the stored information until it is programmed again or the device loses power.
And you can also can find the corresponding information to modify the dynamic memory configuration parameters in the above structure too.
Fig 1 Load mode register (From the datasheet of the MT48LC4M32B2P- 6)
pEMC->DYNAMICCONTROL = 0x00000083; /* Issue MODE command */
for (ChipSelect = 0; ChipSelect < 4; ChipSelect++) {
/*uint32_t burst_length;*/
uint32_t DynAddr;
uint8_t Col_len;
Col_len = getColsLen(Dynamic_Config->DevConfig[ChipSelect].DynConfig);
/* get bus wide: if 32bit, len is 4 else if 16bit len is 2 */
/* burst_length = 1 << ((((Dynamic_Config->DynConfig[ChipSelect] >> 14) & 1)^1) +1); */
if (Dynamic_Config->DevConfig[ChipSelect].DynConfig & (1 << EMC_DYN_CONFIG_DATA_BUS_WIDTH_BIT)) {
/*32bit bus */
/*burst_length = 2;*/
Col_len += 2;
}
else {
/*burst_length = 4;*/
Col_len += 1;
}
/* Check for RBC mode */
if (!(Dynamic_Config->DevConfig[ChipSelect].DynConfig & EMC_DYN_CONFIG_LPSDRAM)) {
if (!(Dynamic_Config->DevConfig[ChipSelect].DynConfig & (0x7 << EMC_DYN_CONFIG_DEV_SIZE_BIT))) {
/* 2 banks => 1 bank select bit */
Col_len += 1;
}
else {
/* 4 banks => 2 bank select bits */
Col_len += 2;
}
}
DynAddr = Dynamic_Config->DevConfig[ChipSelect].BaseAddr;
if (DynAddr != 0) {
uint32_t temp;
uint32_t ModeRegister;
ModeRegister = Dynamic_Config->DevConfig[ChipSelect].ModeRegister;
temp = *((volatile uint32_t *) (DynAddr | (ModeRegister << Col_len)));
temp = temp;
}
}
pEMC->DYNAMICCONTROL = 0x00000000; /* Issue NORMAL command */
Hope it helps.
Have a great day,
TIC
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
This is what i am trying to do.
I ve been playing around with variations of my sdram timings but below is my "default" configuration.
So far the same reult.
Content stay in sdram only for a short period of time.
When i try to read them almost right after write content is there.
After about a while (approximately 4,000,000 for loops time)
content gets messed.
STATIC const IP_EMC_DYN_CONFIG_T IS4245S16320D_config = {
EMC_NANOSECOND(64000000 / 8192), /* Row refresh time */
0x01, /* Command Delayed */
EMC_NANOSECOND(18), /* tRP */
EMC_NANOSECOND(42), /* tRAS */
EMC_NANOSECOND(70), /* tSREX */
EMC_CLOCK(0x01), /* tAPR */
EMC_CLOCK(0x05), /* tDAL */
EMC_NANOSECOND(12), /* tWR */
EMC_NANOSECOND(60), /* tRC */
EMC_NANOSECOND(60), /* tRFC */
EMC_NANOSECOND(70), /* tXSR */
EMC_NANOSECOND(12), /* tRRD */
EMC_CLOCK(0x02), /* tMRD */
{
{
EMC_ADDRESS_DYCS0, /* Keil Board uses DYCS0 for SDRAM */
3, /* RAS */
EMC_DYN_MODE_WBMODE_PROGRAMMED |
EMC_DYN_MODE_OPMODE_STANDARD |
EMC_DYN_MODE_CAS_3 |
EMC_DYN_MODE_BURST_TYPE_SEQUENTIAL |
EMC_DYN_MODE_BURST_LEN_8,
EMC_DYN_CONFIG_DATA_BUS_16 |
EMC_DYN_CONFIG_LPSDRAM |
EMC_DYN_CONFIG_32Mx16_4BANKS_13ROWS_10COLS |
EMC_DYN_CONFIG_MD_SDRAM
},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0}
}
};
void initDynMem(LPC_EMC_T *pEMC, IP_EMC_DYN_CONFIG_T *Dynamic_Config, uint32_t EMC_Clock)
{
uint32_t ChipSelect, tmpclk;
volatile int i;
for (ChipSelect = 0; ChipSelect < 4; ChipSelect++) {
LPC_EMC_T *EMC_Reg_add = (LPC_EMC_T *) ((uint32_t) pEMC + (ChipSelect << 5));
EMC_Reg_add->DYNAMICRASCAS0 = Dynamic_Config->DevConfig[ChipSelect].RAS |
((Dynamic_Config->DevConfig[ChipSelect].ModeRegister <<
(8 - EMC_DYN_MODE_CAS_BIT)) & 0xF00);
EMC_Reg_add->DYNAMICCONFIG0 = Dynamic_Config->DevConfig[ChipSelect].DynConfig;
}
pEMC->DYNAMICREADCONFIG = Dynamic_Config->ReadConfig; /* Read strategy */
pEMC->DYNAMICRP = convertTimmingParam(EMC_Clock, Dynamic_Config->tRP, 1);
pEMC->DYNAMICRAS = convertTimmingParam(EMC_Clock, Dynamic_Config->tRAS, 1);
pEMC->DYNAMICSREX = convertTimmingParam(EMC_Clock, Dynamic_Config->tSREX, 1);
pEMC->DYNAMICAPR = convertTimmingParam(EMC_Clock, Dynamic_Config->tAPR, 1);
pEMC->DYNAMICDAL = convertTimmingParam(EMC_Clock, Dynamic_Config->tDAL, 0);
pEMC->DYNAMICWR = convertTimmingParam(EMC_Clock, Dynamic_Config->tWR, 1);
pEMC->DYNAMICRC = convertTimmingParam(EMC_Clock, Dynamic_Config->tRC, 1);
pEMC->DYNAMICRFC = convertTimmingParam(EMC_Clock, Dynamic_Config->tRFC, 1);
pEMC->DYNAMICXSR = convertTimmingParam(EMC_Clock, Dynamic_Config->tXSR, 1);
pEMC->DYNAMICRRD = convertTimmingParam(EMC_Clock, Dynamic_Config->tRRD, 1);
pEMC->DYNAMICMRD = convertTimmingParam(EMC_Clock, Dynamic_Config->tMRD, 1);
for (i = 0; i < 1000; i++) { /* wait 100us */
}
pEMC->DYNAMICCONTROL = 0x00000183; /* Issue NOP command */
for (i = 0; i < 1000; i++) {}
pEMC->DYNAMICCONTROL = 0x00000103; /* Issue PALL command */
pEMC->DYNAMICREFRESH = 3; /* ( 2 * 16 ) -> 32 clock cycles */
for (i = 0; i < 80; i++) {}
tmpclk = EMC_DIV_ROUND_UP(convertTimmingParam(EMC_Clock, Dynamic_Config->RefreshPeriod, 0), 16);
pEMC->DYNAMICREFRESH = tmpclk;
pEMC->DYNAMICCONTROL = 0x00000083; /* Issue MODE command */
for (ChipSelect = 0; ChipSelect < 4; ChipSelect++) {
/*uint32_t burst_length;*/
uint32_t DynAddr;
uint8_t Col_len;
Col_len = getColsLen(Dynamic_Config->DevConfig[ChipSelect].DynConfig);
/* get bus wide: if 32bit, len is 4 else if 16bit len is 2 */
/* burst_length = 1 << ((((Dynamic_Config->DynConfig[ChipSelect] >> 14) & 1)^1) +1); */
if (Dynamic_Config->DevConfig[ChipSelect].DynConfig & (1 << EMC_DYN_CONFIG_DATA_BUS_WIDTH_BIT)) {
/*32bit bus */
/*burst_length = 2;*/
Col_len += 2;
}
else {
/*burst_length = 4;*/
Col_len += 1;
}
/* Check for RBC mode */
if (!(Dynamic_Config->DevConfig[ChipSelect].DynConfig & EMC_DYN_CONFIG_LPSDRAM)) {
if (!(Dynamic_Config->DevConfig[ChipSelect].DynConfig & (0x7 << EMC_DYN_CONFIG_DEV_SIZE_BIT))) {
/* 2 banks => 1 bank select bit */
Col_len += 1;
}
else {
/* 4 banks => 2 bank select bits */
Col_len += 2;
}
}
DynAddr = Dynamic_Config->DevConfig[ChipSelect].BaseAddr;
if (DynAddr != 0) {
uint32_t temp;
uint32_t ModeRegister;
ModeRegister = Dynamic_Config->DevConfig[ChipSelect].ModeRegister;
temp = *((volatile uint32_t *) (DynAddr | (ModeRegister << Col_len)));
temp = temp;
}
}
pEMC->DYNAMICCONTROL = 0x00000000; /* Issue NORMAL command */
/* enable buffers */
pEMC->DYNAMICCONFIG0 |= 1 << 19;
pEMC->DYNAMICCONFIG1 |= 1 << 19;
pEMC->DYNAMICCONFIG2 |= 1 << 19;
pEMC->DYNAMICCONFIG3 |= 1 << 19;
}
Sdram datasheet
http://www.issi.com/WW/pdf/42-45R-S_86400D-16320D-32160D.pdf
My model is 16320D
8M x 16 x 4 banks
Hi Dimitris Sideris,
Please try the following structure, note that: only 128 Mb dynamic external memory space is be mapped to the DYCS0.
And I was wondering if you can share the sch of your customize board.
/* Keil SDRAM timing and chip Config */
STATIC const IP_EMC_DYN_CONFIG_T IS42S16400_config = {
EMC_NANOSECOND(64000000 / 4096), /* Row refresh time */
0x01, /* Command Delayed */
EMC_NANOSECOND(20),
EMC_NANOSECOND(42),
EMC_NANOSECOND(63),
EMC_CLOCK(0x05),
EMC_CLOCK(0x05),
EMC_NANOSECOND(2),
EMC_NANOSECOND(63),
EMC_NANOSECOND(63),
EMC_NANOSECOND(63),
EMC_NANOSECOND(14),
EMC_CLOCK(0x02),
{
{
EMC_ADDRESS_DYCS0, /* Keil Board uses DYCS0 for SDRAM */
3, /* RAS */
EMC_DYN_MODE_WBMODE_PROGRAMMED |
EMC_DYN_MODE_OPMODE_STANDARD |
EMC_DYN_MODE_CAS_3 |
EMC_DYN_MODE_BURST_TYPE_SEQUENTIAL |
EMC_DYN_MODE_BURST_LEN_8,
EMC_DYN_CONFIG_DATA_BUS_32 |
EMC_DYN_CONFIG_LPSDRAM |
EMC_DYN_CONFIG_4Mx32_4BANKS_12ROWS_8COLS |
EMC_DYN_CONFIG_MD_SDRAM
},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0}
}
};
Hope it helps.
Have a great day,
TIC
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Also is it 128 mbit or megabyte?
I see at UM10503 table 412. Memory bank selection
EMC_DYCS0 0x2800 0000 - 0x2FFF FFFF Dynamic 128 MB
I understand that it is 128mbyte. Wrong?
Hi Dimitris Sideris,
I think I got messed with the MB and Mb, the 512 Mb is equal to the 64 MB.
And the previous structure should be modified.
/* Keil SDRAM timing and chip Config */
STATIC const IP_EMC_DYN_CONFIG_T IS42S1632D_config = {
EMC_NANOSECOND(64000000 / 4096), /* Row refresh time */
0x01, /* Command Delayed */
EMC_NANOSECOND(20),
EMC_NANOSECOND(42),
EMC_NANOSECOND(63),
EMC_CLOCK(0x05),
EMC_CLOCK(0x05),
EMC_NANOSECOND(2),
EMC_NANOSECOND(63),
EMC_NANOSECOND(63),
EMC_NANOSECOND(63),
EMC_NANOSECOND(14),
EMC_CLOCK(0x02),
{
{
EMC_ADDRESS_DYCS0, /* Keil Board uses DYCS0 for SDRAM */
3, /* RAS */
EMC_DYN_MODE_WBMODE_PROGRAMMED |
EMC_DYN_MODE_OPMODE_STANDARD |
EMC_DYN_MODE_CAS_3 |
EMC_DYN_MODE_BURST_TYPE_SEQUENTIAL |
EMC_DYN_MODE_BURST_LEN_8,
EMC_DYN_CONFIG_DATA_BUS_16 |
EMC_DYN_CONFIG_32Mx16_4BANKS_13ROWS_10COLS |
EMC_DYN_CONFIG_MD_SDRAM
},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0}
}
};
Have a great day,
TIC
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Please make things clear.
1. Is the above timings ur suggestion for my setup?
If yes EMC_NANOSECOND(64000000 / 4096) must be EMC_NANOSECOND(64000000 / 8192) according to my datasheet.
Also where do you find these timings? In sdram datasheet i can olny use timings from a column (-5, -6, -7 ) and not mix them.
2. You said you got wrong Mb and MB. Is it true that DYCS0 of emc can handle 128MByte? My sdram is 512mbit (64MByte).
Thanks for your reply.
1. Is the above timings ur suggestion for my setup?
Yes, the AC ELECTRICAL CHARACTERISTICS table illustrates these parameters and the I check the Trep again, its value should be EMC_NANOSECOND(64000000/8192).
2. Is it true that DYCS0 of emc can handle 128MByte?
Yes.
Have a great day,
TIC
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Thanks a lot for the help so far.
It is now working.
It seems like i didnt have any issue with the sdram configuration and timings setup.
Board_Init method was configuring debugout to use uart0 and was initializing uart0 tx pin which was conflicting with CAS pin of sdram.
After changing the pins of uart0 sdram worked fine!
Thanks a lot again!
Here is the schematic of the connection of the lpc and the sdram
Hi Dimitris Sideris,
It can works on my board, I've attached the testing result and code which you can refer to.
#include "board.h"
#include "mem_tests.h"
#include <stdio.h>
#include <cr_section_macros.h>
/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/
#define DRAM_BASE_ADDRESS (uint32_t *) 0x28000000
#if (defined(BOARD_HITEX_EVA_1850) || defined(BOARD_HITEX_EVA_4350))
/* 8MB of Hitex board */
#define DRAM_SIZE (8 * 1024 * 1024)
#elif (defined(BOARD_KEIL_MCB_1857) || defined(BOARD_KEIL_MCB_4357))
//#define DRAM_SIZE (8 * 1024 * 1024)
#endif
#define BUF_SIZE 1024
__attribute__(( section(".noinit.$RAM5"), aligned(8) ))
uint8_t data_buffer[BUF_SIZE];
/*****************************************************************************
* Public types/enumerations/variables
****************************************************************************/
void fill_data_buffer() {
for (int i = 0; i < BUF_SIZE; i++)
{
if (i<BUF_SIZE/2) {
data_buffer[i] = 0x0A;
}
else {
data_buffer[i] = 0x0B;
}
}
}
/*****************************************************************************
* Private functions
****************************************************************************/
/*****************************************************************************
* Public functions
****************************************************************************/
/**
* @brief Main routine for example_memtest
* @return Nothing
*/
int main(void)
{
MEM_TEST_SETUP_T memSetup;
uint32_t index;
SystemCoreClockUpdate();
Board_Init();
fill_data_buffer();
for (index = 0; index < BUF_SIZE; index++)
{
DEBUGOUT("\r\n %x, \r\n", data_buffer[index]);
}
while(1)
{}
// /* Walking 0 test */
// memSetup.start_addr = DRAM_BASE_ADDRESS;
// memSetup.bytes = DRAM_SIZE;
// if (mem_test_walking0(&memSetup)) {
// DEBUGSTR("Walking 0 memory test passed\r\n");
// }
// else {
// DEBUGOUT("Walking 0 memory test failed at address %p\r\n", memSetup.fail_addr);
// DEBUGOUT(" Expected %08x, actual %08x\r\n", memSetup.ex_val, memSetup.is_val);
// }
//
// /* Walking 1 test */
// memSetup.start_addr = DRAM_BASE_ADDRESS;
// memSetup.bytes = DRAM_SIZE;
// if (mem_test_walking1(&memSetup)) {
// DEBUGSTR("Walking 1 memory test passed\r\n");
// }
// else {
// DEBUGOUT("Walking 1 memory test failed at address %p\r\n", memSetup.fail_addr);
// DEBUGOUT(" Expected %08x, actual %08x\r\n", memSetup.ex_val, memSetup.is_val);
// }
//
// /* Address test */
// memSetup.start_addr = DRAM_BASE_ADDRESS;
// memSetup.bytes = DRAM_SIZE;
// if (mem_test_address(&memSetup)) {
// DEBUGSTR("Address test passed\r\n");
// }
// else {
// DEBUGOUT("Address test failed at address %p\r\n", memSetup.fail_addr);
// DEBUGOUT(" Expected %08x, actual %08x\r\n", memSetup.ex_val, memSetup.is_val);
// }
//
// /* Inverse address test */
// memSetup.start_addr = DRAM_BASE_ADDRESS;
// memSetup.bytes = DRAM_SIZE;
// if (mem_test_invaddress(&memSetup)) {
// DEBUGSTR("Inverse address test passed\r\n");
// }
// else {
// DEBUGOUT("Inverse address test failed at address %p\r\n", memSetup.fail_addr);
// DEBUGOUT(" Expected %08x, actual %08x\r\n", memSetup.ex_val, memSetup.is_val);
// }
//
// /* Pattern test */
// memSetup.start_addr = DRAM_BASE_ADDRESS;
// memSetup.bytes = DRAM_SIZE;
// if (mem_test_pattern(&memSetup)) {
// DEBUGSTR("Pattern (0x55/0xAA) test passed\r\n");
// }
// else {
// DEBUGOUT("Pattern (0x55/0xAA) test failed at address %p\r\n", memSetup.fail_addr);
// DEBUGOUT(" Expected %08x, actual %08x\r\n", memSetup.ex_val, memSetup.is_val);
// }
//
// /* Seeded pattern test */
// memSetup.start_addr = DRAM_BASE_ADDRESS;
// memSetup.bytes = DRAM_SIZE;
// if (mem_test_pattern_seed(&memSetup, 0x12345678, 0x50005)) {
// DEBUGSTR("Seeded pattern test passed\r\n");
// }
// else {
// DEBUGOUT("Seeded pattern test failed at address %p\r\n", memSetup.fail_addr);
// DEBUGOUT(" Expected %08x, actual %08x\r\n", memSetup.ex_val, memSetup.is_val);
// }
/* Never returns, for warning only */
return 0;
}
Hope it helps.
Have a great day,
TIC
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Can you share ur sdram initialization code and process?
I have reached in two colclusions with the so far expirements and tries.
1. Values get written in sdram only for a very short period of time.
If i write values to an array that lies in sdram and soon after write i read the value, content is there.
If i write values to an array, the write sequence completes and then if i try to read values from that array content is not there.
2. If array in sdram is really small everything seem to work fine. If array gets bigger the above symptoms are occured.
Any help please NXP?
I am sure it works for you!
The thing is that my initialization might be wrong.
Can you post the emc and sdram initialization process of your working example?