This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nRF51822 raw transmit/receive not working

Hi,

I'm trying to get a simple single packet transmit-receive working with the nRF51822. I have the following code shared between my transmitter and receiver:

#include <nrf51.h>
#include <nrf51_bitfields.h>

const int PACKET_S0_FIELD_SIZE = 0;
const int PACKET_LENGTH_FIELD_SIZE = 8;
const int PACKET_S1_FIELD_SIZE = 0;

const int PACKET_BASE_ADDRESS_LENGTH = 3;
const int PACKET_STATIC_LENGTH = 0;
const int PACKET_MAX_LENGTH = 128;

void RadioEnable()
{
	// All radio registers are reset when the peripheral is powered off/on.
	NRF_RADIO->POWER = 1;
}

void RadioDisable()
{
	NRF_RADIO->POWER = 0;
}


// Configure the radio in a BLE-like mode.
void RadioConfigure()
{
	// Maximum transmit power.
	NRF_RADIO->TXPOWER = RADIO_TXPOWER_TXPOWER_Pos4dBm << RADIO_TXPOWER_TXPOWER_Pos;

	// Modulation mode - compatable with BLE.
	NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit << RADIO_MODE_MODE_Pos;

	// I'll use a fixed frequency of 2407 MHz for now.
	NRF_RADIO->FREQUENCY = 7;
	// BLE sets the data whitening IV to the same as the frequency. I assume there is a good reason.
	NRF_RADIO->DATAWHITEIV = 7;

	// Radio address config. BLE uses a fixed "access address" of 0x8e89bed6. I'll just use a different one.

	// BLE version:
	//
	// NRF_RADIO->PREFIX0 = 0x0000008e;
	// NRF_RADIO->BASE0 = 0x89bed600;
	//
	// Our version:
	NRF_RADIO->PREFIX0 = 0x00000024;
	NRF_RADIO->BASE0 = 0x35f29300;

	// Transmit and receive with the same address (logical address 0).
	NRF_RADIO->TXADDRESS = 0;
	NRF_RADIO->RXADDRESSES = (RADIO_RXADDRESSES_ADDR0_Enabled << RADIO_RXADDRESSES_ADDR0_Pos);

	// Packet configuration
	NRF_RADIO->PCNF0 =
			(PACKET_S0_FIELD_SIZE << RADIO_PCNF0_S0LEN_Pos) |
			(PACKET_LENGTH_FIELD_SIZE << RADIO_PCNF0_LFLEN_Pos) |
			(PACKET_S1_FIELD_SIZE << RADIO_PCNF0_S1LEN_Pos);

	// Packet configuration
	NRF_RADIO->PCNF1 =
			(RADIO_PCNF1_WHITEEN_Enabled << RADIO_PCNF1_WHITEEN_Pos) |
			(RADIO_PCNF1_ENDIAN_Little << RADIO_PCNF1_ENDIAN_Pos) |
			(PACKET_BASE_ADDRESS_LENGTH << RADIO_PCNF1_BALEN_Pos) |
			(PACKET_STATIC_LENGTH << RADIO_PCNF1_STATLEN_Pos) |
			(PACKET_MAX_LENGTH << RADIO_PCNF1_MAXLEN_Pos);

	// CRC Config. BLE doesn't include the address in the CRC for some reason but I decided to.
	NRF_RADIO->CRCCNF  =
			(RADIO_CRCCNF_SKIPADDR_Include << RADIO_CRCCNF_SKIPADDR_Pos) |
			(RADIO_CRCCNF_LEN_Three << RADIO_CRCCNF_LEN_Pos);

	// Same 3-byte CRC as BLE.
	NRF_RADIO->CRCINIT = 0x00555555;
	NRF_RADIO->CRCPOLY = 0x0000065B;

	// Lock interframe spacing, so that the radio won't send too soon / start RX too early.
	// Not sure this is needed.
	NRF_RADIO->TIFS = 145;

	// Set up shortcuts.
	NRF_RADIO->SHORTS =
			(RADIO_SHORTS_READY_START_Enabled << RADIO_SHORTS_READY_START_Pos) |
			(RADIO_SHORTS_END_DISABLE_Enabled << RADIO_SHORTS_END_DISABLE_Pos);

}

// Space for transmission and reception. The extra byte is for the length.
static uint8_t packetBuffer[PACKET_MAX_LENGTH + 1];

void RadioTransmit(const vector<uint8_t>& packet)
{
	// Copy it into a buffer with its length.
	int len = packet.size();
	if (len > PACKET_MAX_LENGTH)
		len = PACKET_MAX_LENGTH;

	packetBuffer[0] = len;
	for (int i = 0; i < len; ++i)
		packetBuffer[i+1] = packet[i];

	// You always have to set the packet pointer.
	NRF_RADIO->PACKETPTR = reinterpret_cast<uint32_t>(packetBuffer);

	// Clear the disabled event.
	NRF_RADIO->EVENTS_DISABLED = 0;

	// Start the TXEN task. This will trigger the READY event.
	NRF_RADIO->TASKS_TXEN = 1;

	// A shortcut will then trigger the START task.
	// When finished, this will trigger the END event.
	// Another shortcut will start the DISABLE task, which will trigger the DISABLED event.
	// So we just wait for that.

	while (NRF_RADIO->EVENTS_DISABLED == 0)
	{
	}
}

// TODO: Use interrupts.
vector<uint8_t> RadioReceive()
{
	for (;;)
	{
		// You always have to set the packet pointer.
		NRF_RADIO->PACKETPTR = reinterpret_cast<uint32_t>(packetBuffer);

		// Clear the disabled event.
		NRF_RADIO->EVENTS_DISABLED = 0;

		// Start the RXEN task. This will trigger the READY event.
		NRF_RADIO->TASKS_RXEN = 1;

		// A shortcut will then trigger the START task.
		// When finished, this will trigger the END event.
		// Another shortcut will start the DISABLE task, which will trigger the DISABLED event.
		// So we just wait for that.

		while (NRF_RADIO->EVENTS_DISABLED == 0)
		{
		}

		if (NRF_RADIO->CRCSTATUS == 1)
			return vector<uint8_t>(packetBuffer + 1, packetBuffer + 1 + packetBuffer[0]);
	}
}

I transmit like this:

RadioEnable();
RadioConfigure();

// onButtonPress:
vector<uint8_t> packet = {0x01, 0x02, 0x03};
RadioTransmit(packet);

RadioTransmit() returns more or less immediately so I think it is working. To receive I do this:

RadioEnable();
RadioConfigure();

for (;;)
{
     vector<uint8_t> packet = RadioReceive();
     pc.printf("Got packet, length %d\n", packet.size());
}

Unfortunately it seems that RadioReceive() never returns. I'm not sure how to debug this. Can anyone see anything wrong with my code, or have any suggestions for debugging?

Related