Why are external SDRAM initializations so different on LPCOpen vs. mbed?

cancel
Showing results for 
Search instead for 
Did you mean: 

Why are external SDRAM initializations so different on LPCOpen vs. mbed?

Jump to solution
909 Views
Contributor III

I'm confused by the difference between initialization routines for an external SDRAM in mbed (EALib) vs. LPCOpen examples. I'm using the Embedded Artists LPC4088 QuickStart Board in MCUXpresso IDE v10.0.2 [Build 411] [2017-07-11]. The board has an external 32 MB SDRAM chip.

One the one hand, you have the mbed-based EALib, in which you're ostensibly supposed to call sdram_init() before using the external SDRAM. (See sdram.cpp.) sdram_init() appears to be setting values in quite a few control registers.

On the other hand, you have the example LPCOpen Software for LPC40xx (direct download link), which runs on the same board, but does almost none of that. Looking at the periph_memtest example in there, we see that only SystemCoreClockUpdate() and Board_Init() are called before accessing the memory. The only commonality between these and EALib's sdram_init() is that there is one control register whose value they both modify (LPC_SYSCTL->PCONP).

Why the discrepancy? How is LPCOpen getting by doing so little? Or why is EALib/mbed doing so much unnecessary stuff?

1 Solution
72 Views
Contributor III

Very informative, thanks. Now I can put together the answer to my original question (which I didn't know how to ask).

I asked how the LPCOpen code was getting by without initializing the external SDRAM. But it only seemed to me like that because main() is not the entry point in this case, and the memory is initialized before main().

You described in your latest comment the location in memory that specifies the location of the reset handler function. (The reset handler function is what I would say is the "entry point" at the lowest level (or close to it).) In this case, the entry point is the ResetISR() function, located in cr_startup_lpc40xx.c.

So the portion of the call tree leading to the memory initialization (before main()) is as shown below (where each function calls the next).

Functionsource file
ResetISR()cr_startup_lpc40xx.c
SystemInit()sysinit.c
Board_SystemInit()board_sysinit.c
Board_SetupExtMemory()board_sysinit.c

[EDIT: At risk of poor form, I'm marking this (my own) comment as "correct", but your comments as "helpful", since they all helped me put it together.]

View solution in original post

0 Kudos
6 Replies
72 Views
NXP TechSupport
NXP TechSupport

Hi Brendan McDonnell,

Thank you for your interest in NXP Semiconductor products and 
for the opportunity to serve you.
In LPCOpen library, SDRAM is initialized before the jump to main();

void Board_SetupExtMemory(void)
{
    /* Setup EMC Delays */
    /* Move all clock delays together */
    LPC_SYSCTL->EMCDLYCTL = (CLK0_DELAY) | (CLK0_DELAY << 8) | (CLK0_DELAY << 16 | (CLK0_DELAY << 24));

    /* Setup EMC Clock Divider for divide by 2 */
    /* Setup EMC clock for a divider of 2 from CPU clock. Enable EMC clock for
       external memory setup of DRAM. */
    Chip_Clock_SetEMCClockDiv(SYSCTL_EMC_DIV2);
    Chip_SYSCTL_PeriphReset(SYSCTL_RESET_EMC);

    /* Init EMC Controller -Enable-LE mode- clock ratio 1:1 */
    Chip_EMC_Init(1, 0, 0);

    /* Init EMC Dynamic Controller */
    Chip_EMC_Dynamic_Init((IP_EMC_DYN_CONFIG_T *) &IS42S32800D_config);

    /* Init EMC Static Controller CS0 */
    Chip_EMC_Static_Init((IP_EMC_STATIC_CONFIG_T *) &SST39VF320_config);

    
    /* Init EMC Static Controller CS1 */
    Chip_EMC_Static_Init((IP_EMC_STATIC_CONFIG_T *) &K9F1G_config);

    /* EMC Shift Control */
    LPC_SYSCTL->SCS |= 1;
}

/* Set up and initialize hardware prior to call to main */
void Board_SystemInit(void)
{
    Board_SetupMuxing();
    Board_SetupClocking();
    Board_SetupExtMemory();
}

Hope this is clear.

Have a great day,
TIC

 

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

72 Views
Contributor III

jeremyzhou wrote:

In LPCOpen library, SDRAM is initialized before the jump to main();

What is the entry point, and how/where is that defined?

Thanks for the info.

0 Kudos
72 Views
NXP Employee
NXP Employee

Hi Brendan,

wherever in the code the SDRAM is initialized, the instructions are finally the same. But there are of course different ways to program the instructions. Simple sequential write instructions to all required registers, working with structs and loops, etc. But to make the SDRAM working, you need to have them all written correctly and in the right order.

The position in the code where this initialization is done is also debatable. You only need to take care that it is done before you access it. You could think of 2 extreme scenarios:

  1. You just want to use the SDRAM for a display frame buffer. All executable code and variables are in flash and RAM. You don't provide the SDRAM memory area as available memory to the linker. So latest when you set up your display you need to prepare the SDRAM.

  2. You want to place code and variables into the SDRAM and you want the linker to do this. Therefore you need to prepare the SDRAM in a very early stage, you can even do this in startup.s. The linker can place all C objects into the SDRAM, only the startup.s is executed from the boot memory, e.g. the internal flash. All other objects will be copied from the non-volatile memory to the SDRAM and then executed from there.

In LPCOpen we selected something between 1) and 2). The startup.s and the sys_init stuff (sysinit and board_sysinit) runs from the boot memory and prepares all the rest, for example also the SDRAM. At the end of the sys_init stuff the compiler may place code for relocation of objects which were specified in the linker file (scatter file) to be somewhere else, for example in the SDRAM.

Another meaningful example is the placement of code into the SDRAM with a debugger. Here it it is very clear that you need to set up the PLLs and the SDRAM memory interface with an ini script before the debugger can write the code image to the SDRAM.

Whenever and wherever you perform the SDRAM initialization, you only need to be done with it before it's getting accessed.

Regards,

Bernhard.

72 Views
Contributor III

Hi Bernhard,

Apologies for my delay in responding. Priorities shift...

Thanks for the info. I'm still not quite clear on the answers to my questions, though.

I asked,

What is the entry point, and how/where is that defined?

You said, in part,

Bernhard Fink wrote:

In LPCOpen ... The startup.s and the sys_init stuff (sysinit and board_sysinit) runs from the boot memory and prepares all the rest, for example also the SDRAM.

When the microcontroller boots, what runs first, and how is it configured to be the first thing to run? For instance, is SystemInit() the first thing to run? What if I wanted something else to execute before the first thing - how would I change that?

Also, startup.s is not in this sample code.

0 Kudos
72 Views
NXP Employee
NXP Employee

Hi Brendon,

you're right, if you use the GCC setup, then the startup files are realized in C code in the framework.

IAR and Keil tools normally use an assembler file, just another thing which is just a philosophy. Technically both options are there, one tool simply uses it this way, the other one the other way.

The entry point is always the reset handler. If you able to localize it, then you have the piece of code which gets located at the address the linker puts it to.

The beginning of an image for the ARM Cortex-M is always the same:

- 4 bytes for address vector to stack pointer start

- 4 bytes for address vector to reset handler start

- 14 words with ARM exception vector addresses

- platform dependent number of IRQ vector addresses

So when you look into the final binary, the second word tells you where the linker placed the reset handler. Normally the linker gets all the freedom to place it wherever it wants to, except if you hard-code it.

Anyway, in the GCC world the startup file is normally called cr_startup_xxxx.c, in there you might find "ResetISR" and that's the reset handler (in principle just another naming convention, could be different).

The way it is set up there, decides how it could work with the SDRAM.

  • If you want to relocate the whole code to the SDRAM before you start with execution, you need to initialize the SDRAM at first.
  • If you work on the basic init and the board bring up from internal SRAM or from Flash, then you can do the SDRAM init later and you relocate then all other objects to SDRAM starting with the object where main() is located.

Maybe this helps a little bit.

Regards,

Bernhard.

73 Views
Contributor III

Very informative, thanks. Now I can put together the answer to my original question (which I didn't know how to ask).

I asked how the LPCOpen code was getting by without initializing the external SDRAM. But it only seemed to me like that because main() is not the entry point in this case, and the memory is initialized before main().

You described in your latest comment the location in memory that specifies the location of the reset handler function. (The reset handler function is what I would say is the "entry point" at the lowest level (or close to it).) In this case, the entry point is the ResetISR() function, located in cr_startup_lpc40xx.c.

So the portion of the call tree leading to the memory initialization (before main()) is as shown below (where each function calls the next).

Functionsource file
ResetISR()cr_startup_lpc40xx.c
SystemInit()sysinit.c
Board_SystemInit()board_sysinit.c
Board_SetupExtMemory()board_sysinit.c

[EDIT: At risk of poor form, I'm marking this (my own) comment as "correct", but your comments as "helpful", since they all helped me put it together.]

View solution in original post

0 Kudos