add library to control nodric nRF24L01(+) transceivers
This commit is contained in:
parent
c25693e14c
commit
f42fcc3b8f
427
lib/nrf24.c
Normal file
427
lib/nrf24.c
Normal file
@ -0,0 +1,427 @@
|
||||
/* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
/* Copyright (c) 2015 King Kévin <kingkevin@cuvoodoo.info> */
|
||||
/* This library allows to communicate with a nordic semiconductor nRF24L01 2.4GHz single chip transceiver
|
||||
* this library uses the SPI bus and requires interrupts to handle the IRQ
|
||||
*/
|
||||
#include <stdint.h> // Standard Integer Types
|
||||
#include <stdlib.h> // General utilities
|
||||
#include <stdbool.h> // Boolean
|
||||
#include <string.h> // Memory utilities
|
||||
|
||||
#include <avr/io.h> // AVR device-specific IO definitions
|
||||
#include <avr/interrupt.h> // Interrupts
|
||||
|
||||
#include <spi.h> // SPI functions
|
||||
#include <nrf24.h> // nRF24L01 configuration
|
||||
|
||||
#include <stdio.h> // Standard IO facilities
|
||||
#include <avr/pgmspace.h> // Program Space Utilities
|
||||
|
||||
#if defined(IRQ_DDR) && defined(IRQ_IO)
|
||||
/* if the nRF24L01 is initialized with interrupts, watch for nrf_activity to go true
|
||||
* once true, check if transmission or reception happened using nrf24_activity(), then nrf24_tx_activity() or nrf24_rx_activity()
|
||||
* you can then check is transmission succeeded using nrf24_tx_succeeded()
|
||||
* or get the received data using nrf24_rx_data()
|
||||
* set it to false after checks are done
|
||||
*/
|
||||
volatile bool nrf24_flag = false;
|
||||
#endif
|
||||
/* stay in RX mode to receive data */
|
||||
bool rx = false;
|
||||
|
||||
/* initialize the nRF24L01 */
|
||||
void nrf24_init()
|
||||
{
|
||||
// configure SPI
|
||||
spi_init(); // SPI is used to communicate with the nRF24L01
|
||||
// configure IO
|
||||
CE_DDR |= (1<<CE_IO); // set CE as output
|
||||
CE_PORT &= ~(1<<CE_IO); // disable CE (TR/RX)
|
||||
// initialise variables
|
||||
rx = false;
|
||||
// power up device
|
||||
// use spi_transfer_blocking in case global interrupt has not been enabled
|
||||
uint8_t cmd[2]; // to send commands
|
||||
cmd[0] = 0x00+0x00; // R_REGISTER command + CONFIG register
|
||||
spi_transfer_blocking(cmd,sizeof(cmd)); // read configuration
|
||||
#if defined(IRQ_DDR) && defined(IRQ_IO)
|
||||
cmd[1] &= ~(0x70); // enable interrupt by clearing MASK_RX_DR, MASK_TX_DS, MASK_MAX_RT
|
||||
#else
|
||||
cmd[1] |= (0x70); // disable interrupt by setting MASK_RX_DR, MASK_TX_DS, MASK_MAX_RT
|
||||
#endif
|
||||
cmd[1] |= (1<<1); // set PWR_UP to power up
|
||||
cmd[1] &= ~(1<<2); // set CRC to 1 byte
|
||||
//cmd[1] |= (1<<2); // set CRC to 2 byte
|
||||
cmd[0] = 0x20+0x00; // W_REGISTER command + CONFIG register
|
||||
spi_transfer_blocking(cmd,sizeof(cmd)); // write configuration
|
||||
// flush TX FIFO
|
||||
cmd[0] = 0x00+0x00; // R_REGISTER command + CONFIG register
|
||||
spi_transfer_blocking(cmd,sizeof(cmd)); // read config
|
||||
cmd[0] = 0x20+0x00; // W_REGISTER command + CONFIG register
|
||||
cmd[1] &= ~(1<<0); // set PRIM_RX to 0 (PTX)
|
||||
spi_transfer_blocking(cmd,sizeof(cmd)); // write config to got in PTX mode
|
||||
cmd[0] = 0xe1; // FLUSH_TX
|
||||
spi_transfer_blocking(cmd,1); // flush TX FIFO
|
||||
// flush RX FIFO
|
||||
cmd[0] = 0x00+0x00; // R_REGISTER command + CONFIG register
|
||||
spi_transfer_blocking(cmd,sizeof(cmd)); // read config
|
||||
cmd[0] = 0x20+0x00; // W_REGISTER command + CONFIG register
|
||||
cmd[1] |= (1<<0); // set PRIM_RX to 1 (PRX)
|
||||
spi_transfer_blocking(cmd,sizeof(cmd)); // write config to got in PRX mode
|
||||
cmd[0] = 0xe2; // FLUSH_RX
|
||||
spi_transfer_blocking(cmd,1); // flush RX FIFO
|
||||
// clear interrupts
|
||||
cmd[0] = 0x20+0x07; // W_REGISTER command + STATUS register
|
||||
cmd[1] = 0x70; // clear interrupts
|
||||
spi_transfer_blocking(cmd,sizeof(cmd)); // clear interrupts
|
||||
// enable auto acknowledge
|
||||
cmd[0] = 0x20+0x01; // W_REGISTER command + EN_AA register
|
||||
cmd[1] = 0x3f; // enable auto for all channels
|
||||
spi_transfer_blocking(cmd,sizeof(cmd)); // write auto acknowledge
|
||||
// enable data pipes 0 (to enable acknowledgement) and 1 (to receive)
|
||||
cmd[0] = 0x20+0x02; // W_REGISTER command + EN_RXADDR register
|
||||
cmd[1] = 0x03; // enable RX pipes 0 and 1
|
||||
spi_transfer_blocking(cmd,sizeof(cmd)); // enable pipes
|
||||
// enable dynamic payload
|
||||
cmd[0] = 0x20+0x1d; // W_REGISTER command + FEATURE register
|
||||
cmd[1] = 0x04; // set EN_DPL
|
||||
spi_transfer_blocking(cmd,sizeof(cmd)); // enable dynamic payload
|
||||
cmd[0] = 0x20+0x1c; // W_REGISTER command + DYNPD register
|
||||
cmd[1] = 0x3f; // set DPL_Px
|
||||
spi_transfer_blocking(cmd,sizeof(cmd)); // enable dynamic payload on all pipes
|
||||
// set address width to 5 bytes
|
||||
cmd[0] = 0x20+0x03; // W_REGISTER command + SETUP_AW register
|
||||
cmd[1] = 0x03; // set to 5 bytes
|
||||
spi_transfer_blocking(cmd,sizeof(cmd)); // set address width
|
||||
// set RF: data rate, power
|
||||
cmd[0] = 0x00+0x06; // R_REGISTER command + RF_SETUP register
|
||||
spi_transfer_blocking(cmd,sizeof(cmd)); // read RF setup
|
||||
cmd[0] = 0x20+0x06; // W_REGISTER command + RF_SETUP register
|
||||
cmd[1] &= ~(1<<3); // set RF_DR to 1 Mbps
|
||||
//cmd[1] |= (1<<3); // set RF_DR to 2 Mbps
|
||||
cmd[1] |= (1<<2)|(1<<1); // set RF_PWR to 0 dBm (max)
|
||||
spi_transfer_blocking(cmd,sizeof(cmd)); // set RF: data rate, power
|
||||
// set re-transmit properties
|
||||
cmd[0] = 0x20+0x04; // W_REGISTER command + SETUP_RETR register
|
||||
cmd[1] = 0x1f; // set ARD to 500uS and ARC to 15
|
||||
spi_transfer_blocking(cmd,sizeof(cmd)); // set re-transmit properties
|
||||
// enable interrupt
|
||||
#if defined(IRQ_IO)
|
||||
IRQ_DDR &= ~(1<<IRQ_IO); // set IRQ as input
|
||||
#if defined(IRQ_INT) && (IRQ_INT==1) && (IRQ_IO==PD2) // INT0 interrupt
|
||||
EIMSK |= (1<<INT0); // enable interrupt for IRQ pin
|
||||
EICRA &= ~(1<<ISC00); // interrupt on falling edge
|
||||
EICRA |= (1<<ISC01); // interrupt on falling edge
|
||||
#elif defined(IRQ_INT) && (IRQ_INT==1) && (IRQ_IO==PD3) // INT1 interrupt
|
||||
EIMSK |= (1<<INT1); // enable interrupt for IRQ pin
|
||||
EICRA &= ~(1<<ISC10); // interrupt on falling edge
|
||||
EICRA |= (1<<ISC11); // interrupt on falling edge
|
||||
#else // PCINT interrupt
|
||||
PCICR |= (1<<IRQ_PCIE); // enable interrupt for IRQ port
|
||||
IRQ_PCMSK |= (1<<IRQ_IO); // enable interrupt for IRQ pin
|
||||
#endif
|
||||
nrf24_flag = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* register names */
|
||||
const char reg_00[] PROGMEM = "CONFIG";
|
||||
const char reg_01[] PROGMEM = "EN_AA";
|
||||
const char reg_02[] PROGMEM = "EN_RXADDR";
|
||||
const char reg_03[] PROGMEM = "SETUP_AW";
|
||||
const char reg_04[] PROGMEM = "SETUP_RETR";
|
||||
const char reg_05[] PROGMEM = "RF_CH";
|
||||
const char reg_06[] PROGMEM = "RF_SETUP";
|
||||
const char reg_07[] PROGMEM = "STATUS";
|
||||
const char reg_08[] PROGMEM = "OBSERVE_TX";
|
||||
const char reg_09[] PROGMEM = "CD";
|
||||
const char reg_10[] PROGMEM = "RX_ADDR_P0";
|
||||
const char reg_11[] PROGMEM = "RX_ADDR_P1";
|
||||
const char reg_12[] PROGMEM = "RX_ADDR_P2";
|
||||
const char reg_13[] PROGMEM = "RX_ADDR_P3";
|
||||
const char reg_14[] PROGMEM = "RX_ADDR_P4";
|
||||
const char reg_15[] PROGMEM = "RX_ADDR_P5";
|
||||
const char reg_16[] PROGMEM = "TX_ADDR";
|
||||
const char reg_17[] PROGMEM = "RX_PW_P0";
|
||||
const char reg_18[] PROGMEM = "RX_PW_P1";
|
||||
const char reg_19[] PROGMEM = "RX_PW_P2";
|
||||
const char reg_20[] PROGMEM = "RX_PW_P3";
|
||||
const char reg_21[] PROGMEM = "RX_PW_P4";
|
||||
const char reg_22[] PROGMEM = "RX_PW_P5";
|
||||
const char reg_23[] PROGMEM = "FIFO_STATUS";
|
||||
/* register names table */
|
||||
PGM_P const reg_names[] PROGMEM = {
|
||||
reg_00,
|
||||
reg_01,
|
||||
reg_02,
|
||||
reg_03,
|
||||
reg_04,
|
||||
reg_05,
|
||||
reg_06,
|
||||
reg_07,
|
||||
reg_08,
|
||||
reg_09,
|
||||
reg_10,
|
||||
reg_11,
|
||||
reg_12,
|
||||
reg_13,
|
||||
reg_14,
|
||||
reg_15,
|
||||
reg_16,
|
||||
reg_17,
|
||||
reg_18,
|
||||
reg_19,
|
||||
reg_20,
|
||||
reg_21,
|
||||
reg_22,
|
||||
reg_23
|
||||
};
|
||||
/* register size */
|
||||
const uint8_t reg_sizes[] PROGMEM = {1,1,1,1,1,1,1,1,1,1,5,5,1,1,1,1,5,1,1,1,1,1,1,1};
|
||||
|
||||
/* dump config */
|
||||
void nrf24_dump()
|
||||
{
|
||||
uint8_t cmd[6]; // SPI nFR24L01 command
|
||||
uint8_t reg_size; // the register size
|
||||
char* str; // to print strings
|
||||
for (uint8_t i=0; i<sizeof(reg_sizes); i++) { // go through registers
|
||||
cmd[0] = 0x00+i; // R_REGISTER command + register
|
||||
reg_size = pgm_read_byte(&(reg_sizes[i]));
|
||||
spi_transfer_wait(cmd,1+reg_size); // read register
|
||||
str = malloc(strlen_PF((uint_farptr_t)pgm_read_word(&(reg_names[i]))));
|
||||
strcpy_PF(str, (uint_farptr_t)pgm_read_word(&(reg_names[i])));
|
||||
printf(str);
|
||||
free(str);
|
||||
printf(": ");
|
||||
for (uint8_t j=0; j<reg_size; j++) {
|
||||
printf("%02x ",cmd[1+j]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* set the 5 bytes TX address
|
||||
* it will be used as the destination address of the data to transmit
|
||||
* this address will also be used (in RX_ADDR_P0) to receive the ack
|
||||
*/
|
||||
void nrf24_set_tx_addr(uint8_t* addr)
|
||||
{
|
||||
uint8_t cmd[6]; // command
|
||||
cmd[0] = 0x20+0x10; // W_REGISTER command + TX_ADDR register
|
||||
memcpy(&cmd[1],addr,sizeof(cmd)-1); // copy address
|
||||
spi_transfer_wait(cmd,sizeof(cmd)); // write TX_ADDR
|
||||
cmd[0] = 0x20+0x0A; // W_REGISTER command + RX_ADDR_P0 register
|
||||
memcpy(&cmd[1],addr,sizeof(cmd)-1); // copy address (since it has been overwritten)
|
||||
spi_transfer_wait(cmd,sizeof(cmd)); // write RX_ADDR_P0
|
||||
}
|
||||
|
||||
/* set the 5 bytes RX address
|
||||
* it will be used as the address of the receiving device
|
||||
* this address will be used in RX_ADDR_P1
|
||||
*/
|
||||
void nrf24_set_rx_addr(uint8_t* addr)
|
||||
{
|
||||
uint8_t cmd[6]; // command
|
||||
cmd[0] = 0x20+0x0B; // W_REGISTER command + RX_ADDR_P1 register
|
||||
memcpy(&cmd[1],addr,sizeof(cmd)-1); // copy address
|
||||
spi_transfer_wait(cmd,sizeof(cmd)); // write RX_ADDR_P1
|
||||
}
|
||||
|
||||
/* set the RF channel to transmit on */
|
||||
void nrf24_set_rf_channel(uint8_t channel)
|
||||
{
|
||||
if (channel>125) {
|
||||
return;
|
||||
}
|
||||
/* verify there is space in the FIFO */
|
||||
uint8_t cmd[2]; // command
|
||||
cmd[0] = 0x20+0x05; // W_REGISTER command + RF_CH register
|
||||
cmd[1] = channel; // set channel
|
||||
spi_transfer_wait(cmd,sizeof(cmd)); // write RF_CH
|
||||
}
|
||||
|
||||
/* transmit <payload> with of <length> bytes (max 32 bytes)
|
||||
* returns false if input is corrupted or FIFO is already full
|
||||
* returns true after payload is written
|
||||
*/
|
||||
bool nrf24_transmit(uint8_t* payload, uint8_t length)
|
||||
{
|
||||
if (payload==NULL || length==0 || length>32) { // ensure data and size is valid
|
||||
return false;
|
||||
}
|
||||
/* check if TX FIFO is full */
|
||||
uint8_t cmd[2]; // command
|
||||
cmd[0] = 0x00+0x17; // R_REGISTER command + FIFO_STATUS register
|
||||
spi_transfer_wait(cmd,sizeof(cmd)); // read FIFO status
|
||||
if (cmd[1]&(1<<5)) { // TX_FULL
|
||||
return false;
|
||||
}
|
||||
/* go into TX mode */
|
||||
cmd[0] = 0x00+0x00; // R_REGISTER command + CONFIG register
|
||||
spi_transfer_wait(cmd,sizeof(cmd)); // read config
|
||||
cmd[0] = 0x20+0x00; // W_REGISTER command + CONFIG register
|
||||
cmd[1] &= ~(1<<0); // set PRIM_RX to 0 (PTX)
|
||||
spi_transfer_wait(cmd,sizeof(cmd)); // write config to got in PTX mode
|
||||
/* write TX payload */
|
||||
uint8_t* tx = calloc(length+1,sizeof(uint8_t));
|
||||
tx[0] = 0xa0; // W_TX_PAYLOAD command
|
||||
memcpy(&tx[1],payload,length); // copy data
|
||||
spi_transfer_wait(tx,length+1); // write TX payload
|
||||
/* start transmission */
|
||||
CE_PORT |= (1<<CE_IO); // enable CE to start transmission
|
||||
// clean memory (the payload transfer is complete at this point)
|
||||
free(tx);
|
||||
tx = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* put device into RX mode or disable it */
|
||||
void nrf24_enable_rx(bool enable)
|
||||
{
|
||||
rx = enable; // remember to stay in RX mode
|
||||
if (rx) {
|
||||
uint8_t cmd[2]; // SPI command
|
||||
cmd[0] = 0x00+0x00; // R_REGISTER command + CONFIG register
|
||||
spi_transfer_wait(cmd,sizeof(cmd)); // read config
|
||||
cmd[0] = 0x20+0x00; // W_REGISTER command + CONFIG register
|
||||
cmd[1] |= (1<<0); // set PRIM_RX to 1 (PRX)
|
||||
spi_transfer_wait(cmd,sizeof(cmd)); // write config to got in PRX mode
|
||||
CE_PORT |= (1<<CE_IO); // enable CE to start receiving
|
||||
} else {
|
||||
uint8_t cmd[2]; // SPI command
|
||||
cmd[0] = 0x00+0x00; // R_REGISTER command + CONFIG register
|
||||
spi_transfer_wait(cmd,sizeof(cmd)); // read config
|
||||
if (cmd[1]&(1<<0)) { // currently in RX mode
|
||||
CE_PORT &= ~(1<<CE_IO); // disable CE to go to sleep
|
||||
} // do not disable if in TX mode
|
||||
}
|
||||
}
|
||||
|
||||
/* handle IRQ interrupt */
|
||||
#if defined(IRQ_IO)
|
||||
#if defined(IRQ_INT) && (IRQ_INT==1) && (IRQ_IO==PD2) // INT0 interrupt
|
||||
ISR(INT0_vect)
|
||||
#elif defined(IRQ_INT) && (IRQ_INT==1) && (IRQ_IO==PD3) // INT1 interrupt
|
||||
ISR(INT1_vect)
|
||||
#else // PCINT interrupt
|
||||
ISR(IRQ_PCINT_vect)
|
||||
#endif
|
||||
{ /* RX or TX succeeded or failed */
|
||||
nrf24_flag = true; // warn user
|
||||
}
|
||||
#endif
|
||||
|
||||
/* check the current status of the device
|
||||
* return nrf24_activity_t bits correspoinding to the activies
|
||||
* call it after an interrupt
|
||||
* puts device back in PRX mode if transmission completed and rx has been enabled
|
||||
* puts device back to sleep if transmission completed and rx has not been enabled
|
||||
*/
|
||||
uint8_t nrf24_activity()
|
||||
{
|
||||
uint8_t to_return = 0; // is there activity
|
||||
uint8_t cmd[2]; // SPI nFR24L01 command
|
||||
// get status
|
||||
cmd[0] = 0xff; // NOP to read STATUS
|
||||
spi_transfer_wait(cmd,1); // read STATUS register
|
||||
// clear receive interrupt
|
||||
to_return = cmd[0]&(0x70); // copy RX_DR, TS_DS, MAX_RT
|
||||
if ((cmd[0]&0x0e)<0x0b) { // payload is available based on RX_P_NO
|
||||
to_return |= RX_AVAILABLE; // warn user
|
||||
}
|
||||
if (cmd[0]&(0x70)) { // activity cause by interrupt
|
||||
cmd[0] = 0x20+0x07; // W_REGISTER command + STATUS register
|
||||
cmd[1] = 0x70; // clear interrupts
|
||||
spi_transfer_wait(cmd,2); // clear interrupt
|
||||
}
|
||||
if (to_return&TX_FAILED) { // transmission failed based on MAX_RT
|
||||
cmd[0] = 0xe1; // FLUSH_TX command
|
||||
spi_transfer_wait(cmd,1); // flush failed TX_FIFO
|
||||
}
|
||||
// verify is there is still data to transmit
|
||||
cmd[0] = 0x00+0x17; // R_REGISTER command + FIFO_STATUS register
|
||||
spi_transfer_wait(cmd,2); // read FIFO_STATUS register
|
||||
if (!(cmd[1]&(1<<4))) { // check TX_EMPTY, if not empty put is TX mode
|
||||
cmd[0] = 0x00+0x00; // R_REGISTER command + CONFIG register
|
||||
spi_transfer_wait(cmd,2); // read config
|
||||
cmd[0] = 0x20+0x00; // W_REGISTER command + CONFIG register
|
||||
cmd[1] &= ~(1<<0); // set PRIM_RX to 0 (PTX)
|
||||
spi_transfer_wait(cmd,2); // write config to got in PTX mode
|
||||
CE_PORT |= (1<<CE_IO); // enable CE to start transmission
|
||||
} else if (rx) { // go in RX mode if enables (and TX FIFO is empty)
|
||||
cmd[0] = 0x00+0x00; // R_REGISTER command + CONFIG register
|
||||
spi_transfer_wait(cmd,2); // read config
|
||||
cmd[0] = 0x20+0x00; // W_REGISTER command + CONFIG register
|
||||
cmd[1] |= (1<<0); // set PRIM_RX to 1 (PRX)
|
||||
spi_transfer_wait(cmd,2); // write config to got in PRX mode
|
||||
CE_PORT |= (1<<CE_IO); // enable CE to start receiving
|
||||
} else { // nothing to send, and RX is not enabled
|
||||
CE_PORT &= ~(1<<CE_IO); // disable CE to go to sleep
|
||||
}
|
||||
|
||||
return to_return;
|
||||
}
|
||||
|
||||
/* verify if data is available in the RX FIFO */
|
||||
bool nrf24_data_available()
|
||||
{
|
||||
uint8_t cmd[2]; // SPI nFR24L01 command
|
||||
cmd[0] = 0x00+0x17; // R_REGISTER command + FIFO_STATUS register
|
||||
spi_transfer_wait(cmd,sizeof(cmd)); // read STATUS register
|
||||
return !(cmd[1]&0x01); // not RX FIFO empty
|
||||
}
|
||||
|
||||
/* writes to received payload in provided <payload> pointer
|
||||
* returns size of received data
|
||||
* returns 0 if no data is available
|
||||
* write maximum <size> in <payload> (max payload size is 32)
|
||||
*/
|
||||
uint8_t nrf24_rx_payload(uint8_t* payload, uint8_t size)
|
||||
{
|
||||
uint8_t to_return = 0; // the size of the data
|
||||
uint8_t cmd[2]; // SPI nFR24L01 command
|
||||
cmd[0] = 0x60; // R_RX_PL_WID command
|
||||
spi_transfer_wait(cmd,2); // get size (and STATUS)
|
||||
if ((cmd[0]&0x0e)==0x0e) { // RX_FIFO empty based on RX_P_NO
|
||||
to_return = 0; // no data is available
|
||||
} else if (cmd[1]>32) { // something is wrong
|
||||
cmd[0] = 0xe2; // FLUSH_RX command
|
||||
spi_transfer_wait(cmd,1); // flush, as suggested by the note
|
||||
to_return = 0;
|
||||
} else { // data is available
|
||||
to_return = cmd[1];
|
||||
if (to_return>size) { // avoid buffer overflow
|
||||
to_return = size;
|
||||
}
|
||||
// go into RX mode
|
||||
cmd[0] = 0x00+0x00; // R_REGISTER command + CONFIG register
|
||||
spi_transfer_wait(cmd,2); // read config
|
||||
cmd[0] = 0x20+0x00; // W_REGISTER command + CONFIG register
|
||||
cmd[1] |= (1<<0); // set PRIM_RX to 1 (PRX)
|
||||
spi_transfer_wait(cmd,2); // write config to got in PRX mode
|
||||
// read RX payload
|
||||
uint8_t* data = calloc(to_return+1,sizeof(uint8_t)); // re-allocated memory to get data
|
||||
data[0] = 0x61; // R_RX_PAYLOAD command
|
||||
spi_transfer_wait(data,to_return+1); // read FIFO (automatically deleted)
|
||||
memcpy(payload,&data[1],to_return); // copy payload
|
||||
free(data); // clean memory
|
||||
data = NULL; // clean memory
|
||||
}
|
||||
|
||||
return to_return;
|
||||
}
|
102
lib/nrf24.h
Normal file
102
lib/nrf24.h
Normal file
@ -0,0 +1,102 @@
|
||||
/* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
/* Copyright (c) 2015 King Kévin <kingkevin@cuvoodoo.info> */
|
||||
/* This library allows to communicate with a nordic semiconductor nRF24L01 2.4GHz single chip transceiver */
|
||||
|
||||
/* Chip Enable pin to activate TX/RX */
|
||||
#define CE_IO PB1
|
||||
#define CE_PORT PORTB
|
||||
#define CE_DDR DDRB
|
||||
#define CE_PIN PINB
|
||||
/* Interrupt ReQuest pin to activate TX/RX */
|
||||
// comment out IRQ_IO if you don't want to use interrupts
|
||||
#define IRQ_IO PD2
|
||||
#define IRQ_PORT PORTD
|
||||
#define IRQ_DDR DDRD
|
||||
#define IRQ_PIN PIND
|
||||
#define IRQ_PCIE PCIE2
|
||||
#define IRQ_PCMSK PCMSK2
|
||||
#define IRQ_PCINT_vect PCINT2_vect
|
||||
// if you use PD2 or PD3 you can use the INT0 or INT1 interrupt so to not take over a whole PORT PCINT interrupt
|
||||
#if defined(IRQ_IO) && ((IRQ_IO==PD2)||(IRQ_IO==PD3))
|
||||
// comment or set to 0 if you prefer to use PCINT interrupt
|
||||
// define and set to 1 if you prefer to use INT interrupt
|
||||
#define IRQ_INT 1
|
||||
#endif
|
||||
|
||||
#if defined(IRQ_DDR) && defined(IRQ_IO)
|
||||
/* if the nRF24L01 is initialized with interrupts, watch for nrf_activity to go true
|
||||
* once true, check if transmission or reception happened using nrf24_activity(), then nrf24_tx_activity() or nrf24_rx_activity()
|
||||
* you can then check is transmission succeeded using nrf24_tx_succeeded()
|
||||
* or get the received data using nrf24_rx_data()
|
||||
* set it to false after checks are done
|
||||
*/
|
||||
extern volatile bool nrf24_flag;
|
||||
#endif
|
||||
|
||||
/* initialize the nRF24L01 */
|
||||
void nrf24_init();
|
||||
/* set the 5 bytes TX address
|
||||
* it will be used as the destination address of the data to transmit
|
||||
* this address will also be used (in RX_ADDR_P0) to receive the ack
|
||||
*/
|
||||
void nrf24_set_tx_addr(uint8_t* addr);
|
||||
/* set the 5 bytes RX address
|
||||
* it will be used as the address of the receiving device
|
||||
* this address will be used in RX_ADDR_P1
|
||||
*/
|
||||
void nrf24_set_rx_addr(uint8_t* addr);
|
||||
/* set the RF channel to transmit on */
|
||||
void nrf24_set_rf_channel(uint8_t channel);
|
||||
/* transmit <payload> with of <length> bytes (max 32 bytes)
|
||||
* returns false if input is corrupted or FIFO is already full
|
||||
* returns true after payload is written
|
||||
*/
|
||||
bool nrf24_transmit(uint8_t* payload, uint8_t length);
|
||||
/* put device into RX mode or disable it */
|
||||
void nrf24_enable_rx(bool enable);
|
||||
/* handle IRQ interrupt */
|
||||
#if defined(IRQ_IO)
|
||||
#if defined(IRQ_INT) && (IRQ_INT==1) && (IRQ_IO==PD2) // INT0 interrupt
|
||||
ISR(INT0_vect);
|
||||
#elif defined(IRQ_INT) && (IRQ_INT==1) && (IRQ_IO==PD3) // INT1 interrupt
|
||||
ISR(INT1_vect);
|
||||
#else // PCINT interrupt
|
||||
ISR(IRQ_PCINT_vect);
|
||||
#endif
|
||||
#endif
|
||||
/* check the current status of the device
|
||||
* return nrf24_activities bits correspoinding to the activies
|
||||
* call it after an interrupt
|
||||
* puts device back in PRX mode if transmission completed and rx has been enabled
|
||||
* puts device back to sleep if transmission completed and rx has not been enabled
|
||||
*/
|
||||
enum nrf24_activities {
|
||||
TX_SUCCEEDED = (1<<5),
|
||||
TX_FAILED = (1<<4),
|
||||
RX_RECEIVED = (1<<6),
|
||||
RX_AVAILABLE = (1<<3)
|
||||
};
|
||||
uint8_t nrf24_activity();
|
||||
/* writes to received payload in provided <payload> pointer
|
||||
* returns size of received data
|
||||
* returns 0 if no data is available
|
||||
* write maximum <size> in <payload> (max payload size is 32)
|
||||
*/
|
||||
uint8_t nrf24_rx_payload(uint8_t* payload, uint8_t size);
|
||||
/* verify if data is available in the RX FIFO */
|
||||
bool nrf24_data_available();
|
||||
/* dump config */
|
||||
void nrf24_dump();
|
Loading…
Reference in New Issue
Block a user