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@0:123cac2364c4, 2019-05-17 (annotated)
- Committer:
- fbcosentino
- Date:
- Fri May 17 13:36:56 2019 +0000
- Revision:
- 0:123cac2364c4
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.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
fbcosentino | 0:123cac2364c4 | 1 | #include "nRFBareRadio.h" |
fbcosentino | 0:123cac2364c4 | 2 | |
fbcosentino | 0:123cac2364c4 | 3 | /* |
fbcosentino | 0:123cac2364c4 | 4 | #ifdef TARGET_NRF52 |
fbcosentino | 0:123cac2364c4 | 5 | #define RADIO_RECEIVE_EVENT EVENTS_CRCOK |
fbcosentino | 0:123cac2364c4 | 6 | #else |
fbcosentino | 0:123cac2364c4 | 7 | #define RADIO_RECEIVE_EVENT EVENTS_END |
fbcosentino | 0:123cac2364c4 | 8 | #endif*/ |
fbcosentino | 0:123cac2364c4 | 9 | |
fbcosentino | 0:123cac2364c4 | 10 | RadioConfig::RadioConfig() { |
fbcosentino | 0:123cac2364c4 | 11 | frequency = 2; |
fbcosentino | 0:123cac2364c4 | 12 | rate = RADIO_RATE_2M; |
fbcosentino | 0:123cac2364c4 | 13 | tx_power = RADIO_TX_0dBm; |
fbcosentino | 0:123cac2364c4 | 14 | data_length = 32; // compatible to nRF24 (range 1-32) |
fbcosentino | 0:123cac2364c4 | 15 | address_length = 5; // compatible to nRF24 (range 3-5) |
fbcosentino | 0:123cac2364c4 | 16 | use_whitening = RADIO_NO_WHITENING; // compatible to nRF24 (no change) |
fbcosentino | 0:123cac2364c4 | 17 | endianness = RADIO_BIGENDIAN; // compatible to nRF24 (no change) |
fbcosentino | 0:123cac2364c4 | 18 | crc_poly = 0x1021; // compatible to nRF24 (no change) |
fbcosentino | 0:123cac2364c4 | 19 | crc_init = 0xFFFF; // compatible to nRF24 (no change) |
fbcosentino | 0:123cac2364c4 | 20 | } |
fbcosentino | 0:123cac2364c4 | 21 | |
fbcosentino | 0:123cac2364c4 | 22 | |
fbcosentino | 0:123cac2364c4 | 23 | |
fbcosentino | 0:123cac2364c4 | 24 | // Partially based on a version by Manuel Caballero |
fbcosentino | 0:123cac2364c4 | 25 | // https://os.mbed.com/users/mcm/ |
fbcosentino | 0:123cac2364c4 | 26 | |
fbcosentino | 0:123cac2364c4 | 27 | BareRadio::BareRadio() { |
fbcosentino | 0:123cac2364c4 | 28 | data_len = 32; |
fbcosentino | 0:123cac2364c4 | 29 | for (int i=0; i<data_len; i++) packet[i] = 0; |
fbcosentino | 0:123cac2364c4 | 30 | ConfigClock(); |
fbcosentino | 0:123cac2364c4 | 31 | } |
fbcosentino | 0:123cac2364c4 | 32 | |
fbcosentino | 0:123cac2364c4 | 33 | int BareRadio::ConfigClock() { |
fbcosentino | 0:123cac2364c4 | 34 | int i; |
fbcosentino | 0:123cac2364c4 | 35 | |
fbcosentino | 0:123cac2364c4 | 36 | NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; // flag |
fbcosentino | 0:123cac2364c4 | 37 | NRF_CLOCK->TASKS_HFCLKSTART = 1; // start task |
fbcosentino | 0:123cac2364c4 | 38 | |
fbcosentino | 0:123cac2364c4 | 39 | for (i=0; i<10000; i++) { |
fbcosentino | 0:123cac2364c4 | 40 | if (NRF_CLOCK->EVENTS_HFCLKSTARTED) return 1; |
fbcosentino | 0:123cac2364c4 | 41 | wait_us(10); |
fbcosentino | 0:123cac2364c4 | 42 | } |
fbcosentino | 0:123cac2364c4 | 43 | return 0; // could not configure timer in 100ms |
fbcosentino | 0:123cac2364c4 | 44 | } |
fbcosentino | 0:123cac2364c4 | 45 | |
fbcosentino | 0:123cac2364c4 | 46 | void BareRadio::Setup(int mode, RadioAddress address, RadioConfig& config) { |
fbcosentino | 0:123cac2364c4 | 47 | // According to datasheet, power off and on causes a reset on all registers |
fbcosentino | 0:123cac2364c4 | 48 | NRF_RADIO->POWER = ( RADIO_POWER_POWER_Disabled << RADIO_POWER_POWER_Pos ); // POWER OFF |
fbcosentino | 0:123cac2364c4 | 49 | wait_us(10); |
fbcosentino | 0:123cac2364c4 | 50 | NRF_RADIO->POWER = ( RADIO_POWER_POWER_Enabled << RADIO_POWER_POWER_Pos ); // POWER ON |
fbcosentino | 0:123cac2364c4 | 51 | |
fbcosentino | 0:123cac2364c4 | 52 | // calculate the BASE0 length based on the total address length |
fbcosentino | 0:123cac2364c4 | 53 | // total address length must be in the range [3,5] |
fbcosentino | 0:123cac2364c4 | 54 | int BASE0_len = config.address_length - 1; |
fbcosentino | 0:123cac2364c4 | 55 | if (BASE0_len < 2) BASE0_len = 2; |
fbcosentino | 0:123cac2364c4 | 56 | if (BASE0_len > 4) BASE0_len = 4; |
fbcosentino | 0:123cac2364c4 | 57 | |
fbcosentino | 0:123cac2364c4 | 58 | data_len = config.data_length; |
fbcosentino | 0:123cac2364c4 | 59 | |
fbcosentino | 0:123cac2364c4 | 60 | // Configure data rate (0=1M, 1=2M, 2=250K, 3=BLE1M) |
fbcosentino | 0:123cac2364c4 | 61 | NRF_RADIO->MODE = ( config.rate << RADIO_MODE_MODE_Pos ); |
fbcosentino | 0:123cac2364c4 | 62 | |
fbcosentino | 0:123cac2364c4 | 63 | // Configure packet: NO S0,S1 or Length fields & 8-bit preamble. |
fbcosentino | 0:123cac2364c4 | 64 | // Compatible to nRF24 without dynamic payload |
fbcosentino | 0:123cac2364c4 | 65 | NRF_RADIO->PCNF0 = ( 0 << RADIO_PCNF0_LFLEN_Pos ) | |
fbcosentino | 0:123cac2364c4 | 66 | ( 0 << RADIO_PCNF0_S0LEN_Pos ) | |
fbcosentino | 0:123cac2364c4 | 67 | ( 0 << RADIO_PCNF0_S1LEN_Pos ) |
fbcosentino | 0:123cac2364c4 | 68 | #ifdef TARGET_NRF52 |
fbcosentino | 0:123cac2364c4 | 69 | | ( RADIO_PCNF0_S1INCL_Automatic << RADIO_PCNF0_S1INCL_Pos ) |
fbcosentino | 0:123cac2364c4 | 70 | | ( RADIO_PCNF0_PLEN_8bit << RADIO_PCNF0_PLEN_Pos ) |
fbcosentino | 0:123cac2364c4 | 71 | #endif |
fbcosentino | 0:123cac2364c4 | 72 | ; |
fbcosentino | 0:123cac2364c4 | 73 | |
fbcosentino | 0:123cac2364c4 | 74 | // Configure static payload length |
fbcosentino | 0:123cac2364c4 | 75 | NRF_RADIO->PCNF1 = ( config.data_length << RADIO_PCNF1_MAXLEN_Pos) | // this is to truncate the packet |
fbcosentino | 0:123cac2364c4 | 76 | ( config.data_length << RADIO_PCNF1_STATLEN_Pos) | // this is to configure the radio |
fbcosentino | 0:123cac2364c4 | 77 | ( BASE0_len << RADIO_PCNF1_BALEN_Pos) | |
fbcosentino | 0:123cac2364c4 | 78 | ( config.endianness << RADIO_PCNF1_ENDIAN_Pos) | |
fbcosentino | 0:123cac2364c4 | 79 | ( config.use_whitening << RADIO_PCNF1_WHITEEN_Pos); |
fbcosentino | 0:123cac2364c4 | 80 | |
fbcosentino | 0:123cac2364c4 | 81 | // Whitening value |
fbcosentino | 0:123cac2364c4 | 82 | NRF_RADIO->DATAWHITEIV = ( ( 0x55 & RADIO_DATAWHITEIV_DATAWHITEIV_Msk ) << RADIO_DATAWHITEIV_DATAWHITEIV_Pos ); |
fbcosentino | 0:123cac2364c4 | 83 | |
fbcosentino | 0:123cac2364c4 | 84 | // Configure address Prefix0 and Base0 |
fbcosentino | 0:123cac2364c4 | 85 | unsigned int addr[5] = {address.A0, address.A1, address.A2, address.A3, address.A4}; |
fbcosentino | 0:123cac2364c4 | 86 | unsigned int base_address = 0; |
fbcosentino | 0:123cac2364c4 | 87 | int i = 0; |
fbcosentino | 0:123cac2364c4 | 88 | while (i<BASE0_len) { |
fbcosentino | 0:123cac2364c4 | 89 | base_address |= (addr[i] << (i*8)); |
fbcosentino | 0:123cac2364c4 | 90 | i++; |
fbcosentino | 0:123cac2364c4 | 91 | } |
fbcosentino | 0:123cac2364c4 | 92 | NRF_RADIO->BASE0 = base_address; |
fbcosentino | 0:123cac2364c4 | 93 | NRF_RADIO->PREFIX0 = ( ( addr[i] & RADIO_PREFIX0_AP0_Msk ) << RADIO_PREFIX0_AP0_Pos ); |
fbcosentino | 0:123cac2364c4 | 94 | |
fbcosentino | 0:123cac2364c4 | 95 | // Initialize CRC ( two bytes ) |
fbcosentino | 0:123cac2364c4 | 96 | // Includes address field for nRF24 compatibility |
fbcosentino | 0:123cac2364c4 | 97 | NRF_RADIO->CRCCNF = (RADIO_CRCCNF_LEN_Two << RADIO_CRCCNF_LEN_Pos) | |
fbcosentino | 0:123cac2364c4 | 98 | (RADIO_CRCCNF_SKIPADDR_Include << RADIO_CRCCNF_SKIPADDR_Pos); |
fbcosentino | 0:123cac2364c4 | 99 | |
fbcosentino | 0:123cac2364c4 | 100 | NRF_RADIO->CRCPOLY = ( config.crc_poly << RADIO_CRCPOLY_CRCPOLY_Pos ); |
fbcosentino | 0:123cac2364c4 | 101 | NRF_RADIO->CRCINIT = ( config.crc_init << RADIO_CRCINIT_CRCINIT_Pos ); |
fbcosentino | 0:123cac2364c4 | 102 | |
fbcosentino | 0:123cac2364c4 | 103 | #ifdef TARGET_NRF52 |
fbcosentino | 0:123cac2364c4 | 104 | // Enable fast rampup, new in nRF52 |
fbcosentino | 0:123cac2364c4 | 105 | NRF_RADIO->MODECNF0 = ( RADIO_MODECNF0_DTX_B0 << RADIO_MODECNF0_DTX_Pos ) | |
fbcosentino | 0:123cac2364c4 | 106 | ( RADIO_MODECNF0_RU_Fast << RADIO_MODECNF0_RU_Pos ); |
fbcosentino | 0:123cac2364c4 | 107 | #endif |
fbcosentino | 0:123cac2364c4 | 108 | |
fbcosentino | 0:123cac2364c4 | 109 | NRF_RADIO->FREQUENCY = ( ( config.frequency & RADIO_FREQUENCY_FREQUENCY_Msk ) << RADIO_FREQUENCY_FREQUENCY_Pos ); // Frequency = 2400 + FREQUENCY (MHz). |
fbcosentino | 0:123cac2364c4 | 110 | |
fbcosentino | 0:123cac2364c4 | 111 | |
fbcosentino | 0:123cac2364c4 | 112 | // Configure address of the packet and logic address to use |
fbcosentino | 0:123cac2364c4 | 113 | NRF_RADIO->PACKETPTR = (unsigned int)&packet[0]; // Almost the same as (unsigned int)packet, |
fbcosentino | 0:123cac2364c4 | 114 | // but sizeof() will return normal pointer size |
fbcosentino | 0:123cac2364c4 | 115 | |
fbcosentino | 0:123cac2364c4 | 116 | // Transmit to address 0 |
fbcosentino | 0:123cac2364c4 | 117 | NRF_RADIO->TXADDRESS = ( 0 << RADIO_TXADDRESS_TXADDRESS_Pos); |
fbcosentino | 0:123cac2364c4 | 118 | |
fbcosentino | 0:123cac2364c4 | 119 | // Output Power: 0dBm @2400MHz |
fbcosentino | 0:123cac2364c4 | 120 | NRF_RADIO->TXPOWER = ( config.tx_power << RADIO_TXPOWER_TXPOWER_Pos ); |
fbcosentino | 0:123cac2364c4 | 121 | |
fbcosentino | 0:123cac2364c4 | 122 | // TX |
fbcosentino | 0:123cac2364c4 | 123 | if (mode == RADIO_MODE_TX) { |
fbcosentino | 0:123cac2364c4 | 124 | |
fbcosentino | 0:123cac2364c4 | 125 | // Disable receiving address |
fbcosentino | 0:123cac2364c4 | 126 | NRF_RADIO->RXADDRESSES = ( RADIO_RXADDRESSES_ADDR0_Disabled << RADIO_RXADDRESSES_ADDR0_Pos ); |
fbcosentino | 0:123cac2364c4 | 127 | |
fbcosentino | 0:123cac2364c4 | 128 | // Configure shortcuts. |
fbcosentino | 0:123cac2364c4 | 129 | NRF_RADIO->SHORTS = ( RADIO_SHORTS_READY_START_Enabled << RADIO_SHORTS_READY_START_Pos ) | |
fbcosentino | 0:123cac2364c4 | 130 | ( RADIO_SHORTS_END_DISABLE_Enabled << RADIO_SHORTS_END_DISABLE_Pos ); |
fbcosentino | 0:123cac2364c4 | 131 | } |
fbcosentino | 0:123cac2364c4 | 132 | |
fbcosentino | 0:123cac2364c4 | 133 | // RX |
fbcosentino | 0:123cac2364c4 | 134 | if (mode == RADIO_MODE_RX) { |
fbcosentino | 0:123cac2364c4 | 135 | // Use logical address 0 (BASE0 + PREFIX0 byte 0) |
fbcosentino | 0:123cac2364c4 | 136 | NRF_RADIO->RXADDRESSES = ( RADIO_RXADDRESSES_ADDR0_Enabled << RADIO_RXADDRESSES_ADDR0_Pos ); |
fbcosentino | 0:123cac2364c4 | 137 | |
fbcosentino | 0:123cac2364c4 | 138 | // Configure shortcuts. |
fbcosentino | 0:123cac2364c4 | 139 | NRF_RADIO->SHORTS = ( RADIO_SHORTS_READY_START_Enabled << RADIO_SHORTS_READY_START_Pos ) | |
fbcosentino | 0:123cac2364c4 | 140 | ( RADIO_SHORTS_END_START_Enabled << RADIO_SHORTS_END_START_Pos ); |
fbcosentino | 0:123cac2364c4 | 141 | |
fbcosentino | 0:123cac2364c4 | 142 | NRF_RADIO->TASKS_RXEN = 1; // Enable receiver |
fbcosentino | 0:123cac2364c4 | 143 | } |
fbcosentino | 0:123cac2364c4 | 144 | } |
fbcosentino | 0:123cac2364c4 | 145 | |
fbcosentino | 0:123cac2364c4 | 146 | |
fbcosentino | 0:123cac2364c4 | 147 | void BareRadio::Transmit(char * data) { |
fbcosentino | 0:123cac2364c4 | 148 | Transmit((unsigned char *)data); |
fbcosentino | 0:123cac2364c4 | 149 | } |
fbcosentino | 0:123cac2364c4 | 150 | void BareRadio::Transmit(unsigned char * data) { |
fbcosentino | 0:123cac2364c4 | 151 | // data must be an array of (unsigned) char at least data_len elements wide |
fbcosentino | 0:123cac2364c4 | 152 | for (int i=0; i<data_len; i++) packet[i] = data[i]; |
fbcosentino | 0:123cac2364c4 | 153 | |
fbcosentino | 0:123cac2364c4 | 154 | // Transmits one packet |
fbcosentino | 0:123cac2364c4 | 155 | NRF_RADIO->TASKS_TXEN = 1; // Enable transmitter |
fbcosentino | 0:123cac2364c4 | 156 | while ( ( NRF_RADIO->EVENTS_DISABLED ) == 0 ); // Wait until transmission complete |
fbcosentino | 0:123cac2364c4 | 157 | NRF_RADIO->EVENTS_DISABLED = 0; // Clear flag |
fbcosentino | 0:123cac2364c4 | 158 | // Time on air: 150 us |
fbcosentino | 0:123cac2364c4 | 159 | |
fbcosentino | 0:123cac2364c4 | 160 | } |
fbcosentino | 0:123cac2364c4 | 161 | |
fbcosentino | 0:123cac2364c4 | 162 | int BareRadio::Receive(char * data) { |
fbcosentino | 0:123cac2364c4 | 163 | return Receive((unsigned char *) data); |
fbcosentino | 0:123cac2364c4 | 164 | } |
fbcosentino | 0:123cac2364c4 | 165 | int BareRadio::Receive(unsigned char * data) { |
fbcosentino | 0:123cac2364c4 | 166 | // returns true if a packet has arrived and data was replaced |
fbcosentino | 0:123cac2364c4 | 167 | if ( NRF_RADIO->EVENTS_END == 1 ) { |
fbcosentino | 0:123cac2364c4 | 168 | NRF_RADIO->EVENTS_END = 0; |
fbcosentino | 0:123cac2364c4 | 169 | if (NRF_RADIO->CRCSTATUS) { |
fbcosentino | 0:123cac2364c4 | 170 | for (int i=0; i<data_len; i++) data[i] = packet[i]; |
fbcosentino | 0:123cac2364c4 | 171 | return 1; |
fbcosentino | 0:123cac2364c4 | 172 | } |
fbcosentino | 0:123cac2364c4 | 173 | } |
fbcosentino | 0:123cac2364c4 | 174 | return 0; |
fbcosentino | 0:123cac2364c4 | 175 | |
fbcosentino | 0:123cac2364c4 | 176 | } |