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.
Diff: nRFBareRadio.cpp
- Revision:
- 0:123cac2364c4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nRFBareRadio.cpp Fri May 17 13:36:56 2019 +0000 @@ -0,0 +1,176 @@ +#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; + +}