Helpful ReplyHot!Live Bootloader question

Page: 123 > Showing page 1 of 3
Author
realexander
Senior Member
  • Total Posts : 137
  • Reward points : 0
  • Joined: 2006/04/08 09:50:42
  • Location: 0
  • Status: offline
2016/04/27 11:18:06 (permalink)
0

Live Bootloader question

Hi,
 
If I understand the live bootloader correctly, your program must occupy less than half of your flash. When you come out with version 2 of your program, it must be linked to occupy the top half of the flash. Then, version 3 would occupy the bottom half of your flash again.
 
So what happens if a user has version 1, they skip version 2, then want to upgrade to version 3. Versions 1 and 3 have both been linked to occupy the lower half of flash memory. Is it simply not possible to do that upgrade?
 
It also seems difficult and error-prone to change the link locations with every version. Not only do you need to swap link files, but if you have data in a hard-coded location (e.g. the USB MSD likes to hard-code the location of the disk image) you have to change that too.
 
My goal is this: I have an app that already supports a USB MSD and CDC. I want the user to be able to upgrade by dragging a file to the MSD, opening up a terminal window, and giving the app a command to upgrade. (The file is compressed by zlib, so it can fit on the MSD even though it has an image of the firmware.) Live update seems like the way to go, but I would welcome alternative suggestions.
 
Thank you,
   Bob
 
post edited by realexander - 2016/04/27 11:21:59
#1
bikeoid
Super Member
  • Total Posts : 168
  • Reward points : 0
  • Joined: 2010/04/30 05:58:38
  • Location: 0
  • Status: offline
Re: Live Bootloader question 2016/04/27 11:43:34 (permalink)
4 (2)
The way LiveUpdate works when programs use less than half the flash is straightforward.    Perform standard development with normal virtual addresses that map to the lower virtual bank of both boot and program flash.  To switch, program the new bits to the alternate flash bank.   Then write a flag to boot flash to indicate which bank should be active.   The boot flash should look at this flag at each restart to know which program flash bank to activate.   The program bank swaps the physical->virtual mapping so that program addresses do not need to be changed.
 
Notes:
  1. The standard bootloader example does not update boot flash (including configuration registers).
  2. If you store configuration data to a section of program flash, take this into consideration when swapping program flash banks, possibly by writing a copy of the configuration data to the alternate bank after programming (assuming that the entire alternate flash bank was erased before programming)
#2
Larry.Standage
Moderator
  • Total Posts : 784
  • Reward points : 0
  • Joined: 2011/12/30 09:50:47
  • Location: 0
  • Status: offline
Re: Live Bootloader question 2016/04/27 12:40:35 (permalink)
3 (1)
You don't need to change the linker script. Link as though it will run in the lower addresses (because it will). The bootloader library will automatically translate the addresses from the lower half to the upper half and write it there.
 
The only thing to worry about then is how to identify which version is the one to run, and swap the flash panels before jumping into it.
#3
realexander
Senior Member
  • Total Posts : 137
  • Reward points : 0
  • Joined: 2006/04/08 09:50:42
  • Location: 0
  • Status: offline
Re: Live Bootloader question 2016/04/27 19:14:58 (permalink)
0
Thank you. I see now that the NVMCON SWAP (or PFSWAP - what's the difference?) bit swaps the high and low halves of the flash. But I still don't understand how you determine the correct SWAP bit at boot time.
 
At reset, the SWAP bit is set to zero so the low physical flash is mapped to low virtual addresses. A live bootloader app (like MCHP's liveUpdate demo) runs the bootloader.c code (Bootloader_Tasks()) at startup. Bootloader_Tasks() checks the top half of the flash to see if anything is programmed there. If there's something there, it sets the SWAP bit to one and jumps to it.
 
So now we're running the new code. It's a live bootloader too. So it calls Bootloader_Tasks() which sees that there's something in the high flash (it's seeing the old version of the firmware). It sets the SWAP bit (but it was already set, so it has no effect) and jumps to the beginning of itself. And so we have an infinite loop.
 
I don't see how MCHP's liveUpdate gets out of this. More importantly, I don't see how I solve this for my own app. Do I put a version number at a known location in flash memory, so that I can choose the newer firmware? Are there other commonly used solutions?
 
Thank you,
   Bob
 
#4
NKurzman
A Guy on the Net
  • Total Posts : 15508
  • Reward points : 0
  • Joined: 2008/01/16 19:33:48
  • Location: 0
  • Status: online
Re: Live Bootloader question 2016/04/27 19:24:17 (permalink)
3 (1)
Not sure about the Microchip Logic.  But the theory is the bootlooader decides which has the code you want to use. Once you are Happy with the New Bootload you switch to that.  If your program has a use previous version you need to put that information somewhere so the bootloader knows.  So what to page use should get stored somewhere.
If the Version is the "key" you could use that, Assuming there is no need to go back.
 
#5
uaz
New Member
  • Total Posts : 24
  • Reward points : 0
  • Joined: 2015/06/22 20:53:20
  • Location: 0
  • Status: offline
Re: Live Bootloader question 2016/04/27 19:39:32 (permalink)
0
I believe the current live update bootloader code only allows one time flash update. The following is a piece of code I took from Bootloader.c:
void __longcall__ __attribute__ ((section (".cache_init"))) SwapFlashPanels(void)
{
    void (*fptr)(void);

    PLIB_NVM_MemoryModifyInhibit(NVM_ID_0);
    PLIB_NVM_FlashWriteKeySequence(NVM_ID_0, NVM_PROGRAM_UNLOCK_KEY1);
    PLIB_NVM_FlashWriteKeySequence(NVM_ID_0, NVM_PROGRAM_UNLOCK_KEY2);
    PLIB_NVM_ProgramFlashBank2LowerRegion(NVM_ID_0);

    /* Disable Global Interrupts */
    PLIB_INT_Disable(INT_ID_0);
    fptr = (void (*)(void))BOOTLOADER_RESET_ADDRESS;
    fptr();
}

 
With only
PLIB_NVM_ProgramFlashBank2LowerRegion(NVM_ID_0);
there is no way going back to flash bank 1. You may want to add a custom code alternating between flash 1 and flash 2 based on PFSWAP value.
#6
bikeoid
Super Member
  • Total Posts : 168
  • Reward points : 0
  • Joined: 2010/04/30 05:58:38
  • Location: 0
  • Status: offline
Re: Live Bootloader question 2016/04/27 20:04:48 (permalink)
0
Disclaimer - I began with a much older version of Harmony, so the usual cautions apply.

I ended up with different versions of bootloader_tasks() for the bootloader code VS the application, but I think that there is a conditional #if(BOOTLOADER_STATE_SAVE == 1) that does the same thing. To put the logic in a nutshell, here are some code fragments:
 
#define VIRTUAL_LAST_BOOT_PAGE_BASE 0xBFC10000
#define PHYSICAL_LAST_BOOT_PAGE_BASE 0x1FC10000

            // Right after programming, Activate new program by setting a flag word
            // in last page of boot flash and restart
            PLIB_NVM_FlashWriteKeySequence(NVM_ID_0, 0xAA996655);
            PLIB_NVM_FlashWriteKeySequence(NVM_ID_0, 0x556699AA);
            PLIB_NVM_BootPageWriteProtectionDisable(NVM_ID_0, LOWER_BOOT_ALIAS_PAGE4);
            // Which page are we currently running out of?
            if (PLIB_NVM_ProgramFlashBank2IsLowerRegion(NVM_ID_0)) {
                // We are swapped now, so we need to erase the last page
                PLIB_NVM_FlashAddressToModify(NVM_ID_0, KVA_TO_PA(PHYSICAL_LAST_BOOT_PAGE_BASE));
                APP_NVMOperation(PAGE_ERASE_OPERATION);
                while (!PLIB_NVM_FlashWriteCycleHasCompleted(NVM_ID_0));
                PLIB_NVM_MemoryModifyInhibit(NVM_ID_0);
                //PLIB_NVM_ProgramFlashBank1LowerRegion(NVM_ID_0); // Done by bootloader
                SYS_CONSOLE_PRINT( "%s", "Erased Lower Boot alias page 4 to FFFF\r\n");
            } else {
                APP_NVMWordWrite((void *) PHYSICAL_LAST_BOOT_PAGE_BASE, 0);
                while (!PLIB_NVM_FlashWriteCycleHasCompleted(NVM_ID_0));
                PLIB_NVM_MemoryModifyInhibit(NVM_ID_0);
                //PLIB_NVM_ProgramFlashBank2LowerRegion(NVM_ID_0); // Done by bootloader
                SYS_CONSOLE_PRINT( "%s", "Cleared Lower Boot alias page 4 to 0000\r\n");
            }

   // Jump to PIC32 reset address (bootloader)
....
....


case BOOTLOADER_CHECK_FOR_FLASH_SWAP:
// For every startup in bootloader
/* Check the first word of the second boot flash. If it is blank,
            don't swap the memory. */
            if (*(unsigned int *) VIRTUAL_LAST_BOOT_PAGE_BASE != 0xFFFFFFFF) {
                 PLIB_NVM_ProgramFlashBank2LowerRegion(NVM_ID_0);
                SYS_CONSOLE_PRINT( "%s", "Flash swapped\r\n");
            } else {
                 PLIB_NVM_ProgramFlashBank1LowerRegion(NVM_ID_0);
                SYS_CONSOLE_PRINT( "%s", "Normal Flash Order Selected\r\n");
            }

 // Jump to start of application in program flash
....

post edited by bikeoid - 2016/04/27 20:09:20
#7
uaz
New Member
  • Total Posts : 24
  • Reward points : 0
  • Joined: 2015/06/22 20:53:20
  • Location: 0
  • Status: offline
Re: Live Bootloader question 2016/04/27 20:12:04 (permalink)
0
Hi bikeoid, 
 
So if I understand correctly, you swap your flash bank from the program flash?
 
Thanks
UAZ
#8
bikeoid
Super Member
  • Total Posts : 168
  • Reward points : 0
  • Joined: 2010/04/30 05:58:38
  • Location: 0
  • Status: offline
Re: Live Bootloader question 2016/04/28 04:14:14 (permalink)
0
uaz
So if I understand correctly, you swap your flash bank from the program flash?

 
 To clarify my code segments above - I wanted to load the new program from the live application that runs over the network.   The first code block above resides in program flash, and after validating and completing the program load - sets the flag residing in boot flash.    The second code block resides in the bootloader and after checking the flag in boot flash, swaps the program flash bank / or not on each processor start.
#9
realexander
Senior Member
  • Total Posts : 137
  • Reward points : 0
  • Joined: 2006/04/08 09:50:42
  • Location: 0
  • Status: offline
Re: Live Bootloader question 2016/04/28 19:24:04 (permalink)
0
I hope you'll indulge me with a little more help.
 
I have the bootloader mostly working: it burns the high bank, checks version numbers, swaps banks, and jumps to 0xbfc00000. At 0xbfc00000, there's an instruction "BEQ ZERO, ZERO, __reset_switch_isa". I can see in the disassembly code that __reset_switch_isa has a "JAL _startup" instruction. Looks good.
 
But when I step into the "BEQ ZERO, ZERO, __reset_switch_isa" instruction, I end up far away at address 0x1d000000. That's simple_tlb_refill_excpt. The PIC32's Cause register is 0x00800008 (ExcCode is 2, which isn't defined). BadVAddr is 0x1fc00000, which makes sense. It appears something is not set up right for executing a swapped flash bank.
 
What do I need to do?
 
Thank you,
   Bob
 
#10
bikeoid
Super Member
  • Total Posts : 168
  • Reward points : 0
  • Joined: 2010/04/30 05:58:38
  • Location: 0
  • Status: offline
Re: Live Bootloader question 2016/04/29 12:19:56 (permalink)
0
The first thing that comes to mind would be that the cache should be invalidated before running the new program.   But jumping to the bootloader start should do exactly that as part of the startup code.
 
Just as a test, try-
  •  Confirm that you can jump to the bootloader without programming the 2nd bank or swapping. 
  •  Program the exact same program in the second bank, swap, then confirm that it runs.
 
#11
bikeoid
Super Member
  • Total Posts : 168
  • Reward points : 0
  • Joined: 2010/04/30 05:58:38
  • Location: 0
  • Status: offline
Re: Live Bootloader question 2016/04/29 13:12:16 (permalink)
3 (1)
2 more thoughts: be sure to disable interrupts before jumping into the bootloader.   Also, I'm not sure that single step works when jumping back into the bootloader.
#12
schmerse
New Member
  • Total Posts : 29
  • Reward points : 0
  • Joined: 2017/02/21 03:35:29
  • Location: Germany
  • Status: offline
Re: Live Bootloader question 2017/08/15 03:00:32 (permalink)
0
Dear all,
 
I'm also trying to implement a live update, my hw is an PIC32MZ1024EFH144.
 
Up to now I did the following:
1. Implementaion of an UDP socket that gets update data from a PC host and NVM functions for writing the data to the inactive bank.
2. I do have two configs for generating Code for bank 1 and bank 2. The PC host merges the hex-files to one hex-file which contains Code for bank 1 and bank 2. Code for bank 1 starts at 0x1D000000, Code for bank 2 starts at 0x1D080000. Config bank 1 works with linker script a, config bank 2 works with linker script b. The only difference is the base address.
3. After flashing the CPU with PICkit3 it runs the Code from 0x1D000000. After writing data to the inactive bank (which is bank 2 at 0x1D080000 in this case) an update flag is written at 0xBFC10000, a sw reset is performed and _on_reset() selects the bank from which the Code shall be running. 
4. What I see now is very confusing. I do have a version constant which I set differently to see if the update was performed correctly and I pass it to a visualization that is connected to my PIC via Ethernet. When I poll the version string it alternates between the version that I downloaded via PICkit3 and the version that has been downloaded via live update. To me it seems like code of both banks is running.
 
Any ideas why this happens?
 
Thanks in advance,
schmerse
#13
realexander
Senior Member
  • Total Posts : 137
  • Reward points : 0
  • Joined: 2006/04/08 09:50:42
  • Location: 0
  • Status: offline
Re: Live Bootloader question 2017/08/15 05:06:59 (permalink)
0
schmerse, I'm about to leave on vacation, so I can't give a very detailed response. But I finally got my live update working and realized I had made lots of mistakes in my first implementation, and it was easier than I thought it was.
 
First, you don't need to code or link the live update any differently from the original. I.e. get rid of your two different configurations linking to two different addresses; always link to 0x1D000000. Second, you need to set TSEQ to the version number and CSEQ to its complement. You can find TSEQ and CSEQ in the Harmony Configurator -> Device and Project Configuration -> PIC32MZ1024EFH144 Device Configuration -> SEQ3. (TSEQ and CSEQ are combined to form the BFxSEQ0 configuration register that you'll see mentioned in the PIC32 reference manual. But The Harmony Configurator does that for you.)
 
When the PIC32 starts up, it will look at TSEQ in both banks of memory. It will make sure the values are valid by seeing whether CSEQ is the complement of TSEQ. If both TSEQs are valid, it chooses the larger one and remaps that memory bank to 0x1D000000. That's all done by the PIC32 hardware; you don't need (and shouldn't have) an _on_reset function selecting the bank.
 
One little quirk: The PIC32 prohibits programming of the JTAGEN configuration bit via a bootloader (see http://www.microchip.com/forums/m947541.aspx) so I had to clear it myself at startup time or I'd lose control of some pins. I just did:
   CFGCONbits.JTAGEN = 0;
 
Regarding your code that burns the upgrade into the other bank of memory: remember that you need to write both the Boot Flash Memory and the Program Flash Memory.
 
I hope this helps. Gotta fly now (literally).
 
- Bob
 
#14
realexander
Senior Member
  • Total Posts : 137
  • Reward points : 0
  • Joined: 2006/04/08 09:50:42
  • Location: 0
  • Status: offline
Re: Live Bootloader question 2017/08/15 05:13:33 (permalink)
0
 
UPDATE: Sorry, you do need an _on_reset. The PIC32 swaps the Boot Flash, but doesn't swap the Program Flash. My code is:


// Called from the CRT startup code. Resides in the boot flash
// See http://www.microchip.com/forums/m946552.aspx
void __attribute__ ((section (".cache_init"),address(0x9fc01000))) _on_reset()
{
    // Switch to the matching program flash bank
    if (NVMCONbits.BFSWAP)
    {
        NVMCONbits.WREN = 0;
        NVMKEY = 0;
        NVMKEY = 0xaa996655;
        NVMKEY = 0x556699aa;
        NVMCONSET = 1 << 7;
    }
}

#15
schmerse
New Member
  • Total Posts : 29
  • Reward points : 0
  • Joined: 2017/02/21 03:35:29
  • Location: Germany
  • Status: offline
Re: Live Bootloader question 2017/08/15 05:56:52 (permalink)
0
Thank you Bob, have a nice vacation!
 
I will try to understand what you wrote and correct my approach, seems like it has been the wrong way how I started in general. I will start again from scratch...
 
To avoid any mistakes in the beginning I probably will be back with many questions shortly ;-)
#16
schmerse
New Member
  • Total Posts : 29
  • Reward points : 0
  • Joined: 2017/02/21 03:35:29
  • Location: Germany
  • Status: offline
Re: Live Bootloader question 2017/09/12 03:06:47 (permalink)
0
Hi Bob,
 
I hope you had a nive vacation!
 
Do you remember how you recovered from that issue:
 
But when I step into the "BEQ ZERO, ZERO, __reset_switch_isa" instruction, I end up far away at address 0x1d000000. That's simple_tlb_refill_excpt. The PIC32's Cause register is 0x00800008 (ExcCode is 2, which isn't defined). BadVAddr is 0x1fc00000, which makes sense. It appears something is not set up right for executing a swapped flash bank.
 
Thank you in advance,
schmerse
 
 
#17
realexander
Senior Member
  • Total Posts : 137
  • Reward points : 0
  • Joined: 2006/04/08 09:50:42
  • Location: 0
  • Status: offline
Re: Live Bootloader question 2017/09/12 05:20:28 (permalink)
0
Hi Schmerse,
 
I don't remember having the problem you describe. It looks like you're trying to reboot the PIC32, right? In my case, I have the user turn the device off and on again after upgrading the firmware, but in your case you should call the SoftReset() library function.
 
Remember that when reset, the PIC32 checks for the newest code in Boot Flash and swaps blocks accordingly. This is done by the PIC32 hardware in response to a reset, not by the startup code. If you just jump to __reset_switch_isa, you don't get the benefit of that Boot Flash swap; you need to trigger a true reset.
 
- Bob
 
#18
schmerse
New Member
  • Total Posts : 29
  • Reward points : 0
  • Joined: 2017/02/21 03:35:29
  • Location: Germany
  • Status: offline
Re: Live Bootloader question 2017/09/18 03:03:13 (permalink)
0
Hi Bob,
 
I do the SoftReset() and the PIC32 comes up with the code which I put in PFM2 (which starts at 0x1d080000) - but it's also executing some code from PFM1 (which starts at 1xd000000).
 
When upreading the memory after having performed an update I can see that there are some jumps back to PFM1 which have not been programmed from the update that was dedicated to PFM2.
 
Is there any logic on the pic that can do those strange things? Or can that be an Silicon error on mz1024efh144?
 
Thanks in advance for any comment.
schmerse
 
#19
realexander
Senior Member
  • Total Posts : 137
  • Reward points : 0
  • Joined: 2006/04/08 09:50:42
  • Location: 0
  • Status: offline
Re: Live Bootloader question 2017/09/18 08:01:00 (permalink)
3 (1)
The PIC32 is only doing two things: swapping the boot flash based on the version numbers in the BFxSEQ0 register, and jumping to your startup code. 
 
It doesn't swap the PFM blocks (the code I posted for _on_reset() does that - and that code has to be in the boot flash, because if it's in PFM and it swaps the PFM blocks, all hell will break loose) and it doesn't arbitrarily jump to code. If it's executing code in both PFM1 and PFM2, it has to be because some of your code is linked to each of those blocks, or your code is jumping to an invalid address. As we all know, there are many conventional ways a microcontroller can end up executing code somewhere off in the weeds. That's what I think is happening.
 
You were originally trying to manage swapping blocks manually. Is it possible some of that code hasn't been removed yet?
 
- Bob
#20
Page: 123 > Showing page 1 of 3
Jump to:
© 2018 APG vNext Commercial Version 4.5