cancel
Showing results for 
Search instead for 
Did you mean: 

During startup I occasionally get stuck in the function UTIL_SEQ_WaitEvt located in STM32_seq.c.

Louis Loving
Senior

Here is the function running in my STM32WB55CG:

/**
 *  this function can be nested
 */
void UTIL_SEQ_WaitEvt( UTIL_SEQ_bm_t evt_id_bm )
{
  UTIL_SEQ_bm_t event_waited_id_backup;
  UTIL_SEQ_bm_t current_task_id_bm;
 
  /** store in local the current_task_id_bm as the global variable CurrentTaskIdx
   *  may be overwritten in case there are nested call of UTIL_SEQ_Run()
   */
  current_task_id_bm = (1 << CurrentTaskIdx);
 
  /** backup the event id that was currently waited */
  event_waited_id_backup = EvtWaited;
  EvtWaited = evt_id_bm;
  /**
   *  wait for the new event
   *  note: that means that if the previous waited event occurs, it will not exit
   *  the while loop below.
   *  The system is waiting only for the last waited event.
   *  When it will go out, it will wait again fro the previous one.
   *  It case it occurs while waiting for the second one, the while loop will exit immediately
   */
  while((EvtSet & EvtWaited) == 0)
  {
    UTIL_SEQ_EvtIdle(current_task_id_bm, EvtWaited);
  }
  EvtSet &= (~EvtWaited);
  EvtWaited = event_waited_id_backup;
 
  return;
}

The code repeatedly calls UTIL_SEQ_EvtIdle(current_task_id_bm, EvtWaited).

current_task_id_bm is set to: CFG_TASK_SYSTEM_HCI_ASYNCH_EVT_ID

EvtWaited is set to: CFG_IDLEEVT_HCI_CMD_EVT_RSP_ID

Since I am not getting stuck there every time, it feels like some kind of race condition.

The comment seems to mention never leaving the while loop but I am not understanding it if it is telling me how to fix or prevent it.

Thanks for any help.

13 REPLIES 13
Piranha
Chief II
  1. The line 29 does a read–modify–write. If an interrupt happens between read and write operations and it uses UTIL_SEQ_SetEvt() or UTIL_SEQ_ClrEvt() to set/clear some event, then the result of that action is lost when the write at line 29 completes. A race condition!
  2. EvtSet is not defined as volatile and therefore the compiler is not required to read that variable every time it is tested at a line 25. Actually as the EvtSet is not volatile and it is already read at line 25, the compiler is not required to read it again at line 29. That means that the window for a race condition to happen is extended from the read operation at line 25 down to the write operation at line 29.
  3. EvtWaited also is not defined as volatile and therefore functions UTIL_SEQ_IsEvtPend() and UTIL_SEQ_Run() can read wrong values when called from UTIL_SEQ_EvtIdle().
  4. Function UTIL_SEQ_IsEvtPend() currently is not interrupt-safe because it does two read operations, which cannot be atomic. It's logic should be encapsulated in a critical section to allow it to be used from ISR.
  5. Function UTIL_SEQ_WaitEvt() also is not interrupt-safe and cannot be called from ISR. I'm guessing, but in this case it seems to be intentionally designed that way. Unfortunately it's not documented anywhere, which functions can be called from ISR!

@Christophe Arnal​, @Remi QUINTIN​, these are serious bugs in a fundamental software component. Also, if the SEQUENCER is used in CPU2 firmware, these bugs could be even related to this serious issue:

https://community.st.com/s/question/0D53W00000Y2gzOSAR/permanently-damaged-radio-rx-path-on-stm32wb55

Louis Loving
Senior
void hci_cmd_resp_wait(uint32_t timeout)
{
  UTIL_SEQ_WaitEvt(1 << CFG_IDLEEVT_HCI_CMD_EVT_RSP_ID);
  return;
}

I have also noticed that the function that calls UTIL_SEQ_WaitEvt is called with a timeout that is never used.

Is this something that should be implemented?

MeteHan
Associate II

Hi Louis,

This problem generally happens when you are using wrong wireless stack for your application. For example if you want to use a ble application you have to update your stack to one of compitable ble stack to M0 core. Please search for wireless stack update for more. For addition if you are using one of st's example, there is a readme file thats tell you which wireless stack you have to use.

Thanks MeteHan, I am running a BLE application with the BLE Stack for the M0 core programmed per the release notes.

​Hello,

Here are the feedback to the points raised :

  1. This is correct and will be fixed in the next version
  2. This is correct and will be fixed in the next version. In addition, for the same reason, TaskSet and TaskMask will be declared as volatile as they can me modified from an ISR while they can be cached in the UTIL_SEQ_Run() function
  3. This is not correct. EvtWaited  is updated only when moving out from the while loop in UTIL_SEQ_WaitEvt() so when either UTIL_SEQ_IsEvtPend() and UTIL_SEQ_Run() is called , it will report properly the current waited id.
  4. As long as EvtWaited  is not required to be volatile, UTIL_SEQ_IsEvtPend() is interrupt safe
  5. It would clearly be a mistake to call UTIL_SEQ_WaitEvt()  from an ISR. The header file of the sequencer will be updated to list which fucntion may be called from an ISR and which one shall not be.

Regards.

​Hello,

This parameter is useless. It was introduced in the purpose of building a standard interface but in our STM32WB applications, it is not relevant.

Regards.

Christophe Arnal
ST Employee

​Hello,

This is a bit tricky. As long as you are in the startup phase, I believe it is unlikely that you are facing one of the race conditions that have been spotted and confirmed in the sequencer ( unless you added your own events in addition to the existing one).

To my understanding, you just received the system ready event from CPU2 and within the process that has received this system ready event, you sent some HCI command and for one of them, the CPU2 is not responding.

That would be goof if you could :

1/ confirm if you added or not your own events

2/ Identify which HCI command is not getting an answer from CPU2 - You may screenshot the function calling tree with your debugger.

3/ Check if this is the first HCI command that is not responded

4/ Check the value reported at the start of SRAM2 @0x20030000 where the CPU2 reports a keyword in case it has either detected an error or is in hardfault. Otherwise, you should read back that address of the shared table.

Regards.

Louis Loving
Senior

Thanks Christophe.

I have not added any events. I will work to get you answers for you other questions.

Unfortunately with our hardware we did not leave ourselves any way to connect a debugger. I am working on code to read the value reported at the start of SRAM2 and print it out via UART. Is AN5185, Table 5, the best description of what we should expect to see?

One item of note that is a concern of ours is that this only seems to be happening with our latest batch of STM32WB55CGs. Previously, we have not seen this issue when running the same code but we are now seeing this happen on several units.

Christophe Arnal
ST Employee

Hello,

As long as you have only traces over UART available, you may use the embedded HCI traces to check which command is pending.

This can be enabled in tl_dbg_conf.h

I would set following configuration

#define TL_SHCI_CMD_DBG_EN      1   /* Reports System commands sent to CPU2 and the command response */
#define TL_SHCI_CMD_DBG_RAW_EN  0   /* Reports raw data System commands sent to CPU2 and the command response */
#define TL_SHCI_EVT_DBG_EN      1   /* Reports System Asynchronous Events received from CPU2 */
#define TL_SHCI_EVT_DBG_RAW_EN  0   /* Reports raw data System Asynchronous Events received from CPU2 */
 
#define TL_HCI_CMD_DBG_EN       1   /* Reports BLE command sent to CPU2 and the command response */
#define TL_HCI_CMD_DBG_RAW_EN   0   /* Reports raw data BLE command sent to CPU2 and the command response */
#define TL_HCI_EVT_DBG_EN       1   /* Reports BLE Asynchronous Events received from CPU2 */
#define TL_HCI_EVT_DBG_RAW_EN   0   /* Reports raw data BLE Asynchronous Events received from CPU2 */
 
#define TL_MM_DBG_EN            0   /* Reports the informations of the buffer released to CPU2 */

This should ouptut the system ready event received from CPU2 and all commands/events on either BLE or system channel exchanged between both CPUs.

Regards.