Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nrf52840 Timeslot API Gazell

Hello,

For the past couple weeks I have been trying to get Gazell working concurrently with BLE using the timeslot api. Everything appears to be working correctly - all of the timeslot api event handlers and callbacks are called at times that make sense, however if I attempt a transmission neither the nrf_gzll_device_tx_success or the nrf_gzll_device_tx_failed callbacks fire.

My code is heavily based off of the nrf51-ble-gzll-device-uart example, the only significant change being the addition of a call to NRF_SDC_SOC_OBSERVER to ensure that sys_evt_handler is called on soc events. In main the BLE stack is initialized as per the examples provided in the SDK and gazell_sd_radio_init is called before BLE advertising is started. Much later, nrf_gzll_add_packet_to_tx_fifo is called. At this point, since I have no other Gazell devices present, I would expect the transmission to fail, however as mentioned previously, nrf_gzll_device_tx_failed is never called.

I've added logging to all of the relevant functions and as far as I can tell everything with the Timeslot API is working correctly and no errors are being raised, so I'm not sure why this isn't behaving the way I'd expect.

OS: Linux

SW: nrf5 SDK v16, s140 7.0.1

HW: Custom board based around a nrf52840 module

The file containing all of the Gazell related code is below

Thanks

#ifndef __GAZELL_HOST_H__
#define __GAZELL_HOST_H__

#include <stdint.h>
#include <string.h>
#include "nrf_gzll.h"
#include "nrf_assert.h"
#include "nrf_soc.h"
#include "nrf_sdh.h"
#include "nrf_sdh_soc.h"
#include "app_error.h"
#include "app_util_platform.h"

void RADIO_IRQHandler(void);

#define PIPE_NUMBER 0
#define TX_PAYLOAD_LENGTH 32
#define ACK_PAYLOAD_LENGTH 32

static nrf_radio_request_t m_timeslot_request;
static uint32_t m_slot_length;
static volatile bool m_cmd_recieved = false;
static volatile bool m_gzll_initialized = false;

static nrf_radio_signal_callback_return_param_t signal_callback_return_param;
static uint8_t ack_payload[ACK_PAYLOAD_LENGTH];

void HardFault_Handler(uint32_t program_counter, uint32_t link_register) {
}

void m_configure_next_event() {
	//NRF_LOG_DEBUG("m_configure_next_event");
	m_slot_length = 25000;
	m_timeslot_request.request_type = NRF_RADIO_REQ_TYPE_EARLIEST;
	m_timeslot_request.params.earliest.hfclk = NRF_RADIO_HFCLK_CFG_NO_GUARANTEE;
	m_timeslot_request.params.earliest.priority = NRF_RADIO_PRIORITY_NORMAL;
	m_timeslot_request.params.earliest.length_us = m_slot_length;
	m_timeslot_request.params.earliest.timeout_us = 100000;
}

void sys_evt_dispatch(uint32_t evt_id, void *p_context) {
	NRF_LOG_DEBUG("sys_evt_dispatch");
	ret_code_t err;
	
	switch(evt_id) {
		case NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN:
		case NRF_EVT_RADIO_SESSION_IDLE:
		case NRF_EVT_RADIO_SESSION_CLOSED:
			ASSERT(false);
			break;
		case NRF_EVT_RADIO_BLOCKED:
		case NRF_EVT_RADIO_CANCELED:
			m_configure_next_event();
			err = sd_radio_request(&m_timeslot_request);
			APP_ERROR_CHECK(err);
			break;
		default:
			break;
	}
}

static void m_on_start() {
	//NRF_LOG_DEBUG("m_on_start");
	bool res;
	signal_callback_return_param.params.request.p_next = NULL;
	signal_callback_return_param.callback_action  = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;
	
	if(!m_gzll_initialized) {
		res = nrf_gzll_init(NRF_GZLL_MODE_DEVICE);
		ASSERT(res);
		res = nrf_gzll_set_base_address_0(0xE7E7E7E7);
		ASSERT(res);
		res = nrf_gzll_set_device_channel_selection_policy(NRF_GZLL_DEVICE_CHANNEL_SELECTION_POLICY_USE_CURRENT);
		ASSERT(res);
		res = nrf_gzll_set_xosc_ctl(NRF_GZLL_XOSC_CTL_MANUAL);
		ASSERT(res);
		nrf_gzll_set_max_tx_attempts(100);
		res = nrf_gzll_enable();
		ASSERT(res);
		m_gzll_initialized = true;
		NRF_LOG_DEBUG("m_on_start:gazell initialized");
	} else {
		res = nrf_gzll_set_mode(NRF_GZLL_MODE_DEVICE);
		ASSERT(res);
		//NRF_LOG_DEBUG("m_on_start:gazell in device mode");
	}
	
	NRF_TIMER0->INTENSET = TIMER_INTENSET_COMPARE0_Msk;
	NRF_TIMER0->CC[0] = m_slot_length - 4000;
	NVIC_EnableIRQ(TIMER0_IRQn);
}

static void m_on_multitimer() {
	//NRF_LOG_DEBUG("m_on_multitimer");
	NRF_TIMER0->EVENTS_COMPARE[0] = 0;
	(void)NRF_TIMER0->EVENTS_COMPARE[0];
	
	if(nrf_gzll_get_mode() != NRF_GZLL_MODE_SUSPEND) {
		signal_callback_return_param.params.request.p_next = NULL;
		signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;
		nrf_gzll_set_mode(NRF_GZLL_MODE_SUSPEND);
		NRF_TIMER0->INTENSET = TIMER_INTENSET_COMPARE0_Msk;
		NRF_TIMER0->CC[0] = m_slot_length - 1000;
	} else {
		ASSERT(nrf_gzll_get_mode() == NRF_GZLL_MODE_SUSPEND);
		m_configure_next_event();
		signal_callback_return_param.params.request.p_next = &m_timeslot_request;
		signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END;
	}
}

nrf_radio_signal_callback_return_param_t *m_radio_callback(uint8_t signal_type) {
	//NRF_LOG_DEBUG("m_radio_callback");
	switch(signal_type) {
		case NRF_RADIO_CALLBACK_SIGNAL_TYPE_START:
			m_on_start();
			break;
		case NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO:
			signal_callback_return_param.params.request.p_next = NULL;
			signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;
			RADIO_IRQHandler();
			break;
		case NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0:
			m_on_multitimer();
			break;
		default:
			ASSERT(false);
	}
	
	return &signal_callback_return_param;
}

uint32_t gazell_sd_radio_init() {
	uint32_t err = NRF_SUCCESS;
	
	//err = softdevice_sys_evt_handler_set(sys_evt_dispatch);
	//APP_ERROR_CHECK(err);
	NRF_SDH_SOC_OBSERVER(m_soc_observer, 1, sys_evt_dispatch, NULL);
	
	err = sd_radio_session_open(m_radio_callback);
	if(err != NRF_SUCCESS) return err;
	
	m_configure_next_event();
	
	err = sd_radio_request(&m_timeslot_request);
	if(err != NRF_SUCCESS) {
		sd_radio_session_close();
		return err;
	}
	
	return NRF_SUCCESS;
}

void gazell_send() {
	NRF_LOG_DEBUG("gazell_send");
	char msg[] = "test";
	nrf_gzll_add_packet_to_tx_fifo(0, (uint8_t*)msg, sizeof(msg));
	nrf_gzll_flush_tx_fifo(0);
}

void nrf_gzll_device_tx_success(uint32_t pipe, nrf_gzll_device_tx_info_t tx_info) {
	NRF_LOG_DEBUG("nrf_gzll_device_tx_success");
	uint32_t ack_payload_length = ACK_PAYLOAD_LENGTH;
	if(tx_info.payload_received_in_ack) {
		if(nrf_gzll_fetch_packet_from_rx_fifo(pipe, ack_payload, &ack_payload_length)) {
			ASSERT(ack_payload_length == 1);
			m_cmd_recieved = true;
		}
	}
}

void nrf_gzll_device_tx_failed(uint32_t pipe, nrf_gzll_device_tx_info_t tx_info) {
	NRF_LOG_DEBUG("nrf_gzll_device_tx_failed");
}

static uint8_t data_payload[NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH];

void nrf_gzll_host_rx_data_ready(uint32_t pipe, nrf_gzll_host_rx_info_t rx_info) {
	NRF_LOG_DEBUG("nrf_gzll_host_rx_data_ready");
	
	uint32_t data_payload_length = NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH;
	
	nrf_gzll_fetch_packet_from_rx_fifo(pipe, data_payload, &data_payload_length);
	if(data_payload_length > 0 && data_payload_length <= 20) {
		//handle incoming data...
	}
}

void nrf_gzll_disabled() {
	NRF_LOG_DEBUG("nrf_gzll_disabled");
}

#endif

Related