Last active
August 29, 2015 14:06
-
-
Save nuft/62a82a600d9500f54b2b to your computer and use it in GitHub Desktop.
nRF24L01+ example code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "nRF24L01p.h" | |
/* addr is 5 bytes long (SETUP_AW = AW_5) */ | |
void nrf_setup_ptx(uint8_t channel, uint8_t addr[]) | |
{ | |
ce_low(); | |
// PRX, CRC, PWR_UP | |
nRF24L01p_write_register(CONFIG, PWR_UP | EN_CRC); | |
// 0dBm pwr, 250Kbps | |
nRF24L01p_write_register(RF_SETUP, RF_PWR(3) | RF_DR_250K); | |
// Enhanced ShockBurst Auto Acknowledgment on | |
nRF24L01p_write_register(EN_AA, ENAA_P0); | |
// enable dynamic packet length | |
nRF24L01p_write_register(FEATURE, EN_DPL | EN_ACK_PAY); | |
// enable dpl for pipe 0 | |
nRF24L01p_write_register(DYNPD, DPL_P0); | |
// 1 retransmit, 1500us auto retransmit delay | |
nRF24L01p_write_register(SETUP_RETR, ARD(6) | ARC(1)); | |
// channel 0..127 | |
nRF24L01p_write_register(RF_CH, channel); | |
// address | |
nRF24L01p_write_register(SETUP_AW, AW_5); | |
nRF24L01p_set_addr(TX_ADDR, addr); | |
nRF24L01p_set_addr(RX_ADDR_P0, addr); | |
nRF24L01p_write_register(EN_RXADDR, ERX_P0); | |
nRF24L01p_write_register(RX_PW_P0, 32); | |
// clear all interrupts | |
nRF24L01p_write_register(STATUS, RX_DR | TX_DS | MAX_RT); | |
nRF24L01p_flush_tx(); | |
nRF24L01p_flush_rx(); | |
} | |
void nrf_send_packet_ptx(uint8_t *pkt) | |
{ | |
nRF24L01p_write_register(CONFIG, PWR_UP | EN_CRC); | |
if (nRF24L01p_get_status_register() & TX_FULL) | |
nRF24L01p_flush_tx(); | |
nRF24L01p_write_register(STATUS, TX_DS | MAX_RT); | |
// fill payload fifo | |
nRF24L01p_write_tx_payload(pkt, 32); | |
// send packet | |
ce_high(); | |
os_delay_ms(1); | |
while(!(nRF24L01p_get_status_register() & (TX_DS | MAX_RT))); | |
ce_low(); | |
} | |
void nrf_setup_prx(uint8_t channel, uint8_t addr[]) | |
{ | |
ce_low(); | |
// PRX, CRC, PWR_UP | |
nRF24L01p_write_register(CONFIG, PWR_UP | PRIM_RX | EN_CRC); | |
// 0dBm pwr, 250Kbps | |
nRF24L01p_write_register(RF_SETUP, RF_PWR(3) | RF_DR_250K); | |
// Enhanced ShockBurst Auto Acknowledgment on | |
nRF24L01p_write_register(EN_AA, ENAA_P0); | |
// enable dynamic packet length | |
nRF24L01p_write_register(FEATURE, EN_DPL | EN_ACK_PAY); | |
// enable dpl for pipe 0 | |
nRF24L01p_write_register(DYNPD, DPL_P0); | |
// 1 retransmit, 1500us auto retransmit delay | |
nRF24L01p_write_register(SETUP_RETR, ARD(6) | ARC(1)); | |
// channel 0..127 | |
nRF24L01p_write_register(RF_CH, channel); | |
// address | |
nRF24L01p_write_register(SETUP_AW, AW_5); | |
nRF24L01p_set_addr(TX_ADDR, addr); | |
nRF24L01p_set_addr(RX_ADDR_P0, addr); | |
nRF24L01p_write_register(EN_RXADDR, ERX_P0); | |
nRF24L01p_write_register(RX_PW_P0, 32); | |
// clear all interrupts | |
nRF24L01p_write_register(STATUS, RX_DR | TX_DS | MAX_RT); | |
nRF24L01p_flush_tx(); | |
nRF24L01p_flush_rx(); | |
} | |
void radio_receive_prx(uint8_t *rx_pkt, uint8_t rx_pkt_len, uint8_t *tx_pkt, uint8_t *tx_pkt_len) | |
{ | |
nRF24L01p_write_register(STATUS, RX_DR | TX_DS | MAX_RT); | |
if (!(nRF24L01p_read_register(FIFO_STATUS) & FIFO_TX_FULL)) | |
nRF24L01p_write_ack_payload(0, tx_pkt, tx_pkt_len); | |
ce_high(); | |
while(true) { | |
uint8_t sreg = nRF24L01p_get_status_register(); | |
if ((sreg & RX_DR) == RX_DR && (sreg & RX_P_NO) != RX_P_NO) { | |
ce_low(); | |
*rx_pkt_len = nRF24L01p_read_rx_payload_len(); | |
if (rx_pkt != NULL) | |
nRF24L01p_read_rx_payload(rx_pkt, *rx_pkt_len); | |
else | |
nRF24L01p_flush_rx(); | |
break; | |
} | |
os_delay_ms(1); | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <gpio.h> | |
#include <spi.h> | |
#include "nRF24L01p.h" | |
/* | |
* nRF24L01p HW interface: | |
* IRQ: interrupt (out) | |
* CE: chip enable (in) | |
* SPI: CSN, SCK, MOSI, MISO | |
* config: MSBit first, LSByte first, CSN active low, | |
* max 10Mbps, cpol=0 (idle=low), cpha=0 (first edge) | |
*/ | |
// !!! | |
// CS inactive time min 50ns | |
// nRF24L01p commands | |
#define R_REGISTER 0x00 // 000A AAAA | |
#define W_REGISTER 0x20 // 001A AAAA | |
#define R_RX_PAYLOAD 0x61 | |
#define W_TX_PAYLOAD 0xA0 | |
#define FLUSH_TX 0xE1 | |
#define FLUSH_RX 0xE2 | |
#define REUSE_TX_PL 0xE3 | |
#define R_RX_PL_WID 0x60 | |
#define W_ACK_PAYLOAD 0xA8 // 1010 1PPP | |
#define W_TX_PAYLOAD_NOACK 0xB0 | |
#define NOP 0xFF | |
struct nRF24L01p *nrf; | |
void ce_high(void) | |
{ | |
gpio_set(&nrf->ce); | |
} | |
void ce_low(void) | |
{ | |
gpio_clear(&nrf->ce); | |
} | |
// | |
// Low level commands | |
// | |
uint8_t nRF24L01p_get_status_register(void) | |
{ | |
uint8_t cmd = NOP; | |
spi_single_access(&nrf->spi, &cmd, &cmd, 1); | |
return cmd; | |
} | |
uint8_t nRF24L01p_read_register(uint8_t addr) | |
{ | |
addr = R_REGISTER | (addr & 0x1F); | |
uint8_t reg; | |
struct spi_transfer t[] = { | |
{.r=NULL, .t=&addr, .len=1}, | |
{.r=®, .t=NULL, .len=1}}; | |
spi_access(&nrf->spi, t, 2); | |
return reg; | |
} | |
void nRF24L01p_write_register(uint8_t addr, uint8_t val) | |
{ | |
uint8_t buf[] = {W_REGISTER | (addr & 0x1F), val}; | |
spi_single_access(&nrf->spi, NULL, buf, 2); | |
} | |
void nRF24L01p_read_multibyte_register(uint8_t addr, uint8_t *buf, uint8_t len) | |
{ | |
uint8_t cmd = R_REGISTER | (addr & 0x1F); | |
struct spi_transfer t[] = { | |
{.r=NULL, .t=&cmd, .len=1}, | |
{.r=buf, .t=NULL, .len=len}}; | |
spi_access(&nrf->spi, t, 2); | |
} | |
void nRF24L01p_write_multibyte_register(uint8_t addr, uint8_t *buf, uint8_t len) | |
{ | |
uint8_t cmd = W_REGISTER | (addr & 0x1F); | |
struct spi_transfer t[] = { | |
{.r=NULL, .t=&cmd, .len=1}, | |
{.r=NULL, .t=buf, .len=len}}; | |
spi_access(&nrf->spi, t, 2); | |
} | |
void nRF24L01p_read_rx_payload(uint8_t *buf, uint8_t len) | |
{ | |
if (len == 0) | |
return; | |
uint8_t cmd = R_RX_PAYLOAD; | |
struct spi_transfer t[] = { | |
{.r=NULL, .t=&cmd, .len=1}, | |
{.r=buf, .t=NULL, .len=len}}; | |
spi_access(&nrf->spi, t, 2); | |
} | |
void nRF24L01p_write_tx_payload(uint8_t *buf, uint8_t len) | |
{ | |
uint8_t cmd = W_TX_PAYLOAD; | |
struct spi_transfer t[] = { | |
{.r=NULL, .t=&cmd, .len=1}, | |
{.r=NULL, .t=buf, .len=len}}; | |
spi_access(&nrf->spi, t, 2); | |
} | |
void nRF24L01p_flush_tx(void) | |
{ | |
uint8_t cmd = FLUSH_TX; | |
spi_single_access(&nrf->spi, NULL, &cmd, 1); | |
} | |
void nRF24L01p_flush_rx(void) | |
{ | |
uint8_t cmd = FLUSH_RX; | |
spi_single_access(&nrf->spi, NULL, &cmd, 1); | |
} | |
void nRF24L01p_reuse_tx_pl(void) | |
{ | |
uint8_t cmd = REUSE_TX_PL; | |
spi_single_access(&nrf->spi, NULL, &cmd, 1); | |
} | |
uint8_t nRF24L01p_read_rx_payload_len(void) | |
{ | |
//* | |
uint8_t cmd = R_RX_PL_WID; | |
uint8_t l; | |
struct spi_transfer t[] = { | |
{.r=NULL, .t=&cmd, .len=1}, | |
{.r=&l, .t=NULL, .len=1}}; | |
spi_access(&nrf->spi, t, 2); | |
return l; | |
} | |
void nRF24L01p_write_ack_payload(uint8_t pipe_nb, uint8_t *buf, uint8_t len) | |
{ | |
uint8_t cmd = W_ACK_PAYLOAD | (pipe_nb & 0x07); | |
struct spi_transfer t[] = { | |
{.r=NULL, .t=&cmd, .len=1}, | |
{.r=NULL, .t=buf, .len=len}}; | |
spi_access(&nrf->spi, t, 2); | |
} | |
void nRF24L01p_write_tx_payload_noack(uint8_t *buf, uint8_t len) | |
{ | |
uint8_t cmd = W_TX_PAYLOAD_NOACK; | |
struct spi_transfer t[] = { | |
{.r=NULL, .t=&cmd, .len=1}, | |
{.r=NULL, .t=buf, .len=len}}; | |
spi_access(&nrf->spi, t, 2); | |
} | |
// | |
// High level functions | |
// | |
void nRF24L01p_power_up(void) | |
{ | |
uint8_t config = nRF24L01p_read_register(CONFIG); | |
nRF24L01p_write_register(CONFIG, config | PWR_UP); | |
} | |
void nRF24L01p_power_down(void) | |
{ | |
uint8_t config = nRF24L01p_read_register(CONFIG); | |
nRF24L01p_write_register(CONFIG, config & ~PWR_UP); | |
} | |
void nRF24L01p_set_addr(uint8_t addr_reg, uint8_t *addr) | |
{ | |
nRF24L01p_write_multibyte_register(addr_reg, addr, 5); | |
} | |
void nRF24L01p_set_channel(uint8_t ch) | |
{ | |
nRF24L01p_write_register(RF_CH, (ch & 0b01111111)); | |
} | |
void nRF24L01p_set_tx_pwr(uint8_t pwr) | |
{ | |
if (pwr > 3) | |
pwr = 3; | |
uint8_t setup = nRF24L01p_read_register(RF_SETUP); | |
setup &= ~RF_PWR(3); | |
setup |= RF_PWR(pwr); | |
nRF24L01p_write_register(RF_SETUP, setup); | |
} | |
bool nRF24L01p_get_rx_pwr(void) | |
{ | |
return nRF24L01p_read_register(RPD); | |
} | |
void nRF24L01p_rx_mode(void) | |
{ | |
uint8_t config = nRF24L01p_read_register(CONFIG); | |
nRF24L01p_write_register(CONFIG, config | PRIM_RX); | |
} | |
void nRF24L01p_tx_mode(void) | |
{ | |
uint8_t config = nRF24L01p_read_register(CONFIG); | |
nRF24L01p_write_register(CONFIG, config & ~PRIM_RX); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef NRF24L01P_H | |
#define NRF24L01P_H | |
#include <stdint.h> | |
#include <gpio.h> | |
#include <spi.h> | |
struct nRF24L01p { | |
spi_dev_t spi; | |
gpio_pin_t mosi; | |
gpio_pin_t miso; | |
gpio_pin_t sck; | |
gpio_pin_t ce; | |
gpio_pin_t irq; | |
}; | |
extern struct nRF24L01p *nrf; | |
// Registers | |
#define CONFIG 0x00 | |
#define EN_AA 0x01 | |
#define EN_RXADDR 0x02 | |
#define SETUP_AW 0x03 | |
#define SETUP_RETR 0x04 | |
#define RF_CH 0x05 | |
#define RF_SETUP 0x06 | |
#define STATUS 0x07 | |
#define OBSERVE_TX 0x08 | |
#define RPD 0x09 | |
#define RX_ADDR_P0 0x0A // multy byte register | |
#define RX_ADDR_P1 0x0B // multy byte register | |
#define RX_ADDR_P2 0x0C | |
#define RX_ADDR_P3 0x0D | |
#define RX_ADDR_P4 0x0E | |
#define RX_ADDR_P5 0x0F | |
#define TX_ADDR 0x10 // multy byte register | |
#define RX_PW_P0 0x11 | |
#define RX_PW_P1 0x12 | |
#define RX_PW_P2 0x13 | |
#define RX_PW_P3 0x14 | |
#define RX_PW_P4 0x15 | |
#define RX_PW_P5 0x16 | |
#define FIFO_STATUS 0x17 | |
#define DYNPD 0x1C | |
#define FEATURE 0x1D | |
// bits | |
// CONFIG | |
#define MASK_RX_DR (1<<6) | |
#define MASK_TX_DS (1<<5) | |
#define MASK_MAX_RT (1<<4) | |
#define EN_CRC (1<<3) | |
#define CRCO (1<<2) | |
#define PWR_UP (1<<1) | |
#define PRIM_RX (1<<0) | |
// EN_AA | |
#define ENAA_P5 (1<<5) | |
#define ENAA_P4 (1<<4) | |
#define ENAA_P3 (1<<3) | |
#define ENAA_P2 (1<<2) | |
#define ENAA_P1 (1<<1) | |
#define ENAA_P0 (1<<0) | |
// EN_RXADDR | |
#define ERX_P5 (1<<5) | |
#define ERX_P4 (1<<4) | |
#define ERX_P3 (1<<3) | |
#define ERX_P2 (1<<2) | |
#define ERX_P1 (1<<1) | |
#define ERX_P0 (1<<0) | |
// SETUP_AW | |
#define AW(x) ((x)<<0) // 1:0 | |
#define AW_3 0x01 | |
#define AW_4 0x02 | |
#define AW_5 0x03 | |
// SETUP_RETR | |
#define ARD(x) ((x)<<4) // 7:4 | |
#define ARC(x) ((x)<<0) // 3:0 | |
// RF_SETUP | |
#define CONT_WAVE (1<<7) | |
#define RF_DR_LOW (1<<5) | |
#define PLL_LOCK (1<<4) | |
#define RF_DR_HIGH (1<<3) | |
#define RF_PWR(x) ((x)<<1) // 2:1 | |
#define RF_DR_1M 0x00 | |
#define RF_DR_2M 0x08 | |
#define RF_DR_250K 0x20 | |
// STATUS | |
#define RX_DR (1<<6) | |
#define TX_DS (1<<5) | |
#define MAX_RT (1<<4) | |
#define RX_P_NO (0x7<<1) // 3:1 | |
#define GET_RX_P_NO(x) (((x)>>RX_P_NO) & 0x7) | |
#define TX_FULL (1<<0) | |
// OBSERVE_TX | |
#define PLOS_CNT(x) (((x)>>4) & 0xF) // 7:4 | |
#define ARC_CNT(x) (((x)>>0) & 0xF) // 3:0 | |
// FIFO_STATUS | |
#define FIFO_TX_REUSE (1<<6) | |
#define FIFO_TX_FULL (1<<5) | |
#define FIFO_TX_EMPTY (1<<4) | |
#define FIFO_RX_FULL (1<<1) | |
#define FIFO_RX_EMPTY (1<<0) | |
// DYNPD | |
#define DPL_P5 (1<<5) | |
#define DPL_P4 (1<<4) | |
#define DPL_P3 (1<<3) | |
#define DPL_P2 (1<<2) | |
#define DPL_P1 (1<<1) | |
#define DPL_P0 (1<<0) | |
// FEATURE | |
#define EN_DPL (1<<2) | |
#define EN_ACK_PAY (1<<1) | |
#define EN_DYN_ACK (1<<0) | |
void ce_high(void); | |
void ce_low(void); | |
uint8_t nRF24L01p_get_status_register(void); | |
uint8_t nRF24L01p_read_register(uint8_t addr); | |
void nRF24L01p_write_register(uint8_t addr, uint8_t val); | |
void nRF24L01p_read_multibyte_register(uint8_t addr, uint8_t *buf, uint8_t len); | |
void nRF24L01p_write_multibyte_register(uint8_t addr, uint8_t *buf, uint8_t len); | |
void nRF24L01p_read_rx_payload(uint8_t *buf, uint8_t len); | |
void nRF24L01p_write_tx_payload(uint8_t *buf, uint8_t len); | |
void nRF24L01p_flush_tx(void); | |
void nRF24L01p_flush_rx(void); | |
void nRF24L01p_reuse_tx_pl(void); | |
uint8_t nRF24L01p_read_rx_payload_len(void); | |
void nRF24L01p_write_ack_payload(uint8_t pipe_nb, uint8_t *buf, uint8_t len); | |
void nRF24L01p_write_tx_payload_noack(uint8_t *buf, uint8_t len); | |
void nRF24L01p_power_up(void); | |
void nRF24L01p_power_down(void); | |
void nRF24L01p_set_addr(uint8_t addr_reg, uint8_t *addr); | |
void nRF24L01p_set_channel(uint8_t ch); | |
void nRF24L01p_set_tx_pwr(uint8_t pwr); | |
bool nRF24L01p_get_rx_pwr(void); | |
void nRF24L01p_rx_mode(void); | |
void nRF24L01p_tx_mode(void); | |
#endif // NRF24L01P_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment