Dual‐Core operation - Francerigo/STM32WL55JC1_end_node GitHub Wiki

Dual Core Communication and LoRa Transmission Flow in STM32WL55JC1

This document explains the dual core implementation that relies on MBMUX for LoRa transmissions in the STM32WL55JC1. In this architecture, the CM4 core handles the application level—making it easy for user intervention—while the CM0+ core manages the LoRa stacks and radio drivers.

Core Roles and Communication

  • CM4 Core (Application Level):

    • Runs user interface and high-level processing.
    • When a transmission is needed, CM4 sends a command (Cmd) to CM0+.
    • CM4 registers features for:
      • MBMUXIF_IsrLoraRespRcvCb (LoRa Response Callback)
      • MBMUXIF_IsrLoraNotifRcvCb (LoRa Notification Callback)
  • CM0+ Core (LoRa/Radio Management):

    • Runs the LoRa stack and radio drivers.
    • When CM0+ receives a command from CM4, it triggers the callback MBMUXIF_IsrLoraCmdRcvCb.
    • CM0+ registers features for:
      • MBMUXIF_IsrLoraAckRcvCb (LoRa Acknowledgement Callback)
      • MBMUXIF_IsrLoraCmdRcvCb (LoRa Command Callback)

Refer to the en.STM32WL-System-Mailbox_Multiplexer_MBXMUX.pdf for further details on the command, response, notification, and acknowledgement processes.

Communication Flow Details

1. CM4 to CM0+ (Command and Acknowledgement)

  • Command (Cmd):
    • CM4 calls a function (e.g., LmHandlerSend in lora_app.c).
    • It sets the values to be sent in the shared buffer (initialized during MBMUX initialization).
    • CM4 then calls LmHandlerSend, which internally calls MBMUXIF_LoRaSendCmd to send a command to CM0+.
  • On the CM0+ Side:
    • The reception of a command triggers the callback MBMUXIF_IsrLoraCmdRcvCb.
    • This callback:
      • Assigns a pointer to an MBMUX_ComParam_t object (passed as a parameter) to a global variable (e.g., LoraComObj).
      • Sets the execution of the task associated with the bitmask CFG_SEQ_Task_MbLoRaCmdRcv.
    • The task MBMUXIF_TaskLoraCmdRcv is registered with the sequencer and, when executed, calls Process_Lora_Cmd(LoraComObj).

2. Processing the Command (Process_Lora_Cmd)

  • The function Process_Lora_Cmd(LoraComObj) examines the MsgId field within the MBMUX_ComParam_t structure (with various types defined in msg_id.h).
  • A switch statement determines the operation to perform based on the command.
  • For example, if MsgId equals LMHANDLER_SEND_ID, this indicates that CM4 is requesting a LoRa transmission.

3. Transmission Request on CM0+

When LmHandlerSend is called (with LMHANDLER_SEND_ID):

  • MAC Checks:
    • The function calls LoRaMacIsBusy(). If busy, it returns LORAMAC_HANDLER_BUSY_ERROR.
    • It checks if the MAC is stopped via LoRaMacIsStopped(). If true, it returns LORAMAC_HANDLER_NO_NETWORK_JOINED.
    • It verifies join status using LmHandlerJoinStatus(). If not joined, it calls LmHandlerJoin() and returns LORAMAC_HANDLER_NO_NETWORK_JOINED.
  • Transmission Setup:
    • The transmission type is set (confirmed or unconfirmed) based on the input.
    • Global parameters, such as data rate (LmHandlerParams.TxDatarate), are updated.
  • Payload Size Validation:
    • The function calls LoRaMacQueryTxPossible() with the payload size.
    • If the payload is too long, an empty frame is prepared to flush pending MAC commands, and the status is set to LORAMAC_HANDLER_PAYLOAD_LENGTH_RESTRICTED.
  • Requesting Transmission:
    • Global transmission parameters (TxParams) are updated.
    • The function calls LoRaMacMcpsRequest(), passing the request structure and an allowDelayedTx flag.
    • A global variable (DutyCycleWaitTime) is updated to enforce duty cycle restrictions.
  • Mapping and Returning Status:
    • The returned MAC status is mapped to a handler status (e.g., LORAMAC_HANDLER_SUCCESS, LORAMAC_HANDLER_BUSY_ERROR, etc.) and returned to CM4.

4. Radio Transmission Sequence on CM0+

  • After the MCPS request is configured, the CM0+ core starts the hardware transmission.
  • While transmitting, CM0+ is in an idle state.
  • When the transmission completes, an interrupt is fired:
    • SUBGHZ_Radio_IRQHandler is invoked (in stm32wlxx_it.c).
    • This calls HAL_SUBGHZ_IRQHandler (in stm32wlxx_hal_subghz.c), which in turn calls HAL_SUBGHZ_TxCpltCallback (in radio_driver.c).
    • The chain continues with RadioOnDioIrq and RadioIrqProcess (in radio.c), eventually triggering OnRadioTxDone.
  • Following transmission, CM0+ may also enter an idle state or process reception in one or two Rx windows, triggering Rx callbacks if necessary.

5. CM4 Post-Transmission

  • Waiting:
    • While waiting for a response, CM4 calls UTIL_SEQ_WaitEvt, entering an idle state while executing queued tasks.
  • Response Handling:
    • When CM0+ sends back a response, CM4’s interrupt fires, and it resumes from the waiting state.
    • The event flags used by UTIL_SEQ_WaitEvt are cleared, and CM4 continues processing.
  • Additional Notifications:
    • After sending the response, CM0+ might also send notifications for other events, which CM4 handles via the registered callback MBMUXIF_IsrLoraNotifRcvCb.

Efficiency Considerations

  • CM4 Core:
    Continues with ADC acquisition and peak processing, running the application tasks.
  • CM0+ Core:
    Manages the LoRa transmission independently. This separation allows the CM4 to perform measurement-related tasks without waiting for the radio transmission to complete.

Optimizing Power Consumption by Modifying Reception Windows

To optimize power consumption, the user can prevent the two RX windows from being activated. This document explains how the reception windows work and how you can modify the behavior to disable one or both windows while still allowing subsequent transmissions.

How Reception Windows Work

In LoRaWAN Class A, after each uplink transmission, the device opens two reception windows (RX1 and RX2) to listen for potential downlink messages:

  • Reception Window Behavior:
    • At the beginning of each RX window, a timer is enabled.
    • The device listens during this period for any downlink packets.
    • If a packet is received, the callback function OnRadioRxDone is called.
    • If no packet is received before the timer expires, OnRadioRxTimeout is triggered.
    • Both functions update the reception parameters and then call OnMacProcessNotify.

Role of OnMacProcessNotify and LmHandlerProcess

  • OnMacProcessNotify:

    • This function signals the MAC layer that a reception event (either a successful RX or a timeout) has occurred.
    • It schedules the execution of the MAC processing routine in the sequencer.
  • LmHandlerProcess:

    • Called by OnMacProcessNotify, LmHandlerProcess drives the LoRaMAC state machine.
    • It performs key operations such as:
      1. Calling LoRaMacProcess() to handle internal MAC events.
      2. Calling LmHandlerPackagesProcess() to process package-specific features.
      3. Checking if a package transmission is pending and, if so, exiting early.
      4. For certain LoRaMAC versions, handling a scheduled uplink by sending an empty frame if an uplink is pending.

This chain ensures that after a reception window ends, the MAC state is refreshed and ready for the next transmission.

Modifying Reception Windows to Save Power

  • Disabling RX Window 1:

    • To prevent RX Window 1 from being activated, you can comment out the call to RxWindowSetup in the OnRxWindow1TimerEvent function in the LoRaMac.c file.
    • This will completely avoid activating RX1.
  • Handling RX Window 2:

    • Before the next transmission, it is necessary to update the reception parameters as done in OnRxWindow2TimerEvent to allow another transmission.
    • In particular, within OnRxWindow2TimerEvent, you can mimic the behavior of OnRadioRxTimeout so that the timer is not started and a timeout is recognized immediately.
    • Once the timeout parameters have been set, calling OnMacProcessNotify will update the MAC parameters and refresh the system state, thereby enabling a new transmission.

LoRaMAC Notification and Acknowledgement Process

OnMacProcessNotify ensures that the LoRaMAC state machine (driven by LmHandlerProcess) processes pending events and resets for further operation. The overall process for handling downlink notifications and acknowledgements involves both cores and a series of function calls and callbacks, as described below.

Notification Flow from CM0+ to CM4

  1. CM0+ Initiates Notification:

    • CM0+ sends a notification to CM4 when ending reception window 2, as part of its transmission cycle.
    • The notification flow follows this sequence:
      • LmHandlerProcessLoRaMacProcessLoRaMacHandleRequestEventsMcpsConfirmOnTxData_mbwrapperMBMUXIF_LoraSendNotif
    • MBMUXIF_LoraSendNotif then calls MBMUX_NotificationSnd, which sends the notification to CM4, passing the parameter FEAT_INFO_LORAWAN_ID.
  2. CM4 Receives the Notification:

    • Upon receiving the notification, CM4 triggers the callback MBMUXIF_IsLoraNotifRcvCb through the mailbox multiplexer.
    • This callback sets the execution of the function Process_Lora_Notif.
  3. Processing the Notification on CM4:

    • Inside Process_Lora_Notif, a switch-case statement checks the message ID.
    • When MsgId equals 58, like after reception window 2, the case LMHANDLER_ON_TX_DATA_CB_ID is selected.
    • In this case, the following occurs:
      • The function pointer callback_mbwrapper.OnTxData is set to 0x8001E01.
      • It is then called as follows:
        callback_mbwrapper.OnTxData((LmHandlerTxParams_t *) com_buffer[0]);
        
      • This call enters the function OnTxData in lora_app.c, which:
        • Verifies that the parameters indicate an MCPS confirmation.
        • Restarts the transmission timer.
      • Finally, the response buffer is cleared and an acknowledgement is sent.

Acknowledgement Flow Back to CM0+

  • While CM4 processes the notification, CM0+ is waiting for an acknowledgement.
  • The acknowledgement sequence on CM0+ follows this chain:
    • IPCC_C2_RX_C2_TX_IRQHandlerHAL_IPCC_TX_IRQHandlerIpccIfIsrTxCbMBMUX_IsrAcknowledgeRcvCbMBMUXIF_IsrTraceAckRcvCb
    • Then, UTIL_SEQ_SetEvt is called, which finishes the waiting for the acknowledgement.
    • Next, UTIL_SEQ_SetTask(... CFG_SEQ_Task_MbTraceAckRcv) is executed, which schedules the task MBMUXIF_TaskTraceAckRcv.
    • Finally, this leads to the calls:
      • TraceUtilCpltCallback(NULL) followed by TRACE_TxCpltCallback.

This sequence ensures that both cores remain synchronized during the transmission cycle, allowing the system to refresh its parameters and proceed with further transmissions.

In essence:

  • The RX windows are normally used to listen for downlinks, but you can disable one to save power (commenting, in LoRaMac.c under OnRxWindow1TimerEvent, the line with the RxWindowSetup function).
  • You must still update the MAC state (via the timeout handling in RX2) so that the system is ready for the next transmission. To do that, substitute RxWindowSetup with OnRadioRxTimeout (in LoRaMac.c under OnRxWindow2TimerEvent).

Conclusion

This dual core architecture leverages MBMUX to facilitate efficient communication between the CM4 and CM0+ cores. CM4 handles high-level application functions and data processing while CM0+ manages the time-critical LoRa transmission. This division of tasks improves system responsiveness and ensures that radio operations do not interrupt or delay application-level processing.

An issue is that the CM4 core is re-enabling the comparator interrupt—which triggers ADC acquisitions—before the CM0+ core has received and processed the final acknowledgement. As a result, CM4 resumes ADC operations while the CM0+ is still waiting for that ACK, leading to a timing conflict. Instead of re-enabling the comparator interrupt immediately after transmission of the ack (inside Process_Lora_Notif), the user can add a controlled delay (using a non-blocking timer or waiting for a specific event) on CM4. This ensures that the ACK is fully processed by CM0+ before ADC acquisitions resume. The code in this github repository uses a 100 ms delay after Process_Lora_Notif, before reenabling the comparator interrupt. This delay allows the CM0+ to receive and process the ack.

When using low power you first enable low power in both sys_conf in both cores ( and also reset the DEBUGGER_ENABLED flag) Then you need to go to stm32_lpm_if.c and, when exiting stopMode, reinitialize the ADC in CM4. Use MX_ADC_Init and not HAL_ADC_Init, because the stop2 mode clears some registers that need to be restored.