spirilis edited this page Jan 30, 2014 · 104 revisions

Welcome to the msprf24 wiki!

Official documentation for the library and use-case examples.


This library is an attempt to provide the TI MSP430 microcontroller platform a rich interface to the Nordic Semiconductor nRF24L01 and nRF24L01+ proprietary 2.4GHz RF digital transceivers. These transceivers are appropriate for transmitting digital data in one-to-one or many-to-one topologies over relatively short distances--typically up to 100 meters although some breakout boards make claims of 1km range (very dubious IMO). They are available through a few vendors although eBay contains plenty of listings from Shenzhen, China and Hong Kong for cheap breakout boards ranging from simplistic PCB trace-antenna designs to RP-SMA WiFi antenna-coupled boards with PA+LNA RF amplifiers onboard.

RF characteristics

The transmission speeds supported include 250Kbps, 1Mbps, 2Mbps(nRF24L01+ / nRF24L01P chips only).
Output power ranges from -18dBm to 0dBm on-chip without external amplification. Boards with PA+LNA amplifiers may achieve higher range.

Power characteristics

Power consumption while active is typically between 7-14mA, while inactive it may range from 0.9uA (powerdown) to 26uA (Standby-I, a semi-sleep mode with quick transition to Standby-II/PTX/PRX mode). It operates off 1.9-3.6V input which is comparable to the MSP430. Boards with PA+LNA will obviously consume more power due to the amplifier--ITead Studio claims 115mA during transmit, 45mA during receive. (ITead PA+LNA board)

I/O and packet management

The transceiver architecture attempts to offload certain protocol functions such as acknowledgement, CRC computation, address matching and duplicate-packet suppression using a system they call Enhanced ShockBurst. These functions are performed by the nRF24 chip's onboard hardware so the MCU is free to sleep or perform other operations. The protocol/packet format supports payloads of 1-32 bytes, either fixed or dynamic payload sizes supported, ability to perform manual acknowledgement of received packets with a return payload, ability to auto-retransmit after certain timeout/delays when acknowledgements are not received and report via IRQ whether a successful receive, transmit or unsuccessful transmit/lost packet due to timeout+maximum retransmission count exceeded condition is present.

This transceiver & protocol is not compatible with 802.15.4, known as ZigBee. It is a Nordic Semi proprietary standard. Unlike XBee and Bluetooth modules which typically incorporate native UARTs for asynchronous serial I/O, this transceiver only supports synchronous SPI. The SPI interface runs at a maximum of 10MHz.

The datasheet for this chip is located on Nordic Semiconductor's website: http://www.nordicsemi.com/eng/content/download/2726/34069/file/nRF24L01P_Product_Specification_1_0.pdf

The product page contains more summary information: http://www.nordicsemi.com/eng/Products/2.4GHz-RF/nRF24L01P

Example use-cases

Remote sensing

A typical application of the nRF24L01+ which takes full advantage of the MSP430's touted low-power modes is remote sensing with periodic wakeup involving an MSP430 circuit attached to sensors in a remote location. An MSP430 using either the VLO or LFXT1 driving ACLK to wake up the device periodically will switch on the nRF24, take sensor measurements and once the nRF24 is ready (5ms Standby-I wakeup time has elapsed), transmit those to a base station, followed by deep powerdown of the nRF24 chip and any sensors involved. LPM3 is an appropriate sleep mode for this application.

RF-powered Serial UART

Using a paired set of nRF24 transceivers + MSP430 with USCI hardware, you could implement a wireless serial port extender by having both transceivers listen in PRX mode for a transmission from the other, momentarily switching to Standby-II/PTX to send data received over its end of the serial connection and vice versa. Serial speeds such as 9600bps should be supportable even with the 250Kbps on-air transmission speed (for maximum range). Using USCI_B in SPI master mode for the nRF24 transceiver and USCI_A in UART mode should support this configuration.

Remote display

A simple MSP430-based circuit driving an LED or LCD display with ample battery or AC power could serve as an RF-accessible display which you can locate anywhere you'd like. A suitable transmitter circuit would have to be constructed, perhaps using a LaunchPad board with boosterpak receiving display update commands over the TUSB serial port and transmitting them to the display. If the remote MSP430 is not tasked with driving the LED/LCD refresh, it can safely enter LPM4 mode as the nRF24L01+ will wake it up using the IRQ pin interrupt upon receiving a packet.

Keyless entry

SparkFun Electronics sells a "Nordic FOB" on their site which incorporates an nRF24L01+ and Atmel ATTiny24 - Nordic FOB

This could easily control an MSP430/nRF24L01+ receiver doing whatever you want (control door locks in a car or building? lighting control? control your own personal batcave? etc)

Only catch is you'd need an Atmel ICSP programmer to reflash the ATTiny24 chip onboard with new firmware and have to use avr-gcc/avrdude tools. Totally wish they made an MSP430 version of that!

Example code

ike's USCI_A RX/TX example


Crappy one-shot PTX example

Using an MSP430G2231 for this

#include <msp430.h>
#include "msprf24.h"
#include "nrf_userconfig.h"

void main()
        char addr[5];
        char buf[32];
        char status;

        BCSCTL1 = CALBC1_1MHZ;
        BCSCTL2 = DIVS_0;  // SMCLK = DCOCLK/1
        // SPI (USI) uses SMCLK, prefer SMCLK=DCO (no clock division)

        /* Initial values for nRF24L01+ library config variables */
        rf_crc = RF24_EN_CRC | RF24_CRCO; // CRC enabled, 16-bit
        rf_addr_width      = 5;
        rf_speed_power     = RF24_SPEED_MIN | RF24_POWER_MIN;
        rf_channel         = 120;
        msprf24_init();  // All RX pipes closed by default
        msprf24_open_pipe(0, 1);  // Open pipe#0 with Enhanced ShockBurst enabled for receiving Auto-ACKs
        msprf24_set_pipe_packetsize(0, 0);  // Dynamic payload length enabled (size=0)

        // Transmit to 'rad01' (0x72 0x61 0x64 0x30 0x31)
        addr[0] = 'r'; addr[1] = 'a'; addr[2] = 'd'; addr[3] = '0'; addr[4] = '1';
        w_rx_addr(0, addr);  // Pipe 0 receives auto-ack's, autoacks are sent back to the TX addr so the PTX node
                             // needs to listen to the TX addr on pipe#0 to receive them.
        buf[0] = '1';
        buf[1] = '\0';
        w_tx_payload(2, buf);

        if (rf_irq & RF24_IRQ_FLAGGED) {
                msprf24_get_irq_reason();  // this updates rf_irq
                if (rf_irq & RF24_IRQ_TX)
                        status = 1;
                if (rf_irq & RF24_IRQ_TXFAILED)
                        status = 0;
                msprf24_irq_clear(RF24_IRQ_MASK);  // Clear any/all of them
        // Do something cool with the 'status' variable
        // ???
        // Profit!
        // Go to sleep forever:

PRX example

Library usage

Configuration tasks

Preparing & performing TX

Preparing & performing RX

Detailed library documentation

Configuration Variables

Imported from #include <msprf24.h>

CRC setting, committed to the transceiver any time a state change occurs such as msprf24_standby(), msprf24_activate_tx(), etc. Changing this on the fly in the middle of an active PRX mode will do nothing unless you pull the transceiver out of PRX and put it back in, i.e. performing msprf24_standby() followed by msprf24_activate_rx()

  • Valid values--any logic-OR'd combination of:
    • RF24_EN_CRC -- Enable CRC
    • RF24_CRCO -- CRC-16 (lack thereof = CRC-8)

Current RF speed & transmit power setting, committed to the transceiver upon issuing msprf24_set_speed_power() (this is run during msprf24_init() FYI)

  • Valid values--logical OR of one RF24_SPEED setting along with one RF24_POWER setting:
    • RF24_SPEED_250KBPS
    • RF24_SPEED_1MBPS
    • RF24_SPEED_2MBPS (not supported on nRF24L01 transceivers, only nRF24L01+)
    • Aliases: RF24_SPEED_MIN, RF24_SPEED_MAX (ditto)
    • RF24_POWER_0DBM
    • Aliases: RF24_POWER_MIN, RF24_POWER_MAX

Current RF channel, committed to the transceiver upon issuing msprf24_set_channel() (this is also run within msprf24_init())

  • Valid values:
    • 0 - 125
      Channel represents frequency slot in 1MHz increments starting at 2400MHz. 250Kbps and 1Mbps modes take up to 1MHz bandwidth, 2Mbps modes take up 2MHz; keep that in mind when staggering different transceiver pairs running at different channels. Prefer keeping transceiver pairs at least 2 channels apart when operating at 250Kbps or 1Mbps, and 3 channels apart when operating at 2Mbps.

Size of Enhanced ShockBurst addresses--valid values are 3, 4 or 5 bytes. Committed to the transceiver using msprf24_set_address_width(), also set during msprf24_init() You cannot transmit to a receiver sporting a different address width than your current setting; it is a global config register.

Status Variables

Probably not used by end users, this happens to hold the last known state of the STATUS register on the chip. The nRF24L01+ transceiver reports back this STATUS register's value every time SPI I/O is performed; when sending the 1st byte of the SPI request (the command), the byte returned by the transceiver is this value.

Used heavily by the end user--this may contain any of the bits specified in the RF24_IRQ #defines, including RF24_IRQ_FLAGGED which signals to the user's application that an nRF24L01+ IRQ has in fact been raised and needs attention. See msprf24_irq_get_reason() for more details.
Note that RF24_IRQ_FLAGGED is automatically cleared when using msprf24_get_irq_reason()


Initialize SPI, GPIO ports used for IRQ/CE/CSN, enable interrupts, wait 100ms (Tpup, power ramp-up time) for the transceiver to boot, carry out setting the current value of all rf_* variables, close all RX pipes, enable two features in the FEATURE register; RF24_EN_DPL and RF24_EN_DYN_ACK (allow pipes to be configured with dynamic payload sizes and allow TX packets with NOACK bit)

  • Arguments: None
  • Returns: Nothing

w_tx_addr(char *addr)
Write a new TX address, to be used as the transmit address for the next packet sent via TX FIFO buffer. Note that when Enhanced ShockBurst autoack is enabled on pipe#0, it is assumed you expect auto-acknowledgements for packets sent to this address--these auto-ack's come in via pipe#0 and therefore you must write the TX address into the RX address for pipe#0.

  • Arguments: Pointer to a char buffer containing an address of rf_addr_width bytes.
  • Returns: Nothing

w_rx_addr(char pipe, char *addr)
Write a new RX address to the named pipe--valid pipes include 0 to 5. Pipe#0 is special as discussed above in w_tx_addr() although for a PRX-only device it works just like a normal RX pipe. What needs special attention is that pipe#2-5 always shares the first 2,3,or 4 bytes (depending on rf_addr_width) with pipe#1, only the last byte in the address can differ from pipe #1. This function honors that restriction--however--if you write an RX address to pipe#2-5 whose first 2/3/4 bytes differ from pipe#1 it will not check, will not notify you and it will only write the last byte to the pipe's RX address leaving you potentially confused as to why your transceiver is not receiving traffic at the address you specified.

Example (rf_addr_width=5 here):

  • RX pipe#0 = 0x1010101010
  • RX pipe#1 = 0xDEADBEEF00
  • RX pipe#2 = 0xDEADBEEF01
  • RX pipe#3 = 0x1010101002
  • RX pipe#4, #5 not enabled

In this scenario the transceiver will receive and acknowledge traffic coming to address 0x1010101010, 0xDEADBEEF00, 0xDEADBEEF01 but it will not acknowledge traffic coming to 0x1010101002 -- it will acknowledge traffic coming to 0xDEADBEEF02. Because pipes 2-5 share the first rf_addr_width-1 bytes with pipe#1 and only differ in the last byte, the first 4 bytes in the address (0x10101010) are ignored by w_rx_addr() with no notification given to the user. Page#40 of the datasheet illustrates this.

  • Arguments: Pipe ID (0-5), pointer to a char buffer containing an address of rf_addr_width bytes.
  • Returns: Nothing

w_tx_payload(char len, char *data)
Write a payload of len bytes from buffer data to the TX FIFO. The TX (and RX) FIFOs have 3 levels, meaning 3 payloads may be queued for transmission. Payload transmission will not occur until msprf24_activate_tx() is run to switch the transceiver state to Standby-II/PTX mode.

  • Arguments: Length (1-32), pointer to a char buffer containing that many bytes.
  • Returns: Nothing

w_tx_payload_noack(char len, char *data)
Write a payload of len bytes from buffer data to the TX FIFO with the expectation that Enhanced ShockBurst auto-ack will be disabled for this frame--the device will not wait for an autoack packet from the PRX receiver. The receiver will notice a "NOACK" bit set in the packet signifying no need to send an acknowledgement. Payload transmission will not occur until msprf24_activate_tx() is run to switch the transceiver state to PTX mode. The feature RF24_EN_DYN_ACK must be enabled (it is by default via msprf24_init())

  • Arguments: Length (1-32), pointer to a char buffer containing that many bytes.
  • Returns: Nothing

r_rx_payload(char len, char *data)
Read contents of RX FIFO--command reads len bytes and writes them to buffer data. That FIFO's contents are removed upon reading (depending on how many packets are queued in the 3-level RX FIFO, more might be available; use msprf24_queue_state() to test for RF24_QUEUE_RXEMPTY before assuming you're done)

  • Arguments: Length (1-32), pointer to a char buffer of at least len bytes.
  • Returns: Pipe# associated with this payload.

Peek the payload size of the next RX FIFO payload available via r_rx_payload()--mandatory for reading RX buffers from pipes with Dynamic Payload Length enabled.

  • Arguments: None
  • Returns: Size of RX FIFO contents in bytes (1-32)

Flush all TX FIFOs.

  • Arguments: None
  • Returns: Nothing

Flush all RX FIFOs. It's important not to run this during a timeperiod where the transceiver might be sending an ACK back to the PTX, i.e. while handling the RX IRQ immediately after receiving; this may abort the ACK process and make the transmitter think the packet was not delivered successfully.

  • Arguments: None
  • Returns: Nothing

msprf24_open_pipe(char pipeid, char autoack)
Enable an RX pipe. All pipes are closed/disabled by default upon msprf24_init() so you must use this to enable each RX pipe you wish to use. Pipeid is a number from 0 to 5, autoack is a boolean (0 = false, anything else = true). If autoack is enabled, the Enhanced ShockBurst protocol is active for that pipe; incoming packets are acknowledged with an ACK reply. Note that for pipe#0, which is also used on a PTX device to receive ACK packets from a remote receiver, autoack informs the transceiver whether Enhanced ShockBurst is in fact being used for the transmission and whether it should wait for an ACK (going through the timeout/autoretransmit sequence). So it's essentially the Enhanced ShockBurst on/off switch for the transmitter.

  • Arguments: PipeID, autoack boolean
  • Returns: Nothing

msprf24_close_pipe(char pipeid)
Close/disable the specified RX pipe. PipeID is a number from 0 to 5.

  • Arguments: PipeID
  • Returns: Nothing

msprf24_pipe_isopen(char pipeid)
A test function to see if the specified pipe is open. Returns a boolean (0=false, 1=true) signifying the state of the pipe in the EN_RXADDR register.

  • Arguments: PipeID
  • Returns: Boolean (0, 1)

msprf24_set_pipe_packetsize(char pipeid, char size)
Configure the packet size expected for a particular RX pipe. Valid sizes include 0-32, with 0 signifying Dynamic Payload Size should be enabled for this pipe allowing any size packet from 1 to 32 bytes. Values from 1-32 specify a static size for the pipe which is enforced; any incoming packets destined to this pipe not matching the specified static payload size will be discarded.

  • Arguments: PipeID, size
  • Returns: Nothing

Reconfigure the transceiver to use & accept addresses of a size specified by the global rf_addr_width variable. This function is intended to be used by setting the global rf_addr_width variable first, then issuing this function. It is run during initialization inside msprf24_init(). Valid address widths include 3, 4 or 5 bytes.

If addresses were written to the TX or RX address registers prior to issuing this command, and the address width is changed from what it was prior, the subsequent behavior is not really specified in the Nordic Semiconductor datasheet and therefore it is imperative that you re-write the TX and/or RX addresses using w_tx_addr() and w_rx_addr() before putting the transceiver on the air.

  • Arguments: None (it does, however, make use of the global rf_addr_width variable--range is 3-5)
  • Returns: Nothing

msprf24_set_retransmit_delay(int us)
Configure the retransmission timeout for TX operation--if a transceiver in PTX mode transmits a packet and Enhanced ShockBurst is enabled for pipe#0 on the PTX device, the PTX device will temporarily enter RX mode to wait for an auto-acknowledgement packet from the PRX receiver device. The PTX will wait the specified us microseconds until deciding to switch back to TX and retransmit the packet, assuming packet loss occurred or the PRX receiver is out of range. This may also occur if the PRX did in fact receive the packet but the auto-acknowledgement reply packet never made it back to the PTX transceiver. If that occurs, the PRX will still continue to auto-acknowledge the retransmissions but only report the packet once to its MCU.

  • Arguments: # Microseconds (valid range 250-4000us, minimum values differ by RF speed and packetsize)
  • Returns: Nothing
  • Default: 2000us

msprf24_set_retransmit_count(char count)
Configure the maximum number of retransmissions tolerated before giving up. After a time interval of count times us microseconds from msprf24_set_retransmit_delay() specified above, the PTX transceiver will give up and raise the MAX_RT IRQ to the MCU signifying that the packet was lost.

  • Arguments: # Retransmits (valid range 1-15)
  • Returns: Nothing
  • Default: 15

Retrieve the contents of a register on the transceiver which records the # of retransmits that occurred during the last attempt to send a packet. This register gets reset with every PTX transmission.

  • Arguments: None
  • Returns: # retransmits, 0-15

Retrieve the contents of a register on the transceiver which records the total number of payloads lost (payloads whose retransmissions reached the threshold specified by msprf24_set_retransmit_count(), raising the MAX_RT IRQ) since the last time the RF channel was set. Likewise, this counter can be reset by issuing a command to set the RF channel--even if the channel you specify is identical to the one already configured. Once this counter reaches its maximum value of 15, it will stay at 15 even if future payloads are lost. The only way to regain use of this counter is to reset the RF channel to clear it.

  • Arguments: None
  • Returns: # packets lost, 0-15

Configure the RF channel used for PTX and PRX operation. The channel is specified by the global variable rf_channel and the intended use is for the user to set rf_channel first, then issue this command. Without modifying rf_channel beforehand, the MCU can issue this command to clear the counter used by msprf24_get_lostpackets() up above.

The channels range from 0 to 125, specifying 1MHz increments above 2400MHz. So channel 125 is 2525MHz (2.525GHz). Note that 250Kbps and 1Mbps data rates use up to 1MHz worth of bandwidth, so two unrelated transceiver pairs should space themselves at least 2 channels apart to avoid any crosstalk. 2Mbps data rates use 2MHz worth of bandwidth so a transceiver pair using channel 30 and another using channel 31, both at 2Mbps, will most certainly clobber each other with crosstalk if they transmit at the same time. Best to keep them at least 3 channels apart.

  • Arguments: None (it does make use of the global variable rf_channel--valid range is 0-125)
  • Returns: Nothing

Configure the RF transceiver's speed and transmit power-level. These are specified together in the rf_speed_power global variable. The parameters for this are detailed well enough above in the Configuration Variables section so please go up there for reference.

  • Arguments: None (it does make use of the global variable rf_speed_power)
  • Returns: Nothing

Read the current state of the RF transceiver (this does in fact query the transceiver over the SPI bus, it does not make assumptions based on local variables) and report it as an integer which the user may evaluate using the RF24_STATE*_ #defines. See the RF24 #defines section below for details.

  • Arguments: None
  • Returns: Integer corresponding to one of the RF24_STATE_* states.

Checks to see if the nRF24 module is attached and communicating; tests basic SPI communication by reading the RF24_AW register to see if the currently-set packet address width is a valid number (and that the reply does not come back 0x00 or 0xFF, for instance).

  • Arguments: None
  • Returns: Boolean integer where 0 is false and 1 is true (1 = nRF module is present & communicating).

Tells the nRF module to power down, i.e. enter low 0.9uA sleep mode. RF24_CONFIG register sets PWR_UP=0, PRIM_RX=0, and the Chip Enable GPIO line will be shut off (set LOW). The nRF24 module will not receive any packets and will not transmit anything during this state, so all I/O should be wrapped up and confirmed done before issuing this function. Often used in conjunction with LPM3 or similar timed sleep states for devices that sleep most of the time but periodically wake up to sample & transmit data.

  • Arguments: None
  • Returns: Nothing

Tells the nRF module to enter Standby-I, a state specified in the datasheet whose characteristics feature quick 130uS transitions to active RX/TX modes. The process of switching from PowerDown to Standby-I involves starting certain crystal oscillators onboard the chip and it usually takes up to 5 milliseconds to complete. The chip draws around 26uA once in this state, and draws a few milliamps during the transient process of starting the crystal oscillators. In my own experience a chip installed in a setup with insufficient capacitance on the power supply will fail during this phase.

  • Arguments: None
  • Returns: Nothing

Enable Primary RX mode (PRX)--activate the transceiver and continually listen for packets coming to any of the configured RX pipes' RX addresses. This function will automatically run msprf24_standby() if necessary to bring the chip out of deep sleep. Assuming you have the IRQ pin configured to interrupt the chip, it is perfectly reasonable to put the MSP430 in LPM4 mode after this function has been issued. Note that the nRF24 module will consume around 13mA current continuously as long as it is in PRX mode.

  • Arguments: None
  • Returns: Nothing

Enable Primary TX mode (PTX) or Standby-II, a preparatory mode characterized by having additional crystal oscillators active but no data to transmit yet. Current consumption in Standby-II is 320uA and the chip enters PTX when the TX buffers are loaded with data. PTX mode uses around 7-11mA current while the 2.4GHz PLL is active and transmitting, varying by transmission speed. If the TX buffers were loaded before issuing msprf24_activate_tx() then the chip enters PTX mode right away and transmits its packet, performing the Enhanced ShockBurst auto-ack process if configured to do so. Once all TX buffers have been transmitted, the chip automatically falls back to Standby-II mode. Issuing msprf24_standby() or msprf24_powerdown() will back it out of this mode into a lower-power mode.

  • Arguments: None
  • Returns: Nothing

This function is fairly simple--it reads the RF24_FIFO_STATUS register off the nRF24 and returns it. The return value may be compared against the #define's RF24_QUEUE_TXFULL, RF24_QUEUE_TXEMPTY, RF24_QUEUE_RXFULL, RF24_QUEUE_RXEMPTY and are useful when determining whether there is data left to read from the RX buffers or whether a flush_rx() should be called to purge any stored but unwanted data.

  • Arguments: None
  • Returns: Integer which may be compared against the bits defined in RF24_QUEUE*_

msprf24_rx_pending() This function reads the STATUS register and returns 1 if there is incoming RX FIFO data available and 0 if not.

  • Arguments: None
  • Returns: An integer representing a boolean 0 or 1.

Very important function--reads the STATUS register and stores the relevant IRQ info in the rf_irq global variable. Recommend running this immediately upon wakeup from LPM after issuing any nRF24 transceiver operations (RX or TX). You can then test the rf_irq variable against the IRQ #define's such as RF24_IRQ_TXFAILED, RF24_IRQ_TX, RF24_IRQ_RX to see what happened.

After reading this you should (assuming PRX mode here) pull data using r_rx_payload() and then clear the IRQ using msprf24_irq_clear() as is mentioned below--however do note that if additional packets come through during the time executing code between msprf24_irq_clear() and your next LPM, you may find rf_irq's RF24_IRQ_FLAGGED bit re-set. It may be a good idea to design the handler loop so it checks that before going back into LPM just in case you have multiple requests to handle before going back to sleep. Otherwise the nRF24's RX queues will stack up and potentially fill, causing future packets to be lost and the transceiver will sit in sleep mode forever. For PTX mode, just running msprf24_irq_clear() after this function is sufficient.

  • Arguments: None
  • Returns: An integer testable with RF24_IRQ*_ #define's, this value is also stored in the rf_irq global variable.

msprf24_irq_clear(char irqflag)
Clear the IRQs on the nRF24 device. Only the IRQs specified in irqflag are cleared. If you want to make sure all IRQs are cleared without worrying about knowing or specifying which one, use RF24_IRQ_MASK as the argument. Heed all the warnings listed in msprf24_get_irq_reason() above. Issuing this function just acknowledges that the IRQ line should be reset to its default-HIGH state, and future incoming packets or events should re-trigger the IRQ line. Typically that means data has been read & handled, so you should read all RX buffers before issuing this function. It's best to make a loop where RX buffers get read and processed and the loop tests msprf24_queue_state() as listed above to determine if you're truly finished reading all the RX buffers, then issue this function once you're done. For PTX mode it's simple, just run this after msprf24_get_irq_reason().

  • Arguments: IRQ flag specifying which IRQs should be cleared from the device.
  • Returns: Nothing

msprf24_enable_feature(char feature)
Enable a particular feature onboard the nRF24. For the nRF24L01+ these include RF24_EN_DPL (Dynamic Payloads) which is switched ON by default upon msprf24_init(), RF24_EN_ACK_PAY specifies that all auto-acknowledgements must include a payload that is manually written by the PRX device using w_ack_payload()--this is switched OFF by default as it creates more work for the user, RF24_EN_DYN_ACK allows the use of w_tx_payload_noack() in case you want some transmissions to occur without the use of auto-acknowledgement despite it being enabled on the PTX device. A list of features previously enabled is internally maintained by an rf_feature non-global static variable; you need not recall which features are enabled when running this function, just specify the features you want to add.

  • Arguments: Integer corresponding to bits from the RF24_EN*_ #define's, minus RF24_EN_CRC which is not managed through this function.
  • Returns: Nothing

msprf24_disable_feature(char feature)
Disable the specified features. The opposite of msprf24_enable_feature() above. It clears the specified bits from the internal static rf_feature variable, then commits the value of that variable to the device's RF24_FEATURE register.

  • Arguments: Integer corresponding to bits from the RF24_EN*_ #define's, minus RF24_EN_CRC which is not managed through this function.
  • Returns: Nothing

Perform an RF signal presence scan of the current frequency. The nRF24 modules include a special register bit indicating whether a signal is present at greater than -60dBm strength. This function makes use of it by monitoring that bit for approximately 133 milliseconds, composing an 8-bit unsigned integer representing the % of this timeframe where a signal was present. The percentage is referenced against 255, where 255 = 100% and 127 = 50%. Using this and scanning different channels you can determine how busy the various channels are in your current area. PRX mode is used to drive this feature but all RX buffers are routinely flushed and IRQs cancelled while the test is ongoing. Upon leaving this function, if you were in PRX mode prior then you stay in PRX mode, otherwise the transceiver returns in a state of Standby-I (see msprf24_standby() above).

  • Arguments: None
  • Returns: 8-bit unsigned integer representing a percentage

An obscure function which can be used with PTX mode to quickly & efficiently handle packet loss situations. What this function does is tell the transceiver that the current contents of the TX buffer, typically the last transmitted payload but only under an RF24_IRQ_TXFAILED situation--meaning Enhanced ShockBurst is enabled but the PTX failed to receive an acknowledgement--should be reused continuously until either flush_tx() is called or the TX FIFO contents are replaced with another packet. In order to actually use this and re-send the TX FIFO contents, pulse_ce() is issued to signal PTX mode again. A typical use-case would be extended TX retransmissions to overcome RF reception issues with the understanding that Enhanced ShockBurst's default retransmit count is insufficient and the PTX might want to continually retry sending a packet for seconds, maybe even minutes until it gets through with valid acknowledgement. What this function buys you is less time spent rewriting the TX buffer on the nRF24. It's entirely up to you whether it's worth the bother but I suppose it would save a small amount of power not having to clock out the TX FIFO over SPI every time you wish to retry the transmission. After issuing pulse_ce() you can put the MSP430 into LPM sleep and wait for an IRQ indicating RF24_IRQ_TX (finally succeeded) or RF24_IRQ_TXFAILED (another failed transmission) to decide whether to continue. If you decide to abort, use flush_tx() to clear out the FIFO and cancel this TX FIFO-reuse feature.

  • Arguments: None
  • Returns: Nothing

Pulse the Chip Enable (CE) GPIO pin going to the nRF24 module. This "pulse" is always used as a signal to tell the nRF24 to start transmitting its TX FIFO contents. It is internally used by msprf24_activate_tx() to initiate transmission too. Within the context of a PTX device attempting to retransmit a packet, or a PTX device which has several payloads to send, this function must be executed to tell the nRF24 that it is OK to transmit its TX FIFO contents over the air.

  • Arguments: None
  • Returns: Nothing

w_ack_payload(char pipe, char len, char *data)
An obscure function used by a PRX device to send a custom acknowledgement packet--instead of the automated zero-length acknowledgements used by default when the RF24_EN_ACK_PAY feature is disabled. This function works similarly to w_tx_payload() except you must specify the RX pipe whose payload you are acknowledging with this function. Note that when RF24_EN_ACK_PAY feature is enabled, ALL packets must be acknowledged using this function; a failure on the PRX side to use this will result in a PTX device retransmitting frequently until giving up the ghost and reporting RF24_IRQ_TXFAILED to its microcontroller.

Most importantly, note that the acknowledgement payload must be pre-loaded BEFORE the PTX actually sends the packet. Similar to how SPI works, the payload-acknowledgement system involves a bidirectional transaction where data is transmitted & received in the same logical operation (although the PRX->PTX payload ACK transmission obviously occurs after the PTX->PRX payload transmission).

  • Arguments: RX pipe ID, length of buffer, pointer to character buffer containing len bytes.
  • Returns: Nothing

RF24 #defines


Speed setting for 250Kbps

Speed setting for 1Mbps

Speed setting for 2Mbps

  • Only available on nRF24L01+ (Plus) versions of the chip

Corresponds to RF24_SPEED_250KBPS, available on all chips

Corresponds to RF24_SPEED_2MBPS, only available on nRF24L01+ (Plus) chips

TX power

Corresponds to 0dBm transmit power (1mW)

Corresponds to -6dBm transmit power

Corresponds to -12dBm transmit power

Corresponds to -18dBm transmit power

Minimum transmit power; corresponds to RF24_POWER_MINUS18DBM

Maximum transmit power; corresponds to RF24_POWER_0DBM

Transceiver States

Chip not found; the msprf24_current_state() function attempts to do a strawman read of the SETUP_AW register from the chip, determining if the Address Width bits correspond to a valid value (this will not be true if the returned byte is 0x00 or 0xFF, likely found with a chip that is dead or not present).

Chip is present, but is in Power Down (0.9uA power draw) mode.

Chip is present and is powered up but in no RF-active modes. Some clock oscillators are running & ready.

Chip is present, powered up and in active TX mode; but there is no data in the TX FIFO buffer to send, so it is just standing by. The moment the user submits data to the TX FIFO it will quickly switch up to PTX mode. This transition is fast (~130uS).

Active TX transmission in progress. Chip is present, powered up, data is still present within the TX FIFO and it is currently being clocked out over the air.

Active RX mode; packets may or may not be coming in, but the RF transceiver is active, the 2.4GHz PLL is active and the protocol decoder module is actively interpreting any impulses detected over the air.

Device has one or more of the test-modes enabled. This library does not include any functions to enable those test modes although they may be activated manually with the use of w_reg() if you've read the datasheet and know what to set.

IRQ reasons

Signal to the user that an IRQ was received, and the user should attend to the transceiver by reading the IRQ reasons via msprf24_get_irq_reason(). This is a bit set in the rf_irq global variable and it is automatically cleared when the user runs msprf24_get_irq_reason()

Last packet loaded by the user into the TX FIFO has been successfully transmitted with any applicable auto-acknowledgement packets successfully received. If auto-ack features are turned off, every transmission will throw this IRQ regardless whether it successfully reached its destination.

Last packet loaded by the user into the TX FIFO was not successfully transmitted; auto-acknowledgement is enabled and no auto-ack packet was received from the remote receiver within a certain timeout period; all applicable retries have been attempted & exhausted with no success.

A packet has been received and is ready for the user to read using r_rx_payload()

Queue States

TX FIFO is full; user must wait for this FIFO's contents to be transmitted before attempting to write any more. Note that if the FIFO is full perpetually, the user might not have enabled TX mode with msprf24_activate_tx(). Upon activation of TX mode the transceiver will immediately switch to PTX mode.

TX FIFO is empty; user is free to write data to the FIFO. Once written, if the transceiver is already in Standby-II mode, the transceiver will switch to PTX mode within 130uS and send the packet. If not the TX FIFO will remain filled until TX mode is activated.

All RX FIFOs are full so no further incoming packets will be recorded; user must read at least 1 RX FIFO's contents with r_rx_payload() in order to allow new packets to be recorded.

All RX FIFOs are empty. Nothing to read.

Delay Cycles (nrf_userconfig.h)

The # of CPU clock cycles required to implement a 5 millisecond delay. Depends on your MCLK (CPU) speed, which is usually equal to your DCO clock speed.

The # of CPU clock cycles required to implement a 130 microsecond delay.

The # of CPU clock cycles required to implement a 15 microsecond delay. (minimum 10 needed, 15 offers some room for error)

SPI drivers (nrf_userconfig.h)

Uncommenting this define signals that your chip is USCI capable and you wish to use USCI port A for all SPI communication with the nRF24 chip. If this is uncommented, the RF24_SPI_DRIVER_USCI_B listed below MUST be commented out.

Uncommenting this define signals that your chip is USCI capable and you wish to use USCI port B for all SPI communication with the nRF24 chip. This is the most common port used because USCI port A contains the UART used for asynchronous serial communication, e.g. with a PC. If this is uncommented, the RF24_SPI_DRIVER_USCI_A listed above MUST be commented out.

Uncommenting this tells the USCI SPI code to make use of the USCI IRQs for driving communication, dropping into LPM0 sleep mode during actual communication to save a little power. If it is commented out, the USCI driver code will merely busy-wait in a while() loop until the relevant UCx0RXIFG Interrupt Flag is set.

Uncommenting this is only appropriate if the RF24_SPI_DRIVER_USCI_USE_IRQ define is uncommented too, in which case the msprf24 library supplies its own Interrupt Service Routine for handling IRQs thrown by the USCI module. Note that this ISR handles the USCIAB0RX_VECTOR interrupt; if your code utilizes USCI_A RX you may want to comment this out and supply your own ISR.

If you do supply your own ISR, in order to support the msprf24 library's USCI IRQ functionality your USCIAB0RX_VECTOR routine must test for the Interrupt Flag of the relevant USCI port used by the nRF24 and clear its Interrupt Enable flag afterwards. E.g., for having the nRF24 on USCI_A:

if (IFG2 & UCA0RXIFG) {
  IE2 &= ~UCA0RXIE;

Or if your nRF24 chip is using USCI_B:

if (IFG2 & UCB0RXIFG) {
  IE2 &= ~UCB0RXIE;

What about USI?

If you have a USI capable chip, you need not uncomment any of the SPI_DRIVER_USCI-related defines. The USI driver will be automatically enabled with full IRQ support. If you want to supply your own USI ISR, you will need to edit msprf24.c and remove the USI_VECTOR ISR code near the bottom of the file.

The supplied ISR code is very simple; it clears the IFG for the USI and exits from LPM0 mode. Any other device that makes use of the USI module would probably require the same treatment; moreover, you can also make use of the spi_transfer() and spi_transfer16() functions for your own purposes outside the nRF24 operations, so you might not have to write separate USI code.

Also note that msprf24_init() automatically handles an errata from the 2nd-generation MSP430 Value Line chips where an erroneous number of clock bits are produced on the very first SPI transfer--see USI5 in http://www.ti.com/lit/er/slaz072/slaz072.pdf

IRQ,CSN,CE ports (nrf_userconfig.h)

Denotes the MSP430 Port housing the IRQ line from the nRF24 chip; it must be an Interrupt-capable port, usually port 1 or port 2. E.g. if the IRQ pin from the nRF24 is attached to P2.0, this would be defined as 2.

Denotes the pin within the nrfIRQport housing the IRQ line from the nRF24 chip. Set this to one of the BITx macros, e.g. BIT0, BIT1, BIT2. Very important to use the BITx macro and not a straight integer. Port P2.0 would have this defined as BIT0, for example.

Denotes the MSP430 Port housing the CSN (SPI Chip-Select) pin. This is driven by the MSP430 and may be on any port you please.

Set this to the SFR name of the relevant port. If nrfCSNport is set to 2, this should be defined as P2OUT. If it's set to 1, this should be defined as P1OUT.

The pin within the nrfCSNport used for the CSN line. Same caveats apply as nrfIRQpin--must use one of the BITx macros.

Denotes the MSP430 Port housing the CE (Chip-Enable) pin. This is driven by the MSP430 and may be on any port you please. This pin is used by the library to enabled active RF transceiver functions, e.g. PRX, Standby-II and PTX modes can't be enabled until this pin is raised high or pulsed.

Similar idea to nrfCSNportout up above. The portout SFR used to drive this port, e.g. P1OUT, P2OUT, P3OUT etc.

Similar to nrfCSNpin and nrfIRQpin up above; denotes which pin on the port is used by this line. Must use one of the BITx macros.

Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.