AVR-Lib
nRF24L01
The Nordic Semiconductor nRF24L01 is a transceiver chip operating in the 2.4GHz band. The following code is my first driver for Atmel ATMEGA8 and ATMEGA168. In my test scenario the ATMEGA168 and ATMEGA8 were connected different. The reason for this is that the ATMEGA168 supports Pin Change Interrupt which the ATMEGA8 doesn't. The chips were connected as follows:
nRF24L01 |
AVR ATMEGA8 |
AVR ATMEGA168 |
Description |
SCK |
PB5 (SCK) |
PB5 (SCK) |
SPI clock signal |
MISO |
PB4 (MISO) |
PB4 (MISO) |
SPI master in, slave out |
MOSI |
PB3 (MOSI) |
PB3 (MOSI) |
SPI master out, slave in |
CSN |
PB1 |
PB1 |
SPI Chip Select |
CE |
PB0 |
PB0 |
Chip Enable Activates RX or TX mode |
IRQ |
PD2 (INT0) |
PD6 (PCINT22) |
Interrupt pin. Active low |
nRF24L01.h
Instruction, memory and bit maps from the datasheet.
Download RF24L01.h
1 /* Memory Map */
2 #define CONFIG 0x00
3 #define EN_AA 0x01
4 #define EN_RXADDR 0x02
5 #define SETUP_AW 0x03
6 #define SETUP_RETR 0x04
7 #define RF_CH 0x05
8 #define RF_SETUP 0x06
9 #define STATUS 0x07
10 #define OBSERVE_TX 0x08
11 #define CD 0x09
12 #define RX_ADDR_P0 0x0A
13 #define RX_ADDR_P1 0x0B
14 #define RX_ADDR_P2 0x0C
15 #define RX_ADDR_P3 0x0D
16 #define RX_ADDR_P4 0x0E
17 #define RX_ADDR_P5 0x0F
18 #define TX_ADDR 0x10
19 #define RX_PW_P0 0x11
20 #define RX_PW_P1 0x12
21 #define RX_PW_P2 0x13
22 #define RX_PW_P3 0x14
23 #define RX_PW_P4 0x15
24 #define RX_PW_P5 0x16
25 #define FIFO_STATUS 0x17
26
27 /* Bit Mnemonics */
28 #define MASK_RX_DR 6
29 #define MASK_TX_DS 5
30 #define MASK_MAX_RT 4
31 #define EN_CRC 3
32 #define CRCO 2
33 #define PWR_UP 1
34 #define PRIM_RX 0
35 #define ENAA_P5 5
36 #define ENAA_P4 4
37 #define ENAA_P3 3
38 #define ENAA_P2 2
39 #define ENAA_P1 1
40 #define ENAA_P0 0
41 #define ERX_P5 5
42 #define ERX_P4 4
43 #define ERX_P3 3
44 #define ERX_P2 2
45 #define ERX_P1 1
46 #define ERX_P0 0
47 #define AW 0
48 #define ARD 4
49 #define ARC 0
50 #define PLL_LOCK 4
51 #define RF_DR 3
52 #define RF_PWR 1
53 #define LNA_HCURR 0
54 #define RX_DR 6
55 #define TX_DS 5
56 #define MAX_RT 4
57 #define RX_P_NO 1
58 #define TX_FULL 0
59 #define PLOS_CNT 4
60 #define ARC_CNT 0
61 #define TX_REUSE 6
62 #define FIFO_FULL 5
63 #define TX_EMPTY 4
64 #define RX_FULL 1
65 #define RX_EMPTY 0
66
67 /* Instruction Mnemonics */
68 #define R_REGISTER 0x00
69 #define W_REGISTER 0x20
70 #define REGISTER_MASK 0x1F
71 #define R_RX_PAYLOAD 0x61
72 #define W_TX_PAYLOAD 0xA0
73 #define FLUSH_TX 0xE1
74 #define FLUSH_RX 0xE2
75 #define REUSE_TX_PL 0xE3
76 #define NOP 0xFF
mirf.h
Header file with public methods and definitions
Download mirf.h
1 #ifndef _MIRF_H_
2 #define _MIRF_H_
3
4 #include <avr/io.h>
5
6 // Mirf settings
7 #define mirf_CH 2
8 #define mirf_PAYLOAD 16
9 #define mirf_CONFIG ( (1<<MASK_RX_DR) | (1<<EN_CRC) | (0<<CRCO) )
10
11 // Pin definitions for chip select and chip enabled of the MiRF module
12 #define CE PB0
13 #define CSN PB1
14
15 // Definitions for selecting and enabling MiRF module
16 #define mirf_CSN_hi PORTB |= (1<<CSN);
17 #define mirf_CSN_lo PORTB &= ~(1<<CSN);
18 #define mirf_CE_hi PORTB |= (1<<CE);
19 #define mirf_CE_lo PORTB &= ~(1<<CE);
20
21 // Public standart functions
22 extern void mirf_init();
23 extern void mirf_config();
24 extern void mirf_send(uint8_t * value, uint8_t len);
25 extern void mirf_set_RADDR(uint8_t * adr);
26 extern void mirf_set_TADDR(uint8_t * adr);
27 extern uint8_t mirf_data_ready();
28 extern void mirf_get_data(uint8_t * data);
29
30 // Public extended functions
31 extern void mirf_config_register(uint8_t reg, uint8_t value);
32 extern void mirf_read_register(uint8_t reg, uint8_t * value, uint8_t len);
33 extern void mirf_write_register(uint8_t reg, uint8_t * value, uint8_t len);
34
35 #endif /* _MIRF_H_ */
mirf.c
Download mirf.c
1 #include "mirf.h"
2 #include "nRF24L01.h"
3 #include "spi.h"
4 #include <avr/io.h>
5 #include <avr/interrupt.h>
6
7 // Defines for setting the MiRF registers for transmitting or receiving mode
8 #define TX_POWERUP mirf_config_register(CONFIG, mirf_CONFIG | ( (1<<PWR_UP) | (0<<PRIM_RX) ) )
9 #define RX_POWERUP mirf_config_register(CONFIG, mirf_CONFIG | ( (1<<PWR_UP) | (1<<PRIM_RX) ) )
10
11 // Flag which denotes transmitting mode
12 volatile uint8_t PTX;
13
14 void mirf_init()
15 // Initializes pins ans interrupt to communicate with the MiRF module
16 // Should be called in the early initializing phase at startup.
17 {
18 // Define CSN and CE as Output and set them to default
19 DDRB |= ((1<<CSN)|(1<<CE));
20 mirf_CE_lo;
21 mirf_CSN_hi;
22
23 #if defined(__AVR_ATmega8__)
24 // Initialize external interrupt 0 (PD2)
25 MCUCR = ((1<<ISC11)|(0<<ISC10)|(1<<ISC01)|(0<<ISC00)); // Set external interupt on falling edge
26 GICR = ((0<<INT1)|(1<<INT0)); // Activate INT0
27 #endif // __AVR_ATmega8__
28
29 #if defined(__AVR_ATmega168__)
30 // Initialize external interrupt on port PD6 (PCINT22)
31 DDRB &= ~(1<<PD6);
32 PCMSK2 = (1<<PCINT22);
33 PCICR = (1<<PCIE2);
34 #endif // __AVR_ATmega168__
35
36 // Initialize spi module
37 spi_init();
38 }
39
40 void mirf_config()
41 // Sets the important registers in the MiRF module and powers the module
42 // in receiving mode
43 {
44 // Set RF channel
45 mirf_config_register(RF_CH,mirf_CH);
46
47 // Set length of incoming payload
48 mirf_config_register(RX_PW_P0, mirf_PAYLOAD);
49
50 // Start receiver
51 PTX = 0; // Start in receiving mode
52 RX_POWERUP; // Power up in receiving mode
53 mirf_CE_hi; // Listening for pakets
54 }
55
56 void mirf_set_RADDR(uint8_t * adr)
57 // Sets the receiving address
58 {
59 mirf_CE_lo;
60 mirf_write_register(RX_ADDR_P0,adr,5);
61 mirf_CE_hi;
62 }
63
64 void mirf_set_TADDR(uint8_t * adr)
65 // Sets the transmitting address
66 {
67 mirf_write_register(TX_ADDR, adr,5);
68 }
69
70 #if defined(__AVR_ATmega8__)
71 SIGNAL(SIG_INTERRUPT0)
72 #endif // __AVR_ATmega8__
73 #if defined(__AVR_ATmega168__)
74 SIGNAL(SIG_PIN_CHANGE2)
75 #endif // __AVR_ATmega168__
76 // Interrupt handler
77 {
78 uint8_t status;
79 // If still in transmitting mode then finish transmission
80 if (PTX) {
81
82 // Read MiRF status
83 mirf_CSN_lo; // Pull down chip select
84 status = spi_fast_shift(NOP); // Read status register
85 mirf_CSN_hi; // Pull up chip select
86
87 mirf_CE_lo; // Deactivate transreceiver
88 RX_POWERUP; // Power up in receiving mode
89 mirf_CE_hi; // Listening for pakets
90 PTX = 0; // Set to receiving mode
91
92 // Reset status register for further interaction
93 mirf_config_register(STATUS,(1<<TX_DS)|(1<<MAX_RT)); // Reset status register
94 }
95 }
96
97 extern uint8_t mirf_data_ready()
98 // Checks if data is available for reading
99 {
100 if (PTX) return 0;
101 uint8_t status;
102 // Read MiRF status
103 mirf_CSN_lo; // Pull down chip select
104 status = spi_fast_shift(NOP); // Read status register
105 mirf_CSN_hi; // Pull up chip select
106 return status & (1<<RX_DR);
107 }
108
109 extern void mirf_get_data(uint8_t * data)
110 // Reads mirf_PAYLOAD bytes into data array
111 {
112 mirf_CSN_lo; // Pull down chip select
113 spi_fast_shift( R_RX_PAYLOAD ); // Send cmd to read rx payload
114 spi_transfer_sync(data,data,mirf_PAYLOAD); // Read payload
115 mirf_CSN_hi; // Pull up chip select
116 mirf_config_register(STATUS,(1<<RX_DR)); // Reset status register
117 }
118
119 void mirf_config_register(uint8_t reg, uint8_t value)
120 // Clocks only one byte into the given MiRF register
121 {
122 mirf_CSN_lo;
123 spi_fast_shift(W_REGISTER | (REGISTER_MASK & reg));
124 spi_fast_shift(value);
125 mirf_CSN_hi;
126 }
127
128 void mirf_read_register(uint8_t reg, uint8_t * value, uint8_t len)
129 // Reads an array of bytes from the given start position in the MiRF registers.
130 {
131 mirf_CSN_lo;
132 spi_fast_shift(R_REGISTER | (REGISTER_MASK & reg));
133 spi_transfer_sync(value,value,len);
134 mirf_CSN_hi;
135 }
136
137 void mirf_write_register(uint8_t reg, uint8_t * value, uint8_t len)
138 // Writes an array of bytes into inte the MiRF registers.
139 {
140 mirf_CSN_lo;
141 spi_fast_shift(W_REGISTER | (REGISTER_MASK & reg));
142 spi_transmit_sync(value,len);
143 mirf_CSN_hi;
144 }
145
146 void mirf_send(uint8_t * value, uint8_t len)
147 // Sends a data package to the default address. Be sure to send the correct
148 // amount of bytes as configured as payload on the receiver.
149 {
150 while (PTX) {} // Wait until last paket is send
151
152 mirf_CE_lo;
153
154 PTX = 1; // Set to transmitter mode
155 TX_POWERUP; // Power up
156
157 mirf_CSN_lo; // Pull down chip select
158 spi_fast_shift( FLUSH_TX ); // Write cmd to flush tx fifo
159 mirf_CSN_hi; // Pull up chip select
160
161 mirf_CSN_lo; // Pull down chip select
162 spi_fast_shift( W_TX_PAYLOAD ); // Write cmd to write payload
163 spi_transmit_sync(value,len); // Write payload
164 mirf_CSN_hi; // Pull up chip select
165
166 mirf_CE_hi; // Start transmission
167 }
Usage
1 // Initialize AVR for use with mirf
2 mirf_init();
3 // Wait for mirf to come up
4 _delay_ms(50);
5 // Activate interrupts
6 sei();
7 // Configure mirf
8 mirf_config();
9 // Test communication
10 mirf_send(buffer,buffersize);
11 while (!mirf_data_ready());
12 mirf_get_data(buffer);