cancel
Showing results for 
Search instead for 
Did you mean: 

Custom loader for SBSFU / STM32WB5MMG - how to run FUS?

crwper
Senior

I am building a custom loader for SBSFU on the STM32WB5MMG. The loader is similar to the BLE_Ota loader, but instead of using BLE, it loads firmware/wireless stack from an onboard microSD card, as well as being able to write CKS keys.

I do need to have FUS or the stack running, so that I can write CKS keys.

Ideally, I think I want to run FUS, since I don't need a BLE interface. However, the last thing SBSFU does before it runs the standalone loader is to lock services, which includes running the wireless stack if FUS is running.

This means that if I reset into FUS in my loader, SBSFU will always start the wireless stack before launching the loader again--preventing me from using FUS in the loader.

I could hack out the bit of code that starts the wireless stack before running the standalone loader, but I've tried to make as few changes to SBSFU as possible, to maintain its integrity, and I'm particularly hesitant to make changes to SECoreBin.

I thought I might be able to add STM32_WPAN to the loader, but not enable any of the built-in templates. However, I think this leaves the wireless stack in an unexpected state, and when I do this the wireless stack doesn't start correctly in my application--SHCI_C2_BLE_Init hangs, if I remember correctly. If I remove power from the board and then reconnect, so that execution doesn't go through the loader, everything works fine.

So, I think I'm looking for guidance either on loading FUS in a custom loader, or on building a minimal BLE application with no actual interface so that I can write CKS keys.

Any help would be greatly appreciated. Thank you!

4 REPLIES 4
crwper
Senior

I've been doing a lot of experimenting with the custom loader, and I think I can narrow down my question.

Ideally, I would want to start FUS in my custom loader, but for the reasons given above, it doesn't seem like this is practical without significant modifications to SBSFU.

Alternatively, what I would like to do is to start the BLE stack, but without any visible external interface--i.e., no advertising, no possiblity to connect, etc.

This is just about what happens if I deselect all the BLE application templates in CubeMX, except that I think this leaves the BLE stack in an undefined state, so that the following sequence of events fails:

  1. Start in SBSFU, start wireless stack, call SHCI_C2_Reinit
  2. Jump to loader, start CPU2, but don't call SHCI_C2_BLE_Init (app_ble.c isn't implemented unless an application template is selected)
  3. Software reset into SBSFU, start wireless stack, call SHCI_C2_Reinit
  4. Jump to user application, start CPU2, call SHCI_C2_BLE_Init with user application parameters, but this never returns

I think what's happening here is that the incomplete implementation of a BLE application in the loader leaves the BLE stack in an undefined state, so that the subsequent call to SHCI_C2_Reinit doesn't have the intended effect, and when the user application tries to re-initialize the BLE stack, this fails.

So, what I'm wondering now is, what is the minimum BLE stack initialization required in the loader so that it will not have a visible external interface, but can be restarted successfully in the user application?

crwper
Senior

I think I've got an answer to this question. Ideally, I'd like to have FUS running when my custom loader runs, but that seems like it would require a bigger change to SBSFU than I'm willing to undertake at the moment.

So, instead, I focused on how far BLE initialization needs to proceed in the loader before a BLE user application executed after the loader runs correctly. I believe (but can't be certain) that this is the same point where the BLE stack recognizes the SHCI_C2_Reinit command.

It makes some sense that this would be when the BLE stack has been initialized far enough to receive BLE commands. According to AN5289, this is when SHCI_C2_BLE_Init is run. There is a little support code needed, but essentially my loader now includes a barebones BLE app with the following APP_BLE_Init:

void APP_BLE_Init(void)
{
  SHCI_CmdStatus_t status;
 
  SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet =
  {
    {{0,0,0}},                          /**< Header unused */
    {0,                                 /** pBleBufferAddress not used */
     0,                                 /** BleBufferSize not used */
     CFG_BLE_NUM_GATT_ATTRIBUTES,
     CFG_BLE_NUM_GATT_SERVICES,
     CFG_BLE_ATT_VALUE_ARRAY_SIZE,
     CFG_BLE_NUM_LINK,
     CFG_BLE_DATA_LENGTH_EXTENSION,
     CFG_BLE_PREPARE_WRITE_LIST_SIZE,
     CFG_BLE_MBLOCK_COUNT,
     CFG_BLE_MAX_ATT_MTU,
     CFG_BLE_SLAVE_SCA,
     CFG_BLE_MASTER_SCA,
     CFG_BLE_LS_SOURCE,
     CFG_BLE_MAX_CONN_EVENT_LENGTH,
     CFG_BLE_HSE_STARTUP_TIME,
     CFG_BLE_VITERBI_MODE,
     CFG_BLE_OPTIONS,
     0,
     CFG_BLE_MAX_COC_INITIATOR_NBR,
     CFG_BLE_MIN_TX_POWER,
     CFG_BLE_MAX_TX_POWER,
     CFG_BLE_RX_MODEL_CONFIG,
     CFG_BLE_MAX_ADV_SET_NBR,
     CFG_BLE_MAX_ADV_DATA_LEN,
     CFG_BLE_TX_PATH_COMPENS,
     CFG_BLE_RX_PATH_COMPENS,
     CFG_BLE_CORE_VERSION
    }
  };
 
  /**
   * Initialize Ble Transport Layer
   */
  Ble_Tl_Init();
 
  /**
   * Do not allow standby in the application
   */
  UTIL_LPM_SetOffMode(1 << CFG_LPM_APP_BLE, UTIL_LPM_DISABLE);
 
  /**
   * Register the hci transport layer to handle BLE User Asynchronous Events
   */
  UTIL_SEQ_RegTask(1<<CFG_TASK_HCI_ASYNCH_EVT_ID, UTIL_SEQ_RFU, hci_user_evt_proc);
 
  /**
   * Starts the BLE Stack on CPU2
   */
  status = SHCI_C2_BLE_Init(&ble_init_cmd_packet);
  if (status != SHCI_Success)
  {
    APP_DBG_MSG("  Fail   : SHCI_C2_BLE_Init command, result: 0x%02x\n\r", status);
    /* if you are here, maybe CPU2 doesn't contain STM32WB_Copro_Wireless_Binaries, see Release_Notes.html */
    Error_Handler();
  }
  else
  {
    APP_DBG_MSG("  Success: SHCI_C2_BLE_Init command\n\r");
  }
 
  return;
}

Following this, no application-specific BLE init is performed, as would usually be done in a BLE application.

After this, the BLE stack sits in a loop ready to receive BLE commands, which presumably includes the SHCI_C2_Reinit command, so SHCI_C2_Reinit is processed correctly in SBSFU before launching the user application later on.

Does this make sense?

Remy ISSALYS
ST Employee

Hello,

The CPU2 is started with C2BOOT. Once it has been started, it will report to CPU1 the ready_event. At this step, all system commands are available. It can be done only once (ie setting a second time C2BOOT will have no effect. Reset and Set C2BOOT has no effect as well). The BLE Stack on CPU2 can be initialized and started. After this, BLE commands can be used.

In case the SBSFU is implemented, it may have already set the C2BOOT bit to startup the CPU2. In that case, to keep the mechanism transparent to the user application, it shall call the system command SHCI_C2_Reinit( ) before jumping to the application. When the CPU2 receives that command, it waits for its event input to be set to restart the CPU2 firmware. This is required because once C2BOOT has been set once, a clear/set on C2BOOT has no effect. When SHCI_C2_Reinit( ) is not called, generating an event to the CPU2 does not have any effect. So, by default, the application shall both set the event flag and set the C2BOOT bit.

Best Regards

Thanks, Remy.

I understand all of this, but the issue is that the SHCI_C2_Reinit() call in SBSFU doesn't always have the desired effect, I think.

In particular, I discovered that if the loader initializes IPCC but does not initialize the BLE stack at all (i.e., the inititalization in app_entry.c is completed, but not the initialization in app_ble.c), then the user application cannot subsequently inititalize the BLE stack as usual--the "faked" initialization that should make SBSFU transparent to the user application doesn't work in this case. It seems like doing this leaves CPU2 in an unexpected state, and the only way to recover is to remove power completely from the processor (a hardware or software reset won't work).

The reason this comes up for me is because my loader reads firmware from a microSD card, rather than using BLE. I need to initialize IPCC so that I can coordinate flash writes with CPU2, but I don't want to initalize BLE since I don't want to have a BLE interface in my loader. Unfortunately, though, it seems like some BLE intitalization is needed, which is what led me to the minimal APP_BLE_Init above.