ATTiny examples¶
rf24ping85¶
2014 Contribution by tong67
Updated 2020 by 2bndy5 for the SpenceKonde ATTinyCore
The RF24 library uses the ATTinyCore by SpenceKonde
This sketch is a duplicate of the ManualAcknowledgements.ino example (without all the Serial input/output code), and it demonstrates a ATTiny25/45/85 or ATTiny24/44/84 driving the nRF24L01 transceiver using the RF24 class to communicate with another node.
A simple example of sending data from 1 nRF24L01 transceiver to another
with manually transmitted (non-automatic) Acknowledgement (ACK) payloads.
This example still uses ACK packets, but they have no payloads. Instead the
acknowledging response is sent with RF24Revamped::send()
. This tactic allows
for more updated acknowledgement payload data, where actual ACK payloads’ data
are outdated by 1 transmission because they have to loaded before receiving a
transmission.
This example was written to be used on 2 devices acting as “nodes”.
85#include "SPI.h"
86#include "RF24Revamped.h"
87
88// CE and CSN are configurable, specified values for ATTiny85 as connected above
89#define CE_PIN 3
90#define CSN_PIN 4
91//#define CSN_PIN 3 // uncomment for ATTiny85 3 pins solution
92
93// instantiate an object for the nRF24L01 transceiver
94RF24Revamped radio(CE_PIN, CSN_PIN);
95
96// Let these addresses be used for the pair
97uint8_t address[][6] = {"1Node", "2Node"};
98// It is very helpful to think of an address as a path instead of as
99// an identifying device destination
100
101// to use different addresses on a pair of radios, we need a variable to
102// uniquely identify which address this radio will use to transmit
103bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
104
105// Used to control whether this node is sending or receiving
106bool role = false; // true = TX node, false = RX node
107
108// For this example, we'll be using a payload containing
109// a string & an integer number that will be incremented
110// on every successful transmission.
111// Make a data structure to store the entire payload of different datatypes
112struct PayloadStruct {
113 char message[7]; // only using 6 characters for TX & RX payloads
114 uint8_t counter;
115};
116PayloadStruct payload;
117
118void setup() {
119
120 // append a NULL terminating character for printing as a c-string
121 payload.message[6] = 0;
122
123 // initialize the transceiver on the SPI bus
124 if (!radio.begin()) {
125 while (1) {} // hold in infinite loop
126 }
127
128 // Set the PA Level low to try preventing power supply related problems
129 // because these examples are likely run with nodes in close proximity to
130 // each other.
131 radio.setPaLevel(RF24_PA_LOW); // RF24_PA_MAX is default.
132
133 // save on transmission time by setting the radio to only transmit the
134 // number of bytes we need to transmit a float
135 radio.setPayloadLength(sizeof(payload)); // char[7] & uint8_t datatypes occupy 8 bytes
136
137 // set the TX address of the RX node into the TX pipe
138 radio.openWritingPipe(address[radioNumber]); // always uses pipe 0
139
140 // set the RX address of the TX node into a RX pipe
141 radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
142
143 if (role) {
144 // setup the TX node
145
146 memcpy(payload.message, "Hello ", 6); // set the outgoing message
147 radio.stopListening(); // put radio in TX mode
148 } else {
149 // setup the RX node
150
151 memcpy(payload.message, "World ", 6); // set the outgoing message
152 radio.startListening(); // put radio in RX mode
153 }
154} // setup()
155
156void loop() {
157
158 if (role) {
159 // This device is a TX node
160
161 bool report = radio.send(&payload, sizeof(payload)); // transmit & save the report
162
163 if (report) {
164 // transmission successful; wait for response and print results
165
166 radio.startListening(); // put in RX mode
167 unsigned long start_timeout = millis(); // timer to detect no response
168 while (!radio.available()) { // wait for response or timeout
169 if (millis() - start_timeout > 200) // only wait 200 ms
170 break;
171 }
172 radio.stopListening(); // put back in TX mode
173
174 // print summary of transactions
175 if (radio.available()) { // is there a payload received?
176
177 PayloadStruct received;
178 radio.read(&received, sizeof(received)); // get payload from RX FIFO
179 payload.counter = received.counter; // save incoming counter for next outgoing counter
180 }
181 } // report
182
183 // to make this example readable in the serial monitor
184 delay(1000); // slow transmissions down by 1 second
185
186 } else {
187 // This device is a RX node
188
189 if (radio.available()) { // is there a payload?
190
191 PayloadStruct received;
192 radio.read(&received, sizeof(received)); // get incoming payload
193 payload.counter = received.counter + 1; // increment incoming counter for next outgoing response
194
195 // transmit response & save result to `report`
196 radio.stopListening(); // put in TX mode
197 radio.send(&payload, sizeof(payload)); // load response to TX FIFO
198 radio.startListening(); // put back in RX mode
199 }
200 } // role
201} // loop
timingSearch3pin¶
2014 Contribution by tong67
Updated 2020 by 2bndy5 for the SpenceKonde ATTinyCore
The RF24 library uses the ATTinyCore by SpenceKonde
This sketch can determine the best settle time values to use for
macros, defined as RF24_CSN_SETTLE_HIGH_DELAY
and RF24_CSN_SETTLE_LOW_DELAY
,
RF24Revamped::csDelay
in RF24Revamped::csn() (private function).
See also
RF24Revamped::csDelay
The settle time values used here are 100/20. However, these values depend on the actual used RC combiniation and voltage drop by LED. The intermediate results are written to TX (PB3, pin 2 – using Serial).
For schematic details, see introductory comment block in the rf24ping85.ino sketch.
20#include <stdio.h>
21#include <SPI.h>
22#include <Arduino.h>
23#include <nRF24L01.h>
24
25
26#if defined (ARDUINO) && !defined (__arm__)
27#if defined(__AVR_ATtinyX5__) || defined(__AVR_ATtinyX4__)
28#define RF24_TINY
29#endif
30#endif
31
32/****************************************************************************/
33
34#if defined(RF24_TINY)
35
36// when Attiny84 or Attiny85 is detected
37#define CE_PIN 3 /** "Chip Enable" pin, activates the RX or TX role */
38#define CSN_PIN 3 /** SPI Chip Select Not */
39
40#else
41// when not running on an ATTiny84 or ATTiny85
42#define CE_PIN 7 /** "Chip Enable" pin, activates the RX or TX role */
43#define CSN_PIN 8 /** SPI Chip Select Not */
44
45#endif
46
47#define MAX_HIGH 100
48#define MAX_LOW 100
49#define MINIMAL 8
50
51// Use these adjustable variables to test for best configuration to be used on
52// the ATTiny chips. These variables are defined as macros in the library's
53// RF24/utility/ATTiny/RF24_arch_config.h file. To change them, simply define
54// the corresponding macro(s) before #include <RF24> in your sketch.
55uint8_t csnHighSettle = MAX_HIGH; // defined as RF24_CSN_SETTLE_HIGH_DELAY
56uint8_t csnLowSettle = MAX_LOW; // defined as RF24_CSN_SETTLE_LOW_DELAY
57
58/****************************************************************************/
59void ce(bool level) {
60 if (CE_PIN != CSN_PIN) digitalWrite(CE_PIN, level);
61}
62
63/****************************************************************************/
64void csn(bool mode) {
65 if (CE_PIN != CSN_PIN) {
66 digitalWrite(CSN_PIN, mode);
67 } else {
68 // digitalWrite(SCK, mode);
69 if (mode == HIGH) {
70 PORTB |= (1 << PINB2); // SCK->CSN HIGH
71 delayMicroseconds(csnHighSettle); // allow csn to settle
72 } else {
73 PORTB &= ~(1 << PINB2); // SCK->CSN LOW
74 delayMicroseconds(csnLowSettle); // allow csn to settle
75 }
76 }
77}
78
79/****************************************************************************/
80uint8_t read_register(uint8_t reg)
81{
82 csn(LOW);
83 SPI.transfer(R_REGISTER | reg);
84 uint8_t result = SPI.transfer(0xff);
85 csn(HIGH);
86 return result;
87}
88
89/****************************************************************************/
90void write_register(uint8_t reg, uint8_t value)
91{
92 csn(LOW);
93 SPI.transfer(W_REGISTER | reg);
94 SPI.transfer(value);
95 csn(HIGH);
96}
97
98/****************************************************************************/
99void setup(void) {
100
101#ifndef __AVR_ATtinyX313__
102 // not enough memory on ATTiny4313 or ATTint2313(a) to use Serial I/O for this sketch
103
104 // start serial port and SPI
105 Serial.begin(115200);
106 SPI.begin();
107 // configure CE and CSN as output when used
108 pinMode(CE_PIN, OUTPUT);
109 if (CSN_PIN != CE_PIN)
110 pinMode(CSN_PIN, OUTPUT);
111
112 // csn is used in SPI transfers. Set to LOW at start and HIGH after transfer. Set to HIGH to reflect no transfer active
113 // SPI command are accepted in Power Down state.
114 // CE pin represent PRX (LOW) or PTX (HIGH) mode apart from register settings. Start in PRX mode.
115 ce(LOW);
116 csn(HIGH);
117
118 // nRF24L01 goes from to Power Down state 100ms after Power on Reset ( Vdd > 1.9V) or when PWR_UP is 0 in config register
119 // Goto Power Down state (Powerup or force) and set in transmit mode
120 write_register(NRF_CONFIG, read_register(NRF_CONFIG) & ~_BV(PWR_UP) & ~_BV(PRIM_RX));
121 delay(100);
122
123 // Goto Standby-I
124 // Technically we require 4.5ms Tpd2stby+ 14us as a worst case. We'll just call it 5ms for good measure.
125 // WARNING: Delay is based on P-variant whereby non-P *may* require different timing.
126 write_register(NRF_CONFIG, read_register(NRF_CONFIG) | _BV(PWR_UP));
127 delay(5) ;
128
129 // Goto Standby-II
130 ce(HIGH);
131 Serial.print("Scanning for optimal setting time for csn");
132
133
134 /************************** Main program *********************************/
135
136 uint8_t result; // used to compare read/write results with read/write cmds
137 bool success = true;
138 uint8_t bottom_success;
139 bool bottom_found;
140 uint8_t value[] = {5, 10};
141 uint8_t limit[] = {MAX_HIGH, MAX_LOW};
142 uint8_t advice[] = {MAX_HIGH, MAX_LOW};
143
144 // check max values give correct behavior
145 for (uint8_t k = 0; k < 2; k++) {
146 bottom_found = false;
147 bottom_success = 0;
148 while (bottom_success < 255) {
149 csnHighSettle = limit[0];
150 csnLowSettle = limit[1];
151 // check current values
152 uint8_t i = 0;
153 while (i < 255 && success) {
154 for (uint8_t j = 0; j < 2; j++) {
155 write_register(EN_AA, value[j]);
156 result = read_register(EN_AA);
157 if (value[j] != result) {
158 success = false;
159 }
160 }
161 i++;
162 }
163 // process result of current values
164 if (!success) {
165 Serial.print("Settle Not OK. csnHigh=");
166 Serial.print(limit[0], DEC);
167 Serial.print(" csnLow=");
168 Serial.println(limit[1], DEC);
169 limit[k]++;
170 bottom_found = true;
171 bottom_success = 0;
172 success = true;
173 } else {
174 Serial.print("Settle OK. csnHigh=");
175 Serial.print(limit[0], DEC);
176 Serial.print(" csnLow=");
177 Serial.println(limit[1], DEC);
178 if (!bottom_found) {
179 limit[k]--;
180 if (limit[k] == MINIMAL) {
181 bottom_found = true;
182 bottom_success = 0;
183 success = true;
184 }
185 } else {
186 bottom_success++;
187 }
188 }
189 } // while (bottom_success < 255)
190 Serial.print("Settle value found for ");
191 if (k == 0) {
192 Serial.print("csnHigh: ");
193 } else {
194 Serial.print("csnLow: ");
195 }
196 Serial.println(limit[k], DEC);
197 advice[k] = limit[k] + (limit[k] / 10);
198 limit[k] = 100;
199 } // for (uint8_t k = 0; k < 2; k++)
200 Serial.print("Advised Settle times are: csnHigh=");
201 Serial.print(advice[0], DEC);
202 Serial.print(" csnLow=");
203 Serial.println(advice[1], DEC);
204
205#endif // not defined __AVR_ATtinyX313__
206}
207
208
209void loop(void) {} // this program runs only once, thus it resides in setup()