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 * *}
NRF2401P.cpp
- Committer:
- epgmdm
- Date:
- 2016-02-08
- Revision:
- 18:220df99d2d41
- Parent:
- 17:b132fc1a27d2
- Child:
- 19:813161fd59a2
File content as of revision 18:220df99d2d41:
/** *@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" */ #include "mbed.h" #include "NRF2401P.h" #include "nRF24l01.h" 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 if (debug) { 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; } void NRF2401P::log(char *msg) { if(debug) { printf("\t <%s \t %s>\n\r", statusString(), msg); wait(0.01); } } 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); } } /** * start here to configure the basics of the NRF */ void NRF2401P::start() { writeReg(CONFIG, 0x0c); // set 16 bit crc setTxRetry(0x05, 0x0f); // 500 uS, 15 retries setRadio(0, 0x03); // 1MB/S 0dB setDynamicPayload(); setChannel(76); // should be clear? setAddressWidth(5); flushRx(); flushTx(); setPwrUp(); setTxMode(); // just make sure no spurious reads.... } /** * Sets up a receiver using shockburst and dynamic payload. Uses pipe 0 * defaults to 5 bytes */ void NRF2401P::quickRxSetup(int channel,long long addrRx) { start(); setChannel(channel); // setRxAddress(addrRx,1); setRxAddress(addrRx,0); setRxMode(); ce=1; wait(0.001f); writeReg(FEATURE,0x06); // Enable dynamic ack packets } /** * 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); } } char NRF2401P::setTxRetry(char delay, char numTries) { char val = (delay&0xf)<<4 | (numTries&0xf); char chk; writeReg(SETUP_RETR, val); readReg(SETUP_RETR, &chk); if (chk&0xff == val) { return 0; } else { return 1; } } /** * Sets up a transmitter using shockburst and dynamic payload. Uses pipe 1 * defaults to 5 bytes */ void NRF2401P::quickTxSetup(int channel,long long addr) { start(); setChannel(channel); setTxAddress(addr); setTxMode(); writeReg(FEATURE,0x06); ce=1; wait (0.0016f); // wait for pll to settle flushTx(); clearStatus(); } /** * 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); } } char NRF2401P::setRadio(char speed, char power) { char val=0, chk=0; if (debug) { sprintf(logMsg, "Set radio"); log(logMsg); } if (speed & 0x02) { val |= (1<<5); } val |= (speed & 0x01)<<3; val |= ((power & 0x03)<<1); printf("\n\r"); writeReg(RF_SETUP, val); // read register to verify settings readReg(RF_SETUP, &chk); if (chk&0x2E == val) { return 0; } else { return 1; } } char NRF2401P::setChannel(char chan) { char chk=0; if (debug) { sprintf(logMsg, "Set channel"); log(logMsg); } writeReg(RF_CH, (chan&0x7f)); readReg(RF_CH, &chk); if (chk&0x7f == chan&0x7f) { return 0; } else { return 1; } } bool NRF2401P::isRPDset() { char val=0; if (debug) { sprintf(logMsg, "Get RPD"); log(logMsg); } readReg(RPD, &val); if (val == 1) { return true; } else { return false; } } /** * Transmits width bytes of data. width <32 */ char NRF2401P::transmitData( char *data, char width ) { if (width>32) return 0; checkStatus(); if ((status>>4)&1) { // Max retries - flush tx flushTx(); } //clearStatus(); //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; wait(0.001); if (debug) { sprintf(logMsg, " Transmit data %d bytes to %02x (%02x) = %10s", width, address, status, data ); log(logMsg); } return status; } /** * re Transmits data */ char NRF2401P::retransmitData( ) { checkStatus(); if ((status>>4)&1) { // Max retries - flush tx flushTx(); } //clearStatus(); //ce = 1; csn = 0; char address = REUSE_TX_PL; //REUSE_TX_PL // set up for writing status = spi->write( address ); csn = 1; wait(0.001); if (debug) { sprintf(logMsg, "Reransmit data" ); log(logMsg); } return status; } /** * sets acknowledge data width bytes of data. width <32 */ char NRF2401P::acknowledgeData( char *data, char width, char pipe ) { ce = 1; csn = 0; //writeReg(0x1d,0x06); // enable payload with ack char address = W_ACK_PAYLOAD | (pipe&0x07); int i; // set up for writing csn = 0; status = spi->write( address ); for ( i = 0; i <width; i++ ) { spi->write( data[ i ] ); } csn = 1; if (debug) { sprintf(logMsg, " acknowledge data %d bytes to %02x (%02x) = %c", width, address, status, *data ); log(logMsg); } return status; } /** * Writes 1 byte data to a register **/ void NRF2401P::writeReg( char address, char data ) { char reg; csn = 0; address &= 0x1F; reg = address | W_REGISTER; status = spi->write( reg ); spi->write( data ); csn = 1; if (debug) { sprintf(logMsg, " register write %02x (%02x) = %02x", address, status, data ); log(logMsg); } } /** * Writes width bytes data to a register, ls byte to ms byte /for adressess **/ void NRF2401P::writeReg( char address, char *data, char width ) { char reg; csn = 0; int i; // set up for writing address &= 0x1F; reg = address| W_REGISTER; status = spi->write( reg ); for ( i = width - 1; i >= 0; i-- ) { spi->write( data[ i ] ); } csn = 1; if (debug) { sprintf(logMsg, " register write %d bytes to %02x (%02x) = %02x %02x %02x", width, address, status, data[0], data[1], data[2] ); log(logMsg); } } /** * Reads 1 byte from a register **/ void NRF2401P::readReg( char address, char *data ) { csn = 0; address &= 0x1F; status = spi->write( address ); *data = spi->write( 0x00 ); csn = 1; if (debug && address != 0x07) { // In debug mode: print out anything other than a status request sprintf(logMsg, " register read %02x (%02x) = %02x", address, status, *data ); log(logMsg); } } /** * Reads n bytes from a register **/ void NRF2401P::readReg( char address, char *data, char width ) { char reg; csn = 0; int i; // set up for writing address &= 0x1F; reg = address| R_REGISTER; status = spi->write( reg ); for ( i = width - 1; i >= 0; i-- ) { data[i] = spi->write( 0x00 ); } csn = 1; if (debug) { sprintf(logMsg, " register read %d bytes from %02x (%02x) = ", width, address, status ); for ( i=0; i<width; i++) sprintf(logMsg, "%s %02x", logMsg, data[i]); log(logMsg); } } /** * Clears the status flags RX_DR, TX_DS, MAX_RT */ void NRF2401P::clearStatus() { writeReg(STATUS, 0x70); if (debug) { sprintf(logMsg, "Clear status (%02x)", status ); log(logMsg); } } /** * flushes TX FIFO and resets status flags */ void NRF2401P::flushTx() { csn = 0; status = spi->write( FLUSH_TX ); csn = 1; clearStatus(); if (debug) { sprintf(logMsg, "Flush TX FIFO (%02x)", status ); log(logMsg); } } /** * flushes RX FIFO and resets status flags */ void NRF2401P::flushRx() { csn = 0; status = spi->write( FLUSH_RX ); csn = 1; clearStatus(); if (debug) { sprintf(logMsg, "Flush RX FIFO (%02x)", status ); log(logMsg); } } /** * Sets PRIM_RX = 0; */ char NRF2401P::setTxMode() { char data; char bit; if (debug) { sprintf(logMsg, "Set Tx Mode"); log(logMsg); } readReg(CONFIG, &data); data &= ~( 1 << 0 ); flushTx(); flushRx(); writeReg(CONFIG, data); writeReg(RX_ADDR_P0, txAdd, addressWidth); // reset p0 writeReg(EN_RXADDR, 0x01); // enable pipe 0 for reading // check readReg(CONFIG, &data); bit = ( data >> 0 ) & 1; ce=1; wait(0.003); if (bit == 0) { return 0; } else { return 1; } } /** * Sets the number of bytes of the address width = 3,4,5 */ char NRF2401P::setAddressWidth( char width ) { char chk=0; addressWidth = width; if ( ( width > 5 ) || ( width < 3 ) ) return false; width -= 2; writeReg(SETUP_AW, width); readReg(SETUP_AW, &chk); if (chk&0x03 == width) { return 0; } else { return 1; } } /** * Sets the address, uses address width set (either 3,4 or 5) */ char NRF2401P::setTxAddress( char *address ) { memcpy (txAdd,address, addressWidth); writeReg(RX_ADDR_P0, address, addressWidth); writeReg(TX_ADDR, address, addressWidth); return 0; // must fix this } /** * Sets the address, uses addess width set (either 3,4 or 5) */ char NRF2401P::setTxAddress( long long address ) { char buff[ 5 ]; char width = addressWidth; for (char w=0; w<width;w++){ char ww = width -w-1; // Reverse bytes buff[w] = ( address >> (8*ww )) &0xFF; } return setTxAddress( buff ); } /** * Sets the address, uses address width set (either 3,4 or 5) * Enables pipe for receiving; */ char NRF2401P::setRxAddress( char *address, char pipe ) { if(debug) { log ("Set Rx Address"); } if (pipe>5) return 0xff; if (pipe ==0) { memcpy(pipe0Add,address, addressWidth); } char reg = 0x0A + pipe; switch ( pipe ) { case ( 0 ) : case ( 1 ) : { writeReg(reg, address, addressWidth); //Write to RX_ADDR_P0 or _P1 break; } case ( 2 ) : case ( 3 ) : case ( 4 ) : case ( 5 ) : { writeReg(reg, address, 1); //Write to RX_ADDR_P2 ... _P5 break; } } readReg(EN_RXADDR, ®); reg |= (1<<pipe); writeReg(EN_RXADDR, reg); //Enable the pipe return 0; // Must fix this } /** * 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 ]; char width = addressWidth; if (pipe>1){ width = 1; } for (char w=0; w<width;w++){ char ww = width -w-1; // Reverse bytes buff[w] = ( address >> (8*ww ) )&0xFF; } return setRxAddress( buff, pipe ); } /** *checks the status flag */ char NRF2401P::checkStatus() { readReg(STATUS, &status); return status; } /** * checks if Ack data available. */ bool NRF2401P::isAckData() { char fifo; readReg(FIFO_STATUS, &fifo); bool isData = !(fifo&0x01); return isData; } /** * checks if RX data available. */ bool NRF2401P::isRxData() { checkStatus(); bool isData = (status>>6)&0x01; return isData; } char NRF2401P::getRxWidth() { char width; if (dynamic) { csn = 0; status = spi->write( R_RX_PL_WID ); width = spi->write(0x00); csn = 1; if (width>32) { // as per product spec flushRx(); wait(0.002f); // little delay (KJN) width=0; } } else { readReg(RX_PW_P1, &width); // width of p1 } 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; if (debug) { sprintf(logMsg, "Receive data %d bytes", width ); log(logMsg); } clearStatus(); return width; } else { if (debug) { sprintf(logMsg, "Receive NO data %d bytes", width ); log(logMsg); } clearStatus(); return 0; } } /** * Sets all the receive pipes to dynamic payload length */ void NRF2401P::setDynamicPayload() { dynamic = true; writeReg(FEATURE, 0x07); // Enable Dyn payload, Payload with Ack and w_tx_noack command writeReg(EN_AA, 0x3f); // EN_AA regi for P1 and P0 writeReg(DYNPD, 0x3F); // KJN - should be 0x3F for all pipes } /** * Sets PWR_UP = 0; * return 0 on success */ char NRF2401P::setPwrDown() { char data; char bit; ce=1; readReg(CONFIG, &data); if (!((data>>1) &0x01)) { return true; // Already powered up }; data &= (0xFD); // clear bit 2 writeReg(CONFIG, data); // check readReg(CONFIG, &data); bit = ( data >> 1 ) & 1; wait(0.005); // wait 5ms if(debug) { sprintf(logMsg, "Set PWR_UP to %x", bit); log(logMsg); } if (bit == 0) { return 0; } else { return 1; } } /** * Sets PWR_UP = 1; * return 0 on success */ char NRF2401P::setPwrUp() { char data; char bit; ce=1; readReg(CONFIG, &data); if ((data>>1) &0x01) { return true; // Already powered up }; data |= (0x02); writeReg(CONFIG, data); // check readReg(CONFIG, &data); bit = ( data >> 1 ) & 1; wait(0.005); // wait 5ms if(debug) { sprintf(logMsg, "Set PWR_UP to %x", bit); log(logMsg); } if (bit == 1) { return 0; } else { return 1; } } /** * Sets PRIM_RX = 0; */ char NRF2401P::setRxMode() { char data; char bit; ce=1; readReg(CONFIG, &data); data |= (0x01); writeReg(CONFIG, data); if (pipe0Add[0]|pipe0Add[1]|pipe0Add[2]|pipe0Add[3]|pipe0Add[4] >0) { setRxAddress(pipe0Add,0); } // check readReg(CONFIG, &data); bit = ( data >> 0 ) & 1; wait (0.001); flushRx(); flushTx(); if (debug) { sprintf(logMsg, " set PRIM_RX to %x", bit); log(logMsg); } if ( bit == 1 ) { return 0; } else { return 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; } void NRF2401P::printReg(char* name, char address, bool newline) { char data; readReg(address, &data); printf("%s = 0x%02x", name, data); if (newline) { printf("\r\n"); } } void NRF2401P::printReg(char* name, char address, char width, bool newline) { char data[width]; readReg(address, data, width); printf("%s = 0x", name); for (int i=width-1; i>=0; i--) { printf("%02x", data[i]); } if (newline) { printf("\r\n"); } } /* * Prints in reverse order for addresses */ void NRF2401P::printRegR(char* name, char address, char width, bool newline) { char data[width]; readReg(address, data, width); printf("%s = 0x", name); for (int i=0; i<width; i++) { printf("%02x", data[i]); } if (newline) { printf("\r\n"); } } void NRF2401P::printDetails() { status = checkStatus(); char w=1; printf("STATUS = 0x%02x RX_DR=%x TX_DS=%x MAX_RT=%x RX_P_NO=%x TX_FULL=%x\r\n", status, (status & (1<<MASK_RX_DR))?1:0, (status & (1<<MASK_TX_DS))?1:0, (status & (1<<MASK_MAX_RT))?1:0, (status >> RX_P_NO) & 7, (status & (1<<TX_FULL))?1:0 ); printRegR("RX_ADDR_P0", RX_ADDR_P0, addressWidth); printRegR("RX_ADDR_P1", RX_ADDR_P1, addressWidth); printRegR("RX_ADDR_P2", RX_ADDR_P2, w); printRegR("RX_ADDR_P3", RX_ADDR_P3, w); printRegR("RX_ADDR_P4", RX_ADDR_P4, w); printRegR("RX_ADDR_P5", RX_ADDR_P5, w); printRegR("TX_ADDR", TX_ADDR, addressWidth); printReg("RX_PW_P0", RX_PW_P0, false); // false for no newline, save some space printReg(" RX_PW_P1", RX_PW_P1, false); printReg(" RX_PW_P2", RX_PW_P2); printReg("RX_PW_P3", RX_PW_P3, false); printReg(" RX_PW_P4", RX_PW_P4, false); printReg(" RX_PW_P5", RX_PW_P5); printReg("SETUP_RETR", SETUP_RETR); printReg("EN_AA", EN_AA); printReg("EN_RXADDR", EN_RXADDR); printReg("RF_CH", RF_CH); printReg("RF_SETUP", RF_SETUP); printReg("CONFIG", CONFIG); printReg("DYNPD", DYNPD); printReg("FEATURE", FEATURE); }