STM32WB55 BLE Command Exclusion Depends on Where a Task ID Is Declared

Adding a new sequencer task to an STM32WB55 application can create overlapping BLE commands even when the task looks correctly registered and scheduled. In ST’s example, the busy-command exclusion mask is computed from an enumeration boundary. A task placed in the non-command group remains eligible while a previous command is pending.

This review targets STM32CubeWB v1.24.0, commit 7c5aa7dcd2c0abe787f922bb06a6213c724d08e4, and P-NUCLEO-WB55.Nucleo BLE_p2pServer. It concerns CPU1 command-submission ownership, not Bluetooth controller credit calculations or completion of a later radio procedure. No overlapping commands were sent.

Follow the shared command buffer

The pinned HCI transport keeps a command-buffer pointer and command-response state. hci_send_req reports busy, prepares and sends the command, waits for its response path, and eventually reports available. It does not create an independent command transaction object for every arbitrary application caller.

A cooperative scheduler does not automatically make this safe. The waiting hook can permit other registered work to execute before the current command call returns. That other work must not submit another command through the same protected path unless the integration explicitly supports it.

Draw the call graph through helpers. A task named “refresh status” may call a helper that reads a BLE parameter; a timer-driven task may decide to stop advertising. Classification depends on reachable ACI/HCI calls, not whether the task’s name contains BLE.

A command-producing task outside the exclusion mask can run during an outstanding HCI command and reach the shared command buffer.

Original integration diagram. The mask protects a software submission boundary, not the complete lifetime of every Bluetooth procedure.

Treat the enumeration boundary as executable policy

In app_conf.h, command-producing tasks appear before CFG_LAST_TASK_ID_WITH_HCICMD. The next enumeration starts the tasks declared never to send such commands. These are contiguous numeric IDs, not descriptive categories that a compiler enforces automatically.

The BLE_StatusNot callback computes the lower-bit mask from that boundary, pauses the listed tasks on busy, and resumes them on available. Placing a new command caller after the marker omits it from both operations.

A concrete review should therefore compare three artifacts: the numeric task-ID list, registered task functions and the transitive list of command callers. Reading only the registration calls misses the policy encoded by the IDs.

For a newly added command task, an original compile-time check can make the intended classification visible:

/* Illustrative project guard; use the project's actual new task ID. */
_Static_assert(CFG_TASK_PRODUCT_COMMAND_ID <
               CFG_LAST_TASK_ID_WITH_HCICMD,
               "Product command task must be covered by HCI exclusion");

This check verifies only placement. It cannot discover an unexpected command in a task classified as non-command. Retain the call-graph review and ensure the total bit mapping remains within the implementation’s supported width.

Leave the response path able to progress

Do not repair a missing task bit by pausing every task or masking all interrupts around the command call. The current command still needs its response-delivery path and the wait-release mechanism to run. Blocking those dependencies can convert an overlap defect into a permanent wait.

The pinned example’s command-response release hook sets the corresponding sequencer event, while its wait hook waits for that event. Review these together with the IPCC interrupt configuration in the actual port. Command exclusion should stop competing producers without preventing the response that releases exclusion.

The asynchronous HCI event task belongs to the command-capable group in this example because its callbacks may themselves issue commands. Do not assume that all event-processing tasks should remain unconditionally runnable, or that every system-channel callback has the same ownership. Preserve the selected example’s channel separation and review changes explicitly.

Give non-sequencer callers a supported entry point

The mask applies to the tasks represented by that sequencer. A command invoked directly from an unrelated interrupt, an added RTOS thread or a diagnostic callback is not made safe merely because a similarly named task ID exists.

Prefer one reviewed submission owner. Other contexts can post bounded requests to that owner through a context-correct mechanism. Define admission failure and request lifetime, and preserve the distinction between a locally queued request and a command already sent to CPU2.

If the product instead requires a different concurrency model, start from an appropriate supported integration and review the transport and wait hooks as a unit. Adding a mutex around only selected callers leaves unprotected routes and can create dependencies on a mutex holder that cannot progress.

Qualify a newly added task before release

Proposed cases include a new command task becoming pending while another command waits, two ordinary producers requesting work together, and a timer path that reaches a command indirectly. Instrument producer identity, busy/available transitions and actual transport submission.

Check that excluded tasks stay pending rather than disappearing, and run after the transport becomes available. Separately verify that a response can still release the current command while competing producers are paused. A software harness can exercise classification without transmitting uncontrolled radio commands.

The release gate is a complete command-caller inventory matched to the effective task mask and response path. It explains precisely why a newly registered task is safe, rather than relying on the reassuring but incomplete statement that the application uses a cooperative scheduler.

Similar Posts