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?

Parents
  • Hi,

    Please have a look at the reciever and transmitter examples found in SDK 11. These show how to send and recieve packets. Particularily the functions send_packet():

    void send_packet()
    {
        // send the packet:
        NRF_RADIO->EVENTS_READY = 0U;
        NRF_RADIO->TASKS_TXEN   = 1;
    
        while (NRF_RADIO->EVENTS_READY == 0U)
        {
            // wait
        }
        NRF_RADIO->EVENTS_END  = 0U;
        NRF_RADIO->TASKS_START = 1U;
    
        while (NRF_RADIO->EVENTS_END == 0U)
        {
            // wait
        }
    
        uint32_t err_code = bsp_indication_text_set(BSP_INDICATE_SENT_OK, "The packet was sent\n\r");
        APP_ERROR_CHECK(err_code);
    
        NRF_RADIO->EVENTS_DISABLED = 0U;
        // Disable radio
        NRF_RADIO->TASKS_DISABLE = 1U;
    
        while (NRF_RADIO->EVENTS_DISABLED == 0U)
        {
            // wait
        }
    }
    

    And read_packet():

    uint32_t read_packet()
    {
        uint32_t result = 0;
    
        NRF_RADIO->EVENTS_READY = 0U;
        // Enable radio and wait for ready
        NRF_RADIO->TASKS_RXEN = 1U;
    
        while (NRF_RADIO->EVENTS_READY == 0U)
        {
            // wait
        }
        NRF_RADIO->EVENTS_END = 0U;
        // Start listening and wait for address received event
        NRF_RADIO->TASKS_START = 1U;
    
        // Wait for end of packet or buttons state changed
        while (NRF_RADIO->EVENTS_END == 0U)
        {
            // wait
        }
    
        if (NRF_RADIO->CRCSTATUS == 1U)
        {
            result = packet;
        }
        NRF_RADIO->EVENTS_DISABLED = 0U;
        // Disable radio
        NRF_RADIO->TASKS_DISABLE = 1U;
    
        while (NRF_RADIO->EVENTS_DISABLED == 0U)
        {
            // wait
        }
        return result;
    }
    

    Should be interesting.

    Best regards,

    Øyvind

  • Yes, the HFCLK should definitely be active while the radio is doing its business. In the transmitter and reciever examples this is handled by having it always turned on.

Reply Children
No Data
Related