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?