Skip to content

Instantly share code, notes, and snippets.

@dragonlock2
Created August 20, 2019 08:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dragonlock2/0b9706dc3f48a7c6ba9d6c096f0a29ec to your computer and use it in GitHub Desktop.
Save dragonlock2/0b9706dc3f48a7c6ba9d6c096f0a29ec to your computer and use it in GitHub Desktop.
RF24 library for Atmel Studio 7
/*
* RF24.c
*
* Adapted from TMRh20's RF24 library
*
* Created: 7/3/2019 1:53:45 AM
* Author: MatthewTran
*/
#include <clock_config.h>
#include <util/delay.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "spi_basic.h"
#include "atmel_start.h"
uint8_t payload_size = 32;
uint8_t addr_width = 5;
bool dynamic_payloads_enabled;
static const uint8_t child_pipe_enable[] = { ERX_P0, ERX_P1, ERX_P2, ERX_P3, ERX_P4, ERX_P5 };
static const uint8_t child_pipe[] = { RX_ADDR_P0, RX_ADDR_P1, RX_ADDR_P2, RX_ADDR_P3, RX_ADDR_P4, RX_ADDR_P5 };
static const uint8_t child_payload_size[] = { RX_PW_P0, RX_PW_P1, RX_PW_P2, RX_PW_P3, RX_PW_P4, RX_PW_P5 };
// register writing/reading extractions
uint8_t RF24_read_register(uint8_t reg, uint8_t* buf, uint8_t len) {
uint8_t status;
CSN_set_level(false);
status = SPI_0_exchange_byte(R_REGISTER | (REGISTER_MASK & reg));
SPI_0_read_block(buf, len);
CSN_set_level(true);
return status;
}
uint8_t RF24_read_one_register(uint8_t reg) {
uint8_t val = 0;
CSN_set_level(false);
SPI_0_exchange_byte(R_REGISTER | (REGISTER_MASK & reg));
val = SPI_0_exchange_byte(0xFF);
CSN_set_level(true);
return val;
}
uint8_t RF24_write_register(uint8_t reg, uint8_t* buf, uint8_t len) {
uint8_t status;
CSN_set_level(false);
status = SPI_0_exchange_byte(W_REGISTER | (REGISTER_MASK & reg));
SPI_0_write_block(buf, len);
CSN_set_level(true);
return status;
}
uint8_t RF24_write_one_register(uint8_t reg, uint8_t val) {
uint8_t status;
CSN_set_level(false);
status = SPI_0_exchange_byte(W_REGISTER | (REGISTER_MASK & reg));
SPI_0_exchange_byte(val);
CSN_set_level(true);
return status;
}
//payload stuff
uint8_t RF24_write_payload(void* buf, uint8_t data_len, uint8_t writeType) {
uint8_t status;
uint8_t blank_len = dynamic_payloads_enabled ? 0 : payload_size - data_len;
CSN_set_level(false);
status = SPI_0_exchange_byte(writeType);
SPI_0_write_block(buf, data_len);
while (blank_len--) {
SPI_0_exchange_byte(0);
}
CSN_set_level(true);
return status;
}
uint8_t RF24_read_payload(void* buf, uint8_t data_len) {
uint8_t status;
if (data_len > payload_size) {
data_len = payload_size;
}
uint8_t blank_len = dynamic_payloads_enabled ? 0 : payload_size - data_len;
CSN_set_level(false);
status = SPI_0_exchange_byte(R_RX_PAYLOAD);
SPI_0_read_block(buf, data_len);
while(blank_len--) {
SPI_0_exchange_byte(0xFF);
}
CSN_set_level(true);
return status;
}
//stuff for begin()
void RF24_flush_rx(void) {
CSN_set_level(false);
SPI_0_exchange_byte(FLUSH_RX);
CSN_set_level(true);
}
void RF24_flush_tx(void) {
CSN_set_level(false);
SPI_0_exchange_byte(FLUSH_TX);
CSN_set_level(true);
}
void RF24_toggle_features(void) { //idk what this does
CSN_set_level(false);
SPI_0_exchange_byte(ACTIVATE);
SPI_0_exchange_byte(0x73);
CSN_set_level(true);
}
void RF24_set_retries(uint8_t delay, uint8_t count) {
RF24_write_one_register(SETUP_RETR, (delay & 0xF) << ARD | (count & 0xF) << ARC);
}
void RF24_powerUp(void) {
uint8_t cfg = RF24_read_one_register(NRF_CONFIG);
if (!(cfg & (1 << PWR_UP))) {
RF24_write_one_register(NRF_CONFIG, cfg | (1 << PWR_UP));
_delay_ms(5);
}
}
void RF24_powerDown(void) {
CE_set_level(false);
RF24_write_one_register(NRF_CONFIG, RF24_read_one_register(NRF_CONFIG) & ~(1 << PWR_UP));
}
//lib stuff
void RF24_setChannel(uint8_t ch) {
RF24_write_one_register(RF_CH, rf24_min(ch, 125));
}
void RF24_setPayloadSize(uint8_t size) {
payload_size = rf24_min(size, 32);
}
void RF24_setDataRate(uint8_t rate) {
//0 = 250kbps, 1 = 1mbps, 2 = 2mbps
uint8_t setup = RF24_read_one_register(RF_SETUP);
setup &= ~(1 << RF_DR_LOW | 1 << RF_DR_HIGH); //reset to 1mbps
if (rate == 0) {
setup |= 1 << RF_DR_LOW;
} else if (rate == 2) {
setup |= 1 << RF_DR_HIGH;
}
RF24_write_one_register(RF_SETUP, setup);
}
void RF24_setPALevel(uint8_t level) {
//0 = min, 3 = max
uint8_t setup = RF24_read_one_register(RF_SETUP) & 0xF8; //clear level bits
if (level > 3) {
level = 3;
}
level = (level << 1);// + 1;
RF24_write_one_register(RF_SETUP, setup |= level);
}
void RF24_enableDynamicPayloads(void) {
RF24_write_one_register(FEATURE, RF24_read_one_register(FEATURE) | (1 << EN_DPL));
RF24_write_one_register(DYNPD, 0x3F); //enable on all pipes
dynamic_payloads_enabled = true;
}
void RF24_begin(void) {
//_delay_ms(5); //radio settle
RF24_write_one_register(NRF_CONFIG, 0x0C); //reset, enable 16-bit CRC
RF24_set_retries(5, 15); //1500us, 15 retries
RF24_setDataRate(0);
RF24_toggle_features();
RF24_write_one_register(FEATURE, 0);
RF24_write_one_register(DYNPD, 0);
dynamic_payloads_enabled = false;
RF24_write_one_register(NRF_STATUS, 1 << RX_DR | 1 << TX_DS | 1 << MAX_RT);
RF24_flush_rx();
RF24_flush_tx();
RF24_powerUp();
RF24_write_one_register(NRF_CONFIG, RF24_read_one_register(NRF_CONFIG) & ~(1 << PRIM_RX));
}
void RF24_openWritingPipe(uint8_t* address) {
RF24_write_register(RX_ADDR_P0, address, addr_width); //TX_ADDR must match RX_ADDR_P0
RF24_write_register(TX_ADDR, address, addr_width);
RF24_write_one_register(RX_PW_P0, payload_size);
}
void RF24_openReadingPipe(uint8_t child, uint8_t* address) {
//not gonna support setting child 0, just use openWritingPipe()
if (child == 0 || child > 5) { return; }
if ( child < 2) {
RF24_write_register(child_pipe[child], address, addr_width);
} else {
RF24_write_register(child_pipe[child], address, 1);
}
RF24_write_one_register(child_payload_size[child], payload_size);
RF24_write_one_register(EN_RXADDR, RF24_read_one_register(EN_RXADDR) | 1 << child_pipe_enable[child]);
}
void RF24_startListening(void) {
RF24_write_one_register(NRF_CONFIG, RF24_read_one_register(NRF_CONFIG) | 1 << PRIM_RX); //enable RX
RF24_write_one_register(NRF_STATUS, 1 << RX_DR | 1 << TX_DS | 1 << MAX_RT); //clear interrupts
CE_set_level(true);
//pipe 0 always open
//not implemented, but moved code over anyway
//for if want to send ack payload
if (RF24_read_one_register(FEATURE) & 1 << EN_ACK_PAY) {
RF24_flush_tx();
}
}
void RF24_stopListening(void) {
CE_set_level(false);
_delay_us(200); //didn't implement txDelay, so just using a num
//again didn't implement, but here just because
if (RF24_read_one_register(FEATURE) & 1 << EN_ACK_PAY) {
_delay_us(200);
RF24_flush_tx();
}
//back to tx
RF24_write_one_register(NRF_CONFIG, RF24_read_one_register(NRF_CONFIG) & ~(1 << PRIM_RX));
//enable rx on pipe0 again, probs bc of the ack, unnecessary for current implementation
RF24_write_one_register(EN_RXADDR, RF24_read_one_register(EN_RXADDR) | 1 << ERX_P0);
}
void RF24_write(void* buf, uint8_t len, bool multicast) {
//cant do multicast == true w/o enabling dynamic ack (check RF24)
RF24_write_payload(buf, len, multicast ? W_TX_PAYLOAD_NO_ACK : W_TX_PAYLOAD);
CE_set_level(true);
_delay_us(10);
CE_set_level(false);
}
void RF24_read(void* buf, uint8_t len) {
RF24_read_payload(buf, len);
//using interrupts, shouldn't need this if have proper ISR
RF24_write_one_register(NRF_STATUS, 1 << RX_DR | 1 << MAX_RT | 1 << TX_DS);
}
void RF24_whatHappened(uint8_t* tx_ok, uint8_t* tx_fail, uint8_t* rx_ready) {
uint8_t status = RF24_write_one_register(NRF_STATUS, 1 << RX_DR | 1 << TX_DS | 1 << MAX_RT);
*tx_ok = status & 1 << TX_DS;
*tx_fail = status & 1 << MAX_RT;
*rx_ready = status & 1 << RX_DR;
}
/*
* RF24.h
*
* Adapted from TRMh20's RF24 library
*
* Created: 7/3/2019 1:19:34 AM
* Author: MatthewTran
*/
#ifndef RF24_H_
#define RF24_H_
#include <stdbool.h>
#include <stdint.h>
#define rf24_max(a,b) (a>b?a:b)
#define rf24_min(a,b) (a<b?a:b)
void RF24_begin(void);
void RF24_setChannel(uint8_t ch);
void RF24_setPayloadSize(uint8_t size);
void RF24_setPALevel(uint8_t level);
void RF24_setDataRate(uint8_t rate);
void RF24_enableDynamicPayloads(void);
void RF24_openWritingPipe(uint8_t* address);
void RF24_openReadingPipe(uint8_t child, uint8_t* address);
void RF24_startListening(void);
void RF24_stopListening(void);
void RF24_write(void* buf, uint8_t len, bool multicast);
void RF24_read(void* buf, uint8_t len);
void RF24_whatHappened(uint8_t* tx_ok, uint8_t* tx_fail, uint8_t* rx_ready);
#endif /* RF24_H_ */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment