Interrupts#
Interrupts create events in their respective interrupt handlers, be it radio interrupts or interrupts from IO pins. The events are later processed in the main event loop from the message queue. The application should always minimize the processing time within an interrupt handler, and leave the processing for event callbacks or to the main loop.
In general, the interrupt scheme is according to any event-based programming architecture, but a few unique and important exceptions apply to the Bluetooth stack:
BGAPI commands cannot be called from interrupt context.
Only the
sl_bt_external_signal()
function can be called from interrupt context.
External Event#
An external event is used to capture all peripheral interrupts as an external signal to be passed to the main event loop and to be processed within that loop. The external event interrupt can come from any of the peripheral interrupt sources, for example IOs, comparators, or ADCs, to name a few. The signal bit array is used for notifying the event handler of what external interrupts have been issued.
The main purpose of the external signal is to trigger an event from the interrupt context to the main event loop.
The BGAPI event
sl_bt_evt_system_external_signal
can be generated by calling thevoid sl_bt_external_signal``(uint32 signals)
function.The function
sl_bt_external_signal
can be called from the interrupt context. If the Platform Core Interrupt API has been configured to use theCORE_ATOMIC_METHOD_BASEPRI
as the implementation method of atomic sections, which is the default configuration, this function must not be called from an interrupt handler with a priority higher thanCORE_ATOMIC_BASE_PRIORITY_LEVEL
.Calling
sl_bt_external_signal
too often can cause memory buffer exhaustion if number of free memory buffers is low, causingsl_bt_external_signal
call to fail. The number of free bytes in the memory buffer can be checked with Resource Report BGAPI.The
signals
parameter of thesl_bt_external_signal
function is passed to thesl_bt_evt_system_external_signal
event.
/**************************************************************************//**
* Bluetooth stack event handler.
*
* @param[in] evt The event coming from the Bluetooth stack
*****************************************************************************/
void sl_bt_on_event(sl_bt_msg_t *evt)
{
...
switch (SL_BT_MSG_ID(evt->header)) {
...
case sl_bt_evt_system_external_signal_id:
// External signal indication (comes from the interrupt handler)
// Handle GPIO IRQ and do something
// External signal command’s parameter can be accessed using
// evt->data.evt_system_external_signal.extsignals
break;
...
}
}
/**
* Handle GPIO interrupts and trigger system_external_signal event
*/
void GPIO_ODD_IRQHandler()
{
static bool radioHalted = false;
uint32_t flags = GPIO_IntGet();
GPIO_IntClear(flags);
//Send gecko_evt_system_external_signal_id event to the main loop sl_bt_external_signal(...);
}
}
Priorities#
The Bluetooth link layer will always execute the most time-critical sections in the radio interrupt directly. Additionally, in a bare metal build, the Bluetooth link layer will use the PendSV interrupt to have higher priority than the Bluetooth host stack or the application code. When an RTOS is included, RTOS task priorities are used to give the link layer the higher priority. Silicon Labs recommends that the radio should have the highest priority interrupts. This is the default configuration, and other interrupts are handled with lower priority. The interrupt priority for the radio is 4; for the Link Layer PendSV interrupt in the bare metal build, the priority is 5; and other interrupts have a default priority of 7. Smaller value is a higher priority interrupt.
To guarantee the proper operation of atomic sections in the Bluetooth stack, the atomic sections need to be configured correctly with respect to the interrupt priorities. Silicon Labs recommends that the BASEPRI
register is used instead of the PRIMASK
register, i.e., CORE_ATOMIC_METHOD
is configured to CORE_ATOMIC_METHOD_BASEPRI
. This is the default configuration. When using CORE_ATOMIC_METHOD_BASEPRI
, the CORE_ATOMIC_BASE_PRIORITY_LEVEL
needs to be set to an equal or higher priority (equal or smaller value) than the radio interrupt and the PendSV interrupt (in bare metal). The default value of CORE_ATOMIC_BASE_PRIORITY_LEVEL
is 3, which is consistent with the default radio interrupt priority 4, and the default link layer PendSV interrupt priority 5 (on bare metal).
For more details on the interrupt configuration and atomic sections, see the Core Interrupt documentation.
The following table describes the three different components within the Bluetooth stack that run in different operating contexts, and their maximum time to disable interrupts for each component to assure connections.
Component | Description | Timing Accuracy | Operating Context | Maximum IRQ Disable | If Timing Requirements are Ignored |
---|---|---|---|---|---|
Radio | Time-critical low level TX/RX radio control | Microseconds | Radio IRQ | < ~10 µs | Packets are not transmitted or received, which will eventually cause supervision timeout and Bluetooth link loss. |
Link layer | Time-critical connection management procedures and encryption | Milliseconds | PendSV IRQ (1) | < ~20 ms | If the link control procedure is not handled in time, Bluetooth link loss may happen. Peripheral-side channel map update and connection update timings are controlled by central device. |
Host Stack | Bluetooth Host Stack, Security Manager, GATT | Seconds | Application | < 30 s | SMP and GATT have a 30 s timeout and if operations are not handled within that timeout Bluetooth link loss will occur. |
(1) PendSV interrupt is only used without RTOS