From 153bf288b86e0bf2baa688fcb0245de3a6bfac30 Mon Sep 17 00:00:00 2001 From: Rihards Skuja Date: Mon, 18 Dec 2017 21:00:04 +0200 Subject: [PATCH] Add nrf24L01+ library --- include/nRF24L01.h | 130 +++++++++++++++ include/nrf24.h | 116 ++++++++++++++ src/main.c | 4 +- src/nrf24.c | 339 ++++++++++++++++++++++++++++++++++++++++ src/radioPinFunctions.c | 68 ++++++++ 5 files changed, 655 insertions(+), 2 deletions(-) create mode 100644 include/nRF24L01.h create mode 100644 include/nrf24.h create mode 100644 src/nrf24.c create mode 100644 src/radioPinFunctions.c diff --git a/include/nRF24L01.h b/include/nRF24L01.h new file mode 100644 index 0000000..4ec208d --- /dev/null +++ b/include/nRF24L01.h @@ -0,0 +1,130 @@ +/* + Copyright (c) 2007 Stefan Engelke + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + $Id$ +*/ + +/* Memory Map */ +#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 CD 0x09 +#define RX_ADDR_P0 0x0A +#define RX_ADDR_P1 0x0B +#define RX_ADDR_P2 0x0C +#define RX_ADDR_P3 0x0D +#define RX_ADDR_P4 0x0E +#define RX_ADDR_P5 0x0F +#define TX_ADDR 0x10 +#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 + +/* Bit Mnemonics */ + +/* configuratio nregister */ +#define MASK_RX_DR 6 +#define MASK_TX_DS 5 +#define MASK_MAX_RT 4 +#define EN_CRC 3 +#define CRCO 2 +#define PWR_UP 1 +#define PRIM_RX 0 + +/* enable auto acknowledgment */ +#define ENAA_P5 5 +#define ENAA_P4 4 +#define ENAA_P3 3 +#define ENAA_P2 2 +#define ENAA_P1 1 +#define ENAA_P0 0 + +/* enable rx addresses */ +#define ERX_P5 5 +#define ERX_P4 4 +#define ERX_P3 3 +#define ERX_P2 2 +#define ERX_P1 1 +#define ERX_P0 0 + +/* setup of address width */ +#define AW 0 /* 2 bits */ + +/* setup of auto re-transmission */ +#define ARD 4 /* 4 bits */ +#define ARC 0 /* 4 bits */ + +/* RF setup register */ +#define PLL_LOCK 4 +#define RF_DR 3 +#define RF_PWR 1 /* 2 bits */ + +/* general status register */ +#define RX_DR 6 +#define TX_DS 5 +#define MAX_RT 4 +#define RX_P_NO 1 /* 3 bits */ +#define TX_FULL 0 + +/* transmit observe register */ +#define PLOS_CNT 4 /* 4 bits */ +#define ARC_CNT 0 /* 4 bits */ + +/* fifo status */ +#define TX_REUSE 6 +#define FIFO_FULL 5 +#define TX_EMPTY 4 +#define RX_FULL 1 +#define RX_EMPTY 0 + +/* dynamic length */ +#define DPL_P0 0 +#define DPL_P1 1 +#define DPL_P2 2 +#define DPL_P3 3 +#define DPL_P4 4 +#define DPL_P5 5 + +/* Instruction Mnemonics */ +#define R_REGISTER 0x00 /* last 4 bits will indicate reg. address */ +#define W_REGISTER 0x20 /* last 4 bits will indicate reg. address */ +#define REGISTER_MASK 0x1F +#define R_RX_PAYLOAD 0x61 +#define W_TX_PAYLOAD 0xA0 +#define FLUSH_TX 0xE1 +#define FLUSH_RX 0xE2 +#define REUSE_TX_PL 0xE3 +#define ACTIVATE 0x50 +#define R_RX_PL_WID 0x60 +#define NOP 0xFF diff --git a/include/nrf24.h b/include/nrf24.h new file mode 100644 index 0000000..7f96cdf --- /dev/null +++ b/include/nrf24.h @@ -0,0 +1,116 @@ +/* +* ---------------------------------------------------------------------------- +* “THE COFFEEWARE LICENSE” (Revision 1): +* wrote this file. As long as you retain this notice you +* can do whatever you want with this stuff. If we meet some day, and you think +* this stuff is worth it, you can buy me a coffee in return. +* ----------------------------------------------------------------------------- +* This library is based on this library: +* https://github.com/aaronds/arduino-nrf24l01 +* Which is based on this library: +* http://www.tinkerer.eu/AVRLib/nRF24L01 +* ----------------------------------------------------------------------------- +*/ +#ifndef NRF24 +#define NRF24 + +#include "nRF24L01.h" +#include + +#define LOW 0 +#define HIGH 1 + +#define nrf24_ADDR_LEN 5 +#define nrf24_CONFIG ((1< Pin HIGH + * - state:0 => Pin LOW */ +/* -------------------------------------------------------------------------- */ +extern void nrf24_ce_digitalWrite(uint8_t state); + +/* -------------------------------------------------------------------------- */ +/* nrf24 CE pin control function + * - state:1 => Pin HIGH + * - state:0 => Pin LOW */ +/* -------------------------------------------------------------------------- */ +extern void nrf24_csn_digitalWrite(uint8_t state); + +/* -------------------------------------------------------------------------- */ +/* nrf24 SCK pin control function + * - state:1 => Pin HIGH + * - state:0 => Pin LOW */ +/* -------------------------------------------------------------------------- */ +extern void nrf24_sck_digitalWrite(uint8_t state); + +/* -------------------------------------------------------------------------- */ +/* nrf24 MOSI pin control function + * - state:1 => Pin HIGH + * - state:0 => Pin LOW */ +/* -------------------------------------------------------------------------- */ +extern void nrf24_mosi_digitalWrite(uint8_t state); + +/* -------------------------------------------------------------------------- */ +/* nrf24 MISO pin read function +* - returns: Non-zero if the pin is high */ +/* -------------------------------------------------------------------------- */ +extern uint8_t nrf24_miso_digitalRead(); + +#endif diff --git a/src/main.c b/src/main.c index d32bc87..abafd09 100644 --- a/src/main.c +++ b/src/main.c @@ -1,10 +1,10 @@ #include #include #include -/* https://github.com/kehribar/nrf24L01_plus */ #include "ds18b20.h" -#include "main.h" +#include "nrf24.h" #include "io.h" +#include "main.h" #ifdef DEBUG #include "debug.h" diff --git a/src/nrf24.c b/src/nrf24.c new file mode 100644 index 0000000..e7dd2e9 --- /dev/null +++ b/src/nrf24.c @@ -0,0 +1,339 @@ +/* +* ---------------------------------------------------------------------------- +* “THE COFFEEWARE LICENSE” (Revision 1): +* wrote this file. As long as you retain this notice you +* can do whatever you want with this stuff. If we meet some day, and you think +* this stuff is worth it, you can buy me a coffee in return. +* ----------------------------------------------------------------------------- +* This library is based on this library: +* https://github.com/aaronds/arduino-nrf24l01 +* Which is based on this library: +* http://www.tinkerer.eu/AVRLib/nRF24L01 +* ----------------------------------------------------------------------------- +*/ +#include "nrf24.h" + +uint8_t payload_len; + +/* init the hardware pins */ +void nrf24_init() +{ + nrf24_setupPins(); + nrf24_ce_digitalWrite(LOW); + nrf24_csn_digitalWrite(HIGH); +} + +/* configure the module */ +void nrf24_config(uint8_t channel, uint8_t pay_length) +{ + /* Use static payload length ... */ + payload_len = pay_length; + + // Set RF channel + nrf24_configRegister(RF_CH, channel); + + // Set length of incoming payload + nrf24_configRegister(RX_PW_P0, 0x00); // Auto-ACK pipe ... + nrf24_configRegister(RX_PW_P1, payload_len); // Data payload pipe + nrf24_configRegister(RX_PW_P2, 0x00); // Pipe not used + nrf24_configRegister(RX_PW_P3, 0x00); // Pipe not used + nrf24_configRegister(RX_PW_P4, 0x00); // Pipe not used + nrf24_configRegister(RX_PW_P5, 0x00); // Pipe not used + + // 1 Mbps, TX gain: 0dbm + nrf24_configRegister(RF_SETUP, (0 << RF_DR) | ((0x03) << RF_PWR)); + + // CRC enable, 1 byte CRC length + nrf24_configRegister(CONFIG, nrf24_CONFIG); + + // Auto Acknowledgment + nrf24_configRegister(EN_AA, (1 << ENAA_P0) | (1 << ENAA_P1) | (0 << ENAA_P2) | (0 << ENAA_P3) | (0 << ENAA_P4) | (0 << ENAA_P5)); + + // Enable RX addresses + nrf24_configRegister(EN_RXADDR, (1 << ERX_P0) | (1 << ERX_P1) | (0 << ERX_P2) | (0 << ERX_P3) | (0 << ERX_P4) | (0 << ERX_P5)); + + // Auto retransmit delay: 1000 us and Up to 15 retransmit trials + nrf24_configRegister(SETUP_RETR, (0x04 << ARD) | (0x0F << ARC)); + + // Dynamic length configurations: No dynamic length + nrf24_configRegister(DYNPD, (0 << DPL_P0) | (0 << DPL_P1) | (0 << DPL_P2) | (0 << DPL_P3) | (0 << DPL_P4) | (0 << DPL_P5)); + + // Start listening + nrf24_powerUpRx(); +} + +/* Set the RX address */ +void nrf24_rx_address(uint8_t *adr) +{ + nrf24_ce_digitalWrite(LOW); + nrf24_writeRegister(RX_ADDR_P1, adr, nrf24_ADDR_LEN); + nrf24_ce_digitalWrite(HIGH); +} + +/* Returns the payload length */ +uint8_t nrf24_payload_length() +{ + return payload_len; +} + +/* Set the TX address */ +void nrf24_tx_address(uint8_t *adr) +{ + /* RX_ADDR_P0 must be set to the sending addr for auto ack to work. */ + nrf24_writeRegister(RX_ADDR_P0, adr, nrf24_ADDR_LEN); + nrf24_writeRegister(TX_ADDR, adr, nrf24_ADDR_LEN); +} + +/* Checks if data is available for reading */ +/* Returns 1 if data is ready ... */ +uint8_t nrf24_dataReady() +{ + // See note in getData() function - just checking RX_DR isn't good enough + uint8_t status = nrf24_getStatus(); + + // We can short circuit on RX_DR, but if it's not set, we still need + // to check the FIFO for any pending packets + if (status & (1 << RX_DR)) { + return 1; + } + + return !nrf24_rxFifoEmpty();; +} + +/* Checks if receive FIFO is empty or not */ +uint8_t nrf24_rxFifoEmpty() +{ + uint8_t fifoStatus; + + nrf24_readRegister(FIFO_STATUS, &fifoStatus, 1); + + return (fifoStatus & (1 << RX_EMPTY)); +} + +/* Returns the length of data waiting in the RX fifo */ +uint8_t nrf24_payloadLength() +{ + uint8_t status; + nrf24_csn_digitalWrite(LOW); + spi_transfer(R_RX_PL_WID); + status = spi_transfer(0x00); + nrf24_csn_digitalWrite(HIGH); + return status; +} + +/* Reads payload bytes into data array */ +void nrf24_getData(uint8_t *data) +{ + /* Pull down chip select */ + nrf24_csn_digitalWrite(LOW); + + /* Send cmd to read rx payload */ + spi_transfer(R_RX_PAYLOAD); + + /* Read payload */ + nrf24_transferSync(data, data, payload_len); + + /* Pull up chip select */ + nrf24_csn_digitalWrite(HIGH); + + /* Reset status register */ + nrf24_configRegister(STATUS, (1 << RX_DR)); +} + +/* Returns the number of retransmissions occured for the last message */ +uint8_t nrf24_retransmissionCount() +{ + uint8_t rv; + nrf24_readRegister(OBSERVE_TX, &rv, 1); + rv = rv & 0x0F; + return rv; +} + +// Sends a data package to the default address. Be sure to send the correct +// amount of bytes as configured as payload on the receiver. +void nrf24_send(uint8_t *value) +{ + /* Go to Standby-I first */ + nrf24_ce_digitalWrite(LOW); + + /* Set to transmitter mode , Power up if needed */ + nrf24_powerUpTx(); + + /* Do we really need to flush TX fifo each time ? */ +#if 1 + /* Pull down chip select */ + nrf24_csn_digitalWrite(LOW); + + /* Write cmd to flush transmit FIFO */ + spi_transfer(FLUSH_TX); + + /* Pull up chip select */ + nrf24_csn_digitalWrite(HIGH); +#endif + + /* Pull down chip select */ + nrf24_csn_digitalWrite(LOW); + + /* Write cmd to write payload */ + spi_transfer(W_TX_PAYLOAD); + + /* Write payload */ + nrf24_transmitSync(value, payload_len); + + /* Pull up chip select */ + nrf24_csn_digitalWrite(HIGH); + + /* Start the transmission */ + nrf24_ce_digitalWrite(HIGH); +} + +uint8_t nrf24_isSending() +{ + uint8_t status; + + /* read the current status */ + status = nrf24_getStatus(); + + /* if sending successful (TX_DS) or max retries exceded (MAX_RT). */ + if ((status & ((1 << TX_DS) | (1 << MAX_RT)))) { + return 0; /* false */ + } + + return 1; /* true */ + +} + +uint8_t nrf24_getStatus() +{ + uint8_t rv; + nrf24_csn_digitalWrite(LOW); + rv = spi_transfer(NOP); + nrf24_csn_digitalWrite(HIGH); + return rv; +} + +uint8_t nrf24_lastMessageStatus() +{ + uint8_t rv; + + rv = nrf24_getStatus(); + + /* Transmission went OK */ + if ((rv & ((1 << TX_DS)))) { + return NRF24_TRANSMISSON_OK; + } + /* Maximum retransmission count is reached */ + /* Last message probably went missing ... */ + else if ((rv & ((1 << MAX_RT)))) { + return NRF24_MESSAGE_LOST; + } + /* Probably still sending ... */ + else { + return 0xFF; + } +} + +void nrf24_powerUpRx() +{ + nrf24_csn_digitalWrite(LOW); + spi_transfer(FLUSH_RX); + nrf24_csn_digitalWrite(HIGH); + + nrf24_configRegister(STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); + + nrf24_ce_digitalWrite(LOW); + nrf24_configRegister(CONFIG, nrf24_CONFIG | ((1 << PWR_UP) | (1 << PRIM_RX))); + nrf24_ce_digitalWrite(HIGH); +} + +void nrf24_powerUpTx() +{ + nrf24_configRegister(STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); + + nrf24_configRegister(CONFIG, nrf24_CONFIG | ((1 << PWR_UP) | (0 << PRIM_RX))); +} + +void nrf24_powerDown() +{ + nrf24_ce_digitalWrite(LOW); + nrf24_configRegister(CONFIG, nrf24_CONFIG); +} + +/* software spi routine */ +uint8_t spi_transfer(uint8_t tx) +{ + uint8_t i = 0; + uint8_t rx = 0; + + nrf24_sck_digitalWrite(LOW); + + for (i = 0; i < 8; i++) { + + if (tx & (1 << (7 - i))) { + nrf24_mosi_digitalWrite(HIGH); + } else { + nrf24_mosi_digitalWrite(LOW); + } + + nrf24_sck_digitalWrite(HIGH); + + rx = rx << 1; + if (nrf24_miso_digitalRead()) { + rx |= 0x01; + } + + nrf24_sck_digitalWrite(LOW); + + } + + return rx; +} + +/* send and receive multiple bytes over SPI */ +void nrf24_transferSync(uint8_t *dataout, uint8_t *datain, uint8_t len) +{ + uint8_t i; + + for (i = 0; i < len; i++) { + datain[i] = spi_transfer(dataout[i]); + } + +} + +/* send multiple bytes over SPI */ +void nrf24_transmitSync(uint8_t *dataout, uint8_t len) +{ + uint8_t i; + + for (i = 0; i < len; i++) { + spi_transfer(dataout[i]); + } + +} + +/* Clocks only one byte into the given nrf24 register */ +void nrf24_configRegister(uint8_t reg, uint8_t value) +{ + nrf24_csn_digitalWrite(LOW); + spi_transfer(W_REGISTER | (REGISTER_MASK & reg)); + spi_transfer(value); + nrf24_csn_digitalWrite(HIGH); +} + +/* Read single register from nrf24 */ +void nrf24_readRegister(uint8_t reg, uint8_t *value, uint8_t len) +{ + nrf24_csn_digitalWrite(LOW); + spi_transfer(R_REGISTER | (REGISTER_MASK & reg)); + nrf24_transferSync(value, value, len); + nrf24_csn_digitalWrite(HIGH); +} + +/* Write to a single register of nrf24 */ +void nrf24_writeRegister(uint8_t reg, uint8_t *value, uint8_t len) +{ + nrf24_csn_digitalWrite(LOW); + spi_transfer(W_REGISTER | (REGISTER_MASK & reg)); + nrf24_transmitSync(value, len); + nrf24_csn_digitalWrite(HIGH); +} diff --git a/src/radioPinFunctions.c b/src/radioPinFunctions.c new file mode 100644 index 0000000..bc9521c --- /dev/null +++ b/src/radioPinFunctions.c @@ -0,0 +1,68 @@ +/* +* ---------------------------------------------------------------------------- +* “THE COFFEEWARE LICENSE” (Revision 1): +* wrote this file. As long as you retain this notice you +* can do whatever you want with this stuff. If we meet some day, and you think +* this stuff is worth it, you can buy me a coffee in return. +* ----------------------------------------------------------------------------- +* Please define your platform spesific functions in this file ... +* ----------------------------------------------------------------------------- +*/ + +#include + +#define set_bit(reg,bit) reg |= (1<