Saturday, January 15, 2022

0000 0000 1000 0100

FrankeNano = Nano + NRF24L01

For some reason (late night purchasing?) I received a combo Nano and Wireless module in the mail and thought it was a pretty cool WiFi capable Nano.


But after investigation I found it was actually an NRF24L01 module sandwiched into the Nano form factor (an RF-Nano, not to be confused with Nano-RF!).

Then began what I thought was going to be a simple project to link two of these together and test the communication distance. It was not a simple project!

To go through all the problems in detail would take too long, but here's a quick dot point summary:

  • The microcontroller at the heart of the RF-Nano purportedly is a clone of the ATMega328p known as the LGT8F328P. It comes with some impressive stats - including 32MHz clock speed. But...all attempts to use known board core combos to communicate with the chip failed. Eventually I caved in and used the standard Nano board core - the ATMega328p version, and it worked?!
  • The LGT8F328P microcontroller supposedly can run at 32MHz - after a few experiments documented in the video below my little darling could barely tick along at 4MHz?!
  • 4MHz means that things like NRF24L01 communication and ADC stuff seem compromised - great! Now I need to burn the bootloader and hope overclocking is not an issue?
  • There is slim documentation for this package and what is available is awful - so I ended up using a known NRF24L01 library instead of the poorly maintained recommended spaghetti-code nonsense library.
  • There are various incarnations of this FrankeNano, which means that the critical CE and CSN pins involved in communication between the Nano and the NRF24L01 module may well be different to the library - advice: follow your traces carefully.
  • There is no documentation for the use of an external antenna, so I just flipped the zero ohm resistor/jumper myself - although I found that this configuration did not improve performance at all, and in fact may have degraded the communication distance between modules. I'm currently experimenting with different external antenna combos.
  • The ICSP headers on the RF-Nano have been sacrificed for the NRF24L01, so when I'm ready to blow up one of these I'll use the pins on the Nano itself and try to clock that microcontroller back up to useable speeds.

You will need a decent power supply, nice chunky current and some beefy capacitors to help with communication - there is still much to be discovered about this strange beast. Good on the Emakefun crew for giving it a shake - it's a worthy idea that I think might need a bit of solid documentation and some well commented example code to make it fly.

Speaking of code - I modified the following that I found on  this site, and the send/receive combo looks like this...

Sending Code:

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

#define CE_PIN   9
#define CSN_PIN 10

int sensorPin = A0;
int ledPin = 2;
bool LEDon = false;

const byte slaveAddress[5] = {'R', 'x', 'A', 'A', 'A'};

RF24 radio(CE_PIN, CSN_PIN);

byte dataToSend;
int potread;
int blinkValue;

unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 200;
unsigned long LEDMillis;
unsigned long BlinkDelay = 200;

void setup() {

  pinMode(sensorPin, INPUT);
  pinMode(ledPin, OUTPUT);
  radio.begin();
  radio.setDataRate( RF24_250KBPS );
  radio.setPALevel(RF24_PA_MAX);
  radio.setChannel(90);
  radio.setRetries(3, 5);
  radio.openWritingPipe(slaveAddress);
}

void switchLED() {
  if (!LEDon) {
    digitalWrite(ledPin, HIGH);
    LEDon = true;
  }
  else {
    digitalWrite(ledPin, LOW);
    LEDon = false;
  }
}

void send() {

  bool rslt;
  dataToSend = blinkValue;
  rslt = radio.write( &dataToSend, sizeof(dataToSend) );
}

void loop() {

  currentMillis = millis();
  if (currentMillis - prevMillis >= txIntervalMillis) {
    potread = analogRead(sensorPin);
    delay(20);
    blinkValue = map(potread, 0, 4095, 1, 255);
    BlinkDelay = 3 * blinkValue;
    send();
    prevMillis = millis();
  }
  if (currentMillis - LEDMillis >= BlinkDelay) {
    switchLED();
    LEDMillis = millis();
  }
}

Receiving Code:

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

#define CE_PIN   9
#define CSN_PIN 10
int ledPin = 2;

unsigned long currentMillis;
unsigned long prevMillis;
unsigned long BlinkDelay = 200;

const byte thisSlaveAddress[5] = {'R', 'x', 'A', 'A', 'A'};

RF24 radio(CE_PIN, CSN_PIN);

byte dataReceived[1];
bool newData = false;
bool LEDon = false;

void setup() {

  pinMode(ledPin, OUTPUT);

  radio.begin();
  radio.setDataRate( RF24_250KBPS );
  radio.setPALevel(RF24_PA_MAX);
  radio.setChannel(90);
  radio.openReadingPipe(1, thisSlaveAddress);
  radio.startListening();
}

void switchLED() {
  if (!LEDon) {
    digitalWrite(ledPin, HIGH);
    LEDon = true;
  }
  else {
    digitalWrite(ledPin, LOW);
    LEDon = false;
  }
}

void getData() {
  if ( radio.available() ) {
    radio.read( &dataReceived, sizeof(dataReceived) );
    while (dataReceived[0] == 0) {
      radio.read( &dataReceived, sizeof(dataReceived) );
      currentMillis = millis();
      if (currentMillis - prevMillis >= BlinkDelay) {
        switchLED();
        prevMillis = millis();
      }
    }
    newData = true;
  }
}

void showData() { // left over from deBug
  if (newData == true) {
    radio.stopListening();
    delay(20);
    newData = false;
    radio.startListening();
    delay(20);
  }
}

void loop() {
  currentMillis = millis();
  getData();
  BlinkDelay = dataReceived[0];
  BlinkDelay = 3 * BlinkDelay;
  if (currentMillis - prevMillis >= BlinkDelay) {
    switchLED();
    prevMillis = millis();
  }
  showData();
}

Here is the video of the work so far, I think there is some more in this as I'm interested in increasing the range to useful levels!



No comments:

Post a Comment