Running code from RAM

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Running code from RAM

5,131 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by kris_sin on Sun Feb 16 16:59:23 MST 2014
Hi guys,

I am using latest LPCXpresso 6.14 with LPCXplorer4330. So far I have run my application on SPIFI Flash but now I wanted run the code from RAM. Can someone help configure linker script, startup file to make the code run from internal SRAM? If someone has modified some basic blinky example that runs from SRAM I would realyy appreciate haring it with me and all forum viewers.
0 Kudos
12 Replies

3,475 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by PaulEmmaMartha on Thu Jul 02 07:04:18 MST 2015
Thank you for the quick response!

problem is solved!

Andreas
0 Kudos

3,475 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by lpcxpresso-support on Wed Jul 01 04:26:50 MST 2015
The memory maps of the LPC43xx parts with and without internal flash are different, so you would need to take that into account as you made the changes. You also need to make sure you make allowances on the LPC4330 for the external flash that you are actually using.

Anyway an untested project is attached.

Regards,
LPCXpresso Support

3,475 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by PaulEmmaMartha on Tue Jun 30 02:28:41 MST 2015
Hi,

have you an example how this works with 4330 ? I try to build with the metioned linker settings but execution failed.

kind regards

Andreas
0 Kudos

3,475 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by kris_sin on Thu Feb 20 15:57:17 MST 2014
Thank You for Your contribution and sharing with perfect example. I debugged in dissassembly window and saw that the code is executed from SRAM. I didn't think that this is possible just by changing linker script. This kind of operation combines advantages of placing code in Flash and SRAM: code works after reset and speed execution is way better because finally the code is executed from SRAM.

For now I think we can close this topic. If I will have more questions/doubts I will create another topic or refresh this one.

Best Regards

3,475 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by lpcxpresso-support on Thu Feb 20 03:07:10 MST 2014
I've attached a simple example showing how you can relocate your application to run mainly from RAM. The example is a modification of one of the examples for the LPC4337-Xplorer board that ships in the LPCXpresso 6 examples directory. I'll try to do an example based on LPCOpen after EmbeddedWorld.

The main modification to the project is that I first of all built the project as normal (ie with the code all in flash), which generated an appropriate linker script file. I then turned off the managed linker script mechansm and copied the previously generated linker scripts into a 'linkscripts' directory for modification.

There is some background information on this at:

http://www.lpcware.com/content/faq/lpcxpresso/own-linker-scripts

Anyway, I have wrapped the changes/additions that I have made to the linker script using

/* RUN_FROM_RAM */ 
  :
/* END RUN_FROM_RAM */


so that you can more easily spot the changes. But basically I have:

[list=1]
  [*]Added entries to the Global Section Table so as to cause the main part of the code to be copied to RAM by the startup code.

  [*]Add some extra code into the first .text section - as we need to make sure that the code that does the copying doesn't attempt to copy itself!

  [*]Renamed the text section where my code to run from RAM will be placed to .text_ram , so as to allow it to be selected and copied into RAM (caused by the change to the Global Section Table above).

  [*]Modified the location that several sections are placed to >RamLoc40 AT>MFlashA512, causing them to be executed from RAM.
[/list]

In addition to the linker script changes above, I also added a dummy main() routine which just calls the renamed real_main(). This was done so that the default breakpoint on main will get set as a hardware breakpoint and hence get hit. If main() were in RAM, a software breakpoint would get used - but this would be overwritten after being set by the debugger by the startup code copying the code into RAM.

Although this example is for the NGX Xplorer board fitted with an LPC4337 (which is the only LPC43xx board I have to hand at the moment), it should be fairly straightforward to use the same principles with your own project for the board that you are using.

It is also worth saying that improving the mechansims within LPCXpresso to more automatically support the relocation of an image to run mainly from RAM like this is on our todo list for the future.

Regards,
LPCXpresso Support
0 Kudos

3,475 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by lpcxpresso-support on Wed Feb 19 15:44:29 MST 2014
Yes, relocating your image to RAM like this is possible. I'm working on an example. Hopefully I'll be able to post this tomorrow.

Regards,
LPCXpresso Support
0 Kudos

3,475 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by kris_sin on Wed Feb 19 14:31:19 MST 2014
Maybe I will start. I made a very simple blinky led - like example in LPCXpresso 6.1.4. I modified linker script to something like this:


MEMORY
{
  /* Define each memory region */
  Flash (rx) : ORIGIN = 0x14000000, LENGTH = 256K /* 256K bytes */
  Ram (rwx) : ORIGIN = 0x10000000, LENGTH = 128K /* 128K bytes */
  Shadow_Ram (rwx) : ORIGIN = 0x00000000, LENGTH = 128K /* 128K bytes */
}

EXTERN (ResetISR)
 
ENTRY(ResetISR)

GROUP(libcr_c.a libcr_eabihelpers.a)

SECTIONS
{
    .text : {
        . = ALIGN(0x400);
        _text_ram = (. - ORIGIN(Shadow_Ram)) + ORIGIN(Ram);

        *(.isr_vector)
        *(.text*)
        . = ALIGN(4);
        *(.rodata*)
        . = ALIGN(4);
       
        *(.after_vectors*)
    } >Shadow_Ram

    . = ALIGN(4);
    _etext = .;
    _etext_ram = (. - ORIGIN(Shadow_Ram)) + ORIGIN(Ram);
    _etext_rom = (. - ORIGIN(Shadow_Ram)) + ORIGIN(Flash);

    . = ORIGIN(Ram);

    .data : {
        _data = .;
        *(.data*)   /* Read-write initialized data */
        . = ALIGN(4);
        _edata = .;
    } >Ram AT >Shadow_Ram
    _data_loadaddr = LOADADDR(.data);

    _data_rom = LOADADDR (.data) + ORIGIN(Flash);
    _edata_rom = _data_rom + SIZEOF (.data);

    .bss : {
        _bss = .;
        *(.bss*)
        *(COMMON)
        . = ALIGN(4);
        _ebss = .;
    } >Ram
   
    PROVIDE(_pvHeapStart = .);
    PROVIDE(_vStackTop = ORIGIN(Ram) + ( ORIGIN(Shadow_Ram) + LENGTH(Shadow_Ram) - 32 ) );
}


So the program should be downloaded to shadow memory located in 0x00000000. Then I modified cr_startup_lpc43xx.c file so while in ResetISR() I will copy the code from SPIFI Flash to internal SRAM. Startup code below:

#define WEAK __attribute__ ((weak))
#define ALIAS(f) __attribute__ ((weak, alias (#f)))

#define CREG_BASE       0x40043000
#define MMIO32(addr)    (*(volatile unsigned long *)(addr))
#define CREG_M4MEMMAP   MMIO32(CREG_BASE + 0x100)

extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack;
extern unsigned long _text_ram; /* Correspond to start of Code in RAM */
extern unsigned long _etext_ram; /* Correspond to end of Code in RAM */
extern unsigned long _etext_rom; /* Correspond to end of Code in ROM */
extern unsigned long _etext;

extern void main(void);
extern void _vStackTop(void);
extern void SystemInit(void);
void pre_main(void);

void ResetISR(void);
WEAK void NMI_Handler(void);
WEAK void HardFault_Handler(void);
WEAK void MemManage_Handler(void);
WEAK void BusFault_Handler(void);
WEAK void UsageFault_Handler(void);
WEAK void SVC_Handler(void);
WEAK void DebugMon_Handler(void);
WEAK void PendSV_Handler(void);
WEAK void SysTick_Handler(void);
WEAK void IntDefaultHandler(void);

void DAC_IRQHandler(void) ALIAS(IntDefaultHandler);
void M0CORE_IRQHandler(void) ALIAS(IntDefaultHandler);
void DMA_IRQHandler(void) ALIAS(IntDefaultHandler);
void FLASH_EEPROM_IRQHandler(void) ALIAS(IntDefaultHandler);
void ETH_IRQHandler(void) ALIAS(IntDefaultHandler);
void SDIO_IRQHandler(void) ALIAS(IntDefaultHandler);
void LCD_IRQHandler(void) ALIAS(IntDefaultHandler);
void USB0_IRQHandler(void) ALIAS(IntDefaultHandler);
void USB1_IRQHandler(void) ALIAS(IntDefaultHandler);
void SCT_IRQHandler(void) ALIAS(IntDefaultHandler);
void RIT_IRQHandler(void) ALIAS(IntDefaultHandler);
void TIMER0_IRQHandler(void) ALIAS(IntDefaultHandler);
void TIMER1_IRQHandler(void) ALIAS(IntDefaultHandler);
void TIMER2_IRQHandler(void) ALIAS(IntDefaultHandler);
void TIMER3_IRQHandler(void) ALIAS(IntDefaultHandler);
void MCPWM_IRQHandler(void) ALIAS(IntDefaultHandler);
void ADC0_IRQHandler(void) ALIAS(IntDefaultHandler);
void I2C0_IRQHandler(void) ALIAS(IntDefaultHandler);
void SPI_IRQHandler(void) ALIAS(IntDefaultHandler);
void I2C1_IRQHandler(void) ALIAS(IntDefaultHandler);
void ADC1_IRQHandler(void) ALIAS(IntDefaultHandler);
void SSP0_IRQHandler(void) ALIAS(IntDefaultHandler);
void SSP1_IRQHandler(void) ALIAS(IntDefaultHandler);
void UART0_IRQHandler(void) ALIAS(IntDefaultHandler);
void UART1_IRQHandler(void) ALIAS(IntDefaultHandler);
void UART2_IRQHandler(void) ALIAS(IntDefaultHandler);
void UART3_IRQHandler(void) ALIAS(IntDefaultHandler);
void I2S0_IRQHandler(void) ALIAS(IntDefaultHandler);
void I2S1_IRQHandler(void) ALIAS(IntDefaultHandler);
void SPIFI_IRQHandler(void) ALIAS(IntDefaultHandler);
void SGPIO_IRQHandler(void) ALIAS(IntDefaultHandler);
void GPIO0_IRQHandler(void) ALIAS(IntDefaultHandler);
void GPIO1_IRQHandler(void) ALIAS(IntDefaultHandler);
void GPIO2_IRQHandler(void) ALIAS(IntDefaultHandler);
void GPIO3_IRQHandler(void) ALIAS(IntDefaultHandler);
void GPIO4_IRQHandler(void) ALIAS(IntDefaultHandler);
void GPIO5_IRQHandler(void) ALIAS(IntDefaultHandler);
void GPIO6_IRQHandler(void) ALIAS(IntDefaultHandler);
void GPIO7_IRQHandler(void) ALIAS(IntDefaultHandler);
void GINT0_IRQHandler(void) ALIAS(IntDefaultHandler);
void GINT1_IRQHandler(void) ALIAS(IntDefaultHandler);
void EVRT_IRQHandler(void) ALIAS(IntDefaultHandler);
void CAN1_IRQHandler(void) ALIAS(IntDefaultHandler);
void VADC_IRQHandler(void) ALIAS(IntDefaultHandler);
void ATIMER_IRQHandler(void) ALIAS(IntDefaultHandler);
void RTC_IRQHandler(void) ALIAS(IntDefaultHandler);
void WDT_IRQHandler(void) ALIAS(IntDefaultHandler);
void M0SUB_IRQHandler(void) ALIAS(IntDefaultHandler);
void CAN0_IRQHandler(void) ALIAS(IntDefaultHandler);
void QEI_IRQHandler(void) ALIAS(IntDefaultHandler);


//*****************************************************************************
//
// The vector table.
// This relies on the linker script to place at correct location in memory.
//
//*****************************************************************************
extern void (* const g_pfnVectors[])(void);

__attribute__ ((section(".isr_vector")))
void (* const g_pfnVectors[])(void) =
{
    // Core Level - CM4
    &_vStackTop,                    // The initial stack pointer
    ResetISR,                       // The reset handler
    NMI_Handler,                    // The NMI handler
    HardFault_Handler,              // The hard fault handler
    MemManage_Handler,              // The MPU fault handler
    BusFault_Handler,               // The bus fault handler
    UsageFault_Handler,             // The usage fault handler
    0,                              // Reserved
    0,                              // Reserved
    0,                              // Reserved
    0,                              // Reserved
    SVC_Handler,                    // SVCall handler
    DebugMon_Handler,               // Debug monitor handler
    0,                              // Reserved
    PendSV_Handler,                 // The PendSV handler
    SysTick_Handler,                // The SysTick handler
    // Chip Level - LPC43 (M4)
    DAC_IRQHandler,           // 16
    M0CORE_IRQHandler,        // 17
    DMA_IRQHandler,           // 18
    0,             // 19
    FLASH_EEPROM_IRQHandler,  // 20
    ETH_IRQHandler,           // 21
    SDIO_IRQHandler,          // 22
    LCD_IRQHandler,           // 23
    USB0_IRQHandler,          // 24
    USB1_IRQHandler,          // 25
    SCT_IRQHandler,           // 26
    RIT_IRQHandler,           // 27
    TIMER0_IRQHandler,        // 28
    TIMER1_IRQHandler,        // 29
    TIMER2_IRQHandler,        // 30
    TIMER3_IRQHandler,        // 31
    MCPWM_IRQHandler,         // 32
    ADC0_IRQHandler,          // 33
    I2C0_IRQHandler,          // 34
    I2C1_IRQHandler,          // 35
    SPI_IRQHandler,           // 36
    ADC1_IRQHandler,          // 37
    SSP0_IRQHandler,          // 38
    SSP1_IRQHandler,          // 39
    UART0_IRQHandler,         // 40
    UART1_IRQHandler,         // 41
    UART2_IRQHandler,         // 42
    UART3_IRQHandler,         // 43
    I2S0_IRQHandler,          // 44
    I2S1_IRQHandler,          // 45
    SPIFI_IRQHandler,         // 46
    SGPIO_IRQHandler,         // 47
    GPIO0_IRQHandler,         // 48
    GPIO1_IRQHandler,         // 49
    GPIO2_IRQHandler,         // 50
    GPIO3_IRQHandler,         // 51
    GPIO4_IRQHandler,         // 52
    GPIO5_IRQHandler,         // 53
    GPIO6_IRQHandler,         // 54
    GPIO7_IRQHandler,         // 55
    GINT0_IRQHandler,         // 56
    GINT1_IRQHandler,         // 57
    EVRT_IRQHandler,          // 58
    CAN1_IRQHandler,          // 59
    0,                        // 60
    VADC_IRQHandler,          // 61
    ATIMER_IRQHandler,        // 62
    RTC_IRQHandler,           // 63
    0,                        // 64
    WDT_IRQHandler,           // 65
    M0SUB_IRQHandler,         // 66
    CAN0_IRQHandler,          // 67
    QEI_IRQHandler,           // 68
};

void ResetISR(void)
{
unsigned long *src, *dest;
    unsigned int * pSCB_VTOR = (unsigned int *) 0xE000ED08;

for (src = &_data_loadaddr, dest = &_data;
dest < &_edata;
src++, dest++) {
*dest = *src;
}

while (dest < &_ebss) {
*dest++ = 0;
}

    pre_main();

    *pSCB_VTOR = (unsigned int) g_pfnVectors;

    main();

    //
    // main() shouldn't return, but if it does, we'll just enter an infinite loop
    //
    while(1)
    {

    }
}

/**
*
*/
void pre_main(void)
{
volatile unsigned *src, *dest;

/* Copy the code from ROM to Real RAM (if enabled) */
if ((&_etext_ram-&_text_ram) > 0)
{
src = &_etext_rom-(&_etext_ram-&_text_ram);
/* Change Shadow memory to ROM (for Debug Purpose in case Boot
* has not set correctly the M4MEMMAP because of debug)
*/
CREG_M4MEMMAP = (unsigned long)src;

for (dest = &_text_ram; dest < &_etext_ram; ) {
*dest++ = *src++;
}

/* Change Shadow memory to Real RAM */
CREG_M4MEMMAP = (unsigned long)&_text_ram;

/* Continue Execution in RAM */
}
}

//*****************************************************************************
// Default exception handlers. Override the ones here by defining your own
// handler routines in your application code.
//*****************************************************************************
__attribute__ ((section(".after_vectors")))
void NMI_Handler(void) {
    while (1) {
    }
}
__attribute__ ((section(".after_vectors")))
void HardFault_Handler(void) {
    while (1) {
    }
}
__attribute__ ((section(".after_vectors")))
void MemManage_Handler(void) {
    while (1) {
    }
}
__attribute__ ((section(".after_vectors")))
void BusFault_Handler(void) {
    while (1) {
    }
}
__attribute__ ((section(".after_vectors")))
void UsageFault_Handler(void) {
    while (1) {
    }
}
__attribute__ ((section(".after_vectors")))
void SVC_Handler(void) {
    while (1) {
    }
}
__attribute__ ((section(".after_vectors")))
void DebugMon_Handler(void) {
    while (1) {
    }
}
__attribute__ ((section(".after_vectors")))
void PendSV_Handler(void) {
    while (1) {
    }
}
__attribute__ ((section(".after_vectors")))
void SysTick_Handler(void) {
    while (1) {
    }
}

//*****************************************************************************
//
// Processor ends up here if an unexpected interrupt occurs or a specific
// handler is not present in the application code.
//
//*****************************************************************************
__attribute__ ((section(".after_vectors")))
void IntDefaultHandler(void) {
    while (1) {
    }
}


As You see after copying ROM to RAM I change memory mapping pointer to internal SRAM.

My current problem is that I cannot write to address 0x00000000 using LPCXpresso's flash loader for SPIFI. Every time I try to debug or just download using GUI, it throws an error that it cannot write to 0x0 address. From the way I thought I should be able to write the image at this place but the software needs to take care of memory mapping register to proper address. I use NXG LPCXplorer 4330 and LPC-Link as debugger.

When I replace "Shadow_Ram" into "Ram", the program will be executed in internal SRAM without any problems but mu intention is to have the code in SPIFI Flash and after reset copy the code in SRAM and execute it from there.

Can anyone from LPCXpresso support can help me with that. Is it even possible with that toolset execute this kind of application?
0 Kudos

3,475 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by kris_sin on Wed Feb 19 08:12:31 MST 2014
Has anybody done it with LPC43xx? This could be very interesting feature, because the code will be in non volatile memory (in SPIFI Flash) but just while starting it will be copied into RAM and executed there.
0 Kudos

3,475 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by kris_sin on Mon Feb 17 06:22:21 MST 2014
Thank You for the answer.

Can You also advice me how to start on SPIFI Flash and then copy the whole code and NVIC vector table during startup to SRAM and execute the code from it?

Best Regards
0 Kudos

3,475 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by lpcxpresso-support on Mon Feb 17 05:03:13 MST 2014
When you create  a new project for LPC43 fleshless parts, the wizard will only define RAM regions by default (unless you select a memory configuration file as you run through the wizard that has a flash region defined in it).

Such a project should then be runnable from RAM. But note that if you are using LPC-Link2 as your debug probe and want to download to RAM, then you will need to modify the debug launch configuration

http://www.lpcware.com/content/forum/how-build-and-debug-lpc-link-2-lpcxpresso-iram-only-projects#co...

For background information on LPC43 support in LPCXpresso IDE, I suggest that you read the below FAQ - as well as the other FAQs it links too..

http://www.lpcware.com/content/faq/lpcxpresso/lpc18-lpc43-support

And for mor more information on memory configuration editor, please read the LPCXpresso User Manual, provided as PDF within your install, as well as in the built in help.

Regards,
LPCXpresso Support
0 Kudos

3,475 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by kris_sin on Mon Feb 17 04:00:15 MST 2014
Yes,

I have searched this forum. There are posts about only functions or ISRs to SRAM, dividing ROM in linker script, plenty of issues with Hard Fault but I didn't find "How to"-like post showing how to configure LPCXpresso for LPC43xx, linker script and modify startup code to place whole code in internal SRAM. I think it would be really useful if someone, who did it posted very simple "Blinky" example running from RAM or at least showing how to do it step by step.

Best Regards
0 Kudos

3,475 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by TheFallGuy on Mon Feb 17 02:40:07 MST 2014
Did you search this site? There are several answers to your question already.

http://www.lpcware.com/search/gss/run%20code%20from%20ram
0 Kudos