cancel
Showing results for 
Search instead for 
Did you mean: 

Steps to perform Firmware Upgrade using ST25DV dynamic tag

Nikhil D&K
Senior

Hello,

I would like to know how can i perform the Device Firmware upgrade using ST25DV dynamic tag.I am using "en.STSW-ST25DV001SC-Source_v1.2.0" and tried out both demonstration examples

  1. ST25DVDemo ( firmware update using internal flash)

I am able to perform firmware update using ST25DV demo example, but after reset it jumps to original firmware.

So i would like to know how can i implement a firmware upgrade feature using "ST25DVDemo" example so that after reset it boots to the uploaded firmware instead of the old firmware.

Thanks,

Nikhil.

1 ACCEPTED SOLUTION

Accepted Solutions
Rene Lenerve
ST Employee

Hi @NK.13omalan​,

Ok, with the dual bank I will list 3 ways to proceed, let me just summarize the concept for the dual bank.

Double bank means the MCU has 2 flash memory areas which can be remapped using a dedicated option bytes. This remap allows to set the boot address to the bank1 or bank2 by resetting or setting this option byte. So, no need to change vector table address and compilation address with both firmware (original or updated),

Option 1 : Original firmware is programmed in Bank1 (0x08000000), when doing firmware upgrade the new firmware is programmed at Bank2 address (0x08080000). When update is done the option byte BFB2 must be set to swap Bank address, then reset MCU to boot each time on Bank2 (now at 0x08000000) and Bank1 adress will be remapped at 0x08080000. You can repeat the operation but with Bank1 this time which will receive the new firmware (and so on).

Option 2 : Original firmware in Bank1, Firmware upgrade firmware on Bank2. When performing the firmware upgrade swap Bank to Bank2 first to run the firmware upgrade procedure then erase Bank1, program with the new firmware and swap again to reboot to the new firmware.

Option 3 : This is a on the fly firmware upgrade using RAM, here is the link for all the details on that technique https://www.st.com/content/ccc/resource/technical/document/application_note/group0/ab/6a/0f/b7/1a/84/40/c3/DM00230416/files/DM00230416.pdf/jcr:content/translations/en.DM00230416.pdf

Another documentation that could give you some information on booting with STM32 : https://www.st.com/content/ccc/resource/technical/document/application_note/b9/9b/16/3a/12/1e/40/0c/CD00167594.pdf/files/CD00167594.pdf/jcr:content/translations/en.CD00167594.pdf

You can find an example of code in the package stm32CubeL4 to perform the Bank swapping (https://www.st.com/en/embedded-software/stm32cubel4.html) in the folder Projects\NUCLEO-L476RG\Examples\FLASH\FLASH_DualBoot.

I hope this gives you more details on how to proceed.

Kind Regards.

View solution in original post

36 REPLIES 36
Rene Lenerve
ST Employee

Hi @NK.13omalan​,

The demo is just a demonstration on how to exchange data between reader and tag using the mailbox feature of the tag, among the possibilities is to perform a firmware update. That's why after the reset it returns to the original firmware.

There is different ways to perform a firmware upgrade, but what to have in mind first is that you can't read and write flash memory in the same time. So, to perform a firmware upgrade you need to write the new firmware in another area of the flash memory than the current code executed, and start to this new location at boot.

For the STM32F405 MCU you need to code a bootloader and place it at the start address then jump to the firmware address updated (this needs some configuration in your different firmwares).

Some MCUs have a dual bank feature that allows to switch between banks at boot (unfortunately not the F405).

Using also an external flash memory may help, but not available on the demo kit.

Using the STM32's bootloader located in ROM, but it will require you to add an additional MCU to communicate with the bootloader code (many interfaces are available in that case UART, I²C, SPI, ...), not available on the disco kit too.

I hope this will help you.

Kind Regards.

Nikhil D&K
Senior

Hello @Rene Lenerve​, thanks for reply.

We are using STM32L496 board whose memory organization shows that it is divided in dual bank. So i will be leveraging that for the firmware upgrade implementation.

The downloaded firmware will be written at the Bank 1 of memory, while Bank 0 will be running my application code.

So can you please elaborate the steps of using dual bank for the firmware upgrade. From the code, i understood that i will be writing firmware to the Dual Bank 1 address.

But after that what will be the further steps for upgrade ?

Rene Lenerve
ST Employee

Hi @NK.13omalan​,

Ok, with the dual bank I will list 3 ways to proceed, let me just summarize the concept for the dual bank.

Double bank means the MCU has 2 flash memory areas which can be remapped using a dedicated option bytes. This remap allows to set the boot address to the bank1 or bank2 by resetting or setting this option byte. So, no need to change vector table address and compilation address with both firmware (original or updated),

Option 1 : Original firmware is programmed in Bank1 (0x08000000), when doing firmware upgrade the new firmware is programmed at Bank2 address (0x08080000). When update is done the option byte BFB2 must be set to swap Bank address, then reset MCU to boot each time on Bank2 (now at 0x08000000) and Bank1 adress will be remapped at 0x08080000. You can repeat the operation but with Bank1 this time which will receive the new firmware (and so on).

Option 2 : Original firmware in Bank1, Firmware upgrade firmware on Bank2. When performing the firmware upgrade swap Bank to Bank2 first to run the firmware upgrade procedure then erase Bank1, program with the new firmware and swap again to reboot to the new firmware.

Option 3 : This is a on the fly firmware upgrade using RAM, here is the link for all the details on that technique https://www.st.com/content/ccc/resource/technical/document/application_note/group0/ab/6a/0f/b7/1a/84/40/c3/DM00230416/files/DM00230416.pdf/jcr:content/translations/en.DM00230416.pdf

Another documentation that could give you some information on booting with STM32 : https://www.st.com/content/ccc/resource/technical/document/application_note/b9/9b/16/3a/12/1e/40/0c/CD00167594.pdf/files/CD00167594.pdf/jcr:content/translations/en.CD00167594.pdf

You can find an example of code in the package stm32CubeL4 to perform the Bank swapping (https://www.st.com/en/embedded-software/stm32cubel4.html) in the folder Projects\NUCLEO-L476RG\Examples\FLASH\FLASH_DualBoot.

I hope this gives you more details on how to proceed.

Kind Regards.

Hello @Rene Lenerve​ , thanks for information. I will go forward with option 2 as it seems to be more standard way.

We also have a PC software developed in C# for doing the firmware update alongside our product. We have implemented the READ ID and PRESENT_PASSWORD steps, where READ_ID is used for getting the current firmware version as response and PRESENT_PASSWORD is used for granting access to update firmware.

Now i would like to know how to send the (.bin) file provided in the demo folder for the firmware upgrade. Because the header byte (byte containing inSegment, segId, position, ackCtrl, pktLen, type) of the payload changes with the starting segment, intermediated packets and ending segment. So how to keep track of that on the PC software side, how the calculation is done such that i know which header byte is needed to be sent, because i don't know how the starting segment and ending segment is also calculated.

Here is the log from STM32L4 of the first packet received after of the upgraded firmware during the firmware transfer process (i.e after successful password authentication)

[12:06:52:556] 18825 RxState = FTM_READ_IDLE�??�?�
[12:06:52:560] 18828 RxState = FTM_READ_CMD�??�?�
[12:06:52:658] Alert pin INT �??�?�
[12:06:52:664] 18933 Rx-->0x15,0x0,0x0,0x6d,0x7d,0x4,0x40,0x24,0x0,0x20,0xa1,0x1,0xa,0x8,0xe3,0x3b,0xa,0x8,0x21,0x2b,0xa,0x8,0x25,0x37,0xa,0x8,0x75,0x11,0xa,0x8,0x95,0x49,0xa,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x53,0x44,0xa,0x8,0xc5,0x11,0xa,0x8,0x0,0x0,0x0,0x0,0xe5,0x3b,0xa,0x8,0x31,0x45,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xb9,0x12,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,0x8,0xbb,0x1,0xa,�??�?�
[12:06:52:764] 19034 pkt.length - 0xf4�??�?�
[12:06:52:769] 19036 pkt.totalLength - 0x6d7d�??�?�
[12:06:52:769] 19039 pkt.ctrl.byte - 0x15�??�?�
[12:06:52:774] 19042 pkt.crc - 0x0�??�?�
[12:06:52:774] 19044 pkt.has_crc - 0x0�??�?�
[12:06:52:780] 19046 Starting Segment 0�??�?�
[12:06:52:780] 19048 GetCrc 2004fe5d 244�??�?�
[12:06:52:780] TEST : 0x4�??�?�
[12:06:52:786] 19052 ST25FTM_GetCrc : 0xd96be537�??�?�

And below is the some packet frames decoded to get understanding. Here you can see the header bytes change for the packet. The logs below are stripped out and the packets received at the time of the new starting segment and ending segment are only displayed.

 
Firmwware Update 
 
 
1st frame: 
   ST25FTM_Ctrl_Byte_t :   0x15
 
   inSegment :1
   segId: 0;
   position: ST25FTM_FIRST_PACKET (01);
   ackCtrl: 01     
   pktLen: 0;
   type : 0
 
Starting Segment 0
 
 
 
2nd frame: 
   ST25FTM_Ctrl_Byte_t :   0x09
 
   inSegment :1
   segId: 0;
   position: ST25FTM_MIDDLE_PACKET (10);
   ackCtrl: 00
   pktLen: 0;
   type : 0
 
 
intermediate frame: 
   ST25FTM_Ctrl_Byte_t :   0x69
 
   inSegment : 1
   segId: 0;
   position: ST25FTM_MIDDLE_PACKET (10);
   ackCtrl: 10
   pktLen: 1;
   type : 0
 
 
Ending Segment 0
 
 
 
intermediate frame: 
   ST25FTM_Ctrl_Byte_t :   0x1b
 
   inSegment : 1
   segId: 1;
   position: ST25FTM_MIDDLE_PACKET (10);
   ackCtrl: 01
   pktLen: 0;
   type : 0
 
 
Starting Segment : 1
 
 
   ST25FTM_Ctrl_Byte_t :   0xb
 
   inSegment : 1
   segId: 1;
   position: ST25FTM_MIDDLE_PACKET (10);
   ackCtrl: 00
   pktLen: 0;
   type : 0
 
.
.
,
,
 
   ST25FTM_Ctrl_Byte_t :   0x6b
 
   inSegment : 1
   segId: 1;
   position: ST25FTM_MIDDLE_PACKET (10);
   ackCtrl: 10
   pktLen: 1;
   type : 0
 
 
Ending Segment 1
 
 
   ST25FTM_Ctrl_Byte_t :   0x19
 
   inSegment : 1
   segId: 0;
   position: ST25FTM_MIDDLE_PACKET (10);
   ackCtrl: 01
   pktLen: 0;
   type : 0
 
 
Starting Segment : 2
 
   ST25FTM_Ctrl_Byte_t :   0x09
 
   inSegment :1
   segId: 0;
   position: ST25FTM_MIDDLE_PACKET (10);
   ackCtrl: 00
   pktLen: 0;
   type : 0

So can you please elaborate how the firmware packets (in the form of chunks) are sent from the App/PC software so that i can apply the same logic in my custom desktop application.

Rene Lenerve
ST Employee

Hi @NK.13omalan​,

You seem to have downloaded sources for the ST25DV-DISCOVERY kit which is based on discovery board which embeds a STM32F405 MCU. May I suggest you to download sources from the ST25DV64KC-DISCO kit which embeds an STM32L476 (Link STSW-ST25DV002), this will be closer to your MCU (especially for flash management).

In the User Manual of this disco kit the protocol used in the demo is described and the header data explained. Let me know which information is missing to build segments and packets in order to help you better?

Kind Regards.

Hello @Rene Lenerve​ , thanks for information. I will be referring the docs you mentioned above.

Currently ,I have successfully stored the received firmware packets to this address (0x080A0000) of the Bank 2 of the STM32L4 by referring the firmware package "STSW-ST25DV002" as mentioned by you. Meanwhile my application firmware is running on Bank 1.

Now in example after successful firmware upgrade i have to touch anywhere on screen to start the upgraded firmware (i.e on touching screen the MSP is set to the upgraded firmware address and a calls to a JUMP function , which runs the upgraded firmware).

In my case as i don't have any touch screen in my product, i have set the MSP to new firmware address(ADDRESS 0x080A0000 in BANK2 ) and calling JUMP function result into a hard fault condition.

Here , is the code i am referring to jump.

/**
  * @brief  Jump to user program.
  * @param  None No parameters.
  * @return None.
  */
void COMMAND_Jump( void )
{
 
  /* Jump to user application */
    JumpAddress = *(__IO uint32_t *)(FIRMWARE_ADDRESS + 4);
    Jump_To_Application = (pFunction) JumpAddress;
    /* Initialize user application's Stack Pointer */
    __set_MSP( *(__IO uint32_t *)FIRMWARE_ADDRESS );
    Jump_To_Application( );
}

Can you suggest what could be the issue here ?

Rene Lenerve
ST Employee

Hi @NK.13omalan​,

Jumping to another firmware at a specific address was not your first intention according to your previous posts. To do this, you have to change the compilation parameters (mainly the scatter file) and especially the address of the vector table.

But the option with the dual bank lets you get rid of that. the only action you need to perform in this case is to switch the bank order and reset the MCU.

According to the examples in stm32CubeL4 package, after writing the firmware in the correct bank (take care to check that 0x080A0000 is the correct beginning address of the second Bank of your MCU, this could be different from MCUs), you should do the following operation, please read the Reference Manual of your MCU (flash section, option bytes), these options are used to customized the general settings of your MCU, but misused can lead to unwanted effects that can brick your MCU :

HAL_FLASH_Unlock();
	  
      /* Clear OPTVERR bit set on virgin samples */
      __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
 
      /* Allow Access to option bytes sector */ 
      HAL_FLASH_OB_Unlock();
      
      /* Get the Dual boot configuration status */
      HAL_FLASHEx_OBGetConfig(&OBInit);
      
      /* Enable/Disable dual boot feature */
      OBInit.OptionType = OPTIONBYTE_USER;
      OBInit.USERType   = OB_USER_BFB2;
      
      /* Swap between Bank1 and Bank2, to adapt to use case */
      if (((OBInit.USERConfig) & (OB_BFB2_ENABLE)) == OB_BFB2_ENABLE)
      { /* Bank1 mapped  to 0x00000000 at boot */
        OBInit.USERConfig = OB_BFB2_DISABLE;
      }
      else
      { /* Bank2 mapped  to 0x00000000 at boot */
        OBInit.USERConfig = OB_BFB2_ENABLE;
      }
      
      if(HAL_FLASHEx_OBProgram (&OBInit) != HAL_OK)
      {
        /*
        Error occurred while setting option bytes configuration.
        User can add here some code to deal with this error.
        To know the code error, user can call function 'HAL_FLASH_GetError()'
        */
        /* Infinite loop */
        while (1)
        {
          BSP_LED_On(LED3);
        }
      }
      
      /* Start the Option Bytes programming process */  
      if (HAL_FLASH_OB_Launch() != HAL_OK)
      {
        /*
        Error occurred while reloading option bytes configuration.
        User can add here some code to deal with this error.
        To know the code error, user can call function 'HAL_FLASH_GetError()'
        */
        /* Infinite loop */
        while (1)
        {
          BSP_LED_On(LED3);
        }
      }
 
      /* Prevent Access to option bytes sector */
      HAL_FLASH_OB_Lock();
    
      /* Disable the Flash option control register access (recommended to protect 
      the option Bytes against possible unwanted operations) */
      HAL_FLASH_Lock();

I hope this can help you.

Kind Regards.

Hello @Rene Lenerve​ , thanks for information.

As quoted by you, 

" But the option with the dual bank lets you get rid of that. the only action you need to perform in this case is to switch the bank order and reset the MCU. "

By the above statement did you mean the "Option 1" which you have mentioned in the previous reply, right ? And this won't apply to "Option 2" which also use both the banks.

Regarding OPTION 1:

Query 1 :

Currently the Bank 1 (Main program) is at 0x08000000 and the upgraded firmware is on Bank 2 at address 0x08080000. 

The code snippet which you have shared (i.e Setting BFB2 byte), will be called after successfully validating the written firmware (upgraded) at the Bank 2 starting address. Now calling the reset function will swap the bank address (i.e Bank 2 -> 0x08000000 and Bank 1 -> 0x08080000) and execute the updated program from Bank 2. So do i need to keep the track of the last updated bank or address (i.e where the upgraded firmware was last downloaded) ?

By the looks of it, it seems very simple. I have to just download the firmware at address 0x0808000 every time, than verify it. If verification (CRC) is successful, set the BFB2 option byte (i.e using the code snippet given by you above) and reset the board. It will boot with the newly upgraded firmware. Is that right ?

Query 2 :

I have read the Firmware upgrade process from the document "UM2949 stswst25dv002-firmware-for-the-st25dv64kcdisco-board-stmicroelectronics" as mentioned by you previously.

In the demo firmware code, i can see the the CRC verification happening after transmission of every segment (i.e 20 packets). So if i do CRC checking for every received segment, do i have to verify the final checksum of the whole firmware received or CRC checking of the each segment is enough ? I know it will be consuming more time if i verify the firmware checksum but would like to know the standard steps. 

Query 3:

Currently the L4 ST25DV example flash write length is set to 512 bytes in function "FTM_FlushToFlash". Can't we increase the length to 1024 or 2048 bytes?

We successfully tried with writing 1024 bytes but failed writing 2048 bytes in one go. 

Regarding OPTION 2:

If we use option 2, we have to implement custom boot loader, right ? Than we have to use magic number to know if new firmware is available.

Rene Lenerve
ST Employee

Hi @NK.13omalan​,

Option 1 and 2 are using Dual Bank feature, using BFB2 to swap banks. The difference between Option1 and Option2 is for the former, you alternately program the firmware in each bank (which must embeds the firmware upgrade in code), for the latter you have firmware for firmware upgrade in one bank swapping only when you need to upgrade your firmware and you only program the other bank.

Boot Loader is used without Bank swapping and needs some configuration to be implemented (another story).

Query 1:

That's right, and the swap to the new bank is permanent (until you overwrite this BFB2 of course).

Query 2:

You can use the CRC IP in Accumulate mode so you can inject data throughout firmware transfer. But you also have the option of doing it all at once at the end.

Query 3:

It depends on the size of your FLASH (and each Bank is half the size of the flash memory, may be your issue with 2048 bytes).

Kind Regards.