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.

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers nRFBareRadio.cpp Source File

nRFBareRadio.cpp

00001 #include "nRFBareRadio.h"
00002 
00003 /*
00004 #ifdef TARGET_NRF52
00005 #define RADIO_RECEIVE_EVENT   EVENTS_CRCOK
00006 #else
00007 #define RADIO_RECEIVE_EVENT   EVENTS_END
00008 #endif*/
00009 
00010 RadioConfig::RadioConfig() {
00011     frequency = 2;                      
00012     rate = RADIO_RATE_2M;
00013     tx_power = RADIO_TX_0dBm;
00014     data_length = 32;                   // compatible to nRF24 (range 1-32)
00015     address_length = 5;                 // compatible to nRF24 (range 3-5)
00016     use_whitening = RADIO_NO_WHITENING; // compatible to nRF24 (no change)
00017     endianness = RADIO_BIGENDIAN;       // compatible to nRF24 (no change)
00018     crc_poly = 0x1021;                  // compatible to nRF24 (no change)
00019     crc_init = 0xFFFF;                  // compatible to nRF24 (no change)
00020 }
00021 
00022 
00023 
00024 // Partially based on a version by Manuel Caballero
00025 // https://os.mbed.com/users/mcm/
00026 
00027 BareRadio::BareRadio() {
00028     data_len = 32;
00029     for (int i=0; i<data_len; i++) packet[i] = 0;
00030     ConfigClock();
00031 }
00032 
00033 int BareRadio::ConfigClock() {
00034     int i;
00035     
00036     NRF_CLOCK->EVENTS_HFCLKSTARTED  =   0; // flag
00037     NRF_CLOCK->TASKS_HFCLKSTART     =   1; // start task
00038 
00039     for (i=0; i<10000; i++) {
00040         if (NRF_CLOCK->EVENTS_HFCLKSTARTED) return 1;
00041         wait_us(10);
00042     }
00043     return 0; // could not configure timer in 100ms
00044 }
00045 
00046 void BareRadio::Setup(int mode, RadioAddress address, RadioConfig& config) {
00047     // According to datasheet, power off and on causes a reset on all registers
00048     NRF_RADIO->POWER = ( RADIO_POWER_POWER_Disabled << RADIO_POWER_POWER_Pos ); // POWER OFF
00049     wait_us(10);
00050     NRF_RADIO->POWER = ( RADIO_POWER_POWER_Enabled  << RADIO_POWER_POWER_Pos ); // POWER ON
00051 
00052     // calculate the BASE0 length based on the total address length
00053     // total address length must be in the range [3,5]
00054     int BASE0_len = config.address_length - 1;
00055     if (BASE0_len < 2) BASE0_len = 2;
00056     if (BASE0_len > 4) BASE0_len = 4;
00057     
00058     data_len = config.data_length;
00059 
00060     // Configure data rate (0=1M, 1=2M, 2=250K, 3=BLE1M)
00061     NRF_RADIO->MODE  = ( config.rate << RADIO_MODE_MODE_Pos );
00062 
00063     // Configure packet: NO S0,S1 or Length fields & 8-bit preamble. 
00064     // Compatible to nRF24 without dynamic payload
00065     NRF_RADIO->PCNF0 = ( 0                            << RADIO_PCNF0_LFLEN_Pos  ) |
00066                        ( 0                            << RADIO_PCNF0_S0LEN_Pos  ) |
00067                        ( 0                            << RADIO_PCNF0_S1LEN_Pos  )
00068     #ifdef TARGET_NRF52
00069                      | ( RADIO_PCNF0_S1INCL_Automatic << RADIO_PCNF0_S1INCL_Pos )
00070                      | ( RADIO_PCNF0_PLEN_8bit        << RADIO_PCNF0_PLEN_Pos   )
00071     #endif
00072                      ;
00073 
00074     // Configure static payload length 
00075     NRF_RADIO->PCNF1 = ( config.data_length           << RADIO_PCNF1_MAXLEN_Pos) |  // this is to truncate the packet
00076                        ( config.data_length           << RADIO_PCNF1_STATLEN_Pos) | // this is to configure the radio
00077                        ( BASE0_len                    << RADIO_PCNF1_BALEN_Pos) |
00078                        ( config.endianness            << RADIO_PCNF1_ENDIAN_Pos) |
00079                        ( config.use_whitening         << RADIO_PCNF1_WHITEEN_Pos);
00080 
00081     // Whitening value
00082     NRF_RADIO->DATAWHITEIV = ( ( 0x55 & RADIO_DATAWHITEIV_DATAWHITEIV_Msk ) << RADIO_DATAWHITEIV_DATAWHITEIV_Pos );
00083 
00084     // Configure address Prefix0 and Base0
00085     unsigned int addr[5] = {address.A0, address.A1, address.A2, address.A3, address.A4};
00086     unsigned int base_address = 0;
00087     int i = 0;
00088     while (i<BASE0_len) {
00089         base_address |= (addr[i] << (i*8));
00090         i++;
00091     }
00092     NRF_RADIO->BASE0   = base_address;
00093     NRF_RADIO->PREFIX0 = ( ( addr[i] & RADIO_PREFIX0_AP0_Msk ) << RADIO_PREFIX0_AP0_Pos );
00094 
00095     // Initialize CRC ( two bytes )
00096     // Includes address field for nRF24 compatibility
00097     NRF_RADIO->CRCCNF    =   (RADIO_CRCCNF_LEN_Two << RADIO_CRCCNF_LEN_Pos) |
00098                            (RADIO_CRCCNF_SKIPADDR_Include << RADIO_CRCCNF_SKIPADDR_Pos);
00099 
00100     NRF_RADIO->CRCPOLY   =   ( config.crc_poly     << RADIO_CRCPOLY_CRCPOLY_Pos );
00101     NRF_RADIO->CRCINIT   =   ( config.crc_init     << RADIO_CRCINIT_CRCINIT_Pos );
00102 
00103     #ifdef TARGET_NRF52
00104     // Enable fast rampup, new in nRF52
00105     NRF_RADIO->MODECNF0  =   ( RADIO_MODECNF0_DTX_B0  << RADIO_MODECNF0_DTX_Pos ) |
00106                            ( RADIO_MODECNF0_RU_Fast << RADIO_MODECNF0_RU_Pos  );
00107     #endif
00108 
00109     NRF_RADIO->FREQUENCY =   ( ( config.frequency & RADIO_FREQUENCY_FREQUENCY_Msk ) << RADIO_FREQUENCY_FREQUENCY_Pos );      // Frequency = 2400 + FREQUENCY (MHz).
00110 
00111 
00112     // Configure address of the packet and logic address to use
00113     NRF_RADIO->PACKETPTR =   (unsigned int)&packet[0]; // Almost the same as (unsigned int)packet,
00114                                                      // but sizeof() will return normal pointer size
00115 
00116     // Transmit to address 0
00117     NRF_RADIO->TXADDRESS = ( 0 << RADIO_TXADDRESS_TXADDRESS_Pos);
00118 
00119     // Output Power: 0dBm  @2400MHz
00120     NRF_RADIO->TXPOWER   =   ( config.tx_power << RADIO_TXPOWER_TXPOWER_Pos );
00121                            
00122   // TX
00123   if (mode == RADIO_MODE_TX) {
00124         
00125         // Disable receiving address
00126         NRF_RADIO->RXADDRESSES = ( RADIO_RXADDRESSES_ADDR0_Disabled << RADIO_RXADDRESSES_ADDR0_Pos );
00127 
00128         // Configure shortcuts.
00129         NRF_RADIO->SHORTS    =   ( RADIO_SHORTS_READY_START_Enabled << RADIO_SHORTS_READY_START_Pos ) |
00130                                  ( RADIO_SHORTS_END_DISABLE_Enabled << RADIO_SHORTS_END_DISABLE_Pos );
00131   }
00132   
00133     // RX
00134     if (mode == RADIO_MODE_RX) {
00135         // Use logical address 0 (BASE0 + PREFIX0 byte 0)
00136         NRF_RADIO->RXADDRESSES = ( RADIO_RXADDRESSES_ADDR0_Enabled << RADIO_RXADDRESSES_ADDR0_Pos );
00137 
00138         // Configure shortcuts.
00139         NRF_RADIO->SHORTS    =   ( RADIO_SHORTS_READY_START_Enabled << RADIO_SHORTS_READY_START_Pos ) |
00140                                  ( RADIO_SHORTS_END_START_Enabled << RADIO_SHORTS_END_START_Pos );
00141                                  
00142         NRF_RADIO->TASKS_RXEN = 1; // Enable receiver
00143     }                           
00144 }
00145 
00146 
00147 void BareRadio::Transmit(char * data) {
00148     Transmit((unsigned char *)data);
00149 }
00150 void BareRadio::Transmit(unsigned char * data) {
00151     // data must be an array of (unsigned) char at least data_len elements wide
00152     for (int i=0; i<data_len; i++) packet[i] = data[i];
00153     
00154     // Transmits one packet
00155     NRF_RADIO->TASKS_TXEN                   =    1; // Enable transmitter
00156     while ( ( NRF_RADIO->EVENTS_DISABLED )  == 0 ); // Wait until transmission complete
00157     NRF_RADIO->EVENTS_DISABLED              =    0; // Clear flag
00158     // Time on air: 150 us      
00159 
00160 }
00161 
00162 int BareRadio::Receive(char * data) {
00163     return Receive((unsigned char *) data);
00164 }
00165 int BareRadio::Receive(unsigned char * data) {
00166     // returns true if a packet has arrived and data was replaced
00167     if ( NRF_RADIO->EVENTS_END == 1 ) {
00168         NRF_RADIO->EVENTS_END = 0;
00169         if (NRF_RADIO->CRCSTATUS) {
00170             for (int i=0; i<data_len; i++) data[i] = packet[i];
00171             return 1;
00172         }
00173     }
00174     return 0;
00175     
00176 }