Hello,
I am implementing a radio interface with a master and a slave. the master sends a synchronization frame every 1ms. this way the slave can transmit data for 500us, every 1ms.
the principle works well, but my slave sometimes receives corrupted packets. he therefore loses an opportunity to transmit information.
Is there any way to make the link more robust?
here is the configuration:
Thanks for help
#define RADIO_CHANNEL 0
#define RADIO_MODE NRF_RADIO_MODE_NRF_2MBIT
#define TIMER_INST_IDX 0
#define CHAN_TO_FREQ(_channel) (2400 + _channel)
// Radio config
nrf_radio_modecnf0_set(NRF_RADIO, true, RADIO_MODECNF0_DTX_Center);
nrf_radio_crc_configure(NRF_RADIO, RADIO_CRCCNF_LEN_Two, NRF_RADIO_CRC_ADDR_SKIP, 0);
nrf_radio_txaddress_set(NRF_RADIO, 0);
nrf_radio_rxaddresses_set(NRF_RADIO, 1);
nrf_radio_prefix0_set(NRF_RADIO, 0xAB);
nrf_radio_base0_set(NRF_RADIO, 0xABABABAB);
nrf_radio_packet_conf_t packet_conf;
uint16_t frequency;
// Configure sync packet
memset(&packet_conf, 0, sizeof(packet_conf));
packet_conf.lflen = 8;
packet_conf.maxlen = (sizeof(tx_packet) - 1);
packet_conf.statlen = 0;
packet_conf.balen = 4;
packet_conf.big_endian = true;
packet_conf.whiteen = true;
packet_conf.plen = NRF_RADIO_PREAMBLE_LENGTH_16BIT;
total_payload_size = 2 + (packet_conf.balen + 1) + 1 + packet_conf.maxlen;
nrf_radio_packet_configure(NRF_RADIO, &packet_conf);
nrf_radio_mode_set(NRF_RADIO, RADIO_MODE);
nrf_radio_txpower_set(NRF_RADIO, RADIO_TXPOWER_TXPOWER_Pos8dBm);
frequency = CHAN_TO_FREQ(RADIO_CHANNEL);
nrf_radio_frequency_set(NRF_RADIO, frequency);
/* Includes -----------------------------------------------------------------*/
#include "hidBridgeHostInt_rfCtrl.h"
#include <zephyr/sys/byteorder.h>
#include <zephyr/irq.h>
#include <hal/nrf_radio.h>
#include <nrfx_timer.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
#include "hidBridge_common.h"
#include "debugLog.h"
/* Global variables ---------------------------------------------------------*/
#define RX_BUFF_SIZE MAX(HID_REPORT_ABS_VAL_SIZE, HID_REPORT_BTN_EVT_SIZE) + COM_HEADER_SIZE
#define TX_BUFF_SIZE MAX(HID_REPORT_ABS_VAL_SIZE, HID_REPORT_BTN_EVT_SIZE) + COM_HEADER_SIZE
#define BUFF_SIZE HIDPP36_IN_OUT_REPORT_SIZE + COM_HEADER_SIZE
#define RADIO_CHANNEL 0
#define RADIO_MODE NRF_RADIO_MODE_NRF_2MBIT
#define TIMER_INST_IDX 0
#define CHAN_TO_FREQ(_channel) (2400 + _channel)
#define SYNC_PACKET 0x33
#define LEN_OFFSET 0
#define DATA_OFFSET 1
/* Private constants --------------------------------------------------------*/
/* Private macros -----------------------------------------------------------*/
/* Private typedefs ---------------------------------------------------------*/
/* Private variables --------------------------------------------------------*/
static bool mb_radioModeTX = true;
static bool mb_dataToSend = false;
// Buffer for the radio TX packet
static uint8_t tx_packet[BUFF_SIZE] = {0};
// Buffer for the radio RX packet.
static uint8_t rx_packet[BUFF_SIZE] = {0};
// Number of transmitted packets.
static uint32_t tx_packet_cnt = 0;
// Number of received packets with valid CRC.
static uint32_t rx_packet_cnt = 0;
// Total payload size
static uint16_t total_payload_size;
/* Private prototypes -------------------------------------------------------*/
static void
button_cb (uint32_t button_state, uint32_t has_changed);
static void
timer_handler (nrf_timer_event_t event_type, void * p_context);
static void
clock_init (void);
void
radio_handler (const void *context);
static void
radio_disable (void);
static void
radio_enableTx (void);
static void
radio_enableRx (void);
/* Public functions ---------------------------------------------------------*/
int16_t
hidBridgeHostInt_rfCtrl_init (void)
{
nrfx_err_t status;
int ret;
debugLog_subscribe(__FILE__, DEBUGLOG_LEVEL_Info);
clock_init();
irq_connect_dynamic(RADIO_IRQn, IRQ_PRIO_LOWEST, radio_handler, NULL, 0);
irq_enable(RADIO_IRQn);
// Radio config
nrf_radio_modecnf0_set(NRF_RADIO, true, RADIO_MODECNF0_DTX_Center);
nrf_radio_crc_configure(NRF_RADIO, RADIO_CRCCNF_LEN_Two, NRF_RADIO_CRC_ADDR_SKIP, 0);
nrf_radio_txaddress_set(NRF_RADIO, 0);
nrf_radio_rxaddresses_set(NRF_RADIO, 1);
nrf_radio_prefix0_set(NRF_RADIO, 0xAB);
nrf_radio_base0_set(NRF_RADIO, 0xABABABAB);
nrf_radio_packet_conf_t packet_conf;
uint16_t frequency;
// Configure sync packet
memset(&packet_conf, 0, sizeof(packet_conf));
packet_conf.lflen = 8;
packet_conf.maxlen = (sizeof(tx_packet) - 1);
packet_conf.statlen = 0;
packet_conf.balen = 4;
packet_conf.big_endian = true;
packet_conf.whiteen = true;
packet_conf.plen = NRF_RADIO_PREAMBLE_LENGTH_16BIT;
total_payload_size = 2 + (packet_conf.balen + 1) + 1 + packet_conf.maxlen;
nrf_radio_packet_configure(NRF_RADIO, &packet_conf);
nrf_radio_mode_set(NRF_RADIO, RADIO_MODE);
nrf_radio_txpower_set(NRF_RADIO, RADIO_TXPOWER_TXPOWER_Pos8dBm);
frequency = CHAN_TO_FREQ(RADIO_CHANNEL);
nrf_radio_frequency_set(NRF_RADIO, frequency);
dk_leds_init(); // only for test
dk_buttons_init(button_cb);
IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_TIMER_INST_GET(TIMER_INST_IDX)), IRQ_PRIO_LOWEST,
NRFX_TIMER_INST_HANDLER_GET(TIMER_INST_IDX), 0, 0);
nrfx_timer_t timer_inst = NRFX_TIMER_INSTANCE(TIMER_INST_IDX);
uint32_t base_frequency = NRF_TIMER_BASE_FREQUENCY_GET(timer_inst.p_reg);
nrfx_timer_config_t config = NRFX_TIMER_DEFAULT_CONFIG(base_frequency);
config.bit_width = NRF_TIMER_BIT_WIDTH_32;
config.p_context = "Some context";
status = nrfx_timer_init(&timer_inst, &config, timer_handler);
NRFX_ASSERT(status == NRFX_SUCCESS);
nrfx_timer_clear(&timer_inst);
uint32_t desired_ticks = nrfx_timer_us_to_ticks(&timer_inst, 500);
nrfx_timer_extended_compare(&timer_inst, NRF_TIMER_CC_CHANNEL0, desired_ticks,
NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
nrfx_timer_enable(&timer_inst);
// Success
return 0;
}
void
hidBridgeHostInt_rfCtrl_sendData (uint8_t *p_data, uint16_t length)
{
if (mb_dataToSend == false)
{
mb_dataToSend = true;
tx_packet[LEN_OFFSET] = length;
memcpy(&tx_packet[DATA_OFFSET], p_data, length);
}
else
{
log_error("Interface Busy - lost data");
}
}
void
radio_handler (const void *context)
{
const struct radio_test_config *config =
(const struct radio_test_config *) context;
if (nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_CRCOK)) {
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CRCOK);
if (false == mb_radioModeTX)
{
if (COM_HEADER_DATA_ABS_VAL == rx_packet[DATA_OFFSET])
{
log_info("RX COM_HEADER_DATA_ABS_VAL");
}
else if (COM_HEADER_DATA_BTN_EVT == rx_packet[DATA_OFFSET])
{
log_info("RX COM_HEADER_DATA_BTN_EVT");
}
else
{
log_error("unknown packet type");
}
rx_packet_cnt++;
}
}
else if (nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_END)) {
dk_set_led(2,true);
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_END);
if (true == mb_radioModeTX)
{
tx_packet_cnt++;
}
}
else
{
log_error("not handle event");
}
}
/* Private functions --------------------------------------------------------*/
static void
timer_handler (nrf_timer_event_t event_type, void * p_context)
{
if(event_type == NRF_TIMER_EVENT_COMPARE0)
{
char * p_msg = p_context;
dk_set_led(1,mb_radioModeTX);
if (false == mb_radioModeTX)
{
radio_disable();
radio_enableTx();
mb_radioModeTX = true;
}
else
{
radio_disable();
radio_enableRx();
mb_radioModeTX = false;
}
}
}
static void
clock_init (void)
{
int err;
int res;
struct onoff_manager *clk_mgr;
struct onoff_client clk_cli;
clk_mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF);
if (!clk_mgr) {
log_error("Unable to get the Clock manager");
return;
}
sys_notify_init_spinwait(&clk_cli.notify);
err = onoff_request(clk_mgr, &clk_cli);
if (err < 0) {
log_error("Clock request failed: %d", err);
return;
}
do {
err = sys_notify_fetch_result(&clk_cli.notify, &res);
if (!err && res) {
log_error("Clock could not be started: %d", res);
return;
}
} while (err);
log_info("Clock has started");
}
static void
radio_disable (void)
{
nrf_radio_shorts_set(NRF_RADIO, 0);
nrf_radio_int_disable(NRF_RADIO, ~0);
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_DISABLED);
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
while (!nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_DISABLED)) {
/* Do nothing */ // TODO: not blocking fct !!!
}
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_DISABLED);
}
static void
radio_enableTx (void)
{
nrf_radio_packetptr_set(NRF_RADIO, tx_packet);
nrf_radio_shorts_set(NRF_RADIO, NRF_RADIO_SHORT_READY_START_MASK);
nrf_radio_int_enable(NRF_RADIO, NRF_RADIO_INT_END_MASK);
if (mb_dataToSend == false)
{
tx_packet[LEN_OFFSET] = 1;
tx_packet[DATA_OFFSET] = SYNC_PACKET;
}
else
{
mb_dataToSend = false;
}
dk_set_led(2,false);
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_TXEN);
}
static void
radio_enableRx (void)
{
nrf_radio_shorts_set(NRF_RADIO,
NRF_RADIO_SHORT_READY_START_MASK |
NRF_RADIO_SHORT_END_START_MASK);
nrf_radio_packetptr_set(NRF_RADIO, rx_packet);
nrf_radio_int_enable(NRF_RADIO, NRF_RADIO_INT_CRCOK_MASK);
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_RXEN);
}
/* Includes -----------------------------------------------------------------*/
#include <zephyr/sys/byteorder.h>
#include <zephyr/irq.h>
#include <hal/nrf_radio.h>
#include <nrfx_timer.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
#include "hidBridge_common.h"
#include "debugLog.h"
/* Global variables ---------------------------------------------------------*/
#define RX_BUFF_SIZE MAX(HID_REPORT_ABS_VAL_SIZE, HID_REPORT_BTN_EVT_SIZE) + COM_HEADER_SIZE
#define TX_BUFF_SIZE MAX(HID_REPORT_ABS_VAL_SIZE, HID_REPORT_BTN_EVT_SIZE) + COM_HEADER_SIZE
#define BUFF_SIZE HIDPP36_IN_OUT_REPORT_SIZE + COM_HEADER_SIZE
#define RADIO_CHANNEL 0
#define RADIO_MODE NRF_RADIO_MODE_NRF_2MBIT
#define TIMER_INST_IDX 0
#define CHAN_TO_FREQ(_channel) (2400 + _channel)
#define SYNC_PACKET 0x33
#define RX_DELAY_US 400
#define TX_DELAY_US 400
#define LEN_OFFSET 0
#define DATA_OFFSET 1
/* Private constants --------------------------------------------------------*/
/* Private macros -----------------------------------------------------------*/
/* Private typedefs ---------------------------------------------------------*/
/* Private variables --------------------------------------------------------*/
static bool mb_radioModeTX = false;
static bool mb_dataToSend = false;
// Buffer for the radio TX packet
static uint8_t tx_packet[BUFF_SIZE] = {0};
static uint8_t tx_length = 0;
// Buffer for the radio RX packet.
static uint8_t rx_packet[BUFF_SIZE] = {0};
// Number of transmitted packets.
static uint32_t tx_packet_cnt = 0;
// Number of received packets with valid CRC.
static uint32_t rx_packet_cnt = 0;
// Total payload size
static uint16_t total_payload_size;
static nrfx_timer_t m_timer_inst = NRFX_TIMER_INSTANCE(TIMER_INST_IDX);
/* Private prototypes -------------------------------------------------------*/
static void
button_cb (uint32_t button_state, uint32_t has_changed);
static void
timer_handler (nrf_timer_event_t event_type, void * p_context);
static void
clock_init (void);
void
radio_handler (const void *context);
static void
radio_disable (void);
static void
radio_enableTx (void);
static void
radio_enableRx (void);
static void
startTimer (uint32_t us_delay);
/* Public functions ---------------------------------------------------------*/
int16_t
hidBridgeDevInt_rfCtrl_init (void)
{
nrfx_err_t status;
int ret;
debugLog_subscribe(__FILE__, DEBUGLOG_LEVEL_Info);
clock_init();
irq_connect_dynamic(RADIO_IRQn, IRQ_PRIO_LOWEST, radio_handler, NULL, 0);
irq_enable(RADIO_IRQn);
// Radio config
nrf_radio_modecnf0_set(NRF_RADIO, true, RADIO_MODECNF0_DTX_Center);
nrf_radio_crc_configure(NRF_RADIO, RADIO_CRCCNF_LEN_Two, NRF_RADIO_CRC_ADDR_SKIP, 0);
nrf_radio_txaddress_set(NRF_RADIO, 0);
nrf_radio_rxaddresses_set(NRF_RADIO, 1);
nrf_radio_prefix0_set(NRF_RADIO, 0xAB);
nrf_radio_base0_set(NRF_RADIO, 0xABABABAB);
nrf_radio_packet_conf_t packet_conf;
uint16_t frequency;
// Configure sync packet
memset(&packet_conf, 0, sizeof(packet_conf));
packet_conf.lflen = 8;
packet_conf.maxlen = (sizeof(tx_packet) - 1);
packet_conf.statlen = 0;
packet_conf.balen = 4;
packet_conf.big_endian = true;
packet_conf.whiteen = true;
packet_conf.plen = NRF_RADIO_PREAMBLE_LENGTH_16BIT;
total_payload_size = 2 + (packet_conf.balen + 1) + 1 + packet_conf.maxlen;
nrf_radio_packet_configure(NRF_RADIO, &packet_conf);
nrf_radio_mode_set(NRF_RADIO, RADIO_MODE);
nrf_radio_txpower_set(NRF_RADIO, RADIO_TXPOWER_TXPOWER_Pos8dBm);
frequency = CHAN_TO_FREQ(RADIO_CHANNEL);
nrf_radio_frequency_set(NRF_RADIO, frequency);
radio_disable();
radio_enableRx();
dk_leds_init(); // TODO: remove only for test
dk_buttons_init(button_cb);
IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_TIMER_INST_GET(TIMER_INST_IDX)), IRQ_PRIO_LOWEST,
NRFX_TIMER_INST_HANDLER_GET(TIMER_INST_IDX), 0, 0);
uint32_t base_frequency = NRF_TIMER_BASE_FREQUENCY_GET(m_timer_inst.p_reg);
nrfx_timer_config_t config = NRFX_TIMER_DEFAULT_CONFIG(base_frequency);
config.bit_width = NRF_TIMER_BIT_WIDTH_32;
config.p_context = "Some context";
status = nrfx_timer_init(&m_timer_inst, &config, timer_handler);
NRFX_ASSERT(status == NRFX_SUCCESS);
nrfx_timer_clear(&m_timer_inst);
// Success
return 0;
}
void
hidBridgeDevInt_rfCtrl_sendData (uint8_t *p_data, uint16_t length)
{
if ((mb_dataToSend == false) && (length < BUFF_SIZE))
{
tx_packet[LEN_OFFSET] = length;
memcpy(&tx_packet[DATA_OFFSET], p_data, length);
mb_dataToSend = true;
// start transmission if radio already configure in tx mode
if (true == mb_radioModeTX)
{
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_START);
}
}
else
{
log_error("RF interface busy or length to long");
}
}
void
radio_handler (const void *context)
{
const struct radio_test_config *config =
(const struct radio_test_config *) context;
if (nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_CRCOK)) {
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CRCOK);
dk_set_led(0,false);
if (false == mb_radioModeTX)
{
if (SYNC_PACKET == rx_packet[DATA_OFFSET])
{
startTimer (RX_DELAY_US);
rx_packet_cnt++;
if (rx_packet_cnt >= 1000)
{
log_info("SYNC 1s");
rx_packet_cnt = 0;
}
}
else
{
log_info("RX DATA");
}
dk_set_led(0,true);
}
}
else if (nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_END))
{
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_END);
mb_dataToSend = false;
if (true == mb_radioModeTX)
{
tx_packet_cnt++;
}
}
else if (nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_READY))
{
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_READY);
dk_set_led(2,mb_radioModeTX);
}
else
{
log_error("not handle event");
}
}
/* Private functions --------------------------------------------------------*/
static void
timer_handler (nrf_timer_event_t event_type, void * p_context)
{
if(event_type == NRF_TIMER_EVENT_COMPARE0)
{
char * p_msg = p_context;
dk_set_led(1,(mb_radioModeTX));
if (false == mb_radioModeTX)
{
startTimer (TX_DELAY_US);
radio_disable();
radio_enableTx();
mb_radioModeTX = true;
}
else
{
radio_disable();
radio_enableRx();
mb_radioModeTX = false;
}
}
}
static void
clock_init (void)
{
int err;
int res;
struct onoff_manager *clk_mgr;
struct onoff_client clk_cli;
clk_mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF);
if (!clk_mgr) {
log_error("Unable to get the Clock manager");
return;
}
sys_notify_init_spinwait(&clk_cli.notify);
err = onoff_request(clk_mgr, &clk_cli);
if (err < 0) {
log_error("Clock request failed: %d", err);
return;
}
do {
err = sys_notify_fetch_result(&clk_cli.notify, &res);
if (!err && res) {
log_error("Clock could not be started: %d", res);
return;
}
} while (err);
log_info("Clock has started");
}
static void
radio_disable (void)
{
nrf_radio_shorts_set(NRF_RADIO, 0);
nrf_radio_int_disable(NRF_RADIO, ~0);
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_DISABLED);
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
while (!nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_DISABLED)) {
/* Do nothing */ // TODO: not blocking fct !!!
}
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_DISABLED);
}
static void
radio_enableTx (void)
{
nrf_radio_packetptr_set(NRF_RADIO, tx_packet);
// SHORT ready and start if data to send already configured
if (mb_dataToSend == true)
{
nrf_radio_shorts_set(NRF_RADIO, NRF_RADIO_SHORT_READY_START_MASK);
}
nrf_radio_int_enable(NRF_RADIO, NRF_RADIO_INT_END_MASK);
nrf_radio_int_enable(NRF_RADIO, NRF_RADIO_INT_READY_MASK);
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_TXEN);
}
static void
radio_enableRx (void)
{
nrf_radio_shorts_set(NRF_RADIO,
NRF_RADIO_SHORT_READY_START_MASK |
NRF_RADIO_SHORT_END_START_MASK);
nrf_radio_packetptr_set(NRF_RADIO, rx_packet);
nrf_radio_int_enable(NRF_RADIO, NRF_RADIO_INT_CRCOK_MASK);
nrf_radio_int_enable(NRF_RADIO, NRF_RADIO_INT_READY_MASK);
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_RXEN);
}
static void
startTimer (uint32_t us_delay)
{
uint32_t desired_ticks = nrfx_timer_us_to_ticks(&m_timer_inst, us_delay);
nrfx_timer_clear(&m_timer_inst);
nrfx_timer_extended_compare(&m_timer_inst, NRF_TIMER_CC_CHANNEL0, desired_ticks,
NRF_TIMER_SHORT_COMPARE0_STOP_MASK|NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
nrfx_timer_enable(&m_timer_inst);
}