This is a work in progress for an NRF2401P
Dependents: NRF_receiver sender locker4 Weather_Station_Ofiicial ... more
About
This is a simple library to drive the nRF24l01+.
Hardware
This uses the commonly available breakout. The connections are shown below
Software
Use case: For a simple transmitter
tx code snipet
#include "NRF2401P.h" int main() { * * long long addr1=0xAB00CD; // setup address - any 5 byte number - same as RX * int channel =0x12; // [0-126] setup channel, must be same as RX * bool txOK; * char msg[32]; * char ackData[32]; * char len; * * // Setup * NRF2401P nrf1(PTD6,PTD7, PTD5,PTD4, PTC12); //mosi, miso, sclk, csn, ce) * nrf1.quickTxSetup(channel, addr1); // sets nrf24l01+ as transmitter * * // transmit * strcpy (msg, "Hello"); * txOK= nrf1.transmitData(msg,strlen(msg)); * * // read ack data if available * if (nrf1.isAckData()) { * len= nrf1.getRxData(ackData); // len is number of bytes in ackData * } *}
Use case: For a simple receiver
rx code snipet
#include "NRF2401P.h" *int main(){ * * long long addr1=0xAB00CD; // setup address - any 5 byte number - same as TX * int channel =0x12; // [0-126] setup channel, must be same as TX * bool txOK; * char msg[32]; * char ackData[32]; * char len; * * // Setup * NRF2401P nrf1(PTD6,PTD7, PTD5,PTD4, PTC12); //mosi, miso, sclk, csn, ce) * nrf1.quickRxSetup(channel, addr1); // sets nrf24l01+ as receiver, using pipe 1 * * // set ack data * sprintf(ackData,"Ack data"); * nrf1.acknowledgeData(ackData, strlen(ackData),1); // ack for pipe 1 * * // receive * while (! nrf1.isRxData()); // note this blocks until RX data * len= nrf1.getRxData(msg); // gets the message, len is length of msg * *}
Diff: NRF2401P.cpp
- Revision:
- 0:8fd0531ae0be
- Child:
- 1:ff53b1ac3bad
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NRF2401P.cpp Thu Jun 11 11:19:57 2015 +0000 @@ -0,0 +1,550 @@ +#include "mbed.h" +#include "NRF2401P.h" + +/** + *@section DESCRIPTION + * mbed NRF2401+ Library + *@section LICENSE + * Copyright (c) 2015, Malcolm McCulloch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * @file "NRF2401P.cpp" + */ + + + +NRF2401P::NRF2401P ( PinName mosi, PinName miso, PinName sclk, PinName _csn, PinName _ce ) : + csn( DigitalOut( _csn ) ), ce( DigitalOut( _ce ) ) +{ + addressWidth = 5; + pc = new Serial( USBTX, USBRX ); // tx, rx + sprintf(logMsg, "Initialise " ); + log(logMsg); + spi = new SPI( mosi, miso, sclk, NC ); //SPI (PinName mosi, PinName miso, PinName sclk, PinName _unused=NC) + spi->frequency( 10000000 ); // 1MHZ max 10 MHz + spi->format( 8, 0 ); // 0: 0e 08; 1: 0e 00; 2:0e 00 ;3:1c 00 + csn = 1; + ce = 0; + dynamic = false; + debug=false; + +}; + +/** +* writes to pc and waits +*/ +void NRF2401P::log (char *msg) +{ + if(debug) { + pc->printf("%s \t %s\n\r",statusString(), msg); + wait(0.1); + }; +} + +void NRF2401P::scratch() +{ + int status = 0; + int register1 = 0; + ce = 0; + for ( char i = 0; i < 24; i++ ) { + csn = 0; + //wait_us(100); + status = spi->write( i ); + register1 = spi->write( 0x00 ); + csn = 1; + sprintf(logMsg, " register %02x (%02x) = %02x", i, status, register1 ); + log(logMsg); + } + +} +/** +* Sets up a reciever using shockburst and dynamic payload. Uses pipe 1 +* defaults to 5 bytes +*/ +void NRF2401P::quickRxSetup(int channel,long long addr) +{ + setRadio(0,3); + setChannel(channel); + setRxMode(); + setPwrUp(); + setAddressWidth(3); + setRxAddress(addr,1); + setDynamicPayload(); + writeReg(0x02,0x03); // EN_RXADDR for P1 and P0 + writeReg(0x01,0x3f); // EN_AA regi for P1 and P0 + + ce=1; + wait (0.1f); +} +/** +* Sets up for receive of a message to address 0XA0A0A0 +*/ + +char NRF2401P::testReceive() +{ + char message[64]; + char width; + int channel = 0x12; + long long addr=0xA0B0C0; + debug = true; + quickRxSetup(channel, addr); + + while (1) { + while (!isRxData()) { + //wait(0.5); + }; + width=getRxData(message); + message[width]='\0'; + sprintf(logMsg,"Received= [%s]",message); + log(logMsg); + }; +} + +/** +* Sets up a transmitter using shockburst and dynamic payload. Uses pipe 1 +* defaults to 5 bytes +*/ +void NRF2401P::quickTxSetup(int channel,long long addr) +{ + setRadio(0,3); + setChannel(channel); + + setTxMode(); + setPwrUp(); + setDynamicPayload(); + setAddressWidth(3); + setTxAddress(addr); + ce=1; + wait (0.0016f); // wait for pll to settle +} + +/** +* Sets up for transmit of a message to address 0XA0A0A0 +*/ + +char NRF2401P::testTransmit() +{ + long long addr=0xA0B0C0; + int channel = 0x12; + char data[32] ; + int i=0; + quickRxSetup(channel, addr); + while (1) { + sprintf(data," packet %03d", i++ |100); + transmitData(data,18); + wait (1.0); + } + +} +/** +*Speed : +‘0x00’ – 1Mbps +‘0x01’ – 2Mbps +‘0x02’ – 250kbps +‘0x03’ – Reserved +Power: +'0x00' – -18dBm +'0x01' – -12dBm +'0x02' – -6dBm +'0x03' – 0dBm +*/ +char NRF2401P::setRadio(char speed,char power) +{ + char val=0; + sprintf(logMsg, "Set radio"); + log(logMsg); + if (speed & 0x02) { + val |= (1<<5); + } + val |= (speed & 0x01)<<3; + + val |= ((power &0x03)<<1); + writeReg (0x06,val); + +} +/** +Set RF_CH = chan; + +F0= 2400 + chan [MHz] +*/ +char NRF2401P::setChannel(char chan) +{ + sprintf(logMsg, "Set channel"); + log(logMsg); + writeReg (0x05,(chan&0x7f)); +} +/** +* Transmits width bytes of data. width <32 +*/ +char NRF2401P::transmitData( char *data, char width ) +{ + ce = 1; + csn = 0; + char address = 0XA0; + int i; + // set up for writing + status = spi->write( address ); + for ( i = 0; i <width; i++ ) { + spi->write( data[ i ] ); + } + csn = 1; + sprintf(logMsg, " Transmit data %d bytes to %02x (%02x) = %02x", width, address, status, data ); + log(logMsg); + return status; + +} + +/** +* sets acknowledge data width bytes of data. width <32 +*/ +char NRF2401P::acknowledgeData( char *data, char width, char pipe=1 ) +{ + ce = 1; + csn = 0; + writeReg(0x1d,0x06); // enable payload with ack + char address = 0XA8| (pipe&0x07); + int i; + // set up for writing + status = spi->write( address ); + for ( i = 0; i <width; i++ ) { + spi->write( data[ i ] ); + } + csn = 1; + sprintf(logMsg, " acknowledge data %d bytes to %02x (%02x) = %02x", width, address, status, *data ); + log(logMsg); + return status; + +} +/** +* Writes 1 byte data to a register +**/ +char NRF2401P::writeReg( char address, char data ) +{ + char status = 0; + char reg; + csn = 0; + address &= 0x1F; + reg = address | 0x20; + status = spi->write( reg ); + spi->write( data ); + csn = 1; + sprintf(logMsg, " register write %02x (%02x) = %02x", address, status, data ); + log(logMsg); + return status; +} +/** +* Writes width bytes data to a register, ls byte to ms byte /for adressess +**/ +char NRF2401P::writeReg( char address, char *data, char width ) +{ + char reg; + csn = 0; + int i; + // set up for writing + address &= 0x1F; + reg = address| 0x20; + status = spi->write( reg ); + for ( i = width - 1; i >= 0; i-- ) { + spi->write( data[ i ] ); + } + csn = 1; + sprintf(logMsg, " register write %d bytes to %02x (%02x) = %02x %02x %02x", width, address, status, data[0], data[1], data[2] ); + log(logMsg); + return status; +} +/** +* Reads 1 byte from a register +**/ +char NRF2401P::readReg( char address, char *data ) +{ + csn = 0; + address &= 0x1F; + status = spi->write( address ); + *data = spi->write( 0x00 ); + csn = 1; + // sprintf(logMsg, " register read %02x (%02x) = %02x", address, status, *data ); + // log(logMsg); + return status; +} +/** +* Clears the status flags RX_DR, TX_DS, MAX_RT +*/ +bool NRF2401P::clearStatus() +{ + status = writeReg(0x07,0x70); + sprintf(logMsg, "Clear status (%02x)", status ); + log(logMsg); +} +/** +* flushes TX FIFO and resets status flags +*/ +bool NRF2401P::flushTx() +{ + csn = 0; + status = spi->write( 0xE1 ); + csn = 1; + clearStatus(); + sprintf(logMsg, "Flush TX FIFO (%02x)", status ); + log(logMsg); + return; +} + +/** +* flushes RX FIFO and resets status flags +*/ +bool NRF2401P::flushRx() +{ + csn = 0; + status = spi->write( 0xE2 ); + status = spi->write( 0xFF ); //Update status + csn = 1; + sprintf(logMsg, "Flush RX FIFO (%02x)", status ); + log(logMsg); +} +/** +* Sets PRIM_RX = 0; +*/ +bool NRF2401P::setTxMode() +{ + char data; + char bit; + sprintf(logMsg, "Set Tx Mode"); + log(logMsg); + readReg( 0x00, &data ); + data &= ~( 1 << 0 ); + writeReg( 0x00, data ); + // check + readReg( 0x00, &data ); + bit = ( data >> 0 ) & 1; + ce=1; + clearStatus(); + flushTx(); + wait(0.003); + return ( bit == 0 ); +} + +/** +* Sets the number of bytes of the address width = 3,4,5 +*/ +bool NRF2401P::setAddressWidth( char width ) +{ + addressWidth = width; + if ( ( width > 5 ) || ( width < 3 ) ) + return false; + width -= 2; + return writeReg( 0x03, width ); + +} +/** +* Sets the address, uses addess width set (either 3,4 or 5) +*/ +char NRF2401P::setTxAddress( char *address ) +{ + writeReg( 0x0A, address, addressWidth ); //Write to RX_ADDR_P0 + return writeReg( 0x10, address, addressWidth ); //Write to TX_ADDR + +} + +/** +* Sets the address, uses addess width set (either 3,4 or 5) +*/ +char NRF2401P::setTxAddress( long long address ) +{ + + char buff[ 5 ]; + buff[ 0 ] = address & 0xff; + buff[ 1 ] = ( address >> 8 ) & 0xFF; + buff[ 2 ] = ( address >> 16 ) & 0xFF; + buff[ 3 ] = ( address >> 24 ) & 0xFF; + buff[ 4 ] = ( address >> 32 ) & 0xFF; + return setTxAddress( buff ); + +} + +/** +* Sets the address, uses addess width set (either 3,4 or 5) +*/ +char NRF2401P::setRxAddress( char *address, char pipe ) +{ + log ("Set Rx Address"); + char reg = 0x0A + pipe; + switch ( pipe ) { + case ( 0 ) : + case ( 1 ) : { + status = writeReg( reg, address, addressWidth ); //Write to RX_ADDR_P0 or _P1 + break; + } + case ( 2 ) : + case ( 3 ) : + case ( 4 ) : + case ( 5 ) : { + status = writeReg( reg, address, 1 ); //Write to RX_ADDR_P2 ... _P5 + break; + } + + } + // writeReg( 0x0A, address, addressWidth ); //Write to RX_ADDR_P0 + return status; + +} + +/** +* Sets the address of pipe (<=5), uses addess width set (either 3,4 or 5) +*/ +char NRF2401P::setRxAddress( long long address, char pipe ) +{ + char buff[ 5 ]; + buff[ 0 ] = address & 0xff; + buff[ 1 ] = ( address >> 8 ) & 0xFF; + buff[ 2 ] = ( address >> 16 ) & 0xFF; + buff[ 3 ] = ( address >> 24 ) & 0xFF; + buff[ 4 ] = ( address >> 32 ) & 0xFF; + return setRxAddress( buff, pipe ); +} + +bool NRF2401P::isRxData() +{ + readReg(0x07,&status); + bool isData = (status>>6)&0x01; + return isData; +} +/** +* returns the width of the dynamic payload +*/ +char NRF2401P::getRxWidth() +{ + char width; + if (dynamic) { + csn = 0; + status = spi->write( 0x60 ); + width = spi->write(0x00); + csn = 1; + + if (width>32) { + flushRx(); + width=0; + } + } else { + status = readReg(0x12,&width); // width of p1 + + } + // width=18; + return width; +} +/** +* return message in buffer, mem for buffer must have been allocated. +* Return value is number of bytes of buffer +*/ +char NRF2401P::getRxData(char * buffer) +{ + char address = 0x61; + char width; + width = getRxWidth(); + bool isData = (status>>6)&0x01; + if (isData) { + csn = 0; + int i; + // set up for reading + status = spi->write( address ); + for ( i = 0; i <= width; i++ ) { + buffer[i]=spi->write(0x00 ); + } + csn = 1; + sprintf(logMsg, "Receive data %d bytes", width ); + log(logMsg); + clearStatus(); + return width; + + } else { + sprintf(logMsg, "Receive NO data %d bytes", width ); + log(logMsg); + clearStatus(); + return 0; + } + +} + +/** +* Sets all the receive pipes to dynamic payload length +*/ +char NRF2401P::setDynamicPayload() +{ + dynamic = true; + writeReg (0x1D,0x04); + return(writeReg(0x1C, 0x1F)); +} +/** +* Sets PWR_UP = 1; +*/ +bool NRF2401P::setPwrUp() +{ + char data; + char bit; + ce=1; + readReg( 0x00, &data ); + data |= ( 0x02 ); + writeReg( 0x00, data ); + // check + readReg( 0x00, &data ); + bit = ( data >> 1 ) & 1; + sprintf(logMsg, "Set PWR_UP to %x", bit); + log(logMsg); + wait(0.005); // wait 5ms + return ( bit == 1 ); +} +/** +* Sets PRIM_RX = 0; +*/ +bool NRF2401P::setRxMode() +{ + char data; + char bit; + ce=1; + readReg( 0x00, &data ); + data |= ( 0x03 ); + writeReg( 0x00, data ); + // check + readReg( 0x00, &data ); + bit = ( data >> 0 ) & 1; + sprintf(logMsg, " set PRIM_RX to %x", bit); + log(logMsg); + clearStatus(); + flushRx(); + return ( bit == 1 ); +} +/** +* Prints status string +*/ +char * NRF2401P::statusString() +{ + char *msg; + msg = statusS; + if (((status>>1) & 0x07)==0x07) { + sprintf(msg,"RX empty"); + } else { + sprintf(msg,"pipe %02x",(status>>1) & 0x07); + } + + if ((status>>6)&0x01) strcat(msg," RX_DR,"); + if ((status>>5)&0x01) strcat(msg," TX_DS,"); + if ((status>>4)&0x01) strcat(msg," MAX_RT,"); + if ((status>>0)&0x01) strcat(msg," TX_FLL,"); + + return msg; +} \ No newline at end of file