pub struct Nrf24l01<SPI, CE> { /* private fields */ }
Expand description
The nRF24L01 driver type. This struct encapsulates all functionality.
For the different configuration options see: NrfConfig
.
§Examples
use nrf24::Nrf24l01;
use nrf24::config::NrfConfig;
// Initialize the chip with deafault configuration.
let nrf24 = Nrf24l01::new(spi, ce, &mut delay, NrfConfig::default()).unwrap();
Implementations§
Source§impl<SPI, CE> Nrf24l01<SPI, CE>
impl<SPI, CE> Nrf24l01<SPI, CE>
Sourcepub fn new<D: DelayNs>(
spi: SPI,
ce: CE,
delay: &mut D,
config: NrfConfig,
) -> Result<Self, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn new<D: DelayNs>( spi: SPI, ce: CE, delay: &mut D, config: NrfConfig, ) -> Result<Self, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Creates a new nRF24L01 driver with the given configuration.
This function initializes the device, configures it according to the provided settings, and performs validation to ensure proper communication with the chip. After initialization, the device is powered up and ready to use.
§Arguments
spi
- SPI interface for communicating with the nRF24L01 chip, this type should implement theSpiDevice
trait fromembedded_hal
ce
- Chip Enable pin for controlling the chip’s operating statesdelay
- Delay provider for timing requirements during initializationconfig
- Configuration settings for the chip (seeNrfConfig
for options)
§Errors
This function may return errors in the following situations:
- SPI communication errors
- Chip enable pin errors
- Communication errors with the module (e.g., incorrect configuration register values)
§Examples
use nrf24::{Nrf24l01, SPI_MODE};
use nrf24::config::{NrfConfig, PALevel, DataRate};
// Initialize hardware interfaces (platform-specific)
let spi = setup_spi(SPI_MODE);
let ce = setup_pin();
let mut delay = setup_delay();
// Create custom configuration
let config = NrfConfig::default()
.channel(76)
.data_rate(DataRate::R2Mbps)
.pa_level(PALevel::Low);
// Initialize the nRF24L01 driver
match Nrf24l01::new(spi, ce, &mut delay, config) {
Ok(nrf) => {
// Successfully initialized
// Continue with nrf.open_reading_pipe(), nrf.start_listening(), etc.
},
Err(e) => {
// Handle initialization error
panic!("Failed to initialize nRF24L01: {:?}", e);
}
}
§Note
The chip requires some settling time after power-up. This function includes appropriate delays to ensure reliable initialization.
Sourcepub fn is_connected(
&mut self,
) -> Result<bool, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn is_connected( &mut self, ) -> Result<bool, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Checks if the chip is connected to the SPI bus.
§Examples
if !chip.is_connected()? {
// Handle disconnection
}
Sourcepub fn open_reading_pipe<T: Into<DataPipe>>(
&mut self,
pipe: T,
addr: &[u8],
) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn open_reading_pipe<T: Into<DataPipe>>( &mut self, pipe: T, addr: &[u8], ) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Opens a reading pipe for reading data on an address.
§Examples
chip.open_reading_pipe(DataPipe::DP0, b"Node1")?;
pipe
can either be an instance of the type DataPipe
or an integer.
Note that if an integer is provided, numbers higher than 5 will default to reading pipe 0.
§Warnings
You have to call this before calling start_listening()
.
Sourcepub fn open_writing_pipe(
&mut self,
addr: &[u8],
) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn open_writing_pipe( &mut self, addr: &[u8], ) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Sourcepub fn start_listening(
&mut self,
) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn start_listening( &mut self, ) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Starts listening on the pipes that are opened for reading. Used in Receiver Mode.
§Examples
// First open data pipe 0 with address "Node1"
chip.open_reading_pipe(DataPipe::DP0, b"Node1")?;
// Configure the chip to listening modes (non blocking)
chip.start_listening()
// Now we can check for available messages and read them
§Warnings
Make sure at least one pipe is opened for reading using the open_reading_pipe()
method.
Sourcepub fn stop_listening(
&mut self,
) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn stop_listening( &mut self, ) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Stops listening.
§Examples
// Configure chip and start listening
chip.open_reading_pipe(DataPipe::DP0, b"Node1")?;
chip.start_listening()?;
// ... read data
// Reading is done, now we can stop listening
chip.stop_listening()?;
Sourcepub fn data_available(
&mut self,
) -> Result<bool, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn data_available( &mut self, ) -> Result<bool, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Checks if there are any bytes available to be read.
§Examples
// Chip has to be set in listening mode first
chip.open_reading_pipe(DataPipe::DP0, b"Node1")?;
chip.start_listening()?;
// Check if there is any data to read
while chip.data_available()? {
// ... read the payload
delay.delay_ms(50); // small delay between calls of data_available
}
§Notes
If data_available is called in too rapid succession, the chip can glitch out.
If this is the case, just add a small delay between calling successive data_available
.
Sourcepub fn data_available_on_pipe(
&mut self,
) -> Result<Option<DataPipe>, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn data_available_on_pipe( &mut self, ) -> Result<Option<DataPipe>, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Returns the data pipe where the data is available and None
if no data available.
§Examples
// Chip has to be set in listening mode first
chip.open_reading_pipe(DataPipe::DP0, b"Node1")?;
chip.start_listening()?;
// Check if there is any data to read on pipe 1
while let Some(pipe) = chip.data_available_on_pipe()? {
if pipe == DataPipe::DP1 {
// ... read the payload
delay.delay_ms(50); // small delay between calls of data_available
}
}
Sourcepub fn read(
&mut self,
buf: &mut [u8],
) -> Result<usize, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn read( &mut self, buf: &mut [u8], ) -> Result<usize, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Reads the available payload. To check if there are any payloads available, call
data_available()
.
Make sure the chip is configured in listening mode and at least one data pipe is opened for reading, see:
Returns the number of bytes read into the buffer.
§Examples
// We will be receiving float values
// Set the payload size to 4 bytes, the size of an f32
let config = NrfConfig::default().payload_size(PayloadSize::Static(4));
let chip = Nrf24l01::new(spi, ce, &mut delay, config).unwrap();
// Put the chip in listening mode
chip.open_reading_pipe(DataPipe::DP0, b"Node1");
chip.start_listening();
// The buffer where we will read the data into
let mut buffer = [0u8; 4];
loop {
// Keep reading data if any is available
while let Ok(true) = chip.data_available() {
match chip.read(&mut buffer) {
Err(e) => eprintln!("Error while reading data from buffer: {:?}", e),
Ok(n) => {
println!("Successfully read {} bytes of data!", n);
assert_eq!(n, 4);
// reinterpret memory as a float
let f = f32::from_le_bytes(buffer);
println!("Received value: {}", f);
},
}
}
// Wait some time before trying again
delay.delay_us(50);
}
Sourcepub fn write<D: DelayNs>(
&mut self,
delay: &mut D,
buf: &[u8],
) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn write<D: DelayNs>( &mut self, delay: &mut D, buf: &[u8], ) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Writes data to the opened channel.
§Examples
// We will be sending float values
// Set the payload size to 4 bytes, the size of an f32
let config = NrfConfig::default().payload_size(PayloadSize::Static(4));
let chip = Nrf24l01::new(spi, ce, &mut delay, config).unwrap();
// Put the chip in transmission mode
chip.open_writing_pipe(b"Node1");
chip.stop_listening();
// The buffer where we will write data into before sending
let mut buffer = [0u8; 4];
loop {
let f = get_reading(); // data from some sensor
// reinterpret float to bytes and put into buffer
buffer.copy_from_slice(&f.to_le_bytes());
match chip.write(&mut delay, &buffer) {
Err(e) => eprintln!("Error while sending data {:?}", e),
Ok(_) => {
println!("Successfully wrote the data!");
},
}
// Wait some time before trying again
delay.delay_us(50);
}
Will clear all interrupt flags after write. Returns an error when max retries have been reached.
Sourcepub fn set_retries<T: Into<AutoRetransmission>>(
&mut self,
auto_retry: T,
) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn set_retries<T: Into<AutoRetransmission>>( &mut self, auto_retry: T, ) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Setup of automatic retransmission.
§Arguments
delay
is the auto retransmit delay. Values can be between 0 and 15. The delay before a retransmit is initiated, is calculated according to the following formula:
((delay + 1) * 250) + 86 µs
count
is number of times there will be an auto retransmission. Must be a value between 0 and 15.
§Examples
// Set the auto transmit delay to (5 + 1) * 250) + 86 = 1586µs
// and the retransmit count to 15.
nrf24l01.set_retries((5, 15))?;
Sourcepub fn retries(
&mut self,
) -> Result<AutoRetransmission, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn retries( &mut self, ) -> Result<AutoRetransmission, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Returns the auto retransmission config.
§Examples
// Initialize the chip
let mut chip = Nrf24l01::new(spi_struct, ce_pin, delay, NrfConfig::default())?;
let retries_config = chip.retries()?;
// Default values for the chip
assert_eq!(retries_config.delay(), 1586);
assert_eq!(retries_config.count(), 15);
Sourcepub fn set_channel(
&mut self,
channel: u8,
) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn set_channel( &mut self, channel: u8, ) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Sourcepub fn channel(
&mut self,
) -> Result<u8, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn channel( &mut self, ) -> Result<u8, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Return the frequency channel nRF24L01 operates on. Note that the actual frequency will we the channel +2400 MHz.
§Examples
// Initialize the chip
let mut chip = Nrf24l01::new(spi_struct, ce_pin, delay, NrfConfig::default())?;
// Default is channel 76
assert_eq!(chip.channel()?, 76);
Sourcepub fn set_address_width<T>(
&mut self,
width: T,
) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>where
T: Into<AddressWidth>,
pub fn set_address_width<T>(
&mut self,
width: T,
) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>where
T: Into<AddressWidth>,
Sourcepub fn data_rate(
&mut self,
) -> Result<DataRate, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn data_rate( &mut self, ) -> Result<DataRate, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Sourcepub fn power_amp_level(
&mut self,
) -> Result<PALevel, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn power_amp_level( &mut self, ) -> Result<PALevel, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Sourcepub fn flush_tx(
&mut self,
) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn flush_tx( &mut self, ) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Sourcepub fn flush_rx(
&mut self,
) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn flush_rx( &mut self, ) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Sourcepub fn enable_crc(
&mut self,
scheme: EncodingScheme,
) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn enable_crc( &mut self, scheme: EncodingScheme, ) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Sourcepub fn crc_encoding_scheme(
&mut self,
) -> Result<EncodingScheme, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn crc_encoding_scheme( &mut self, ) -> Result<EncodingScheme, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Get the CRC encoding scheme
§Examples
match chip.crc_encoding_scheme()? {
EncodingScheme::NoRedundancyCheck => println("No crc check"),
EncodingScheme::R1Byte => println("8 bit check"),
EncodingScheme::R2Bytes => println("16 bit check"),
};
Sourcepub fn set_payload_size<T: Into<PayloadSize>>(
&mut self,
payload_size: T,
) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn set_payload_size<T: Into<PayloadSize>>( &mut self, payload_size: T, ) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Sets the payload size in bytes. This can either be static with a set size, or dynamic.
payload_size
can either be an instance of the PayloadSize
enum, or an integer.
§Notes
- A value of 0 means the dynamic payloads will be enabled.
- Values bigger than
MAX_PAYLOAD_SIZE
will be set to the maximum.
§Examples
// Two equal methods to set the chip to dynamic payload mode.
chip.set_payload_size(PayloadSize::Dynamic)?;
chip.set_payload_size(0)?;
// Following methods set a static payload size.
chip.set_payload_size(12)?; // Messages will be 12 bytes
chip.set_payload_size(PayloadSize::Static(12))?; // Same as previous
chip.set_payload_size(49)?; // Messages will be `MAX_PAYLOAD_SIZE`
Sourcepub fn payload_size(&self) -> PayloadSize
pub fn payload_size(&self) -> PayloadSize
Returns the payload size as a PayloadSize
enum.
§Examples
// Initialize chip
let mut chip = Nrf24l01::new(spi_struct, ce_pin, delay, NrfConfig::default())?;
// Default payload size is MAX_PAYLOAD_SIZE
assert_eq!(chip.payload_size()?, PayloadSize::Static(MAX_PAYLOAD_SIZE));
Sourcepub fn power_up<D: DelayNs>(
&mut self,
delay: &mut D,
) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn power_up<D: DelayNs>( &mut self, delay: &mut D, ) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Powers the chip up. Note that a new initialized device will already be in power up mode, so
calling power_up()
is not necessary.
Should be called after power_down()
to put the chip back into power up mode.
§Examples
// Go to sleep
chip.power_down(&mut delay)?;
// Zzz
// ...
chip.power_up(&mut delay)?; // power back up
Sourcepub fn power_down(
&mut self,
) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn power_down( &mut self, ) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Powers the chip down. This is the low power mode. The chip will consume approximatly 900nA.
To power the chip back up, call power_up()
.
§Examples
// Go to sleep
chip.power_down(&mut delay)?;
// Zzz
// ...
chip.power_up(&mut delay)?; // power back up
Sourcepub fn status(
&mut self,
) -> Result<Status, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn status( &mut self, ) -> Result<Status, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Reads the status register from device. See Status
.
Sourcepub fn reset_status(
&mut self,
) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn reset_status( &mut self, ) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Resets the following flags in the status register:
- data ready RX fifo interrupt
- data sent TX fifo interrupt
- maximum number of retries interrupt
Sourcepub fn mask_interrupts(
&mut self,
irq: Interrupts,
) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn mask_interrupts( &mut self, irq: Interrupts, ) -> Result<(), TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Masks the selected interrupt flags.
By default, the IRQ pin will pull low when one of the following events occur:
- Maximum number of retries is reached
- Transmission data is sent
- Receiver data is avaiable to be read
This function allows you to disable these interrupts.
§Note
Masking an interrupt doesn’t prevent the event from occurring or prevent the status flag from being set. It only prevents the external IRQ pin from triggering. You can still read the status register to see if the event occurred, even if the interrupt is masked.
§Examples
let interrupts = Interrupts::new().max_retries().rx_data_ready();
chip.mask_interrupts(interrupts)?;
Disable all interrupts.
let interrupts = Interrupts::all();
chip.mask_interrupt(interrupts);
Sourcepub fn interrupt_src(
&mut self,
) -> Result<Interrupts, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn interrupt_src( &mut self, ) -> Result<Interrupts, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Query which interrupts were triggered.
Clears the interrupt request flags, so new ones can come in.
Sourcepub fn read_config(
&mut self,
) -> Result<NrfConfig, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
pub fn read_config( &mut self, ) -> Result<NrfConfig, TransceiverError<<SPI as SpiErrorType>::Error, <CE as PinErrorType>::Error>>
Reads the config from the device and returns it in a NrfConfig
struct.
Can be used to log the configuration when using defmt
feature.