dparson55 / NRFLite

nRF24L01+ library with AVR 2 pin support, requiring very little code along with YouTube videos showing all available features.
MIT License
161 stars 27 forks source link

NRFLite stopped working on ESP32 and ATtiny3216 #41

Closed mediaDS closed 4 years ago

mediaDS commented 4 years ago

Hi

I am using the Arduino IDE 1.8.9 and using the latest NRFLite library. I am using an ESP32 on one side and a ATTiny3216 on the other side. Both worked fine transmitting/receiving data. Until a few days ago. It stopped working completely. I am using different nRF24L01+ boards - none of them work anymore (they work with the RF24 lib without problems). I double-checked the (SPI) wiring and definition of CE and CSN.

I tried the RF24 library on the ESP32 - working fine. Back to NRFLite: no way, Init always comes with an error and printDetails gives only "1"s. I updated some libraries during the last days or so but have no idea what could cause this, maybe SPI or some strange definition which might have changed?

I am totally lost here. Any ideas?

Please ask if you need more specific informations.

Dieter

mediaDS commented 4 years ago

Some additional informations. Here is the relevant part of it:

Board: MegaTinyCore (latest version from Konde)

ATTiny3216:

Hardware-Wiring and Pinout:

Vcc     O-> 1                            20 <-O GND
CSN    O-> 2 (0)  PA4         PA3 (16)  19 <-O SCK
CE       O-> 3 (1)  PA5         PA2 (15)  18 <-O MISO
ADC0    O-> 4 (2)  PA6 AIN6    PA1 (14)  17 <-O MOSI
ADC1    O-> 5 (3)  PA7 AIN7    PA0 (17)  16 <-O UPDI
ext1    O-> 6 (4)  PB5         PC3 (13)  15 <-O IRQ
ext2    O-> 7 (5)  PB4         PC2 (12)  14 <-O IRQ
RxD T2D O-> 8 (6)  PB3         PC1 (11)  13 <-O Charge
TxD T2E O-> 9 (7)  PB2         PC0 (10)  12 <-O IRQ
SDA     O-> 10 (8) PB1         PB0 (9)   11 <-O SCL

Includes:

#include <SPI.h>
#include <NRFLite.h>
#include <Wire.h>
#include <BH1750.h>
#include <TinyBME280.h>
#include <Adafruit_MLX90614.h>
#include <SparkFunHTU21D.h>
#include <AS3935_Wire.h>
#include <EEPROM.h>
#include <Timer.h>
#include <uCRC16BPBLib.h>

const static uint8_t RadioID = 0x11;           // Wetterstation #1
const static uint8_t DESTINATION_RADIO_ID = 0; // Gateway
const static uint8_t PIN_RADIO_CE = 1;
const static uint8_t PIN_RADIO_CSN = 0;

typedef struct RadioPacket {
....
};

NRFLite NRF24;
RadioPacket radioData;
...

void setup() {
  ...
  Wire.begin();
  ...
  /* Test with a blinking LED in case of error and a software RESET */

  if (!NRF24.init(RadioID, PIN_RADIO_CE, PIN_RADIO_CSN, NRFLite::BITRATE1MBPS, Config.channel)); {
    for (int i = 0; i < 4; i++) { digitalWrite(LEDTEST, !digitalRead(LEDTEST)); delay(500); } 
    digitalWrite(LEDTEST, 1);
    delay(500);
    _PROTECTED_WRITE(RSTCTRL.SWRR,1); 
  }

void loop() {
  ...
  unsigned long oldmillis = 0;
  slowmillis = millis();
  while (!NRF24.hasData()) {
    ...
    if (millis() - oldmillis > 500) { digitalWrite(LEDPIN, !digitalRead(LEDPIN)); oldmillis = millis(); }
  }
  NRF24.readData(&Payload);
  ...
  }

ESP32 part:

#include <WiFi.h>
#include <SPI.h>
#include <NRFLite.h>
#include <PubSubClient.h>
#include <ArduinoOTA.h>
#include <uCRC16BPBLib.h>

const static uint8_t RADIO_ID = 0;       
const static uint8_t PIN_RADIO_CE = 17;
const static uint8_t PIN_RADIO_CSN = 5;

typedef struct RadioPacket {
...
};

NRFLite NRF24;
RadioPacket radioData;
WiFiClient Gateway;
PubSubClient client(Gateway);
NRFLite _radio(Serial);
...

void setup() {
  ...
  analogReadResolution(12);
  Serial.begin(115200);
  ...
  if (NRF24.init(RADIO_ID, PIN_RADIO_CE, PIN_RADIO_CSN, NRFLite::BITRATE1MBPS, Config.channel)); {
  Serial.println();
    Serial.println("nRF24 INIT ERROR");
  Serial.println();
  }
  ...
  Serial.println();
  Serial.println("Setup done");
  Serial.println();
}

void loop() {
  ...
  datavalid = false;
  _radio.printDetails();
  ...
  NRF24.send(Payload.S_RadioID, &Payload, Payload.S_Length);
  ...

I get an initialization error on both boards, If I ignore them I get no data at all and the printDetails function gives just 1s or 255 on all registers. As I said - the RF24 library works fine on the same ESP32 board. It seems like SPI is not working anymore.

dparson55 commented 4 years ago

It does sound like an SPI issue. I'll download the latest Arduino IDE (currently 1.8.12) to make sure it still works on my end. NRFLite depends on the Arduino SPI library so I'll just check to see if anything on it changed.

mediaDS commented 4 years ago

Hi, thank you for looking into the issue, I also installed a clean version on 1.8.12 on two different computers. Unfortunately still the same issue. Please let me know if you've found anything.

Would you say that NRFLIte should work on the new MegaTinyCore micros like the ones I use?

Have a nice day,

Dieter

dparson55 commented 4 years ago

Arduino 1.8.12 is working ok on my end still, so it is probably just an incompatibility with a library that got updated. Since you have things working with the RF24 library, it will definitely be easier to just go with it. But to troubleshoot, try go back to having the nRF24L01 modules plugged into your microcontrollers and go back to using examples from the NRFLite library. Then add 1 piece of hardware and its associated library at a time, and call the methods on the library that you need to ensure it is compiled into your code (if you just include the library and don't call its methods, the compiler will not actually include the code in the binary). Do that until something stops working.

mediaDS commented 4 years ago

HI Dave,

thanks for the info. I will try that. Unfortunately I can't use the RF24 library on my 3216 - it won't work on the new ATTinys. Beside that I love the simplicity of your library and would rather do anything to get it working. Quite frankly - I don't need all the bells and whistles of RF24, just a reliable code like yours.

If you are interested in the outcome just let me know.

Dieter

dparson55 commented 4 years ago

Reading https://github.com/SpenceKonde/megaTinyCore there are some SPI specific notes.

"SPI.swap(1) or SPI.swap(0) will set the the mapping to the alternate (1) or default (0) pins. It will return true if this is a valid option, and false if it is not"

I don't have any of these new micros, don't even have an ESP32 or 8266, so unfortunately I can't be of much help. If you do find a solution I would love to hear about it, in case someone else tries to do the same.

mediaDS commented 4 years ago

Hi Dave,

The new 3216 micros are easy to program In-System with just one UPDI wire - I like them a lot, especially if I have to re-program them already soldered to the PCB.

I did what you said, so here is the first result:

0x01. uninstalled everything Arduino from my workshop PC. After that it was clean as a whistle. 0x02. installed the latest Arduino IDE 1.8.12 0x03. added Kondes MegaTinyCore via board manager 0x04. built the hardware again (3216 + nRF24L01+) - on breadboard and double checked the wiring 0x05. added two LEDs for "Blinkenlights" 0x06. White LED blinking twice = Init error 0x07 Blue LED blinking = All ok, nRF waits for data 0x08. attached USB port via UPDI programmer to the micro 0x09. attached minicom to the second USB port via serial-to-USB adapter. 0x0a. wrote a small script with initializing, print.Details and print.Channels 0x0b. uploaded the code and this is the result in the serial terminal (yay, it does work!)

White LED was blinking twice, after that the blue LED was blinking ... hmm.

Begin:
Init failed.
CONFIG 00001011
EN_AA 00111111
EN_RXADDR 00000011
SETUP_AW 00000011
SETUP_RETR 00011111
RF_CH 01100100
RF_SETUP 00000110
STATUS 00001110
OBSERVE_TX 00000000
RX_PW_P0 00000000
RX_PW_P1 00000000
FIFO_STATUS 00010001
DYNPD 00000011
FEATURE 00000111
TX_ADDR 231,231,231,231,231
RX_ADDR_P0 231,231,231,231,231
RX_ADDR_P1 1,2,3,4,17
Channel   0 
Channel   1 
Channel   2 
Channel   3 
Channel   4 
Channel   5 
Channel   6 
Channel   7 
Channel   8 
Channel   9 
Channel  10 
...
...

So it seems to work for now. I also tried SPI.swap(0) and SPI.swap(1). With 0 I get the above result. If I switch to the alternative then I only get 1s as a result (which makes sense).

Unfortunately the radio.init(...) still gives false as a return value, no matter what I try. I will now add my other board definitions and libraries step-by-step until it stops working. The saga continues ....

mediaDS commented 4 years ago

Normally big boys don't cry, but ... I can't get Arduino IDE to run, always crashes and I cannot install any board definition anymore. This happened suddenly.

Sorry Dave, this might take a bit longer than I expected.

dparson55 commented 4 years ago

It's very confusing why init failed. To determine success or failure, it verifies the CONFIG register was setup correctly. The value of this register is correct, it should be CONFIG 00001011. So I'm at a loss. Maybe try changing the CSN pin to a different pin on your microcontroller once you get the Arduino IDE working again.

mediaDS commented 4 years ago

I am using the SS pin for CSN but yes, I will use another pin instead and let you know. Maybe I am blind but this is what I wrote in the sketch:

  if (!Radio.init(RadioID, PIN_RADIO_CE, PIN_RADIO_CSN, NRFLite::BITRATE1MBPS, 100)); {
    for (int i = 0; i < 4; i++) { digitalWrite(LEDTEST, !digitalRead(LEDTEST)); delay(500); } 
    digitalWrite(LEDTEST, 1);
  }
  Radio.printDetails();

The LED blinks twice and then the controller does a printDetails() which works fine. Anyway, I will have to wait until the Arduino IDE has been fixed.

Have a nice day, Dieter

Edit:

It is exactly the same on a ESP32 with standard SPI wiring.

mediaDS commented 4 years ago

Okay, if I change the CSN pin it won't work at all. It has to be connected to the SS pin (I assume because of Hardware SPI).

Normally I'd use if (!Radio.init(...) then do some error blinkenlights. This does not work. But if I put the return value to a bool then the init works as expected. I assume (I am no expert) this is because you don't return a bool but a uint8_t instead. But, as far as I can remember, a bool is stored as a uint8_t. I am confused, but ok, I get it, bool != uint8_t. See, I learnt (learned) something :)

This does not work:

if (!Radio.init(1,1,0,<bitrate>,100) { sound the alarm and blink the red LED because of an error; }
else ALL OK.

This does work as expected:

bool initfail = (Radio.init(1,1,0,<bitrate>,100);
if (!initfail) { sound the alarm and blink the red LED because of an error; }
else ALL OK.

I'll continue my research ...

mediaDS commented 4 years ago

Done. It works again. Eventually.

After a step-by-step reinstall of all boards and libraries I got it working again. I'm a bit flabbergasted because in the end all boards and libs were installed like it was before. So, beside the init problem described above all is good now. Maybe it was one of the updates, maybe not. I do not know.

Thanks for your help, I will close this issue now.

dparson55 commented 4 years ago

Great to hear it's working again!. Sorry for the confusion in the init, I guess ESP vs AVR now has this major difference in what they consider true vs false. I might have to get an ESP now just to experiment and see what the differences are.

mediaDS commented 4 years ago

Sorry, now I confused you. I was talking about the MegaTinyCore ATtiny3216 micro not the ESP.

I will re-open this again because now I got some problems with the ESP32 - no SPI data. So I have to re-check the wiring (again...). I'll keep you posted.

Edit.

For clarification: the ATtiny3216 is my sensor controller for the outside sending date to the ESP32 gateway inside. It is done via a protokol I designed, so the outdoor module only sends data if the gateway tells it to send a new data packet.

mediaDS commented 4 years ago

Well, I can't get the ESP32 to work with your lib. I did everything from re-wiring to adding some SPI initialization for the VSPI (and HSPI) interface. I also used different pins for CE and CSN. Doesn't work no matter what I do (but maybe I am too inexperienced with SPI stuff).

Due to a deadline I will now use the working RF24 library instead (at least for the time being). But I will have a close look at updated libs of yours. I hope you will get your ESP soon :)

I'll let this issue open if you agree.

dparson55 commented 4 years ago

I would like to help more but unfortunately NRFLite doesn't have the large community of supporters like RF24, and I can't support all the hardware that's out there on my own. But I did confirm that I have NRFLite's list of supported architectures correct: only avr and esp8266. The two architectures you are using, esp32 and megaavr are not on the list and really the Arduino IDE should have warned you that NRFLite was not supported.

I only discovered today that Arduino had different architectures for the ESP32 and the new AVR microcontrollers, so that would have saved us some time. I could have just said these are not supported architectures and recommended the RF24 library since it does support both your architectures. So it would definitely be the library to use. They have a lot more people available to help troubleshoot issues since it is much more popular, while NRFLite is just me and I don't have the hardware you are trying to use.

mediaDS commented 4 years ago

Hi Dave, yes, I do understand. Unfortunately the RF24 works well with ESP32 but not the MegaTinyCore (I tried numerous times). Your lib works very well with MegaTinyCore but not the ESP32 - ain't it funny? :)

Well, since more and more people use ESP32 instead of the old ESP8266 (and the same with the new AVR micros) I can only hope that more and more libs are adjusted to them. Thanks anyway for the help, I learnt a lot.

dparson55 commented 4 years ago

@mediaDS, another person, @bart just added ESP32 support and NRFLite 2.4.0 has an example to show it. Turns out the ESP32 supports configurable SPI pins which you can control yourself.

mediaDS commented 4 years ago

@mediaDS, another person, @bart just added ESP32 support and NRFLite 2.4.0 has an example to show it. Turns out the ESP32 supports configurable SPI pins which you can control yourself.

Hi Dave, sorry for the delay, it's holiday time :)

Thanks for the info, will try it later on since I'm not very happy with RF24 atm.

mediaDS commented 4 years ago

Just tested both boards - doesn't work reliably. On the ESP32 (with the correct wiring) printDetails always gives "1" or "255" and doesn't work reliable. Sometimes it sends, sometimes not. Sometimes one boards sends but the other does not receive anything.

On the ATTiny 3216 MegaAVR it works fines, gives normal results with printDetails and seems to work. But I was unable to maintain a stable connection between the two boards about 10 meters away from each other on a free channel. I tried four different boards (with external and PCB antenna).

Still investigating and trying to find out if its a hardware or software problem. I guess you can add the MegaAVR controllers to the list of supported platforms. But the ESP32 gives me a hard time.

dparson55 commented 4 years ago

If printDetails doesn't work reliably, there's something drastically wrong with the SPI communication between the microcontroller and radio and it is pointless to attempt any wireless communication. Keep focusing on fixing the SPI communication, without it working 100% perfectly, there's no way the radio can work.

mediaDS commented 4 years ago

Hi Dave, thanks for the tipps. I will try to reduce the clock rate which is a good idea anyway.

I'm afraid I did not make myself clear enough - the ESP32 transmits and receives data just fine, just not reliable enough. I am using a protokoll between both controllers -. the ESP32 on one side, the 3216 on the other. The ESP32 sends a command to the 3216 (with a command header of 6 bytes) and gets data (up to a maximum of 32 bytes) back. Very simple. And it works maybe 9 out of 10 times which is not good enough for my project.

Sometimes the 3216 should send 26 bytes of data but only 6 bytes arrive at the ESP32 receiver followed by an ACK error on the transmitter side. Sometimes one byte 0x64 is send but 0x00 is received instead - with no error reported on the transmitter or receiver end.

One observation is that I can send the 6-byte command header from the ESP32 to the 3216 without problems but as soon as I want to receive data back (with various lenghts) the problems occur. So I assume it is when I switch from receiving to transmitting data on either side. I also ran the test sketches from the examples - they work fine on both boards switching between transmitter and receiver.

The printDetails function is always reporting wrong data (all set to '1') on the ESP32 no matter what. Kind of a weird problem I guess.

The hardware does not seem to be the problem. I will solder a new board this afternoon to rule out any hardware problems once and for all. I'll let you know my findings as soon as I have results.

The ESP boards I tested are the Wroover and the Dev kit - just ordinary ESP32 systems which I used in various projects before.

mediaDS commented 4 years ago

In-between results: it seems the ESP32 can only transmit data. I'll try to find out why this is the case. Tested right now with two identical NRF24L01+ boards with external antenna. It also seems that NRF24L01 with PCB antenna are not 100% compatible to boards with PA and external antenna. Maybe a drift in frequency, I don't know.

I also had any eye on the power supply of my boards but both are fine with the usual capacitors in the right place. I also used the boards with HiPower LiFePo batteries - did not make a difference.

bart commented 4 years ago

@mediaDS ESP32 can definitely transmit AND receive data. Works on my board (TTGO) without any issues.

mediaDS commented 4 years ago

Good morning, Rene

I was talking about my ESP32. But it's good to know it should work :)

Anyway, I will rewrite my Sketches today, so I can test it step-by-step. I take it that you use the standard SPI interface of the ESP32 as pointed out in the docs?

I am still scratching my head about the printDetails function which returns the wrong data. I assume this function returns valid data on your ESP32 as well?

mediaDS commented 4 years ago

Here are the relevant lines from the sketch on my ESP32:

Pin Definitions:

const static uint8_t CEPIN = 17;
const static uint8_t CSNPIN = 5;
const static uint8_t MOSIPIN = 23;
const static uint8_t MISOPIN = 19;
const static uint8_t SCKPIN = 18;

setup()

SPI.begin(SCKPIN, MISOPIN, MOSIPIN, CSNPIN);
Radio.init(1, CEPIN, CSNPIN, NRFLite::BITRATE1MBPS, 100, 0));

loop()

    ....  
    ....

    Radio.send(11, &Payload, len, NRFLite::NO_ACK);   // len is the length of the command header (6 bytes)

    ....
    ....

    unsigned long timeout = millis();
    while (!Radio.hasData()) {                       
        if ((millis() - waittimeout) > 400) { 
            break; 
        }
    }      

    ....
    ....

    int datlen = Radio.hasData();    // Length of received data is stored for later use
    Radio.readData(&RcvBuffer);

    ....
    ....

This is, in a nut shell, everything I do. I put data into a (aligned) struct named Payload and send it. Then I wait a maximum of 400mS for an answer. Received data is then in another aligned struct named RcvBuffer. That's all.

I can send the data to the other controller (RadioID 11), that one is receiving the data and sends data back - but it never arrives at my ESP32 (RadioID 1). I always get an error and no data has been received. The transmitting Attiny3216 does not give any error message, no matter if I use NO_ACK or REQUIRES_ACK on either side. Maybe I'm blind but I cannot find any problem here.

dparson55 commented 4 years ago

@bart if you have any idea how to help make printDetails work on the ESP32, that would be great to understand.

@mediaDS what does the code on the ATtiny side look like? You mentioned 9 of 10 times the communication from the ATtiny back to the ESP32 works, is that still the case?

In the ESP32 code you provided, you should do a REQ_ACK send. You should also check to see if datlen is > 0 before attempting to read the data:

loop
{
    if (Radio.send(11, &Payload, len, NRFLite::REQ_ACK) // Ensure the packet was successfully sent.
    {
        unsigned long timeout = millis();
        uint8_t datlen = 0;

        while (true)
        {
            datlen = Radio.hasData();

            if (datlen > 0) // Check to see if data was received.
            {
                Radio.readData(&RcvBuffer);
                break;
            }
            else if (millis() - timeout > 399) // 400 ms timeout.
            {
                break;
            }
        }

        if (datlen > 0)
        {
            // Do data processing.
        }
        else
        {
            // Timeout was reached, no response was received.
        }
    }
}

Here are some more troubleshooting ideas:

You mentioned 9 of 10 times the communication from the ATtiny back to the ESP32 works. Within the same room I usually have 0% packet loss but if I move the radios away from each other in different parts of my home, I can start to get packet losss. If a big appliance starts running (like a washing machine), or someone walks by, or if a door shuts, these can all affect the reliability of the communication with these particular radios.

I had a project where these nRF24L01 radios did not have the necessary range and I had to switch to RFM69C radios to solve the problem. I discussed the issue and showed the different radio in part 6 of my Arduino Wireless Pump Controller project in case the range and reliability of these radios will not work for your situation. The nRF24L01 is really meant for streaming data at high speed between 2 devices in the same room, such as streaming data to a 4x4x4 RGB cube. Though they can work at a further range up to a point, the RFM69C is much better suited for longer range, lower speed communication indoors and outdoors.

mediaDS commented 4 years ago

Good Morning Dave, thanks for the information, very helpful indeed. Let me begin with the code fragment I posted. Unfortunately I removed the part where I handle the timeout. As soon as the timeout hits I set a flag which then skips receiving data and returns. The structure is similar to the code you posted.

I do use the REQ_ACK in my project, I just tested it with NO_ACK to see if there is a problem with the internal ACK responses. Does not make a difference, so I set it back to the REQ_ACK.

On the ATtiny3216 side it looks identical except the RadioIDs are reversed.

#define CEPIN 1               // CE Pin for NRF24L01+
#define CSNPIN 0              // SS Pin for NRF24L01+

setup()

SPI.swap(0);
Radio.init(MyID, CEPIN, CSNPIN, NRFLite::BITRATE1MBPS, Config.channel, 1);

loop()

receiving and transmitting is the same as on the ESP32

I will do some step-by-step testing with the poposed changes, especially the hardware-based communication and the bitrate changes. I'll let you know.

Unfortunately the RFM69C is a no-go for me and my project - it would use too much current (it draws up to 120mA). My outdoor sensor array is battery-driven (LiPo) (and charged by a small solar panel) , so the ATTiny family is the way to go. It's challenging but it will work in the end :)

Beside that I could have used the ESP32 directly with Wifi, but that would draw up to 300mA and would've been too easy, wouldn't it?

mediaDS commented 4 years ago

Hmm, that is a nifty idea with the ACK based communication. I actually overlooked it somehow. I'll have to rewrite a lot of stuff for it but that might work then. I would have to send commands twice, though because the ACK packet is for the next data packet. I'll give it a try.

mediaDS commented 4 years ago

Hi Dave, all is working now (except printDetails on ESP32), thanks so much for your help and suggestions.

Dieter

dparson55 commented 4 years ago

Can you explain your fix so others can reference it in the future?

mediaDS commented 4 years ago

Morning Dave, yes, of course - I just did what you said - using the hardware-based communication via ACK packets. I send a command header to the controller which is then generating the ACK packet for the next received command - which I send as a dummy to get the ACK response:

ESP32: send 3B <RadioID> <NodeID> <command> <length> 90

3216: receives and executes <command> and then packs data with <length> as the ACK response

ESP32: sends 3B <RadioID> <NodeID> 00 00 90

3216: send ACK data packet with <length>

ESP32: receives ACK and generates data for MQTT and display

Pretty simple. As soon as I finish my PCB layouts I will post the relevant parts of the sketches with explanation. The only part I am working at is the timing between sending the command and the dummy packet to actually get the ACK. By the way - the real challenge here was to put 12 floats from the various sensors into 32 bytes including a status dword and 16-bit CRC.

dparson55 commented 4 years ago

Ok good deal and congrats on packing all of that into a single packet!