This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

How to run code from SRAM

I'm having a very difficult time finding out exactly how to run code from the SRAM on an MSP432. I have a function that is very small and needs to operate faster. I could be mistaken, but I believe it could run faster if it weren't running from FLASH, as there are 2 wait states on the MSP432 running at 48MHz.

I've read there are two ways of doing this:
#1 - Copy the code into SRAM, then jump to it
#2 - Put the code in the data section of the startup file, so that it is automatically loaded there by the compiler

I'd like to know how to do both, but for simplicity purposes, I'd really like to know exactly how to set up #2. Thanks!

  • Philip,

    We are looking into your inquiry and will get back to you.

    Regards,
    JH
  • Hi Philip,

    #2 is not fully supported yet. So I would recommend to use #1 for the moment. I will send you a couple of code examples (most likely tomorrow) on how to do this for your reference.

    Regards,

    David
  • With GCC on the MSP430, just tell the compiler to put the function into the .data section, which is automatically copied from flash to SRAM by the C start-up code.

    (Note: this does not work on the MSP432 because the ARM CPU has different memory regions for code and data.)

    __attribute__((section(".data"), noinline))
    void sram_function(void)
    {
        // ...
    }

    The assembler will complain: "Warning: ignoring changed section attributes for .data"

    If you want to avoid that warning, use a custom section, and add it to the linker script:

    .data :
    {
      . = ALIGN(...);
      PROVIDE (__datastart = .);
    
      ...
    
      *(.data .data.* .gnu.linkonce.d.*)
    
      ...
    
      . = ALIGN(...);
      *(.sramcode)         /* <-- my custom section */
    
      ...
    
      PROVIDE (__dataend = .);
    } > RAM AT> ROM
  • Hi Philip,

     For CCS, do the following:

    In you linker file (msp432p401r.cmd):

    MEMORY
    {
        FLASH      (RX) : origin = 0x00000000, length = 0x00040000
        INFO_FLASH (RX) : origin = 0x00200000, length = 0x00004000
    ADD -->    SRAM_RESERVED (RWX) : origin = 0x20000200, length = 0x00000400
    CHANGE --> SRAM       (RWX): origin = 0x20000200 + 0x00000400, length = 0x00010000 - 0x00000600
    ADD -->    SRAM_CODE_RESERVED (RWX) : origin = 0x01000200, length = 0x00000400
    }
    
    
    SECTIONS
    {
        .intvecs:   > 0x00000000
        .text   :   > FLASH
    ADD -->    .code_romToram: RUN_START(code_romToram_run_start), RUN_SIZE(code_romToram_run_size) > FLASH
        .const  :   > FLASH
        .cinit  :   > FLASH
        .pinit  :   > FLASH
    
        .flashMailbox : > 0x00202000
    
        .vtable :   > 0x20000000
    ADD -->    .sram_reserved: RUN_START(sram_reserved_run_start) > SRAM_RESERVED
    ADD -->    .sram_code_reserved: RUN_START(sram_code_reserved_run_start) > SRAM_CODE_RESERVED
        .data   :   > SRAM
        .bss    :   > SRAM
        .sysmem :   > SRAM
        .stack  :   > SRAM (HIGH)
    }

    and in your code:

    //
    // MSP432 main.c
    //
    //****************************************************************************
    #include <stdbool.h>
    #include <stdint.h>
    #include <string.h>
    #include "msp432.h"
    #include "driverlib.h"
    
    //***** Definitions *****
    typedef void ( *function_ptr_t )    ( void );
    
    //***** Global Data *****
    extern int8_t code_romToram_run_start;
    extern int8_t code_romToram_run_size;
    extern int8_t sram_reserved_run_start;
    extern int8_t sram_code_reserved_run_start;
    
    function_ptr_t functionPtr;
    
    /***********************************************************
      Function:
    */
    void main(void)
    {
    .
    .
    .
    	// Copy ROM to RAM
    	memcpy((void *)_symval(&sram_reserved_run_start),
    			(const void *)_symval(&code_romToram_run_start),
    			_symval(&code_romToram_run_size));
    
    	// Run from SRAM Region in the CODE Zone Memory MAP 0x01000000 to 0x01100000
    	// Refer to the DataSheet, CODE Zone Memory Map Section
    	functionPtr = (function_ptr_t)(_symval(&sram_code_reserved_run_start) + 1);
    	functionPtr();
    .
    .
    .
    }
    
    /***********************************************************
      Function:
    
       The following function is defined in ROM, but it will be
       run in RAM.
    */
    #pragma RETAIN(functionRunInRam)
    #pragma CODE_SECTION(functionRunInRam,".code_romToram")
    void functionRunInRam (void)
    {
        while (1)                               // continuous loop
        {
            P1OUT ^= BIT0;                      // Blink P1.0 LED
        	__delay_cycles(2000000);
        }
    }
    

    Please give this a try and let me know if you have further questions.

      Best regards,

        David

  • Uhhhhhh, Clemens Ladisch, I did that first part where I add the line "__attribute__((section(".data"), noinline))". Care to take a guess as to what happened?

    My MSP432 Launchpad seems to now be bricked. I can't program it anymore. The compiler doesn't recognize the device. What the hell......................

  • Well, I ordered a new launchpad and I will be picking it up at Mouser, today. I'll try that code when I get it, David. How will I know if it is running from SRAM? Will the Disassembly instruction address be in SRAM (>=0x20000000), rather than a FLASH address?
  • Hi Philip,

     Sorry to hear that you bricked your Launchpad. Try running the factory reset. Please follow the steps in http://www.ti.com/lit/pdf/slau575 (section 7).

    Philip McCorkle said:
    How will I know if it is running from SRAM? Will the Disassembly instruction address be in SRAM (>=0x20000000), rather than a FLASH address?

     Correct, please open a disassembly window. And actually you will be running from the SRAM CODE DATA Region 0x01000000 (0x20000000 Mirror).

    And...

       Best regards,

        David

  • David, that code is causing my chip to continuously reset. I stepped through with assembly and it DOES seem jump the PC to 0x01000200 just as it goes kaboom.

    I have a few questions...

    First, why did you change the ".flashmailbox" from 0x00200000 to 0x00202000?

    Second, your assembly looks different than mine... For instance, at address 0x00000420, mine shows "4807     LDR             R0, $C$CON5" (functionPtr = (function_ptr_t)(_symval(&sram_code_reserved_run_start) + 1);), while yours shows "4806     ldr             r0, [pc, #0x18]" at a different address - 0x000007b6. Any idea why they are different? I copied and pasted your code, verbatim.......

    Here is a screenshot of the assembly leading up to the crash...

    Here is a screenshot of my SRAM just after it crashed.

  • Hi Philip,

    Philip McCorkle said:
    First, why did you change the ".flashmailbox" from 0x00200000 to 0x00202000?

     Sorry, I forgot to update my linker file, 0x00200000 should be ok.

    I'm attaching my project6471.msp432_sample_ram_project_ccs.zip, please unzip and import into your CCS workspace and let me know if you see the same behavior.

    Thanks,

     David

  • Ha! Yes, that works, David! However, I can't step through the C code for the SRAM function. I'm guessing that is because when I create a breakpoint in my C code inside the function that is copied to SRAM, the breakpoint is -actually- in the FLASH memory version of the function and NOT in the SRAM version? I can make a disassembly breakpoint at 0x01000200, though. I just wish there were some way to step through in C.

    Also, what happens when I call a FLASH function inside this SRAM function? When I try to do it, the faultISR gets called... This is bad news for my application. Any idea what is causing that?
  • Hi Philip,

     Glad to hear that it is working.

    Philip McCorkle said:
    I create a breakpoint in my C code inside the function that is copied to SRAM, the breakpoint is -actually- in the FLASH memory version of the function and NOT in the SRAM version?

    Correct, that is the case.

    Philip McCorkle said:
    I can make a disassembly breakpoint at 0x01000200, though. I just wish there were some way to step through in C.

    And we are working on adding this feature to our compiler/linker.

    Philip McCorkle said:
    what happens when I call a FLASH function inside this SRAM function? When I try to do it, the faultISR gets called... This is bad news for my application. Any idea what is causing that?

    The flash address copied into RAM is not being resolved correctly. Again, this will also be added to our compiler/linker.

     IAR currently supports this - "Initializing code—copying ROM to RAM" (I have an example if you are interested) and if I'm not mistaken GNU(gcc) should support this too, but I do not have an example yet.

      Please let us know if you have further questions.

        Best regards,

         David

  • The solution is too convoluted and as of 12/07/15 the debugger cannot resolve the source code.  The following is how I implemented it.  It works and it is much simpler (similar as how I do it for the MSP430):

    In main.c, change the example's global declarations, main, and functionRunInRam() as follows :

    ...

    //***** Global Data *****
    extern int8_t code_to_ram_start;
    extern int8_t code_in_ram_start;
    extern int8_t code_in_ram_size;

    /***********************************************************
      Function:
    */
    void main(void)
    {
        WDT_A_holdTimer();
        MAP_Interrupt_disableMaster();                // Disabling master interrupts

        // Configure clocks
        startCrystalOscillator();
        setSystemClock(CPU_FREQ);

        // P1.0 as output
        MAP_GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);

        // Copy ROM to RAM
        memcpy(    (void *) _symval(&code_in_ram_start), (const void *) _symval(&code_to_ram_start), _symval(&code_in_ram_size) );

        // Just call the function!!!
        functionRunInRam();

    }

    ...

    #pragma CODE_SECTION(functionRunInRam,".code_in_RAM")
    void functionRunInRam ( void )
    {
        while (1)                               // continuous loop
        {
            P1OUT ^= BIT0;                      // Blink P1.0 LED
            __delay_cycles(2000000);
        }
    }

    Replace the linker script with:

    --retain=interruptVectors
    --retain=flashMailbox

    #define CODE_RUN_IN_RAM_SZ  0x1000            // Pick as much as you need ;)
    #define RAM_SIZE                         0x10000
    #define FLASH_SIZE                     0x40000

    #if(CODE_RUN_IN_RAM_SZ > RAM_SIZE)
    #error That is way too much!
    #endif

    MEMORY
    {
        FLASH       (RX)  : origin = 0x00000000, length = FLASH_SIZE - CODE_RUN_IN_RAM_SZ
        FLASH_2_RAM (RX)  : origin = FLASH_SIZE - CODE_RUN_IN_RAM_SZ, length = CODE_RUN_IN_RAM_SZ
        INFO_FLASH  (RX)  : origin = 0x00200000, length = 0x00004000
        SRAM_CODE   (RWX) : origin = 0x01000000, length = CODE_RUN_IN_RAM_SZ
        SRAM        (RW)  : origin = 0x20000000 + CODE_RUN_IN_RAM_SZ, length = RAM_SIZE - CODE_RUN_IN_RAM_SZ
    }

    /* Section allocation in memory */
    SECTIONS
    {
        .intvecs:   > 0x00000000
        .text   :   > FLASH
        .const  :   > FLASH
        .cinit  :   > FLASH
        .pinit  :   > FLASH

        .flashMailbox : > 0x00200000

        .vtable :   > 0x20000000
        .data   :   > SRAM
        .bss    :   > SRAM
        .sysmem :   > SRAM
        .stack  :   > SRAM (HIGH)

        .code_in_RAM: load = FLASH_2_RAM, run = SRAM_CODE, LOAD_START(code_to_ram_start), RUN_START(code_in_ram_start), RUN_SIZE(code_in_ram_size)
    }

    No need to over divide the RAM area, there is just one same region aliased.

    Voila!
    Pibe

  • Hi Pibe,

    Thanks for looking into this and yes that is a better solution. If I'm not mistaken that functionality was added in v5.2.6 (ti-cgt-arm_5.2.6).

    I'm glad that it is working.

    Best regards,

    David
  • You are welcome.  I am glad that I could port what I did on the MSP430.  Otherwise it could have been for me the last nail in the MSP432 coffin.

    David, if you are in contact with the Voice of the Costumer person, please tell him/her that the MSP432 *CANNOT* have the regular timers not connected to BCLK (ergo, no LPM3 = very inefficient FSMs).


    Regards,

    Pibe

  • I had a customer try and follow the above... It is very early code and apparently we have a 'better way'.  His note below to hopefully help the next guy who comes across this thread save valuable time:

    Good news for us on just using

    #if     __TI_COMPILER_VERSION__ >= 15009000

    __attribute__((ramfunc))

    #endif

    to run from SRAM!

     

    We have spent 3 days trying to figure-out how to execute from SRAM, and still really don’t have it working well.

    I searched the TI forum to learn how. I searched on things like ‘MSP432 RUN FROM SRAM’ . What comes-up “front-n-center” is an overly complicated approach that existed in 2015 that involves editing the link file, creating memory segments, a couple pragmas, and copying from FLASH to SRAM.

    The above ramfunc is sooo much easier...

**Attention** This is a public forum