nRFBareRadio is a library to use the Radio peripheral in a nRF51 or nRF52 Nordic microcontroller in "bare" mode transmitting raw packets, instead of the usual BLE protocols.

nRFBareRadio.cpp

Committer:
fbcosentino
Date:
2019-05-17
Revision:
1:fd37281bcdf7
Parent:
0:123cac2364c4

File content as of revision 1:fd37281bcdf7:

#include "nRFBareRadio.h"

/*
#ifdef TARGET_NRF52
#define RADIO_RECEIVE_EVENT   EVENTS_CRCOK
#else
#define RADIO_RECEIVE_EVENT   EVENTS_END
#endif*/

RadioConfig::RadioConfig() {
    frequency = 2;                      
    rate = RADIO_RATE_2M;
    tx_power = RADIO_TX_0dBm;
    data_length = 32;                   // compatible to nRF24 (range 1-32)
    address_length = 5;                 // compatible to nRF24 (range 3-5)
    use_whitening = RADIO_NO_WHITENING; // compatible to nRF24 (no change)
    endianness = RADIO_BIGENDIAN;       // compatible to nRF24 (no change)
    crc_poly = 0x1021;                  // compatible to nRF24 (no change)
    crc_init = 0xFFFF;                  // compatible to nRF24 (no change)
}



// Partially based on a version by Manuel Caballero
// https://os.mbed.com/users/mcm/

BareRadio::BareRadio() {
    data_len = 32;
    for (int i=0; i<data_len; i++) packet[i] = 0;
    ConfigClock();
}

int BareRadio::ConfigClock() {
    int i;
    
    NRF_CLOCK->EVENTS_HFCLKSTARTED  =   0; // flag
    NRF_CLOCK->TASKS_HFCLKSTART     =   1; // start task

    for (i=0; i<10000; i++) {
        if (NRF_CLOCK->EVENTS_HFCLKSTARTED) return 1;
        wait_us(10);
    }
    return 0; // could not configure timer in 100ms
}

void BareRadio::Setup(int mode, RadioAddress address, RadioConfig& config) {
    // According to datasheet, power off and on causes a reset on all registers
    NRF_RADIO->POWER = ( RADIO_POWER_POWER_Disabled << RADIO_POWER_POWER_Pos ); // POWER OFF
    wait_us(10);
    NRF_RADIO->POWER = ( RADIO_POWER_POWER_Enabled  << RADIO_POWER_POWER_Pos ); // POWER ON

    // calculate the BASE0 length based on the total address length
    // total address length must be in the range [3,5]
    int BASE0_len = config.address_length - 1;
    if (BASE0_len < 2) BASE0_len = 2;
    if (BASE0_len > 4) BASE0_len = 4;
    
    data_len = config.data_length;

    // Configure data rate (0=1M, 1=2M, 2=250K, 3=BLE1M)
    NRF_RADIO->MODE  = ( config.rate << RADIO_MODE_MODE_Pos );

    // Configure packet: NO S0,S1 or Length fields & 8-bit preamble. 
    // Compatible to nRF24 without dynamic payload
    NRF_RADIO->PCNF0 = ( 0                            << RADIO_PCNF0_LFLEN_Pos  ) |
                       ( 0                            << RADIO_PCNF0_S0LEN_Pos  ) |
                       ( 0                            << RADIO_PCNF0_S1LEN_Pos  )
    #ifdef TARGET_NRF52
                     | ( RADIO_PCNF0_S1INCL_Automatic << RADIO_PCNF0_S1INCL_Pos )
                     | ( RADIO_PCNF0_PLEN_8bit        << RADIO_PCNF0_PLEN_Pos   )
    #endif
                     ;

    // Configure static payload length 
    NRF_RADIO->PCNF1 = ( config.data_length           << RADIO_PCNF1_MAXLEN_Pos) |  // this is to truncate the packet
                       ( config.data_length           << RADIO_PCNF1_STATLEN_Pos) | // this is to configure the radio
                       ( BASE0_len                    << RADIO_PCNF1_BALEN_Pos) |
                       ( config.endianness            << RADIO_PCNF1_ENDIAN_Pos) |
                       ( config.use_whitening         << RADIO_PCNF1_WHITEEN_Pos);

    // Whitening value
    NRF_RADIO->DATAWHITEIV = ( ( 0x55 & RADIO_DATAWHITEIV_DATAWHITEIV_Msk ) << RADIO_DATAWHITEIV_DATAWHITEIV_Pos );

    // Configure address Prefix0 and Base0
    unsigned int addr[5] = {address.A0, address.A1, address.A2, address.A3, address.A4};
    unsigned int base_address = 0;
    int i = 0;
    while (i<BASE0_len) {
        base_address |= (addr[i] << (i*8));
        i++;
    }
    NRF_RADIO->BASE0   = base_address;
    NRF_RADIO->PREFIX0 = ( ( addr[i] & RADIO_PREFIX0_AP0_Msk ) << RADIO_PREFIX0_AP0_Pos );

    // Initialize CRC ( two bytes )
    // Includes address field for nRF24 compatibility
    NRF_RADIO->CRCCNF    =   (RADIO_CRCCNF_LEN_Two << RADIO_CRCCNF_LEN_Pos) |
                           (RADIO_CRCCNF_SKIPADDR_Include << RADIO_CRCCNF_SKIPADDR_Pos);

    NRF_RADIO->CRCPOLY   =   ( config.crc_poly     << RADIO_CRCPOLY_CRCPOLY_Pos );
    NRF_RADIO->CRCINIT   =   ( config.crc_init     << RADIO_CRCINIT_CRCINIT_Pos );

    #ifdef TARGET_NRF52
    // Enable fast rampup, new in nRF52
    NRF_RADIO->MODECNF0  =   ( RADIO_MODECNF0_DTX_B0  << RADIO_MODECNF0_DTX_Pos ) |
                           ( RADIO_MODECNF0_RU_Fast << RADIO_MODECNF0_RU_Pos  );
    #endif

    NRF_RADIO->FREQUENCY =   ( ( config.frequency & RADIO_FREQUENCY_FREQUENCY_Msk ) << RADIO_FREQUENCY_FREQUENCY_Pos );      // Frequency = 2400 + FREQUENCY (MHz).


    // Configure address of the packet and logic address to use
    NRF_RADIO->PACKETPTR =   (unsigned int)&packet[0]; // Almost the same as (unsigned int)packet,
                                                     // but sizeof() will return normal pointer size

    // Transmit to address 0
    NRF_RADIO->TXADDRESS = ( 0 << RADIO_TXADDRESS_TXADDRESS_Pos);

    // Output Power: 0dBm  @2400MHz
    NRF_RADIO->TXPOWER   =   ( config.tx_power << RADIO_TXPOWER_TXPOWER_Pos );
                           
  // TX
  if (mode == RADIO_MODE_TX) {
        
        // Disable receiving address
        NRF_RADIO->RXADDRESSES = ( RADIO_RXADDRESSES_ADDR0_Disabled << RADIO_RXADDRESSES_ADDR0_Pos );

        // Configure shortcuts.
        NRF_RADIO->SHORTS    =   ( RADIO_SHORTS_READY_START_Enabled << RADIO_SHORTS_READY_START_Pos ) |
                                 ( RADIO_SHORTS_END_DISABLE_Enabled << RADIO_SHORTS_END_DISABLE_Pos );
  }
  
    // RX
    if (mode == RADIO_MODE_RX) {
        // Use logical address 0 (BASE0 + PREFIX0 byte 0)
        NRF_RADIO->RXADDRESSES = ( RADIO_RXADDRESSES_ADDR0_Enabled << RADIO_RXADDRESSES_ADDR0_Pos );

        // Configure shortcuts.
        NRF_RADIO->SHORTS    =   ( RADIO_SHORTS_READY_START_Enabled << RADIO_SHORTS_READY_START_Pos ) |
                                 ( RADIO_SHORTS_END_START_Enabled << RADIO_SHORTS_END_START_Pos );
                                 
        NRF_RADIO->TASKS_RXEN = 1; // Enable receiver
    }                           
}


void BareRadio::Transmit(char * data) {
    Transmit((unsigned char *)data);
}
void BareRadio::Transmit(unsigned char * data) {
    // data must be an array of (unsigned) char at least data_len elements wide
    for (int i=0; i<data_len; i++) packet[i] = data[i];
    
    // Transmits one packet
    NRF_RADIO->TASKS_TXEN                   =    1; // Enable transmitter
    while ( ( NRF_RADIO->EVENTS_DISABLED )  == 0 ); // Wait until transmission complete
    NRF_RADIO->EVENTS_DISABLED              =    0; // Clear flag
    // Time on air: 150 us      

}

int BareRadio::Receive(char * data) {
    return Receive((unsigned char *) data);
}
int BareRadio::Receive(unsigned char * data) {
    // returns true if a packet has arrived and data was replaced
    if ( NRF_RADIO->EVENTS_END == 1 ) {
        NRF_RADIO->EVENTS_END = 0;
        if (NRF_RADIO->CRCSTATUS) {
            for (int i=0; i<data_len; i++) data[i] = packet[i];
            return 1;
        }
    }
    return 0;
    
}