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.

MSPM0G3519: Problems using Bank Swap application note

Part Number: MSPM0G3519
Other Parts Discussed in Thread: CCSTUDIO, UNIFLASH

Hello!
I'm trying to implement a bank swap function based on the Flash Multi Bank Feature application note and run into problems. I use CCStudio 20.4.0 and the MSPM0G3519 LaunchPad. 

The CSC code example from the application note is placed in bank 0 starting from 0x0000 0000, my application from address 0x0000 0800. The linker file is changed accordingly.  

I program the CSC into the µC using the debug feature of the CCStudio. Subsequently I manually program the application into the µC using the "Import data from file" function of the Memory window. Now the software is started. 

If bank swap is not enabled, the CSC must start the application using the start_app() function (also from the application note). This is done by calling "start_app((uint32_t *) (0x0800));" However, this does not start the application but always returns to the CSC. When single stepping through the start_app() function I can see how the pointer to the vector table is passed to the function correctly. But after execution of the assembly language part, the pointer suddenly is 0x0000 0000, pointing to the vector table of the CSC instead of the application. This obviously starts the CSC again. If I enter the correct vector table address manually after execution of the assembly language part, the application is started correctly.

Is there anything I need to configure in the assmbler or compiler for start_app() to work?

Best regards
Uwe

  • Hi Uwe,

    I saw that we do have the boot manager code demos for MSPM0G3519, dose it work if you do not make any modification on your side?

  • Hi Gary,
    first of all, from my point of view the boot manager code demos are to complex to serve as a starting point and the documentation does not comply with this complexity (at least for me as a beginner on the MSPM0).

    I was not able to make the "customer secure code" example work without any modification, since the /* Check Write Protect Firewall in place */ fails. However, after placing the call to the function "start_app()" in the else-branch (Line 180 in file "customer_secure_code.c") it was called correctly and the firmware image residing in bank 0 was executed as expected. And that is what's important for me at this time.

    Meanwhile I already further analysed the problem. I single stepped through the disassembly of the function start_app() generated in my project. It looks like this:

        start_app()
        0x000003A0    B580                push    {r7, lr}
        0x000003A2    B082                sub     sp, #0x8
        0x000003A4    9001                str     r0, [sp, #0x4]
        0x000003A6    9801                ldr     r0, [sp, #0x4]
        0x000003A8    4906                ldr     r1, [pc, #0x18]
        0x000003AA    6008                str     r0, [r1]
        0x000003AC    9801                ldr     r0, [sp, #0x4]
        0x000003AE    6803                ldr     r3, [r0]
        0x000003B0    469D                mov     sp, r3
        0x000003B2    9801                ldr     r0, [sp, #0x4]
        0x000003B4    4904                ldr     r1, [pc, #0x10]
        0x000003B6    6008                str     r0, [r1]
        0x000003B8    9801                ldr     r0, [sp, #0x4]
        0x000003BA    6840                ldr     r0, [r0, #0x4]
        0x000003BC    4780                blx     r0

    As can be seen, the argument (address of the new vector table) passed in Reg0 is placed on stack, later the stack pointer is reconfigured and now the address of the new vector table is read back from the wrong place on the stack since the stack pointer was changed. The only way to avoid this in my project, is to assign the argument to a global variable so it is not placed on stack.

    Even though the C source code is exactly the same, the disassembly in the "customer secure code" example looks completely different:

        start_app()
        0x00001AE0    6803                ldr     r3, [r0]
        0x00001AE2    469D                mov     sp, r3
        0x00001AE4    4923                ldr     r1, [pc, #0x8c]
        0x00001AE6    6008                str     r0, [r1]
        0x00001AE8    6840                ldr     r0, [r0, #0x4]
        0x00001AEA    4780                blx     r0


    Do you have any idea what causes this different compiling result and how I can avoid it?

    Thanks
    Uwe

  • I have a simple back swap demos that you can refer to as below

    MSPM0G3519 SWAP Function.zip

    This will be easy for you to start.

  • I tried to use your example according the enclosed .ppt. But after executing step 1 (programming "MSPM0G3519_NONMAIN_Change.txt") I cannot finish step 2 (programming "MSPM0G3519_BANK0_Example.txt" and "MSPM0G3519_BANK1_Example.txt") since upon clicking on "Load Image" UniFlash responds with an error message (see screenshot). I can proceed only after DSSM Mass Erase or DSSM Factory Reset. What am I doing wrong here?



    However, this is not my main problem since bank swapping works in my application. More important to me is, why the same C source code of the function "start_app()" produces so different compiling results between the example project and my project (see my post above and source code below).

    static void start_app(uint32_t *vector_table)
    {
        /* The following code resets the SP to the value specified in the
         * provided vector table, and then the Reset Handler is invoked.
         * */
    
        /* Reset the SP with the value stored at vector_table[0] */
        __asm volatile(
            "LDR R3,[%[vectab],#0x0] \n"
            "MOV SP, R3       \n" ::[vectab] "r"(vector_table));
    
        /* Set the Reset Vector to the new vector table (Will be reset to 0x000) */
        SCB->VTOR = (uint32_t) vector_table;
    
        /* Jump to the Reset Handler address at vector_table[1] */
    
        ((void (*)(void))(*(vector_table + 1)))();
    }
    

  • why the same C source code of the function "start_app()" produces so different compiling results between the example project and my project (see my post above and source code below).

    It is due to you/compiler put the such function at different address. Even the same code if you put it in different flash area the firmware code is different.

  • The problem is not the fact that the code is different. The problem is that one compilation result is working as expected and the other one not (because it places important information on the stack and tries to read this back after modifying the stack pointer).

    So let me ask more accurate: What are the prerequisites for the example from the Application Note SPRADN2 ("Flash Multi Bank Feature in MSPM0 Family") to compile in a way that it works? Are there any compiler settings or project configurations to make?

    Did you read my comment regarding the bank swap demo in my previous post? Are the instructions in the .ppt incorrect or am I doing something wrong?

  • Could you help to check if you are using the same compiler version for your code and our demo code?

    And also please also check do you set the same compiler optimization level between your code and our demo code.

  • In both cases I am using TI Clang v4.0.4.LTS. The optimization settings were different. It was "0" in my project and "z" in the demo project.

    After setting it to "1" or to "z" in my project, the compilation result works! To me this is an unexpected behaviour and it should be mentioned in the documentation at least. Usually I start development with no optimization and increase it later. Even though now I know how to achieve a working result, this is not a reasonable option since it makes debugging of other code in the project difficult.

  • Something similar came up in an earlier thread (here) regarding the CSC example. As delivered, that example required -O2 since with -O0 the asm() code fumbled the stack. That thread has some alternate codings that operate properly at any optimization level.

  • Or you can try this code

    Replace the code below

    ((void (*)(void))(*(vector_table + 1)))();
     
    Use this code
    ((void (*)()) (*(uint32_t *)((uint32_t) vector_table+ 4))) ();
  • The result is the same: vector_table is placed on the stack before chnaging the stack pointer.

  • Hi Bruce,

    thanks a lot for the hint.

    Meanwhile I found a similair way to solve the problem: I declared a global variable and assigned the pointer to this variable. I hope this works reliably. However, since this behaviour obviously is known for several months, I would expect an information regarding the required optimization level in the application note (spradn2).

  • I'm glad you found a solution.

    In the other thread it's (twice) mentioned that "it is recommended" to use -O2, but I never found the reference.

    I (personally) prefer the second alternate since it's transparent about what it's doing. In the first alternate it's not at all obvious (outside the explanation in the thread) why caching the pointer in a static variable (which is otherwise useless) solves the problem. But the second is the "minimal change".

    I did test both of them using every -O setting I could think of, so I'm pretty sure they're correct.