sandeepmistry / arduino-LoRa

An Arduino library for sending and receiving data using LoRa radios.
MIT License
1.64k stars 627 forks source link

LoRa fails to start running dual core ESP32 with Bodmers TFT_eSPI library #290

Open FLYINGSC0T opened 4 years ago

FLYINGSC0T commented 4 years ago

Hi, Can anyone help with this issue. I'm running dual core on ESP32 - LoRa on core 0 and TFT_eSPI on core 1. LoRa is assigned to VSPI and TFT_eSPI to HSPI.

The problem is that LoRa will not start if I initialize tft.begin(). If I comment out tft.begin() then LoRa starts ok. I've also tried running on single core with same results.

Ideas why this is happening ? Any advice greatly appreciated.

Thanks in advance.

FLYINGSC0T commented 4 years ago

Hi,

I failed to mention that the problem is only with a ILI9488 display. Swapping over to a ILI9341 display there is no problem when the SPI port is shared and running dual core.

Regards.

morganrallen commented 4 years ago

Are you certain each device is using the correct pins? Have you called LoRa.setPins? Assuming the ILI9488 and ILI9341 use different drivers their default pin assignments might be different.

FLYINGSC0T commented 4 years ago

Hi morganrallen and thanks for your response.

Firstly, is it absolutely necessary to use the "correct pins" as follows: // WIFI_LoRa_32 ports // GPIO5 -- SX1278's SCK // GPIO19 -- SX1278's MISO // GPIO27 -- SX1278's MOSI // GPIO18 -- SX1278's CS // GPIO14 -- SX1278's RESET // GPIO26 -- SX1278's IRQ(Interrupt Request)

My setup is as follows - the GPIO's are the default for TFT_eSPI using the ESP32's VSPI bus: // LoRa setup to use VSPI GPIO's

define SCK_GPIO18 18

define MISO_GPIO19 19

define MOSI_GPIO23 23

define SS_GPIO5 5

define RST_GPIO27 27

define DI0_GPIO26 26

define LoRa_BAND 868E6

I'm calling LoRa.setPins() with: // Start SPI Service & setup the GPIO's SPI.begin(SCK_GPIO18, MISO_GPIO19, MOSI_GPIO23); LoRa.setPins(SS_GPIO5, RST_GPIO27, DI0_GPIO26);

NOTE: SS_GPIO5 has been left out as I think it interferes with the TFT_eSPI chip select settings ?

These settings work using shared VSPI bus as I tested all day today and more than 3500+ packets were received without LoRa stopping and running dual core with an ILI9341 display.

I contacted Bodmer and this was his response: "I suspect that the problem is experienced with the ILI9488 because that display uses 8 bit commands and 18 bit SPI transactions for the pixel colours, whereas the ILI9341 uses 8 bit commands and 16 bit transactions for pixels. This suggests that the LoRa library you are using does not support shared transactions on the SPI bus and maybe assumes it has exclusive use of the SPI bus and it is always configured for 16 bit exchanges. This is just a guess as I do not know what software libraries you are using. If the sketch uses callbacks then this can also cause problems because TFT transactions might get interrupted by SPI exchanges with the RFM95W. The ESP32 has 2 SPI ports so if the pins are spare you could configure the TFT_eSPI library to use the other port."

What do you think ? Is it possible what Bodmer says ? How can the issue be solved ? Is it a problem with the LoRa library/TFT_eSPI library or both ?

I'm running out of ideas.

Thanks in advance for looking into this issue. I would really love to get it all working with a ILI9488 display.

morganrallen commented 4 years ago

The more I'm digging into this I'm realizing this library simply cannot use non-standard SPI pins. Your call to SPI.begin is unlikely to do anything as LoRa.begin calls it again without any arguments. I was starting to think calling LoRa.setSPI might be the ticket but the version check in begin will fail. A reaaally hacky solution might be, accept the .begin failure and manually initialize the radio but I cannot tell if this will actually work. Here's a snippet I came up with....

#include <SPI.h>
#include <LoRa.h>

#define SCK_GPIO18 18
#define MISO_GPIO19 19
#define MOSI_GPIO23 23
#define SS_GPIO5 5
#define RST_GPIO27 27
#define DI0_GPIO26 26
#define LoRa_BAND 868E6

SPIClass LoRaSPI;

void setup() {
 Serial.begin(115200);

 LoRaSPI.begin(SCK_GPIO18, MISO_GPIO19, MOSI_GPIO23);
 LoRa.setSPI(LoRaSPI);
 LoRa.setPins(SS_GPIO5, RST_GPIO27, DI0_GPIO26);
 if(!LoRa.begin(LoRa_BAND)) {
   Serial.println("LoRa.begin failed");
 }
}

This might work but as a couple config steps are skipped there's no way to tell. The only other thing I can think of is using LoRa on it's default pins and moving the display to other... assuming it has better support for alternative SPI config.

morganrallen commented 4 years ago

oh! this actually might work a bit better than I thought. I've looked into how SPIClass is implemented and if .begin is called a second time, it just returns. So LoRa.begin might not fail. Give it a try!

FLYINGSC0T commented 4 years ago

Hi morganrallen,

Thanks again for your valued response.

I tried your suggestions but with no success. So, I re-configured LoRa with the default GPIO's and setup the ILI9488 display to use the same pins sharing the same SPI bus with LoRa.

I had more success in getting LoRa to start. Here's my setup and the output from the serial monitor:

/***

// LoRa setup using default GPIO's

define SCK_GPIO5 5

define MISO_GPIO19 19

define MOSI_GPIO27 27

define SS_GPIO18 18

define RST_GPIO14 14

define DI0_GPIO26 26

define LoRa_BAND 868E6

/***

/ ILI9341/ILI9488 GPIO's with LoRa default GPIO's TFT_SCLK 5 TFT_MISO 19 // ILI9488 - connect T_D0 to MISO but leave TFT MISO disconnected if other SPI devices share MISO TFT_MOSI 27 TFT_CS 15 TFT_DC 2 TFT_RST 4 TOUCH_CS 0 // Chip select pin (T_CS) of touch screen /

In setup() I have:

// Start SPI Service & setup the GPIO's SPI.begin(SCK_GPIO5, MISO_GPIO19, MOSI_GPIO27); //SS_GPIO18 LoRa.setPins(SS_GPIO18, RST_GPIO14, DI0_GPIO26);

Serial.println("==========================="); Serial.print("LoRa ");

if (LoRa.begin(LoRa_BAND)) { // Put LoRa in receive mode LoRa.receive();
Serial.println("started OK !!"); } else { Serial.println("failed to start !!"); //while (1); }

Here is the output from the first run:

10:13:36.317 -> Packet count: 2525 10:13:36.317 -> Received '$GAFSOL,0,45.419983,5.959644,3072,1,0,7185A1F8' with RSSI -44

This is a good packet (number of packets received 2525) - but timed out - caught in a loop somewhere?

The fields consist of: $GAFSOL, - The header info Packeted ID, Latitude, Longitude, Altitude, Heading, Speed, Checksum

Output from the second run:

10:33:45.259 -> Packet count: 41 10:33:45.259 -> Received '$GAFS⸮⸮ ⸮+,-M ⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮' with RSSI -157

Where did this packet come from ? Note the RSSI - LoRa re-started

Then received this - note the RSSI is positive !! - LoRa then re-started - Am I actually receiving this packet or is it interference from the TFT.

10:34:57.401 -> Packet count: 51 10:34:57.401 -> Received '$GAFS⸮⸮ ⸮+,-M0,1F ^,,⸮⸮⸮,⸮⸮⸮⸮⸮E,⸮8⸮' with RSSI 42 10:35:03.278 -> Packet count: 51 10:35:03.278 -> Received ',⸮⸮⸮p⸮⸮⸮D⸮⸮' with RSSI -151

0:38:00.609 -> Packet count: 153 10:38:00.609 -> Received '$GAFS> 10:38:00.609 -> DK⸮C9⸮⸮⸮⸮⸮?>?>⸮>?>p⸮⸮⸮?>&#,,⸮⸮⸮+⸮⸮⸮⸮⸮+⸮+?>#⸮+⸮⸮⸮⸮6?#?6⸮+!⸮#' with RSSI -157

LoRa then re-started - third time !!

Program left running - then crashed with a Guru Meditation Error !!

Final output:

11:07:44.466 -> Packet count: 1615 11:07:44.466 -> Received '$GAFSOL,4,45.420010,4.747347,3041,270,115,DBF46D9F' with RSSI -46 11:07:45.123 -> Packet count: 1615 11:07:45.123 -> Received 'V⸮9⸮⸮⸮⸮ӡJm6⸮&⸮⸮⸮#ò⸮٧⸮y4}⸮⸮⸮-0⸮ ⸮⸮⸮q⸮⸮⸮A⸮⸮(x|⸮i\y⸮⸮⸮Д⸮⸮R⸮ 11:07:45.123 -> ⸮vf⸮x⸮H⸮⸮tKY⸮ 11:07:45.123 -> ⸮⸮P⸮⸮⸮⸮⸮a⸮⸮r=/;s⸮(d!⸮' with RSSI -111 11:07:49.461 -> Packet count: 1616 11:07:49.461 -> Received '$GAFSOL,6,44.206326,7.171940,3041,135,125,9E885043' with RSSI -47 11:07:49.461 -> Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1)

A total of 1615 packets received then a Guru Meditation Error !! What caused this and how can it be fixed ?

So, what do you think ? Any further thoughts ?

My thoughts are that LoRa needs to be setup with the default pins to work with a ILI9488 display. But where are the spurious packets coming from - I don't (seem) to get them when running with a ILI9341 display. Are they coming specifically from the ILI9488 library as this is different from the ILI9341 one as Bodmer mentions ? Do I need to set up something different ?

I'll incorporate what seems to work (?) into the main project sketch over the weekend if I have time and see what happens. In the meantime your further thoughts would be appreciated.

If you like, I can send you the full sketch (not the full project).

Regards.

FLYINGSC0T commented 4 years ago

Hi,

I have incorporated what seemed to work into the main project sketch and ran several tests over the weekend.

These are my findings: Everything works OK when running on just one core - core 1 with both ILI9341 and ILI9488 displays.

Running on both cores with either ILI9341 or ILI9488 displays - LoRa on core 0 and TFT on core 1 does not work.

LoRa fetches the first packet OK then afterwards the behaviour is undetermined. LoRa.parsePacket() always returns 0 and LoRa.Read() is never executed. The output to the serial monitor is garbage.

So what's happening ? What's causing this strange behaviour where the program works fine using just one core but doesn't work when using both cores ?

I really need to use both cores because the updates to the TFT take too long when running on just one core.

I'm scratching my head out in finding a solution !!

Thanks in advance.

Regards.

FLYINGSC0T commented 4 years ago

Hi, To give you an update, I was unsuccessful in implementing both cores of the ESP32 with LoRa. However, I did manage to get multi-threading to work with almost the same result as that if both cores are used.

But, I have an issue. After an undetermined amount of time the receiver stops receiving packets but the transmitter continues to transmit. I've written some code to check if after 1 minute no packets are received then the LoRa module is reset with LoRa.begin(). The module resets and works as expected both transmitting and receiving until the next time the receiver stops. Any ideas what and why this is happening ? I've looked at the HOPERF documentation v1.1 and on page 27 it states "The receiver undertakes a preamble detection process that periodically restarts." Could this be the problem ? Writing code to reset the module is a work-a-round and by no means a satisfactory solution so I would like to find and rectify the problem. Thanks again anyone who can shine any light on this subject. Regards.

morganrallen commented 4 years ago

I cannot think of a reason off hand the preamble detection would cause a receiver to suddenly stop. The preamble is simply how the sender tell the receiver a packet is starting.

The first thing I'd look into is how you're handling the receive interrupt, it's well known (#55) the included examples are problematic in this handling. If you are doing any major work within the receive handler this could be causing issues. If this is the case, follow the advice in PR #55 to eliminate that work.

Additionally we might be able to glean some extra info my dumping the registers at various points. I'd suggest calling LoRa.dumpRegisters(Serial); a 3 points.

additionally PLEASE take the time to properly format (using a code block) the reply as 3 calls to dumpRegisters will be 372 lines long

FLYINGSC0T commented 4 years ago

Hi morganrallen,

Thanks again for your input.

I've attached the output from LoRa.dumpRegisters(Serial); for you to have a look at.

But, an interesting thing - due to incorporating the Serial.println() statements into the program I noticed that the number of resets were greatly reduced. That got me thinking that perhaps they were giving the necessary delays for the LoRa module to "catch up" on the processing. So I changed the values in the calls to vTaskDelay() from 25 to 50. At the same time I put additional yield() calls at certain points in the program. The program has been running now for over 9 hours with 15000+ packets received, 6100+ packets sent and 11 resets which represents 0.07% of the total packets received. I think this is acceptable and I can live with that !!

You might be able to glean more information from the register dump.

BTW I'm not using interrupts.

If I have any more information than I'll post the results.

Regards.

Register Dump.txt

j45p41 commented 3 years ago

Hi, I know this topic is quite old. Did you ever find the solution?

FLYINGSC0T commented 3 years ago

Hi j45p41. It's been some time since I worked on that project as I've been busy with other projects. From memory the problem was solved but I'm not 100% certain. I think it was the case to use the default pins for the LoRa module otherwise there was an interaction. If GPIO's were assigned other than the default ones then the problem occurred. I would have to look at the code to verify what I actually did. What are you actually trying to achieve?

j45p41 commented 3 years ago

Hi j45p41. It's been some time since I worked on that project as I've been busy with other projects. From memory the problem was solved but I'm not 100% certain. I think it was the case to use the default pins for the LoRa module otherwise there was an interaction. If GPIO's were assigned other than the default ones then the problem occurred. I would have to look at the code to verify what I actually did. What are you actually trying to achieve?

Wow, so great that you have responded. You seem to be the only one that has spoken of a solution to an issue that is really making me scratch my head :).

I am setting up a display module based on ESP32-WROOM-32D, RFM95W and ILI9488 display. I already have my hardware on PCB and I am using the default pins for TFT_eSPI and the following pins for LoRa:

#define ss 33
#define rst 12
#define dio0 27

#define MY_CS       33
#define MY_SCLK     25
#define MY_MISO     27
#define MY_MOSI     26

SPIClass spiLoRA(HSPI);
  LoRaClass LoRa2;

setup(){

    LoRa.setSPIFrequency(1E6);

    spiLoRA.begin(MY_SCLK, MY_MISO, MY_MOSI);
    LoRa2.setSPI(spiLoRA);
    LoRa2.setPins(CSN_PIN, rst, dio0);

      while (!LoRa2.begin(433E6)) {
        Serial.println("[LoRa 2] Starting LoRa failed!");
        // LORA2_Status="FAILED";
        delay(1000);
      }

      LoRa2.setSyncWord(0xF3);
      Serial.println("LoRa Initializing OK!");
      tft.println("LoRa Initializing OK!");

}

loop(){
    int packetSize = LoRa2.parsePacket();
    if (packetSize) {
      // received a packet
      Serial.print("Received packet '");
      // tft.print("Received packet '");

      // read packet
      while (LoRa2.available()) {
        String LoRaData = LoRa2.readString();
        Serial.println(LoRaData);

}
yield();
}

This seems to work for about a day with about 20 packets an hour being exchanged but then freezes. I have not gone for sharing the SPI bus because this seems to work ok. It would be great to know how you implemented multi-threading and/or the final working solution.

FLYINGSC0T commented 3 years ago

This is the last code that I have showing the GPIO's I used and how running on dual cores can be set up - hope some of it might help:

// LoRa GPIO setup using the default GPIO's

define SCK_GPIO5 5

define MISO_GPIO19 19

define MOSI_GPIO27 27

define SS_GPIO18 18

define RST_GPIO14 14

define DI0_GPIO26 26

define LoRa_BAND 868E6

/***

/***

/***

// Start LoRa Service if (LoRa.begin(LoRa_BAND)) { // Put LoRa in receive mode LoRa.receive(); Serial.println("started OK. :)"); } else { Serial.println("failed to start. :("); while (1); // HALT }

// Pin the tasks to the appropriate cores // You need to allocate sufficient stack memory that your program needs // I've used 30000 as an example - the same with the TFT task. Here are a couple of links that help to explain: // https://github.com/espressif/arduino-esp32/issues/1884 // https://www.esp32.com/viewtopic.php?t=10629

// <<< IMPORTANT >>> - LoRa core - 2, TFT core - 1 <<< IMPORTANT >>> // xTaskCreatePinnedToCore(LoRa_Task, "LoRa_Task", 30000, NULL, 2, &LoRa_Task1, 1); delay(500); // IMPORTANT - This delay IS needed to allow time to start-up the first task // xTaskCreatePinnedToCore(TFT_Task, "TFT_Task", 20000, NULL, 1, &TFT_Task2, 1); }

/***

/***

/***

j45p41 commented 3 years ago

Thank you very much indeed. I will give it a try.

IoTThinks commented 3 years ago

@FLYINGSC0T So actually, LoRa and TFT will run in the same core 1. However, LoRa task has higher priority than TFT task. I also have some friend has issue with using ESP32-Camera and LoRa at the same time. May be this would help.

// <<< IMPORTANT >>> - LoRa core - 2, TFT core - 1 <<< IMPORTANT >>> // xTaskCreatePinnedToCore(LoRa_Task, "LoRa_Task", 30000, NULL, 2, &LoRa_Task1, 1); delay(500); // IMPORTANT - This delay IS needed to allow time to start-up the first task // xTaskCreatePinnedToCore(TFT_Task, "TFT_Task", 20000, NULL, 1, &TFT_Task2, 1); }

FLYINGSC0T commented 3 years ago

Yes, LoRa and TFT will run on the same core but to achieve multitasking and realise the benefit of both cores you need to setup dual core as mentioned. I personally assigned LoRa to core 2 so that it had 100% of that CPU's time to process just the LoRa commands while at the same time the TFT was running on core 1. In fact, I had the TFT, acquisition of GPS data, Temperature, Pressure and Humidity running on core 1. In the case of priority, for example, if you assign other tasks to the same core then the priority comes into play e.g. if you assigned GPS and TFT to core 1 but gave the GPS priority 1 and TFT priority 5 then the TFT would have the higher priority, i.e. higher the number = higher the priority. This link gives a full explanation of how to use dual cores on the ESP32: https://randomnerdtutorials.com/esp32-dual-core-arduino-ide/ and you will find some other great tutorials on this website. I think I must have changed the code posted earlier for testing purposes but to run on both cores it would be something like:

// <<< IMPORTANT >>> - LoRa core - 2, TFT core - 1 <<< IMPORTANT >>> // xTaskCreatePinnedToCore(LoRa_Task, "LoRa_Task", 30000, NULL, 1, &LoRa_Task1, 2); // LoRa runs on core 2, priority 1 delay(500); // IMPORTANT - This delay IS needed to allow time to start-up the first task // xTaskCreatePinnedToCore(TFT_Task, "TFT_Task", 20000, NULL, 1, &TFT_Task2, 1); // TFT runs on core 1, priority 1

Sorry if I may have mislead you - I forgot which parameter was the core and the one for the priority !!

As an aside, do you use the sprites that are available in Bodmer's TFT_eSPI library ? Well worth looking at and implementing if you haven't already done so. The screen redraws are very fast and avoids any flicker. I now use sprites all of the time.

Regards.

j45p41 commented 3 years ago

Excellent. Thanks for the additional info. I tried it last night on my current pinout setup but I am going back to the breadboard and use common connections, as you pointed and will let you know how it went.

I am actually using lvgl, which sits on top of Bodmer excellent library. https://lvgl.io, https://www.youtube.com/watch?v=FYhmi6MamRs&ab_channel=LVGL

FLYINGSC0T commented 3 years ago

That's great and I look forward to hear how you get on. I hadn't come across LVGL before but it looks very interesting - thank you for sharing. If you are interested in sharing ideas, code etc. and continuing this discussion here is my email address: ga-mecatronics(AT)outlook.com Maybe better to do that rather than "loading up" github as the topic seems to be moving away from LoRa!!

Ddh012345dhD commented 2 years ago

Hi j45p41. It's been some time since I worked on that project as I've been busy with other projects. From memory the problem was solved but I'm not 100% certain. I think it was the case to use the default pins for the LoRa module otherwise there was an interaction. If GPIO's were assigned other than the default ones then the problem occurred. I would have to look at the code to verify what I actually did. What are you actually trying to achieve?

Wow, so great that you have responded. You seem to be the only one that has spoken of a solution to an issue that is really making me scratch my head :).

I am setting up a display module based on ESP32-WROOM-32D, RFM95W and ILI9488 display. I already have my hardware on PCB and I am using the default pins for TFT_eSPI and the following pins for LoRa:

#define ss 33
#define rst 12
#define dio0 27

#define MY_CS       33
#define MY_SCLK     25
#define MY_MISO     27
#define MY_MOSI     26

SPIClass spiLoRA(HSPI);
  LoRaClass LoRa2;

setup(){

    LoRa.setSPIFrequency(1E6);

    spiLoRA.begin(MY_SCLK, MY_MISO, MY_MOSI);
    LoRa2.setSPI(spiLoRA);
    LoRa2.setPins(CSN_PIN, rst, dio0);

      while (!LoRa2.begin(433E6)) {
        Serial.println("[LoRa 2] Starting LoRa failed!");
        // LORA2_Status="FAILED";
        delay(1000);
      }

      LoRa2.setSyncWord(0xF3);
      Serial.println("LoRa Initializing OK!");
      tft.println("LoRa Initializing OK!");

}

loop(){
    int packetSize = LoRa2.parsePacket();
    if (packetSize) {
      // received a packet
      Serial.print("Received packet '");
      // tft.print("Received packet '");

      // read packet
      while (LoRa2.available()) {
        String LoRaData = LoRa2.readString();
        Serial.println(LoRaData);

}
yield();
}

This seems to work for about a day with about 20 packets an hour being exchanged but then freezes. I have not gone for sharing the SPI bus because this seems to work ok. It would be great to know how you implemented multi-threading and/or the final working solution.

Hiu @j45p41 i want to use LoRaDuplexcallback function but LoRa2.receive() function mostly doesn't work