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!