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.

Using dual image bootloader

Other Parts Discussed in Thread: MSP430F5359

Hello!

We some questions about creating a dual image bootloader (in the main memory). We are using for MCU the MSP430F5359/5659 on a custom hardware device. This device uses wireless a wireless medium to upload and upgrade firmware of the device. 

We have read the slaa600a document and looked at the MSPboot project and modified it for the MCU. We also made a simple input program (that flashes a led) that the bootloader needs to jump to and flash when needed. 

Our first step to manual program the input program and the bootloader and then run the bootloader and jump to te application.

When we run the bootloader (with the debugger) it starts but when we jump to the app space using the  TI_MSPBoot_APPMGR_JUMPTOAPP() function the debugger jumps to a wrong address 0x4. It should jump to the app reset vector(0x47FFC). 

Both the bootloader and input program use a large data model for 20 pointers. 

Does the mspboot work with large pointers? And what could be the reason that when jumping to the input program the program pointer jumps to a wrong address? If more information is needed or code is needed please let us know.

In the bootloader linker file we have made the following memory layout:

/* Flash memory addresses */
/* Download area: 87FFF-48000*/
/* App area : 10000-47FFF*/
/* Boot area : 8000-FFFF*/

Of course any feedback is appreciated!

  • Hello,

    After a couple of days we are still stuck at with the same issue, when jumping to the app space from the boot loader  the program is not loaded, there is no led blinking. When using the debugger it jumps to 0x4?

    Does someone have any idea why it jumps not to the 0x47FFC addres?

  • John Hunter78 said:
    Does the mspboot work with large pointers?

    Doesn't appear so. If you dig into the code (which I just did for you) you will see (in TI_MSPBoot_AppMgrDualImg.c) that the addresses are referenced as uint16_t types, which only support addresses less than 0x10000.

    If you want to use upper memory, you will need to modify the code throughout to support that. Not just the programming and validating logic, but also will need to figure out how to handle the interrupt proxy table for 20-bit jumps (and subsequent returns).

  • Hi Brain,

    Thank you for your reply! Yes we have seen it to, if we use uin32_t is stead of unit16 will this solve the large pointer issue?

    if we use:

    extern uint32_t _App_Reset_Vector;   

    and

    const uint32_t Vector_Table[] =
    # endif
    {

    UNUSED, // FFD0 = Reserved
    APP_PROXY_VECTOR(0) // FFD2 = RTC

    // etc
    };

    Will this work? And what could be the reason to that when using TI_MSPBoot_APPMGR_JUMPTOAPP(); it will jump to 0x4? TI_MSPBoot_APPMGR_JUMPTOAPP() is defined as:

    #define TI_MSPBoot_APPMGR_JUMPTOAPP()     {((void (*)()) _App_Reset_Vector) ();}

    We have modified the address variables from uint16_t to uint32_t.

     Thank you for your feedback!

  • John Hunter78 said:
    if we use uin32_t is stead of unit16 will this solve the large pointer issue?

    You'll have to figure that out. I've never used MSPBoot myself and I can't spend 30 minutes or more pouring through all the code for you. I answered the initial question and gave you a jumping off point for doing your conversion.

    Sorry I can't be more help.

  • While bootloader and application may use the large data/code model, the reset vector is located at 0x0FFFE and is a 16 bit vector. (same for all interrupt vectors). So when making an indirect jump over the reset vector to start the application (which is the default and most likely what TI_MSPBoot_JUMPTOAPP() does), this entry point must be in the lower 64k, as well as any ISR entry point. You may generate dummy entry points that just contain a jump to the real function, maybe an indirect jump through a 32 bit vector table in the images, and deciding which image to jump at by a global flag.

  • Jens-Michael Gross said:
    which is the default and most likely what TI_MSPBoot_JUMPTOAPP() does

    No. The reset vector always points to the start of the MSPBoot code. So only that portion has the absolute requirement to be in lower memory. The rest of the system could be modified to support upper memory entry points for the application code.

    I didn't reverse engineer it enough myself to know the exact mechanism but did read the document section that talks about startup sequence and app validation. That and scanned the code enough to see that they were typed as 16-bit wide addresses.

  • Hello Brian and Jens,

    First of all thank you both for your reply's. Today we we didn't got the time to work on the bootloader, we hope that we will have time tomorrow! We will start with converting all the 16 bits variables into 32 unsigned. When we got a working version (hopefully) with higher addresses then we wil post it here! We will keep you posted of our progress!

  • Hello,

    The last two days we have been working to get the MSP boot working on the MSP40F5659/F5359. As a in between step we converted the MSPBoot to be used on the lower addresses (under the 64kb) and we got this working! When we call TI_MSPBoot_APPMGR_JUMPTOAPP() it jumps to our application reset vector which is defined as _App_Reset_Vector = 0xAFFE.

    A strange thing to us is that the application cannot be loaded with the code composer ide, we need to use a flash load tool (FET-430Pro) what could be the reason that we need to flash it with a tool? The bootloader can be loaded with code composer.

    The next step was converting the MSP project and application project to be loaded from the higher memory we defined the areas as followed:

    Bootloader: 0xF000 - FA00
    Bootloader vectors table: 0xFA00 (0xFA00+ 0x100, reserved space size is 0x100), actual space needed 29 vectors each 4 bytes needed to contain the proxy addresses?
    Bootloader reset vector: 0xFFFE (device default)

    App area: 0x10000 - 0x4A000, length is 0x3A000
    App vector table: 0x4AE00, (0x4AE00 + 0x100, reseved space size is 0x100), actual space needed 29 vectors each 4 bytes = 116
    App reset vector: 0x4AFFC, 4 bytes in size

    Download area: Not yet defined.

    But when loading the application via the flash tool and the bootloader with code composer when calling  TI_MSPBoot_APPMGR_JUMPTOAPP() the application is not loaded( the application should blink a led by toggling a led pin in a while loop). This worked with the project below 64k. We changed the proxy table variables from uint16_t to uint32_t, we did this also with all the other unit16_t variables that contain a address. Does the proxy vector table of the bootloader also needs to be uint32_t, we finc it does since it contains the application app proxy addresses?


    Below is the proxtvector table from the Vectors.c file that we have adjusted

    const uint32_t ProxyVectorTable[] =
    # endif
    {
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(0)
    0x4030, (uint32_t) P2_Isr, // APP_PROXY_VECTOR(1)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(2)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(3)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(4)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(5)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(6)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(7)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(8)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(9)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(10)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(11)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(12)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(13)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(14)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(15)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(16)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(17)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(18)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(19)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(20)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(21)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(15)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(16)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(17)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(18)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(19)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(20)
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(21)
    };

    Would could be the reason that the app reset vector is not jumped to when calling TI_MSPBoot_APPMGR_JUMPTOAPP() function when using a larger address? We think it might be in our linker file but we can't seem to find the problem. If we need to post more code for more information please say so. Any suggentions are welcome!

    PS both projects use large data model.

  • John Hunter78 said:
    Below is the proxtvector table from the Vectors.c file that we have adjusted

    const uint32_t ProxyVectorTable[] =
    # endif
    {
    0x4030, (uint32_t) Dummy_Isr, // APP_PROXY_VECTOR(0)
    0x4030, (uint32_t) P2_Isr, // APP_PROXY_VECTOR(1)

    You cannot do that. This table builds up a set of branch instructions. It has to be built up appropriately. 0x4030 is a branch instruction to a 16-bit address.

    You need to make the table be BRA instructions to your 20-bit addresses. The table needs to be aligned appropriately, and your interrupt vectors in the bootloader will also need to be adjusted to jump into the correct location of your new proxy table. Take a look at section 6.5 of the user's guide.

  • Hello Brain,

    Thank you four your reply again! We have some questions and we hope you or someone else can answerer them. With allignment you mean that the origional vector table contains 16-bit addresses and each entry is two bytes in size, with the new vector we need to make each entry 4 bytes in size? With the interrupt vectors this means each address needs to be also four bytes? E.g. the orignal UCB2RXIFG, vectorstarts at: 0x0FFC6 till 0x0FFC8, so this means two bytes. The new vector is from 0x0x0FFC6 to 0x0FFCA, so i can contain four bytes? And the next vector (UCA2RXIFG) starts at 0xFFCB and not at 0xFFC8?

    As for the proxy table with bra instructions should each instruction be identical? Or does each entry has it's own value? Could you give us a small example of a proxy table with 20-bit bra instruction, with one or two entrys? We have looked at 6.5 of the family user guide and namely section 6.5.1.3 Jump Instructions, since this is about jumping to another address, but our assembly knowledge is minimal at best. If you could help us eleborate that would help us greatly.

    Many thanks for the help you have given us so far!
  • John Hunter78 said:
    With allignment you mean that the origional vector table contains 16-bit addresses and each entry is two bytes in size, with the new vector we need to make each entry 4 bytes in size? With the interrupt vectors this means each address needs to be also four bytes? E.g. the orignal UCB2RXIFG, vectorstarts at: 0x0FFC6 till 0x0FFC8, so this means two bytes. The new vector is from 0x0x0FFC6 to 0x0FFCA, so i can contain four bytes? And the next vector (UCA2RXIFG) starts at 0xFFCB and not at 0xFFC8?

    No. You can't do that. The MSP430 vectors are fixed locations and have to be always a single 16-bit address. This is the reason for the proxy table. The peripheral generates an interrupt, the CPU fetches the 16-bit vector and does an interrupt call (with appropriate stack setup).

    The vector is a call into your proxy table, which is itself a set of branch instructions to the location of the real vectors.

    The problem is that the upper 4 bits of the 20-bit address are encoded as part of the BRA instruction, and the lower 16 bits are in the next word address in the code. So you can't just extend the example code to a uint32_t address.

    One possibility is to put each of your ISR routines in their individual code segments, and fix their location in the linker file. Then the proxy table can be built with those hard coded addresses manually.

    I am not an expert in MSP assembly (it's been 20+ years since I did hardcore assembly language on the 8085) but you may be able to create the proxy vector table in assembly, maybe something along the lines of (not a full example):

            NAME    proxyTable              ; module name
    
            PUBLIC  proxyTable              ; make the highloop label vissible
                                            ; outside this module
            RSEG    PROXYTABLE              ; locatable DATA segment name
    
    		EXTERN  P1_Isr
            EXTERN  Dummy_Isr           
            EXTERN  TI_MSPBoot_Comm_Isr 
            EXTERN  TI_MSPBoot_Comm_Isr 
    
    proxyTable:
    
            BRA #P1_Isr              ; APP_PROXY_VECTOR(0) P1
            BRA #Dummy_Isr           ; APP_PROXY_VECTOR(1) P2
            BRA #Dummy_Isr           ; APP_PROXY_VECTOR(2) ADC10
            BRA #TI_MSPBoot_Comm_Isr ; APP_PROXY_VECTOR(3) USCI I2C TX/RX
            BRA #TI_MSPBoot_Comm_Isr ; APP_PROXY_VECTOR(4) USCI I2C STAT
            BRA #Dummy_Isr           ; APP_PROXY_VECTOR(5) TA0_1
            BRA #Dummy_Isr           ; APP_PROXY_VECTOR(6) T0_0
            BRA #Dummy_Isr           ; APP_PROXY_VECTOR(7) WDT
            BRA #Dummy_Isr           ; APP_PROXY_VECTOR(8) COMP_A
            BRA #Dummy_Isr           ; APP_PROXY_VECTOR(9) TA1_1
            BRA #Dummy_Isr           ; APP_PROXY_VECTOR(10) TA1_0
            BRA #Dummy_Isr           ; APP_PROXY_VECTOR(11) NMI
    
            END
    

    That's about all the help I can really provide.

    EDIT: Added # to the target names to force immediate mode addressing in instruction generation.

  • Hello Brain,

    Thank you for your reply, last night we had a brainstorm session and we came up with a other idea: what if we set the proxy table also in the lower main memory? This way we do not have to use larger addresses and our bootloader is just around 1kb. So in our lower memory we have more than enough room for some appication code and the application reset and interrupt table. The application it self will extent in the higher memory but the proxy vector table and the application reset vector will be in the lower memory. Is this possible? Must the application reset vector be in the top of the application space, the last address or is only the actual reset vector fixed? With this suggestion the application space wil wrap around the bootloader space, sharing a bit of the lower memory with the bootloader and extending in the higher memory. Can you give us an idea if this is even possible?

    Below is our sugested memory layout:

    /* Flash memory addresses */
    /* Download area: 87FFF-50000*/
    /* App area : 8000-CFFF and 10000 - 4FFFF*/
    /* Boot area : F000-FA00*/

    Bootloader: 0xF000 - FA00
    Bootloader vectors table: 0xFA00 + size (29 vectors *2 bytes)
    Bootloader reset vector: 0xFFFE (device default)

    App area: 8000-CFFF and 10000 - 4FFFF (FLASH and FLASH2 in linker file)
    App vector table: 0xD000 + size (29 vectors *2 bytes)
    App reset vector: 0xDFFE.
  • Something you can do: the jumps where the interrupt vectors point to need to be in lower 64k (best place would be directly below the interrupt vectors), but they don’t need to be absolute jumps. You can use indirect jumps, taking the destination address from anywhere in 20 bit memory.
    So you can make your application having their own interrupt vector table with 20/32 bit vectors at a known position, and the branch instructions use them.
    e.g. NMI vector (0x0FFFC) points to 0x0FF7C. Application vector (32 bit) is at 0x1FFF8. At 0x0FF7c, there is a BRA &0x1FFF8.
    This way, the jumps in lower memory do not need to know the destination addresses in the application, only the (fixed) position where the application has stored these addresses. Of course this introduces another two MCLK cycles interrupt latency for reading the 32 bit address from there.
  • Hello Jens-Michael,

    Thank you for your reply, we are currently helping one of our customers with some problems and we hope to give this a try next week! Can you give a estimation if the idea what we came up with is also feasible? The Application does not need to start in the higher memory and our bootloader code is very small since it only needs to swap a application image and not download it.

    So in the lower memory we have a total room of 7FFF (FFFF-8000) and our actual bootloader code is not greater then lets say 2000 bytes. So we have room for some actual application code and there proxy vector table(application table). Also could we force the actual vectors, the apllication interrupt routines in the lower memory? If we place the application vectors table(and the vectors?)in the lower memory also then we don't have to use large addresses? Could the following memory layout work, or aleast is this idea feasible? We ask this so that we don't waste time following a wrong train of tought.

    /* Flash memory addresses */
    /* Download area: 87FFF-50000*/
    /* App area : 8000-CFFF and 10000 - 4FFFF*/
    /* Boot area : F000-FA00*/

    Bootloader: 0xF000 - FA00
    Bootloader vectors table: 0xFA00 + size (29 vectors *2 bytes)
    Bootloader reset vector: 0xFFFE (device default)

    App area: 8000-CFFF and 10000 - 4FFFF (FLASH and FLASH2 in linker file)
    App vector table: 0xD000 + size (29 vectors *2 bytes)
    App reset vector: 0xDFFE.

    On your idea you said: "At 0x0FF7c, there is a BRA &0x1FFF8." Can you give us an example of what the BRA value should be? Our how to calculate this instruction value? Thank you for your reply!

  • It should work. However, having the app stored/running from separate flash blocks (and not the one the bootloader is in) has the advantage that you can use bank erase, which is much faster than erasing individual segments.
    With my BRA, I proposed indirect branching. BRA &0x1FFF8 means “branch to the address whose 20bit value is stored at 0x1FFF8”. It does not branch to a fixed address, but rather to the address stored at 0x1FFF8. It’s more or less the 20 bit version of what the processor does by itself with the original 16 bit vector table.
  • Hello Jens-Michael and others,

    Last week we had time to work on the bootloader, we have a version working and it uses the lower space to store the bootloader and part of the application (the rest is stored in 0x10000 and above). We wrote a small application to test the the bootloader, in particually the vector rederection. It workes fine ( we have some buttons on the P1 and P2 interrupt ports) and the ISR's are called correctly!

    Next we ported the exact same memory layout (defined in the .cmd file) to our target project and we run in some problems, the vector rederection does not work. When we press the same buttons the application "hangs" and does not recover. After some debugging we removed some code untils the size of the code fitted below the 0x10000 in the main memory (we did not change the ISR code) and it worked fine again.

    What could be the reason that when the code extens above the 0x10000 the vector rederection does not work anymore? We still use the 16-bit BRA's in our proxy table. Do we need to switch to the 20-bit BRA to solve this problem? And if so can you explain how to callculate the correct 20-bit value BRA value? What makes up a BRA value?

    We hope someone can help us with this issue.

  • If your ISR code is in the lower 64k, then it should work with the default BRA. If you use 20 bit BRA, this has the advantage of allowing the ISR to be placed anywhere. The microcode for the ISR calls makes sure that the RETI instruction will return to the proper 20 bit address (the upper 4 bits of the return address are stored in the upper byte of the saved status register and restored from there on RETI).
    So the problem probably is a different one.
    Note that (normal) functions that can be called from a funciton above 64k need to exit with RETA, even if placed in lower 64k, and need to be called with CALLA even if residing in lower 64k. Because of the required 20bit return address.
    Usually, the compiler tells the linker whether code was compiled with CALLA/RETA (large code model) or CALL/RET (small code model) and hte linker refuses to link objects compiled with different settings. However, when including external libraries, especially those written in assembly, or using assembly code in the project, this is not guaranteed.
    Calculating a 20 bit BRA value is not simple, because the upper 4 bit of the address are part of the insctruction code. The users guide explains how the instructions are assembled.
    IIRC, I have made a demo calculation not too long ago (last year or so) in a different thread. Search the forum for 'proxy table', I think this term was used in this thread.

**Attention** This is a public forum