Last active
July 6, 2019 15:55
-
-
Save bendavis78/2a4b73fa6acc5d1f19631cf516fd6fe9 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
/** | |
* attiny85 pin map: | |
* +-\/-+ | |
* NC PB5 1|o |8 Vcc --- nRF24L01 3v3, pin2 | |
* nRF24L01 CE, pin3 --- PB3 2| |7 PB2 --- nRF24L01 SCK, pin5 | |
* nRF24L01 CSN, pin4 --- PB4 3| |6 PB1 --- nRF24L01 MOSI, pin6 | |
* nRF24L01 GND, pin1 --- GND 4| |5 PB0 --- nRF24L01 MISO, pin7 | |
* +----+ | |
*/ | |
/** | |
* Device settings | |
*/ | |
#define CHANNEL 0x4c | |
#define P0_ADDR 0xE7 | |
#define CID 0xC2 | |
#define PAYLOAD_WIDTH 1 | |
#define F_CPU 1000000UL | |
#include <avr/io.h> | |
#include <util/delay.h> | |
#include <avr/interrupt.h> | |
#include <avr/sleep.h> | |
#include "nRF24L01.h" | |
/** | |
* Simavr debugging | |
*/ | |
#ifdef SIMAVR | |
#include <simavr/avr/avr_mcu_section.h> | |
AVR_MCU((int)1000000, "attiny85"); | |
const struct avr_mmcu_vcd_trace_t _mytrace[] _MMCU_ = { | |
// Data Direction Register | |
{ AVR_MCU_VCD_SYMBOL("DDRB"), .what = (void*)&DDRB, }, | |
// USI Control Register | |
{ AVR_MCU_VCD_SYMBOL("USICR"), .what = (void*)&USICR, }, | |
// USI Status Register | |
{ AVR_MCU_VCD_SYMBOL("USISR"), .what = (void*)&USISR, }, | |
// USI Data Register | |
{ AVR_MCU_VCD_SYMBOL("USIDR"), .what = (void*)&USIDR, }, | |
// Show PORTB bits as NRF pins | |
{ AVR_MCU_VCD_SYMBOL("NRF_MISO"), .mask = _BV(PB0), .what = (void*)&PORTB, }, | |
{ AVR_MCU_VCD_SYMBOL("NRF_MOSI"), .mask = _BV(PB1), .what = (void*)&PORTB, }, | |
{ AVR_MCU_VCD_SYMBOL("NRF_SCK"), .mask = _BV(PB2), .what = (void*)&PORTB, }, | |
{ AVR_MCU_VCD_SYMBOL("NRF_CE"), .mask = _BV(PB3), .what = (void*)&PORTB, }, | |
{ AVR_MCU_VCD_SYMBOL("NRF_CSN"), .mask = _BV(PB4), .what = (void*)&PORTB, }, | |
}; | |
#endif | |
/** | |
* Simple macros for setting/clearing bits | |
*/ | |
#define BIT(x) (_BV(x)) | |
#define SETBITS(x,y) ((x) |= (y)) | |
#define CLEARBITS(x,y) ((x) &= (~(y))) | |
#define SETHIGH(x,y) SETBITS((x), (BIT((y)))) | |
#define SETLOW(x,y) CLEARBITS((x), (BIT((y)))) | |
#define CSN PB4 | |
#define CE PB3 | |
/** | |
* nRF Config | |
*/ | |
void init_spi(void) { | |
// Set PB2 (SCK), PB1 (MISO/NRF_MOSI), PB4 (CSN), and PB3 (CE) as output | |
// Has to be set before SPI-Enable below | |
DDRB |= _BV(PB2) | _BV(PB1) | _BV(PB4) | _BV(PB3); | |
// Set PB0 (MOSI/NRF_MISO) as input, and set it low | |
DDRB &= ~_BV(PB0); | |
PORTB |= _BV(PB0); | |
// Configure USI (Universal Serial Interface) | |
// Wire Mode 0,1: Three-wire mode (uses DO, DI, & USCK pins) | |
// Clock Source Select 1,0,1: Ext. positive edge, software clock strobe | |
USICR |= _BV(USIWM0) | _BV(USICS1) | _BV(USICLK) | _BV(USITC); | |
// PB4 (CSN) high to start with, nothing to be sent to the nRF yet! | |
SETHIGH(PORTB, CSN); | |
// PB3 (CE) low to start with, nothing to send/receive yet! | |
SETLOW(PORTB, CE); | |
} | |
uint8_t write_byte_spi(uint8_t c_data) { | |
// Load byte to Data register | |
USIDR = c_data; | |
// clear flag to be able to receive new data | |
USISR |= _BV(USIOIF); | |
/* Wait for transmission to complete */ | |
while ((USISR & _BV(USIOIF)) == 0) { | |
// Toggle SCK and count a 4-bit counter from 0-15, | |
// When it reaches 15 USIOIF is set! | |
USICR |= _BV(USITC); | |
} | |
_delay_us(10); | |
return USIDR; | |
} | |
uint8_t get_reg(uint8_t reg) { | |
_delay_us(10); | |
// CSN low - nRF starts to listen for command | |
SETLOW(PORTB, CSN); | |
_delay_us(10); | |
// R_Register = set the nRF to reading mode, "reg" = this registry will be read back | |
write_byte_spi(R_REGISTER + reg); | |
// Send NOP (dummy byte) once to receive back the first byte in the "reg" register | |
reg = write_byte_spi(NOP); | |
// CSN Hi - nRF goes back to doing nothing | |
SETHIGH(PORTB, CSN); | |
return reg; | |
} | |
uint8_t *nrf_read(uint8_t reg, uint8_t bytes) { | |
static uint8_t ret[32]; | |
if (reg == W_TX_PAYLOAD) { | |
// W_TX_PAYLOAD is invalid for reading. | |
return ret; | |
} | |
// CSN low - nRF starts to listen for command | |
SETLOW(PORTB, CSN); | |
_delay_us(10); | |
// tell the nRF which register we're working with | |
write_byte_spi(reg); | |
// Send dummy bytes to read out the data | |
int i; | |
for (i=0; i<bytes; i++) { | |
ret[i] = write_byte_spi(NOP); | |
} | |
// CSN High - nRF goes back to doing nothing | |
SETHIGH(PORTB, CSN); | |
return ret; | |
} | |
void nrf_write_bytes(uint8_t reg, uint8_t *bytes, uint8_t size) { | |
// Add the "write" bit to the "reg" | |
if (reg != W_TX_PAYLOAD) { | |
reg = W_REGISTER + reg; | |
} | |
// CSN low - nRF starts to listen for command | |
SETLOW(PORTB, CSN); | |
_delay_us(10); | |
// tell the nRF which register we're working with | |
write_byte_spi(reg); | |
int i; | |
for (i=0; i<size; i++) { | |
write_byte_spi(bytes[i]); | |
} | |
// CSN High - nRF goes back to doing nothing | |
SETHIGH(PORTB, CSN); | |
_delay_us(10); | |
} | |
void nrf_write(uint8_t reg, uint8_t value) { | |
uint8_t bytes[] = {value}; | |
nrf_write_bytes(reg, bytes, 1); | |
} | |
void nrf24L01_init(void) { | |
// allow radio to reach power down if shut down | |
_delay_ms(100); | |
// Enable auto-ack on P0 | |
nrf_write(EN_AA, 0x01); | |
// Set the number of retries and delay | |
// 0xFF = 1111 1111: 4000ms delay, 15 retransmit count | |
nrf_write(SETUP_RETR, 0xFF); | |
// Choose the number of enabled data pipes (1-5) | |
nrf_write(EN_RXADDR, 0x01); | |
// RF_Address width setup (how many bytes is the receiver address, the more the merrier 1-5) | |
// 0x03 = 0000 0011: 5 bytes RF_Address | |
nrf_write(SETUP_AW, 0x03); | |
// RF channel setup - choose frequency 2,400-2,575GHz 1MHz/step | |
nrf_write(RF_CH, CHANNEL); | |
// RF setup - choose power mode and data speed. | |
// 0x26 = 0010 0111: 250kbps, High power | |
nrf_write(RF_SETUP, 0x26); | |
// Set RX address | |
uint8_t rx_addr[5]; | |
int i; | |
for (i=0; i<5; i++) { | |
rx_addr[i] = P0_ADDR; | |
} | |
nrf_write_bytes(RX_ADDR_P0, rx_addr, 5); | |
// Set our static payload width | |
nrf_write(RX_PW_P0, PAYLOAD_WIDTH); | |
/* | |
Write the CONFIG register (0x1E = 00011110) | |
bit 0="0": Act as transmitter | |
bit 1="1": power up | |
bit 2="1": set CRC to 2-byte | |
bit 3="1": enable CRC | |
bit 4="1": MASK_MAX_RT (IRQ not triggered if transmission failed) | |
*/ | |
nrf_write(CONFIG, 0x1E); | |
// device need 1.5ms to reach standby mode (CE=low) | |
_delay_ms(100); | |
} | |
void transmit_payload(uint8_t *payload, uint8_t size) { | |
// Send FLUSH_TX to flush the registry from old data, | |
nrf_read(FLUSH_TX, 0); | |
// Send the data in payload to the nrf. | |
uint8_t payload2[5]; | |
int i; | |
for (i=0; i < size; i++) { | |
payload2[i] = payload[i]; | |
} | |
nrf_write_bytes(W_TX_PAYLOAD, payload2, size); | |
// sei(); // Enable global interrupt (if interrupt is used) | |
// needs a 10ms delay to work after loading the nrf with the payload for some reason | |
_delay_ms(10); | |
// CE high = transmit the data! | |
SETHIGH(PORTB, CE); | |
_delay_us(20); | |
// CE low = stop transmitting | |
SETLOW(PORTB, CE); | |
_delay_ms(10); | |
/* | |
if ((get_reg(STATUS) & _BV(4)) != 0) { | |
// transmission failed; | |
} | |
*/ | |
} | |
void reset(void) { | |
_delay_us(10); | |
// CSN low | |
SETLOW(PORTB, 2); | |
_delay_us(10); | |
// Write to STATUS registry | |
write_byte_spi(W_REGISTER + STATUS); | |
// Reset all IRQ in STATUS registry | |
write_byte_spi(0x70); | |
// CSN IR_High | |
SETHIGH(PORTB, 2); | |
} | |
int main(void) { | |
init_spi(); | |
nrf24L01_init(); | |
// Send 1, 2, 3, 4, 5 every second | |
int i; | |
uint8_t payload[1]; | |
for (i=0; i<5; i++) { | |
transmit_payload(payload, sizeof payload / sizeof *payload); | |
} | |
_delay_us(1); | |
reset(); | |
sleep_cpu(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
did you get this working on your attiny85? What was your receiver's code?