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