Skip to content

quick way to add a gpio toggle for radio notifications to your ble (or otherwise) application

Notifications You must be signed in to change notification settings

droidecahedron/nordic_radio_notifications

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

37 Commits
 
 
 
 

Repository files navigation

Hardware

nRF52840

Software

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

Background

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.

Screenshot

(Example of code addition running on 3 peripherals notifying the central configuration)

image

Missed connection events due to sub optimal network parameters chosen.

image image

No missed CE with optimal network parameters, good usage of the radio

Notes

  • you could use k_sched_lock() and k_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.

Optimizing connection

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;
}

IRQ Connect

This repo utilizes the following:

IRQ_CONNECT(DT_IRQN(DT_NODELABEL(RADIO_NOTI_IRQN_NODELABEL)), RADIO_NOTI_IRQ_PRIO,
radio_notify_cb, NULL, 0);

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.

TechDocs link

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.

image

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.

mpsl_radio_notification_cfg_set(MPSL_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH, // on both events
MPSL_RADIO_NOTIFICATION_DISTANCE_200US, // lowest possible
RADIO_NOTI_IRQN);

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. */
};

About

quick way to add a gpio toggle for radio notifications to your ble (or otherwise) application

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages