Is the code developed for nRF5340 backward compatible with nRF52840 ?

#include <zephyr/logging/log.h>
#include <zephyr/drivers/uart.h>
#include <include/BLEAdvScanner.h>
#include <bluetooth/scan.h>
#include <zephyr/sys/ring_buffer.h>

const struct device *uart= DEVICE_DT_GET(DT_NODELABEL(uart0));

K_THREAD_STACK_DEFINE(scan_thread_stack, 2048);
struct k_thread scan_thread_data;

K_THREAD_STACK_DEFINE(transceiver_thread_stack, 2048);
struct k_thread transceiver_thread_data;


LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_DBG);

static uint32_t g_pktcount=0;

// UART RX primary buffers
uint8_t uart_double_buffer[2][UART_BUF_SIZE];
uint8_t *uart_buf_next = uart_double_buffer[1];

K_SEM_DEFINE(tx_done, 1, 1);
K_SEM_DEFINE(rx_disabled, 0, 1);


static uint8_t rx_buf[128];  // Adjust buffer size if needed
static uint8_t rx_index = 0;
static uint8_t size_expected = 0;

// UART TX fifo
RING_BUF_DECLARE(app_tx_fifo, UART_TX_BUF_SIZE);
volatile int bytes_claimed;

// SCAN message queue
K_MSGQ_DEFINE(scan_msgq, sizeof(scan_msg_queue_item), SCAN_MSG_QUEUE_SIZE, 8);

// UART RX message queue
K_MSGQ_DEFINE(uart_rx_msgq, sizeof(uart_msg_queue_item), UART_RX_MSG_QUEUE_SIZE, 4);


// Callback function called by BLE driver upom receiving a packet during Scanning
// Keep this function short, like an ISR

static void ble_scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,struct net_buf_simple *ad) 
{

	static scan_msg_queue_item new_message;
	new_message.rxdpktindex = g_pktcount++;
	new_message.rssi = rssi;
	new_message.rxtime = k_uptime_get_32();
	new_message.advdata_len = ad->len;
	bt_addr_le_to_str(addr,new_message.advr_addr, sizeof(new_message.advr_addr));

	memcpy(&new_message.advdata, ad->data, ad->len);
	if (k_msgq_put(&scan_msgq, &new_message, K_NO_WAIT) != 0) {
		LOG_ERR("Error: SCAN  message queue full!\n");
	}
}


// Callback function called by BLE driver upom receiving a packet during Scanning
// Keep this function short, like an ISR
static void scan_filter_match(struct bt_scan_device_info *device_info,
			      struct bt_scan_filter_match *filter_match,
			      bool connectable)
{
	
	static scan_msg_queue_item new_message;
	new_message.rxdpktindex = g_pktcount++;
	new_message.rssi = device_info->recv_info->rssi;
	new_message.rxtime = k_uptime_get_32();
	new_message.advdata_len = device_info->adv_data->len;
	bt_addr_le_to_str(device_info->recv_info->addr,new_message.advr_addr, sizeof(new_message.advr_addr));
	memcpy(&new_message.advdata, device_info->adv_data->data, device_info->adv_data->len);
	if (k_msgq_put(&scan_msgq, &new_message, K_NO_WAIT) != 0) {
		LOG_ERR("Error: SCAN  message queue full!\n");
	}

}

BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL,
		NULL, NULL);


static int scan_init(void)
{
	int err;
	struct bt_le_scan_param scan_param = {
		.type       = BT_LE_SCAN_TYPE_PASSIVE,
		.options    = BT_LE_SCAN_OPT_NONE,
		.interval   = SCAN_INTERVAL_TICKS,
		.window     = SCAN_WINDOW_TICKS,
	};
	struct bt_scan_init_param scan_init = {
		.scan_param = &scan_param,
	};

	bt_addr_t addr ={ { 0x11, 0x93, 0xD3, 0x34, 0x22, 0x77 }};
	bt_addr_le_t filter_addr = {
		.a = addr,
		.type = BT_ADDR_LE_RANDOM,
	};
	struct bt_uuid_16 uuid_to_filter = BT_UUID_INIT_16(0x1234);
	

	bt_scan_init(&scan_init);
	bt_scan_cb_register(&scan_cb);

	err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_ADDR, &filter_addr);
	err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_UUID, &uuid_to_filter);
	if (err) {
		LOG_ERR("Scanning filters cannot be set (err %d)", err);
		return err;
	}

	err = bt_scan_filter_enable(BT_SCAN_ADDR_FILTER | BT_SCAN_UUID_FILTER, false);
	if (err) {
		LOG_ERR("Filters cannot be turned on (err %d)", err);
		return err;
	}

	LOG_INF("Scan module initialized");
	return err;
}

static int uart_tx_get_from_queue(void)
{
	uint8_t *data_ptr;
	// Try to claim any available bytes in the FIFO
	bytes_claimed = ring_buf_get_claim(&app_tx_fifo, &data_ptr, UART_TX_BUF_SIZE);

	if(bytes_claimed > 0) {
		// Start a UART transmission based on the number of available bytes
		uart_tx(uart, data_ptr, bytes_claimed, SYS_FOREVER_MS);
	}
	return bytes_claimed;
}

void receive_complete_message(uart_msg_queue_item new_message)
{
	if (new_message.length > 0) {

		if (size_expected > 0) {
			for (int i=0; i<new_message.length; i++) {
				if (new_message.bytes[i] != '\n' && new_message.bytes[i] != '\r') {
					rx_buf[rx_index] = new_message.bytes[i];
					rx_index++;
				}
			}
			LOG_INF("size expected = %u",size_expected); 
			LOG_INF("rx_index = %u",rx_index); 

			if (size_expected == rx_index ){
				rx_buf[rx_index] = 0;
				rx_index = 0;
				size_expected =0;
				LOG_INF("received complete message , %s", rx_buf);
			}
			
		}
		else {
			rx_index =0;
			for (int i=4;i<new_message.length; i++) {
				if (new_message.bytes[i] != '\n' && new_message.bytes[i] != '\r') {
					rx_buf[rx_index] = new_message.bytes[i];
					rx_index++;
				}
				
			}

			for (int i = 0; i < 4; i++) {
				int value;
				if (new_message.bytes[i] >= '0' && new_message.bytes[i] <= '9') {
					value = new_message.bytes[i] - '0';
				} else if (new_message.bytes[i] >= 'A' && new_message.bytes[i] <= 'F') {
					value = 10 + new_message.bytes[i] - 'A';
				} else if (new_message.bytes[i] >= 'a' && new_message.bytes[i] <= 'f') {
					value = 10 + new_message.bytes[i] - 'a';
				} else {
					printf("Error: Invalid hex digit at position %d.\n", i);
					return -1; // Indicate error
				}
				size_expected += value * (1 << (4 * i)); // Multiply by 16^i
   			 }
			//size_expected += new_message.bytes[0] - '0';
			LOG_INF("size expected = %u", size_expected);

			if (size_expected == rx_index ) {
				rx_buf[rx_index] = 0;
				LOG_INF("received complete message , %s", rx_buf);
				size_expected =0;
				rx_index =0;
			}
		}
	}

}

void app_uart_async_callback(const struct device *uart_dev,
							 struct uart_event *evt, void *user_data)
{
 static uart_msg_queue_item new_message;
	switch (evt->type) {
		case UART_TX_DONE:
			// Free up the written bytes in the TX FIFO
			ring_buf_get_finish(&app_tx_fifo, bytes_claimed);

			// If there is more data in the TX fifo, start the transmission
			if(uart_tx_get_from_queue() == 0) {
				// Or release the semaphore if the TX fifo is empty
				k_sem_give(&tx_done);
			}
			break;
		case UART_RX_RDY:
			memcpy(new_message.bytes, evt->data.rx.buf + evt->data.rx.offset, evt->data.rx.len);
			new_message.length = evt->data.rx.len;
			receive_complete_message(new_message);
			break;

		case UART_RX_BUF_REQUEST:
			uart_rx_buf_rsp(uart, uart_buf_next, UART_BUF_SIZE);
			break;

		case UART_RX_BUF_RELEASED:
			uart_buf_next = evt->data.rx_buf.buf;
			break;
		case UART_RX_DISABLED:
			k_sem_give(&rx_disabled);
			break;
		
		default:
			break;
	}
}

static int tx_message_over_uart(const uint8_t * data_ptr, uint32_t data_len)
{
	while(1) {
		// Try to move the data into the TX ring buffer
		uint32_t written_to_buf = ring_buf_put(&app_tx_fifo, data_ptr, data_len);
		data_len -= written_to_buf;
		
		// In case the UART TX is idle, start transmission
		if(k_sem_take(&tx_done, K_NO_WAIT) == 0) {
			uart_tx_get_from_queue();
		}	
		
		// In case all the data was written, exit the loop
		if(data_len == 0) break;

		// In case some data is still to be written, sleep for some time and run the loop one more time
		k_msleep(10);
		data_ptr += written_to_buf;
	}

	return 0;
}

int main(void) {

	int 	err;
	err = bt_enable(NULL);
	if (err) {
		LOG_ERR("Bluetooth init failed (err %d)", err);
		return 0;
	}
	LOG_DBG("Bluetooth Initiated!!");
	
	if (!device_is_ready(uart)){
		LOG_ERR("UART device not ready!!");
	}
	uart_callback_set(uart, app_uart_async_callback, NULL);
	uart_rx_enable(uart, uart_double_buffer[0], UART_BUF_SIZE, UART_RX_TIMEOUT_MS);

	LOG_DBG("UART Initiated!!");

	#ifdef CONFIG_SCANFILTER
		err = scan_init();
		if (err != 0) {
			LOG_ERR("scan_init failed (err %d)", err);
			return 0;
		}
		err = bt_scan_start(BT_SCAN_TYPE_SCAN_PASSIVE);
		if (err) {
			LOG_ERR("Start scanning failed (err %d)", err);
			return;
		}
	#else

		struct bt_le_scan_param scan_param = {
			.type = BT_LE_SCAN_TYPE_PASSIVE,
			.options = BT_LE_SCAN_OPT_FILTER_DUPLICATE,
			.interval = SCAN_INTERVAL_TICKS,
			.window = SCAN_WINDOW_TICKS,
		};
		err = bt_le_scan_start(&scan_param, ble_scan_cb);
		if (err) {
			LOG_ERR("Start scanning failed (err %d)", err);
			return;
		}
		
	#endif

	scan_msg_queue_item incoming_message;

	while (1) {
		k_msgq_get(&scan_msgq, &incoming_message, K_FOREVER);

		// Process the message here.

		static uint8_t addr_buffer[BT_ADDR_LE_STR_LEN + 1], data_buffer[MAX_ADVDATA_LEN+1];

		static uint8_t uart_tx_data[150];
		memcpy(addr_buffer, incoming_message.advr_addr, strlen(incoming_message.advr_addr));
		memcpy(data_buffer, incoming_message.advdata, incoming_message.advdata_len);
		memset(uart_tx_data, 0, 150);
		snprintf(uart_tx_data, sizeof(uart_tx_data), "RX %i: %i: %i: %s: %s\r\n", incoming_message.rxdpktindex, incoming_message.rssi,
								 incoming_message.rxtime, addr_buffer, data_buffer);
		tx_message_over_uart(uart_tx_data, strlen(uart_tx_data));
	}
	return 0;
}

I have this code developed for nRF5340.

Basically it scans for BLE advertisements based on the filters added and transmits the packets through UART.

Now for certain reasons, I wanted to go with nRF52840 and i am doing a study to check if all these features can be supported in lower version SoC?

Questions:

1) Does nRF52840 supports all filter types(whitelist) that has been supported by 5340 ?

2) How efficient is nRF52840 wrt BLE Scanning ? Do we have performance metrics for BLE on this SoC?

3) I have used nRF Connect SDK for 5340 development ? Is that SDK support available for 52840 ? I think it does have zephyr RTOS support ! will there be any limitation ? 

4) Is there any performance benchmark captured to show comparison between nRF5340 and 52840 ?

Parents
  • Hi,

    1) Does nRF52840 supports all filter types(whitelist) that has been supported by 5340 ?

    Yes, it should support all since the BLE stack that provides the functionality is consistent across both these devices.

    2) How efficient is nRF52840 wrt BLE Scanning ? Do we have performance metrics for BLE on this SoC?

    The nRF52840 is quite efficient. Though when you compare with the nRF5340, since it has dal core capability and a slightly more clock speed, the nRF52840 may have slightly lesser performance for very demanding applications. But that said, the 52840 should be very efficient in terms of performance for most of the applications like continuous or periodic scanning with filters etc.

    3) I have used nRF Connect SDK for 5340 development ? Is that SDK support available for 52840 ? I think it does have zephyr RTOS support ! will there be any limitation ? 

    Yes of curse. You can use the nRF Connect SDK to develop for the nRF52840 as well. Limitations are mainly because of the chips itself, i.e. nRF52840 has less RAM and Flash compared to the nRF5340. And as previously mentioned, the nRF52840 has only a single core, so the tasks that were performed in the nRF5340 in both the cores will have to be handled a bit differently here. So the limitations are mainly these (memory, performance etc)

    4) Is there any performance benchmark captured to show comparison between nRF5340 and 52840 ?

    The performance benchmark will depend on the application. The processing power of the nRF5340 is better than the nRF52840 owing to the dual cores. But if you are looking for energy efficiency, for applications not requiring dual cores, the nRF52840 helps for lower power consumption. 

    Regards,

    Priyanka

Reply
  • Hi,

    1) Does nRF52840 supports all filter types(whitelist) that has been supported by 5340 ?

    Yes, it should support all since the BLE stack that provides the functionality is consistent across both these devices.

    2) How efficient is nRF52840 wrt BLE Scanning ? Do we have performance metrics for BLE on this SoC?

    The nRF52840 is quite efficient. Though when you compare with the nRF5340, since it has dal core capability and a slightly more clock speed, the nRF52840 may have slightly lesser performance for very demanding applications. But that said, the 52840 should be very efficient in terms of performance for most of the applications like continuous or periodic scanning with filters etc.

    3) I have used nRF Connect SDK for 5340 development ? Is that SDK support available for 52840 ? I think it does have zephyr RTOS support ! will there be any limitation ? 

    Yes of curse. You can use the nRF Connect SDK to develop for the nRF52840 as well. Limitations are mainly because of the chips itself, i.e. nRF52840 has less RAM and Flash compared to the nRF5340. And as previously mentioned, the nRF52840 has only a single core, so the tasks that were performed in the nRF5340 in both the cores will have to be handled a bit differently here. So the limitations are mainly these (memory, performance etc)

    4) Is there any performance benchmark captured to show comparison between nRF5340 and 52840 ?

    The performance benchmark will depend on the application. The processing power of the nRF5340 is better than the nRF52840 owing to the dual cores. But if you are looking for energy efficiency, for applications not requiring dual cores, the nRF52840 helps for lower power consumption. 

    Regards,

    Priyanka

Children
No Data
Related