todd-herbert / heltec-eink-modules

Third-party Arduino Library for Heltec E-Ink displays
21 stars 4 forks source link

Heltec Lora and eink module no longer working together on Heltec Epaper #15

Open Glenno-H opened 3 months ago

Glenno-H commented 3 months ago

if a "display.update();" is included in the code anywhere, the LoRa side will only receive a packet once, and then never work again.

It was working untill very recently, using previous versions of the Heltec library didnt seem to work.

Heltec ESP32 Dev Boards - 2.0.2 Heltec eink - 4.3.2

#include "LoRaWan_APP.h"
#include "Arduino.h"
#include <heltec-eink-modules.h>
#include "Fonts/FreeSerif9pt7b.h"

// Display Setup
#define PIN_DC      2
#define PIN_CS      4
#define PIN_BUSY    5
LCMEN2R13EFC1 display;       // (Green Tab, V1.1)

// Lora Setup
#define RF_FREQUENCY                                915000000 // Hz
#define TX_OUTPUT_POWER                             14        // dBm
#define LORA_BANDWIDTH                              0         // [0: 125 kHz,
#define LORA_SPREADING_FACTOR                       7         // [SF7..SF12]
#define LORA_CODINGRATE                             1         // [1: 4/5,
#define LORA_PREAMBLE_LENGTH                        8         // Same for Tx and Rx
#define LORA_SYMBOL_TIMEOUT                         0         // Symbols
#define LORA_FIX_LENGTH_PAYLOAD_ON                  false
#define LORA_IQ_INVERSION_ON                        false
#define RX_TIMEOUT_VALUE                            1000
#define BUFFER_SIZE                                 30 // Define the payload size here

char txpacket[BUFFER_SIZE];
char rxpacket[BUFFER_SIZE];

static RadioEvents_t RadioEvents;

int16_t txNumber;

int16_t rssi,rxSize;

bool lora_idle = true;

void setup() {
    Serial.begin(115200);
    Mcu.begin(HELTEC_BOARD,SLOW_CLK_TPYE);

    txNumber=0;
    rssi=0;

    RadioEvents.RxDone = OnRxDone;
    Radio.Init( &RadioEvents );
    Radio.SetChannel( RF_FREQUENCY );
    Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,
                               LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,
                               LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON,
                               0, true, 0, 0, LORA_IQ_INVERSION_ON, true );

    // Eink Display Setup
    // 250 * 122 Res
    display.setBackgroundColor(WHITE);
    display.landscape(); // Go into Landscape mode.
}

void loop()
{
  if(lora_idle)
  {
    lora_idle = false;
    // Serial.println("into RX mode");
    Radio.Rx(0);
  }
  Radio.IrqProcess( );
}

void OnRxDone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr) {
    char str[30];
    memcpy(rxpacket, payload, size);
    rxpacket[size] = '\0';

    Radio.Sleep();
    Serial.printf("\r\nReceived packet: %s, RSSI: %d\r\n", rxpacket, rssi);

    // Debugging: Print before display update
    Serial.println("Before display update");

    // Update the e-ink display with static text
    display.setTextSize(3);
    display.printCenter("TEST"); // Display static text
    display.update();
    delay(100); // Add a delay of 100 milliseconds

    // Debugging: Print after display update
    Serial.println("After display update");

    lora_idle = true;
}

SERIAL OUTPUT

Rebooting... x�� Received packet: 33A3A6A7371D,1572,4072, RSSI: -36 Before display update ESP-ROM:esp32s3-20210327 Build:Mar 27 2021 rst:0x1 (POWERON),boot:0x18 (SPI_FAST_FLASH_BOOT) SPIWP:0xee mode:DIO, clock div:1 load:0x3fce3818,len:0x508 load:0x403c9700,len:0x4 load:0x403c9704,len:0xad0 load:0x403cc700,len:0x29d8 entry 0x403c9880

Received packet: 33A3A6A7371D,1572,4098, RSSI: -36 Before display update After display update E (21343) task_wdt: Task watchdog got triggered. The following tasks/users did not reset the watchdog in time: E (21343) task_wdt: - IDLE0 (CPU 0) E (21343) task_wdt: Tasks currently running: E (21343) task_wdt: CPU 0: loopTask E (21343) task_wdt: CPU 1: IDLE1 E (21343) task_wdt: Aborting. E (21343) task_wdt: Print CPU 0 (current core) backtrace

todd-herbert commented 3 months ago

onRxDone() is an interrupt handler right? My instinct is that the issue might be about running a display update from an interrupt; I think they're meant to be kept as short as possible.

I believe that the code will drop whatever it is doing to run onRxDone. If a previous onRxDone call is still running (display update in progress), that's a recipe for trouble.

I'd try having onRxDone just grab the data, and then have loop() handle any data every time it runs.

todd-herbert commented 3 months ago

It was working untill very recently, using previous versions of the Heltec library didnt seem to work.

I do wonder what could have changed to trigger this issue. Did you update any libraries, or your board package, or anything? Did you only notice when starting a new project?

Glenno-H commented 3 months ago

onRxDone() is an interrupt handler right? My instinct is that the issue might be about running a display update from an interrupt; I think they're meant to be kept as short as possible.

I believe that the code will drop whatever it is doing to run onRxDone. If a previous onRxDone call is still running (display update in progress), that's a recipe for trouble.

I'd try having onRxDone just grab the data, and then have loop() handle any data every time it runs.

Thanks very much for replies!

ok thanks for the suggestion. Im fairly sure it was a Heltec library update that ended up breaking the example code above. I ended up moving away from the heltec lora library anyway, and now use https://github.com/ropg/Heltec_ESP32_LoRa_v3, which seems to incorporate RadioLib.

Weirdly.....the latest eink update (4.4.0) stopped my most recent code from receiving lora, lol. Reverting back to 4.3.2 had it working again mostly......except for updates after recieving lora messages...

todd-herbert commented 3 months ago

I'll have to dig into it and have a play with the two LoRa libraries in the near future. I probably haven't spent as much time testing with that as I should. Let me know if restructuring the keep the display updates out of interrupts is helpful though!

todd-herbert commented 3 months ago

I did some testing with this today. No issues with using RadioLib, but suspiciously, Heltec's LoRa Sender example seems to be having problems: radio freezes on first attempt to transmit.

The fact that I'm seeing similar issues with Heltec's example, even without including the heltec-eink-modules library, makes me suspicious that there is some core issues in their library which needs resolving. I could be wrong about that though.

Personally, I'd be working with RadioLib too. Did you get everything working after the switch?

Glenno-H commented 3 months ago

I did some testing with this today. No issues with using RadioLib, but suspiciously, Heltec's LoRa Sender example seems to be having problems: radio freezes on first attempt to transmit.

The fact that I'm seeing similar issues with Heltec's example, even without including the heltec-eink-modules library, makes me suspicious that there is some core issues in their library which needs resolving. I could be wrong about that though.

Personally, I'd be working with RadioLib too. Did you get everything working after the switch?

Thanks very much for testing all that! I really appreciate it.

Ive taken some time to swtich over to PLatformIO from the Arduino IDE, and am now using a ViewMaster e290, which forces me to use the latest eink versions.

Sadly, Im still struggling to get both the Lora and eink to work together for some reason.

Ive tried all sorts of different methods I could think of, but nothing seems to work.

Heres what I have so far, commenting out the display lines in Setup makes it work fine.

Otherwise I get..

[RadioLib] radio.begin() returned -2 (ERR_CHIP_NOT_FOUND) [RadioLib] Halted

Which feels very similar to the original issue perahps.

#include "Arduino.h"
#include <heltec-eink-modules.h>
#include "Fonts/FreeSans9pt7b.h"
#include "Fonts/FreeSansBold9pt7b.h"

#define HELTEC_POWER_BUTTON
#define HELTEC_NO_DISPLAY_INSTANCE
#define HELTEC_NO_DISPLAY

#include <heltec_unofficial.h>
#define PAUSE               300
#define FREQUENCY           915.0       // for Europe
#define BANDWIDTH           125.0
#define SPREADING_FACTOR    7
#define TRANSMIT_POWER      0

EInkDisplay_VisionMasterE290 display;

void rx();
String rxdata;
volatile bool rxFlag = false;
long counter = 0;
uint64_t last_tx = 0;
uint64_t tx_time;
uint64_t minimum_pause;

void setup() {
  heltec_setup();
  display.landscape();
  display.clear();
  display.setCursor(0, 20);
  display.setFont(&FreeSans9pt7b);
  display.print("Test");

  both.println("Radio init");
  RADIOLIB_OR_HALT(radio.begin());
  // Set the callback function for received packets
  radio.setDio1Action(rx);
  // Set radio parameters
  both.printf("Frequency: %.2f MHz\n", FREQUENCY);
  RADIOLIB_OR_HALT(radio.setFrequency(FREQUENCY));
  both.printf("Bandwidth: %.1f kHz\n", BANDWIDTH);
  RADIOLIB_OR_HALT(radio.setBandwidth(BANDWIDTH));
  both.printf("Spreading Factor: %i\n", SPREADING_FACTOR);
  RADIOLIB_OR_HALT(radio.setSpreadingFactor(SPREADING_FACTOR));
  both.printf("TX power: %i dBm\n", TRANSMIT_POWER);
  RADIOLIB_OR_HALT(radio.setOutputPower(TRANSMIT_POWER));
  // Start receiving
  RADIOLIB_OR_HALT(radio.startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF));
}

void loop() {
  heltec_loop();

    // If a packet was received, display it and the RSSI and SNR
  if (rxFlag) {
    rxFlag = false;
    radio.readData(rxdata);
    if (_radiolib_status == RADIOLIB_ERR_NONE) {
      both.printf("RX [%s]\n", rxdata.c_str());
      both.printf("  RSSI: %.2f dBm\n", radio.getRSSI());
      both.printf("  SNR: %.2f dB\n", radio.getSNR());
    }
    RADIOLIB_OR_HALT(radio.startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF));
  }
}

// Can't do Serial or display things here, takes too much time for the interrupt
void rx() {
  rxFlag = true;
}

and the PlatformIO.ini

[env:vision-master-e290]
platform = espressif32
board = heltec_wifi_lora_32_V3
framework = arduino
monitor_speed = 115200
monitor_filters = esp32_exception_decoder
board_upload.use_1200bps_touch = true
board_build.arduino.lorawan.region = AU915
board_build.arduino.lorawan.class = CLASS_A
build_flags = 
    -D ARDUINO_USB_CDC_ON_BOOT=1
    -D Vision_Master_E290
lib_deps = 
    ropg/Heltec_ESP32_LoRa_v3@^0.9.1
    todd-herbert/heltec-eink-modules@^4.4.0
todd-herbert commented 3 months ago

The ESP32-S3 microcontroller used by the Vision Master and Wireless Paper boards has two SPI busses free for use (FSPI and HSPI). I just took a quick look now at the ropg/Heltec_ESP32_LoRa_v3@^0.9.1 library. By default, it seems to use the HSPI interface for LoRa. I also used HSPI for this display library, as the board schematics suggest to me that Heltec probably intended for LoRa to use FSPI. Seems like the two different libraries are both trying to make use of the HPSI for two different sets of pins, causing the conflict.

It seems like ropg/heltec_esp32_lora_v3 has a config option which allows you to use the FSPI bus instead, which would be worth a try.

In Arduino IDE:

Add #define ARDUINO_heltec_wifi_32_lora_V3 at the very top of your .ino file

In PlatformIO

Modify your platformio.ini file's build flags:

build_flags = 
  -D ARDUINO_USB_CDC_ON_BOOT=1
  -D Vision_Master_E290
  -D ARDUINO_heltec_wifi_32_lora_V3 ; Use FSPI for LoRa

I don't have a LoRaWAN setup here to test with, so my experimenting is with LoRa P2P, but let me know if this change doesn't help, and I'll have a go at debugging your sketch from this side. I can also tidy up my test file and send it as a working example if it helps.

todd-herbert commented 3 months ago

Another thought: how frequently are you receiving LoRa packets? Not really related to the issue, but could be relevant to possible solutions.

Glenno-H commented 3 months ago

The ESP32-S3 microcontroller used by the Vision Master and Wireless Paper boards has two SPI busses free for use (FSPI and HSPI). I just took a quick look now at the ropg/Heltec_ESP32_LoRa_v3@^0.9.1 library. By default, it seems to use the HSPI interface for LoRa. I also used HSPI for this display library, as the board schematics suggest to me that Heltec probably intended for LoRa to use FSPI. Seems like the two different libraries are both trying to make use of the HPSI for two different sets of pins, causing the conflict.

It seems like ropg/heltec_esp32_lora_v3 has a config option which allows you to use the FSPI bus instead, which would be worth a try.

In Arduino IDE:

Add #define ARDUINO_heltec_wifi_32_lora_V3 at the very top of your .ino file

In PlatformIO

Modify your platformio.ini file's build flags:

build_flags = 
  -D ARDUINO_USB_CDC_ON_BOOT=1
  -D Vision_Master_E290
  -D ARDUINO_heltec_wifi_32_lora_V3 ; Use FSPI for LoRa

I don't have a LoRaWAN setup here to test with, so my experimenting is with LoRa P2P, but let me know if this change doesn't help, and I'll have a go at debugging your sketch from this side. I can also tidy up my test file and send it as a working example if it helps.

Thank you so much for your reply and fix ! You are a dead set legend.

Ive got a LOT to learn with all this, and I really appreciate you explaining whats going on, I took this info and ended up switching over to RadioLib proper, everything is working well now.

Glenno-H commented 3 months ago

Another thought: how frequently are you receiving LoRa packets? Not really related to the issue, but could be relevant to possible solutions.

Im receiving every 60 secs.

todd-herbert commented 3 months ago

No problem, good to hear it's working! I'm no expert about any of this either; I'm certainly very inexperienced with LoRa. Figuring it out as I go!

Just for general info, if you're working with the straight RadioLib library, it should theoretically be as simple as:

EInkDisplay_VisionMasterE290 display; SX1262 radio = new Module(PIN_LORA_NSS, PIN_LORA_DIO_1, PIN_LORA_NRST, PIN_LORA_BUSY);

void setup() { radio.begin(); // etc }



___

> Im receiving every 60 secs.

Ahh, shouldn't be an issue then. If you were expecting to receive, say, a packet every second, you would quite likely miss several packets during the ~4 seconds it takes for the display to update; it'd require some more complex handling. 

With a packet every 60 seconds or so though, there's plenty of time for loop() to `readData`, so no risk of missing anything 👍