nRF52840
SDK <v2.5.0
If you are on 2.6 and onward, you can use this: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/samples/bluetooth/connection_event_trigger/README.html
Very good blog on the MSPL timeslot interface by Daniel V that led to a lot of this knowledge. Let's say we want to "estimate" how long connection events and intervals are between two devices.
Sometimes simply toggling a pin when a notification begins and ends doesn't give us the clear picture on what's actually happening on the radio level. The reason for this is because for instance if you toggle the pin on before sending a notification, then toggle it off after the notification completes via callback, the notification complete callback only executes when the device actually hears back. So this doesn't really show you much as far as what's happening on the radio.
Thus, we can use Radio Notifications to toggle a pin in a lightweight IRQ on either edge. This lets us paint a clearer picture of when the notification actually started and stop described above.
In this case, the QDEC IRQn is hijacked as it's not being used. Some peripherals share IRQs! (Link)
As you test and observe the radio activity, you can take some actions to optimize your connection for throughput/rate/etc.
Or maybe you want an interrupt to trigger when the radio is going to turn on. or off. From MPSL doc page :
Radio notifications. It provides a configurable interrupt, usable before and/or after radio activity.
(Example of code addition running on 3 peripherals notifying the central configuration)
Missed connection events due to sub optimal network parameters chosen.
No missed CE with optimal network parameters, good usage of the radio
- you could use
k_sched_lock()
andk_sched_unlock()
within main before bluetooth init and it would work, but it is better to use system work queue. The calls have to be from cooperative thread.
For instance, modifying event length fxn and connection interval from sample
//peripheral
static int set_custom_event_length(uint32_t event_len_us)
{
int err;
struct net_buf *buf;
sdc_hci_cmd_vs_event_length_set_t *cmd_event_len_set;
buf = bt_hci_cmd_create(SDC_HCI_OPCODE_CMD_VS_EVENT_LENGTH_SET, sizeof(*cmd_event_len_set));
if (!buf)
{
printk("Could not allocate command buffer\n");
return -ENOMEM;
}
cmd_event_len_set = net_buf_add(buf, sizeof(*cmd_event_len_set));
cmd_event_len_set->event_length_us = event_len_us;
err = bt_hci_cmd_send_sync(SDC_HCI_OPCODE_CMD_VS_EVENT_LENGTH_SET, buf, NULL);
if (err)
{
printk("Set event length failed (err %d)\n", err);
return err;
}
printk("event length configured\n");
return 0;
}
//central
static int change_connection_interval(uint16_t interval_us)
{
int err;
struct net_buf *buf;
sdc_hci_cmd_vs_conn_update_t *cmd_conn_update;
buf = bt_hci_cmd_create(SDC_HCI_OPCODE_CMD_VS_CONN_UPDATE,
sizeof(*cmd_conn_update));
if (!buf) {
printk("Could not allocate command buffer\n");
return -ENOMEM;
}
uint16_t conn_handle;
err = bt_hci_get_conn_handle(default_conn, &conn_handle);
if (err) {
printk("Failed obtaining conn_handle (err %d)\n", err);
return err;
}
cmd_conn_update = net_buf_add(buf, sizeof(*cmd_conn_update));
cmd_conn_update->conn_handle = conn_handle;
cmd_conn_update->conn_interval_us = interval_us;
cmd_conn_update->conn_latency = 0;
cmd_conn_update->supervision_timeout = 300;
err = bt_hci_cmd_send_sync(SDC_HCI_OPCODE_CMD_VS_CONN_UPDATE, buf, NULL);
if (err) {
printk("Update connection parameters failed (err %d)\n", err);
return err;
}
return 0;
}
This repo utilizes the following:
nordic_radio_notifications/main.c
Lines 33 to 34 in c5c0810
If at some point you want to use IRQ_DIRECT_CONNECT
, be advised of the following:
IRQ_DIRECT_CONNECT
will not allow the scheduler to run, it effectively bypasses the kernels ability run its scheduling point that might otherwise happen after an ISR returns.
From the Radio Notification doc page
Copypasta in case the link dies again...
The radio notification is a configurable feature that enables ACTIVE and INACTIVE (nACTIVE) signals from the MPSL to the application notifying it when timeslot events are active. The application can configure how much in advance the ACTIVE signal occurs.
The radio notification signals are sent right before or at the end of an MPSL timeslot activity. The timeslot activity may be requested by the application or another user of MPSL. To ensure that the radio notification signals behave in a consistent way, the radio notification must always be configured when the MPSL is in an idle state with no active users. Therefore, it is recommended to configure the radio notification signals directly after the MPSL has been enabled.
If it is enabled, the ACTIVE signal is sent before the timeslot events starts. Similarly, if the nACTIVE signal is enabled, it is sent at the end of the timeslot event. These signals can be used by the application developer to synchronize the application logic with the timeslot activity. For example, if the application is using the timeslot for radio activity, the ACTIVE signal can be used to switch off external devices to manage peak current drawn during periods when the radio is ON, or to trigger sensor data collection for transmission during the upcoming event.
As both ACTIVE and nACTIVE use the same software interrupt, it is up to the application to manage them. If both ACTIVE and nACTIVE are configured ON by the application, there will always be an ACTIVE signal before an nACTIVE signal.
When there is sufficient time between timeslot events, both the ACTIVE and nACTIVE notification signals will be present at each event. When there is not sufficient time between the events, the ACTIVE and nACTIVE notification signals will be skipped. There will still be an ACTIVE signal before the first event and an nACTIVE signal after the last event.
t_distance is important to note, as well as whether we want notifications for active and nactive. You can repurpose the mpsl api call to suit your requirements.
nordic_radio_notifications/main.c
Lines 23 to 25 in f9417fa
The list of what is available is in <ncs ver>/nrfxlib/mpsl/include/mpsl_radio_notification.h
/** @brief Guaranteed time for application to process radio inactive notification. */
#define MPSL_RADIO_NOTIFICATION_INACTIVE_GUARANTEED_TIME_US (62)
/** @brief Radio notification distances. */
enum MPSL_RADIO_NOTIFICATION_DISTANCES
{
MPSL_RADIO_NOTIFICATION_DISTANCE_NONE = 0, /**< The event does not have a notification. */
MPSL_RADIO_NOTIFICATION_DISTANCE_200US, /**< The distance from the active notification to start of radio activity. */
MPSL_RADIO_NOTIFICATION_DISTANCE_420US, /**< The distance from the active notification to start of radio activity. */
MPSL_RADIO_NOTIFICATION_DISTANCE_800US, /**< The distance from the active notification to start of radio activity. */
MPSL_RADIO_NOTIFICATION_DISTANCE_1740US, /**< The distance from the active notification to start of radio activity. */
MPSL_RADIO_NOTIFICATION_DISTANCE_2680US, /**< The distance from the active notification to start of radio activity. */
MPSL_RADIO_NOTIFICATION_DISTANCE_3620US, /**< The distance from the active notification to start of radio activity. */
MPSL_RADIO_NOTIFICATION_DISTANCE_4560US, /**< The distance from the active notification to start of radio activity. */
MPSL_RADIO_NOTIFICATION_DISTANCE_5500US /**< The distance from the active notification to start of radio activity. */
};
/** @brief Radio notification types. */
enum MPSL_RADIO_NOTIFICATION_TYPES
{
MPSL_RADIO_NOTIFICATION_TYPE_NONE = 0, /**< The event does not have a radio notification signal. */
MPSL_RADIO_NOTIFICATION_TYPE_INT_ON_ACTIVE, /**< Using interrupt for notification when the radio will be enabled. */
MPSL_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE, /**< Using interrupt for notification when the radio has been disabled. */
MPSL_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH, /**< Using interrupt for notification both when the radio will be enabled and disabled. */
};