Combining Waveshare 2.9" e-paper display with UWB Module (DW1000) on ESP32 WROOM

Hi, I'm new here so let me know if I forgot/can improve something. I really hope someone can help me here.

Situation:
I am currently building a Project that tries to combine the Ultra Wideband DW1000 Chip ranging capabilities with an E-Paper Display from Waveshare.
The DW1000 was pre bundled onto an ESP32-WROOM (bought from makerfabs.com).

Problem:
Over the last couple of weeks I worked out the individual aspects of the prototype with libraries I found online. Now, individually everything works fine. Like I can flash the ESPs with the ranging sketches and it will print out the values fine to the Serial Monitor. Just like that, the E-Paper Display also works great on its own. The Problem Im currently stuck on is combining everything into one working sketch.

AFAIK both modules use SPI to communicate and I think that might be the main direction I have to search in.

Main Libraries used:

  • DW1000Ranging & DW1000 (modified ones for better anchor calibration)
  • GxEPD

The DW1000 comes pre soldered to the board, but from the example codes I assume it uses:

#define SPI_SCK 18
#define SPI_MISO 19
#define SPI_MOSI 23

#define UWB_RST 27 // reset pin
#define UWB_IRQ 34 // irq pin
#define UWB_SS 4   // spi select pin

... for SPI communication.

The E-Paper Display inits SPI with:

GxIO_Class io(SPI, /*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16); // arbitrary selection of 17, 16
GxEPD_Class display(io, /*RST=*/ 16, /*BUSY=*/ 4); // arbitrary selection of (16), 4

... I think.

Full (messy) Sketch:

//Epaper
// mapping suggestion for ESP32, e.g. LOLIN32, see .../variants/.../pins_arduino.h for your board
// NOTE: there are variants with different pins for SPI ! CHECK SPI PINS OF YOUR BOARD
// BUSY -> 4, RST -> 16, DC -> 17, CS -> SS(5), CLK -> SCK(18), DIN -> MOSI(23), GND -> GND, 3.3V -> 3.3V

// include library, include base class, make path known
#include <GxEPD.h>

// select the display class to use, only one
//#include <GxGDEP015OC1/GxGDEP015OC1.h>    // 1.54" b/w
//#include <GxGDEH0154D67/GxGDEH0154D67.h>  // 1.54" b/w
#include <GxGDEM029T94/GxGDEM029T94.h>      // 2.9" b/w
//#include <GxGDEW042T2/GxGDEW042T2.h>      // 4.2" b/w

#include GxEPD_BitmapExamples

// FreeFonts from Adafruit_GFX
#include <Fonts/FreeMonoBold9pt7b.h>
#include <Fonts/FreeMonoBold12pt7b.h>
#include <Fonts/FreeMonoBold18pt7b.h>
#include <Fonts/FreeMonoBold24pt7b.h>
#include <Fonts/Tiny3x3a2pt7b.h>

#include <GxIO/GxIO_SPI/GxIO_SPI.h>
#include <GxIO/GxIO.h>

#if defined(ESP32)

// for SPI pin definitions see e.g.:
// C:\Users\xxx\Documents\Arduino\hardware\espressif\esp32\variants\lolin32\pins_arduino.h

GxIO_Class io(SPI, /*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16); // arbitrary selection of 17, 16
GxEPD_Class display(io, /*RST=*/ 16, /*BUSY=*/ 4); // arbitrary selection of (16), 4

#endif defined(ARDUINO_ARCH_SAMD)

//UWB Libraries
#include <SPI.h>
#include "DW1000Ranging.h"
#include "DW1000.h"

#define TAG_ADDR "7D:00:22:EA:82:60:3B:9C"

// #define DEBUG

#define SPI_SCK 18
#define SPI_MISO 19
#define SPI_MOSI 23

#define UWB_RST 27 // reset pin
#define UWB_IRQ 34 // irq pin
#define UWB_SS 4   // spi select pin

//Datenstruktur für Anchors:
typedef struct _link
{
  uint16_t anchor_addr;
  float range;
  float dbm;
  struct _link *next;
} _link;

_link *uwb_data;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println();
  Serial.println("setup");

  SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
  DW1000Ranging.initCommunication(UWB_RST, UWB_SS, UWB_IRQ); //Reset, CS, IRQ pin !!!!!!!!!!!!!!!!!!!!!!!!!!! if this is commented out, e-paper works
  //define the sketch as anchor. It will be great to dynamically change the type of module
  DW1000Ranging.attachNewRange(newRange);
  DW1000Ranging.attachNewDevice(newDevice);
  DW1000Ranging.attachInactiveDevice(inactiveDevice);
  //Enable the filter to smooth the distance
  //DW1000Ranging.useRangeFilter(true);

  //we start the module as a tag
  //DW1000Ranging.startAsTag(TAG_ADDR, DW1000.MODE_LONGDATA_RANGE_LOWPOWER);
  DW1000Ranging.startAsTag(TAG_ADDR, DW1000.MODE_SHORTDATA_FAST_LOWPOWER);
  //DW1000Ranging.startAsTag(TAG_ADDR, DW1000.MODE_LONGDATA_FAST_LOWPOWER);
  // DW1000Ranging.startAsTag(TAG_ADDR, DW1000.MODE_SHORTDATA_FAST_ACCURACY);
  // DW1000Ranging.startAsTag(TAG_ADDR, DW1000.MODE_LONGDATA_FAST_ACCURACY);
  // DW1000Ranging.startAsTag(TAG_ADDR, DW1000.MODE_LONGDATA_RANGE_ACCURACY);
  uwb_data = init__link();

  display.init(115200); // enable diagnostic output on Serial !!!!!!!!!!!!!!!!!!!!!!!! if this is commented out, UWB Ranging works --- it throws Guru Meditation Errors as long as line 87 (inside GxGDEM...) , which modifies the pinmode of _busy, isnt commented out
  display.setRotation(3);
  Serial.println("setup done");
}

long int runtime = 0;

void loop() {
  // put your main code here, to run repeatedly:
  DW1000Ranging.loop();
  if ((millis() - runtime) > 6000)
  {
    //display_uwb(uwb_data);
    //updateScreen();
    Serial.println("60sec update triggered");
    runtime = millis();
    showGUI();
  }
}

void showGUI() {
  //display.fillScreen(GxEPD_WHITE);
  //display.update();
  display.setTextColor(GxEPD_BLACK);
  display.setFont(&FreeMonoBold9pt7b);
  display.setCursor(25, 25);
  display.print("Short address: ");
  //  Serial.println(currentNearestName);
  display.setCursor(5, 55);
  display.setFont(NULL);
  display.println("Informationen zum Kunstwerk");
  //  display.println(currentNearestDistance);

  display.setCursor(80, 118);
  display.setTextColor(GxEPD_WHITE, GxEPD_BLACK);
  display.println("Nicht Gespeichert");
  display.setCursor(2, 118);
  display.println("Kurz(+)");
  display.setCursor(240, 118);
  display.println("Lang(-)");
  display.fillRect(0, 40, 296, 2, GxEPD_BLACK);
  display.fillRect(0, 110, 296, 2, GxEPD_BLACK);
  display.update();
  Serial.println("inGUI");
}

void newRange()
{
  Serial.print("from: ");
  Serial.print(DW1000Ranging.getDistantDevice()->getShortAddress(), HEX);
  Serial.print("\t Range: ");
  Serial.print(DW1000Ranging.getDistantDevice()->getRange());
  Serial.print(" m");
  Serial.print("\t RX power: ");
  Serial.print(DW1000Ranging.getDistantDevice()->getRXPower());
  Serial.println(" dBm");

  fresh__link(uwb_data, DW1000Ranging.getDistantDevice()->getShortAddress(), DW1000Ranging.getDistantDevice()->getRange(), DW1000Ranging.getDistantDevice()->getRXPower());
  //print__link(uwb_data);
}

void newDevice(DW1000Device *device)
{
  Serial.print("ranging init; 1 device added ! -> ");
  Serial.print(" short:");
  Serial.println(device->getShortAddress(), HEX);

  add__link(uwb_data, device->getShortAddress());
}

void inactiveDevice(DW1000Device *device)
{
  Serial.print("delete inactive device: ");
  Serial.println(device->getShortAddress(), HEX);

  delete__link(uwb_data, device->getShortAddress());
}
//Data _link

_link *init__link()
{
#ifdef DEBUG
  Serial.println("init__link");
#endif
  _link *p = (_link *)malloc(sizeof(_link));
  p->next = NULL;
  p->anchor_addr = 0;
  p->range = 0.0;

  return p;
}

void add__link(_link *p, uint16_t addr)
{
#ifdef DEBUG
  Serial.println("add__link");
#endif
  _link *temp = p;
  //Find _link end
  while (temp->next != NULL)
  {
    temp = temp->next;
  }

  Serial.println("add__link:find _link end");
  //Create a anchor
  _link *a = (_link *)malloc(sizeof(_link));
  a->anchor_addr = addr;
  a->range = 0.0;
  a->dbm = 0.0;
  a->next = NULL;

  //Add anchor to end of _link
  temp->next = a;

  return;
}

_link *find__link(_link *p, uint16_t addr)
{
#ifdef DEBUG
  Serial.println("find__link");
#endif
  if (addr == 0)
  {
    Serial.println("find__link:Input addr is 0");
    return NULL;
  }

  if (p->next == NULL)
  {
    Serial.println("find__link:_link is empty");
    return NULL;
  }

  _link *temp = p;
  //Find target _link or _link end
  while (temp->next != NULL)
  {
    temp = temp->next;
    if (temp->anchor_addr == addr)
    {
      // Serial.println("find__link:Find addr");
      return temp;
    }
  }

  Serial.println("find__link:Can't find addr");
  return NULL;
}

void fresh__link(_link *p, uint16_t addr, float range, float dbm)
{
#ifdef DEBUG
  Serial.println("fresh__link");
#endif
  _link *temp = find__link(p, addr);
  if (temp != NULL)
  {

    temp->range = range;
    temp->dbm = dbm;
    return;
  }
  else
  {
    Serial.println("fresh__link:Fresh fail");
    return;
  }
}

void print__link(_link *p)
{
#ifdef DEBUG
  Serial.println("print__link");
#endif
  _link *temp = p;

  while (temp->next != NULL)
  {
    //Serial.println("Dev %d:%d m", temp->next->anchor_addr, temp->next->range);
    Serial.println(temp->next->anchor_addr, HEX);
    Serial.println(temp->next->range);
    Serial.println(temp->next->dbm);
    temp = temp->next;
  }

  return;
}

void delete__link(_link *p, uint16_t addr)
{
#ifdef DEBUG
  Serial.println("delete__link");
#endif
  if (addr == 0)
    return;

  _link *temp = p;
  while (temp->next != NULL)
  {
    if (temp->next->anchor_addr == addr)
    {
      _link *del = temp->next;
      temp->next = del->next;
      free(del);
      return;
    }
    temp = temp->next;
  }
  return;
}

As I had no idea how to properly DEBUG this I experimented with the code in the sketch and corresponding Libraries. So far I observed that when I comment out either

  • DW1000Ranging.initCommunication(UWB_RST, UWB_SS, UWB_IRQ);
    or
  • display.init(115200);
    either of them work individually. Otherwise I get:
Guru Meditation Error: Core  1 panic'ed (Interrupt wdt timeout on CPU1). 

Core  1 register dump:
PC      : 0x4008a716  PS      : 0x00060d35  A0      : 0x8008996e  A1      : 0x3ffbedbc  
A2      : 0x3ffb7f54  A3      : 0x3ffb8890  A4      : 0x00000004  A5      : 0x00060d23  
A6      : 0x00060d23  A7      : 0x00000001  A8      : 0x3ffb8890  A9      : 0x00000018  
A10     : 0x3ffb8890  A11     : 0x00000018  A12     : 0x3ffc3414  A13     : 0x00060d23  
A14     : 0x007bef68  A15     : 0x003fffff  SAR     : 0x0000001e  EXCCAUSE: 0x00000006  
EXCVADDR: 0x00000000  LBEG    : 0x40085e74  LEND    : 0x40085e79  LCOUNT  : 0x00000000  
Core  1 was running in ISR context:
EPC1    : 0x400e16d3  EPC2    : 0x00000000  EPC3    : 0x00000000  EPC4    : 0x00000000


Backtrace:0x4008a713:0x3ffbedbc |<-CORRUPTED


Core  0 register dump:
PC      : 0x4008a893  PS      : 0x00060035  A0      : 0x80089597  A1      : 0x3ffbe8bc  
A2      : 0x3ffbef68  A3      : 0xb33fffff  A4      : 0x0000abab  A5      : 0x00060023  
A6      : 0x00060021  A7      : 0x0000cdcd  A8      : 0x0000abab  A9      : 0xffffffff  
A10     : 0x3ffc3230  A11     : 0x00000000  A12     : 0x3ffc322c  A13     : 0x00000007  
A14     : 0x007bef68  A15     : 0x003fffff  SAR     : 0x0000001a  EXCCAUSE: 0x00000006  
EXCVADDR: 0x00000000  LBEG    : 0x00000000  LEND    : 0x00000000  LCOUNT  : 0x00000000  


Backtrace:0x4008a890:0x3ffbe8bc |<-CORRUPTED




ELF file SHA256: 0000000000000000

Rebooting...

Do I have to change something with the SPI configuration pins? I read mutliple SPI devices can share the same pins except the CS/SS pins. I tried that at one point, I think, but it didnt change the outcome. I only hope the libraries are compatible with each other and I am the problem and not the rest of the code. If someone can help me, give me a general direction or something I might be missing Id really appreciate it!

Does this produce the exception?

void loop() {
  // put your main code here, to run repeatedly:
  //DW1000Ranging.loop();
  //if ((millis() - runtime) > 6000)
  //{
   // //display_uwb(uwb_data);
   // //updateScreen();
   // Serial.println("60sec update triggered");
   // runtime = millis();
    //showGUI();
  //}
}

Does this produce the exception?

void loop() {
  // put your main code here, to run repeatedly:
  DW1000Ranging.loop();
  //if ((millis() - runtime) > 6000)
  //{
   // //display_uwb(uwb_data);
   // //updateScreen();
   // Serial.println("60sec update triggered");
   // runtime = millis();
    //showGUI();
  //}
}

Does this produce the exception?

void loop() {
  // put your main code here, to run repeatedly:
  DW1000Ranging.loop();
  if ((millis() - runtime) > 6000)
  {
   // //display_uwb(uwb_data);
   // //updateScreen();
   // Serial.println("60sec update triggered");
   runtime = millis();
    //showGUI();
  }
}

Does this produce the exception?

void loop() {
  // put your main code here, to run repeatedly:
  DW1000Ranging.loop();
  if ((millis() - runtime) > 6000)
  {
    //display_uwb(uwb_data);
    //updateScreen();
    Serial.println("60sec update triggered");
   runtime = millis();
    //showGUI();
  }
}

Does this produce the exception?

void loop() {
  // put your main code here, to run repeatedly:
  DW1000Ranging.loop();
  if ((millis() - runtime) > 6000)
  {
   // //display_uwb(uwb_data);
   // //updateScreen();
    Serial.println("60sec update triggered");
    runtime = millis();
   showGUI();
  }
}

Which one does not produce the error?

When commenting this out it stops throwing the exceptions. Because theyre so many after another I assume it throws one everytime it tries to do a ranging. I suspects its a PIN assignment issue or something ... maybe communication is messed up because some sort of eg. delays somewhere in a deeper library which throws off communication? Might wanna try to run them on separat cores maybe? Completely wild guesses though. Not sure how to debug this properly...

Contact the author of the library and share the error with them, typically a EXCVADDR of all 0's represents an array going out of bounds.

When you run the uwb thing by itself do you use pin 34?

You mean for something else?
Atleast not in my sketch. No idea about what the used libraries do in the background.
As for the DW1000 chip I suppose its presoldered to those pins. Thats the board: ESP32 UWB(Ultra Wideband) | Makerfabs
Quite new to SPI, I2C etc. communication which makes it even harder for me to see where the issue lies. Thanks for the attempt! I may open an issue on their github maybe they can help as well.

Did you ever solve this? I have the same error with brand new MF UWB ESP32. The code for the Anchor works but the interrupt error crashes the Tag code

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.