cancel
Showing results for 
Search instead for 
Did you mean: 

BLE_Ota for large files keeps failing

CHossack
Associate III

Hi,

I’m trying to implement OTA using the example software and hardware below. But it seems very unreliable.

  • STM32Cube_FW_WB_V1.7.0\Projects\P-NUCLEO-WB55.Nucleo\Applications\BLE
    • BLE_Ota
    • BLE_p2pServer_ota
    • Compiled with IAR  for ARM 8.50
  • STM32CubeProgrammer API v2.4.0
  • STM32CubeMonitor-RF Version 2.5.0
  • STM32WB55 Nucleo Pack
    • Nucleo board 
      • PNWB55$CU3
    • USB Dongle

I programmed BLE_Ota.out and BLE_p2pServer_ota.out into the P-NUCLEO-WB55 using the STM32CubeProgrammer and verified the green LED is flashing indicating RF messages.

I then used the STM32CubeMonitor-RF with the USB dongle and Nucleo board about 5 cm apart.

And then I tried to perform an OTA update. I found mostly it worked, but sometimes it failed. When it failed, the flash memory at 0x08007000 was all FFs (which is where the new application should be located). I added a break point to BLE_Ota and verified this was due to an invalid magic number (0x94448A29).

When you create a build the address of the last word in your image is stored at offset 140 in your file. The last word should contain the magic value 0x94448A29 for the BLE_OTA to assume the OTA worked correctly.

But when it failed I noticed the magic number was actually located early on in memory. It seems a BLE packet is lost somewhere so the magic number isn’t placed at the correct location.

Since my code is a bit bigger I added some padding to simulated my larger file

Main.c

/* USER CODE BEGIN PTD */
#define p16 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
#define p256 p16,p16,p16,p16,p16,p16,p16,p16,p16,p16,p16,p16,p16,p16,p16,p16
#define p4k p256,p256,p256,p256,p256,p256,p256,p256,p256,p256,p256,p256,p256,p256,p256,p256
#define p64k p4k,p4k,p4k,p4k,p4k,p4k,p4k,p4k,p4k,p4k,p4k,p4k,p4k,p4k,p4k,p4k
const uint8_t padding[] = {p64k,p64k};
uint8_t const * paddingPtr;
/* USER CODE END PTD */
 
:
 
  /* USER CODE BEGIN 1 */
  paddingPtr= &padding[sizeof(padding)-1];
  /* USER CODE END 1 */

With this new larger file I can never get the OTA to work. So it looks likes the OTA is too unreliable to work successfully... or am I doing something wrong?

Thank you for your help

Chris

1 ACCEPTED SOLUTION

Accepted Solutions
CHossack
Associate III

Hi HRadt,

thank you for your answer. The aci_gatt_write_response() seems to be for the BlueNrg device, but it pointed me in the correct direction and with a lot of trail and error I got it working, mainly thanks to you 😉

To help others here's the code you need to change for firmware 1.8.0

C:\Users\<user name>\STM32Cube\Repository\STM32Cube_FW_WB_V1.8.0\Middlewares\ST\STM32_WPAN\ble\svc\Src\otas_stm.c

static SVCCTL_EvtAckStatus_t OTAS_Event_Handler(void *Event)
{
 :
  switch(event_pckt->evt)
  {
    case EVT_VENDOR:
    {
      :
      switch(blue_evt->ecode)
      {
      // ################## INSERT CODE BEGIN ############
      case EVT_BLUE_GATT_WRITE_PERMIT_REQ:
        {
          aci_gatt_write_permit_req_event_rp0 * write_perm_req;
          write_perm_req = (aci_gatt_write_permit_req_event_rp0*)blue_evt->data;
              if(write_perm_req->Attribute_Handle == (OTAS_Context.OTAS_Raw_Data_CharHdle  + 1)) 
              {
                return_value = SVCCTL_EvtAckFlowEnable;          
                aci_gatt_write_resp(write_perm_req->Connection_Handle,
                                        write_perm_req->Attribute_Handle,
                                        0x00, /* write_status = 0 (no error))*/
                                        0x00, /* err_code */
                                        write_perm_req->Data_Length,
                                        (uint8_t *)&(write_perm_req->Data[0]));
              }
        }
        break;
      // ################## INSERT CODE END ############
      :

and also add GATT_NOTIFY_WRITE_REQ_AND_WAIT_FOR_APPL_RESP as shown below

aci_gatt_add_char(OTAS_Context.OTAS_SvcHdle,
                    OTA_UUID_LENGTH,
                    (Char_UUID_t *)OTA_RAW_DATA_CHAR_UUID,
                    OTA_RAW_DATA_CHAR_SIZE,
                    CHAR_PROP_WRITE_WITHOUT_RESP,
                    ATTR_PERMISSION_NONE,
                    GATT_NOTIFY_ATTRIBUTE_WRITE | GATT_NOTIFY_WRITE_REQ_AND_WAIT_FOR_APPL_RESP,
                    10,
                    1,
                    &(OTAS_Context.OTAS_Raw_Data_CharHdle));

This now allows me to perform OTA successfully, even if it is 4 times slower. I think ST should make this the default behaviour, since flaky OTA isn't a good look 😉

cheers

Chris

View solution in original post

10 REPLIES 10
RScot.1
Associate

Hi,

We are experiencing this issue with our prototypes and it's delaying our chip selection work package to the point this is now critical path.

Can anyone from ST provide any insights to this please? If this is not the place to raise issues how do we get support ?

Chris has provided a excellent issue report but if more information is required, please let us know ASAP.

TIA

Christophe Arnal
ST Employee

​Hello,

We have never faced so far this kind of issue.

1/ What is the bin size of the application you want to download ?

2/ Did you check that @0x140 holds the address of the magic word that is expected at the end of the binary ?

3/ at the point you were able to check the magic key word is lower in the flash than expected, could you please dump back the binary from 0x08007000 to the magic keyword and compare that bin to the one you were expecting to download  ? That would be good to see how much differences there are. Are they full sectors missing on just some data from here to there ?

The only thing I have in mind that could explain that some data have not been written in flash resulting to the magic word to be shifted earlier in memory is in case you wanted to wrote in flash whereas this is prevented by the CPU2.

Did you change the way the flash is written on otas_app.c ?

In the implementation, the code is reading back the data to make sure it has been written so in the case above, at worst you will be looping until CPU2 alloas flash processing.

Regards.

CHossack
Associate III

Hi Chris,

thank you for your reply.

Q) What is the bin size of the application you want to download ?

A) Your BLE_p2pServer_ota example is 34K, and after adding ROM padding I boost it up to 164K

Q) Did you check that @0x140 holds the address of the magic word that is expected at the end of the binary ?

A) yes I did. please see attached Stm32CubeProg for confirmation.0693W000002lMMzQAM.jpg0693W000002lMMGQA2.jpg

Q) At the point you were able to check the magic key word is lower in the flash than expected

A) When it failed I noticed the magic number was actually located earlier on in memory than expected

Q)could you please dump back the binary from 0x08007000 to the magic keyword and compare that bin to the one you were expecting to download

A) I compared the correct image with the image in flash after download (but before the OTA erased it due to invalid magic number). Below you can see a missing packet of data on the left side0693W000002lNsmQAE.jpg

Below you can see the magic magic earlier on in memory than expected, with the rest being filled up with FFs0693W000002lNsDQAU.jpg

>>some data have not been written in flash resulting to the magic word to be shifted earlier in memory

I agree

Q) Did you change the way the flash is written on otas_app.c ?

A) No, it's the OTA example from STM32Cube_FW_WB_V1.7.0\Projects\P-NUCLEO-WB55.Nucleo\Applications\BLE

To speed up the down load time I guess you dont use "write with ack" over BLE and increase the link speed to 2MB??? While all of this will speed up download times, it looks like the error rate is too high for large files.

cheers

Dr Christopher Hossack

Christophe Arnal
ST Employee

​Hello,

You may refer to another post CPU2 Wireless Stack behaviour when CPU1 can't process Bluetooth events in time.

It has been reported and confirmed that the flow control is not applied on the physical layer so the remote keeps sending packet whereas the application is not ready and all buffers are full.

This results into packet to be discarded.

The workaround , as listed in the referenced post, is to add the GATT_NOTIFY_WRITE_REQ_AND_WAIT_FOR_APPL_RESP  properties to the raw data characteristics. . This will prevent the remote to send a new packet until aci_gatt_write_resp () is called.

You need to modify the following code in otas_stm.c

/**
   *  Add Raw Data Characteristic
   */
  aci_gatt_add_char(OTAS_Context.OTAS_SvcHdle,
                    OTA_UUID_LENGTH,
                    (Char_UUID_t *)OTA_RAW_DATA_CHAR_UUID,
                    OTA_RAW_DATA_CHAR_SIZE,
                    CHAR_PROP_WRITE_WITHOUT_RESP,
                    ATTR_PERMISSION_NONE,
                    GATT_NOTIFY_ATTRIBUTE_WRITE,
                    10,
                    1,
                    &(OTAS_Context.OTAS_Raw_Data_CharHdle));
 
  OTAS_Context.OTAS_Conf_Status = OTAS_Conf_Not_Pending;

into

/**
   *  Add Raw Data Characteristic
   */
  aci_gatt_add_char(OTAS_Context.OTAS_SvcHdle,
                    OTA_UUID_LENGTH,
                    (Char_UUID_t *)OTA_RAW_DATA_CHAR_UUID,
                    OTA_RAW_DATA_CHAR_SIZE,
                    CHAR_PROP_WRITE_WITHOUT_RESP,
                    ATTR_PERMISSION_NONE,
                    GATT_NOTIFY_ATTRIBUTE_WRITE | GATT_NOTIFY_WRITE_REQ_AND_WAIT_FOR_APPL_RESP,
                    10,
                    1,
                    &(OTAS_Context.OTAS_Raw_Data_CharHdle));
 
  OTAS_Context.OTAS_Conf_Status = OTAS_Conf_Not_Pending;

You should first receive an event in which you allowed the remote request  to write the data with aci_gatt_write_resp () and then you will receive the packet to be written on flash.

Let me know if it fixes your issue.

Regards.

CHossack
Associate III

Hi Christophe,

I changed the BLE_Ota to include "GATT_NOTIFY_WRITE_REQ_AND_WAIT_FOR_APPL_RESP" which resulted in the STM32CubeMonitor-RF responding with "No response" as shown below

0693W000002liGPQAY.jpg

Wouldn't I also need to change STM32CubeMonitor-RF to use the write and response? Also why would adding an extra attribute stop OTA from working.

I double checked I had the correct code by removing my changes and re-testing, and I was back to my original problem.

cheers

Chris

RScot.1
Associate

@Christophe Arnal​ Do you have an update please ? We do not have a solution yet.

TIA, Richard

HRadt.1
Senior

Hi Richard,

I was struggeling with the same issue.

When you use GATT_NOTIFY_WRITE_REQ_AND_WAIT_FOR_APPL_RESP you have to generate the application response on your own.

You have to call aci_gatt_write_response() with the appropriate parameters whenever you receive an EVT_BLUE_GATT_WRITE_PERMIT_REQ event.

CHossack
Associate III

Hi HRadt,

thank you for your answer. The aci_gatt_write_response() seems to be for the BlueNrg device, but it pointed me in the correct direction and with a lot of trail and error I got it working, mainly thanks to you 😉

To help others here's the code you need to change for firmware 1.8.0

C:\Users\<user name>\STM32Cube\Repository\STM32Cube_FW_WB_V1.8.0\Middlewares\ST\STM32_WPAN\ble\svc\Src\otas_stm.c

static SVCCTL_EvtAckStatus_t OTAS_Event_Handler(void *Event)
{
 :
  switch(event_pckt->evt)
  {
    case EVT_VENDOR:
    {
      :
      switch(blue_evt->ecode)
      {
      // ################## INSERT CODE BEGIN ############
      case EVT_BLUE_GATT_WRITE_PERMIT_REQ:
        {
          aci_gatt_write_permit_req_event_rp0 * write_perm_req;
          write_perm_req = (aci_gatt_write_permit_req_event_rp0*)blue_evt->data;
              if(write_perm_req->Attribute_Handle == (OTAS_Context.OTAS_Raw_Data_CharHdle  + 1)) 
              {
                return_value = SVCCTL_EvtAckFlowEnable;          
                aci_gatt_write_resp(write_perm_req->Connection_Handle,
                                        write_perm_req->Attribute_Handle,
                                        0x00, /* write_status = 0 (no error))*/
                                        0x00, /* err_code */
                                        write_perm_req->Data_Length,
                                        (uint8_t *)&(write_perm_req->Data[0]));
              }
        }
        break;
      // ################## INSERT CODE END ############
      :

and also add GATT_NOTIFY_WRITE_REQ_AND_WAIT_FOR_APPL_RESP as shown below

aci_gatt_add_char(OTAS_Context.OTAS_SvcHdle,
                    OTA_UUID_LENGTH,
                    (Char_UUID_t *)OTA_RAW_DATA_CHAR_UUID,
                    OTA_RAW_DATA_CHAR_SIZE,
                    CHAR_PROP_WRITE_WITHOUT_RESP,
                    ATTR_PERMISSION_NONE,
                    GATT_NOTIFY_ATTRIBUTE_WRITE | GATT_NOTIFY_WRITE_REQ_AND_WAIT_FOR_APPL_RESP,
                    10,
                    1,
                    &(OTAS_Context.OTAS_Raw_Data_CharHdle));

This now allows me to perform OTA successfully, even if it is 4 times slower. I think ST should make this the default behaviour, since flaky OTA isn't a good look 😉

cheers

Chris

Christophe Arnal
ST Employee

​Hello,

The correction has implemented is committed and will do the job for sure.

However, the ST development team is still working on the way to stall the flow over the air when CPU1 is slow with default implementation.

Regards.