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”.

/examples/rf24_ATTiny/rf24ping85/rf24ping85.ino
 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.

/examples/rf24_ATTiny/timingSearch3pin/timingSearch3pin.ino
 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()