ESP32 with rfm69 Module and tft Display

Hi Guys,
For weeks I would like to use my ESP32 (38Pins) with the rfm69 module (radiohead library) and the ftf Display (driver ILI9341).
Unfortunately, I can not communicate with both of them. Individually it works.

#include <Arduino.h>

//http://www.airspayce.com/mikem/arduino/RadioHead/classRH__RF69.html


/* ESP32                        RFM69W
GND--------------------------GND   (ground in)
VIN--------------------------3.3V  (3.3V in)
interrupt D0 pin GPIO27-------DIO0  (interrupt request out)
SS pin GPIO26----------------NSS   (chip select in)
SCK SPI pin GPIO18-----------SCK   (SPI clock in)
MOSI SPI pin GPIO23----------MOSI  (SPI Data in)
MISO SPI pin GPIO19----------MISO  (SPI Data out) */


// rf69_reliable_datagram_server.pde
// -*- mode: C++ -*-
// Example sketch showing how to create a simple addressed, reliable messaging server
// with the RHReliableDatagram class, using the RH_RF69 driver to control a RF69 radio.
// It is designed to work with the other example rf69_reliable_datagram_client
// Tested on Moteino with RFM69 http://lowpowerlab.com/moteino/
// Tested on miniWireless with RFM69 www.anarduino.com/miniwireless
// Tested on Teensy 3.1 with RF69 on PJRC breakout board
#include <RHReliableDatagram.h>
#include <RH_RF69.h>
#include <SPI.h>
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#define CLIENT_ADDRESS 1
#define SERVER_ADDRESS 2

#define _cs 15
#define _dc 2
#define _mosi 23
#define _sclk 18
#define _rst 4
#define _miso     //not connected

// Use hardware SPI
Adafruit_ILI9341 tft = Adafruit_ILI9341(_cs, _dc, _rst);


// Singleton instance of the radio driver
//RH_RF69 driver;

// Slave Select is pin 26, interrupt is Pin 27
RH_RF69 driver(26, 27);       // http://www.airspayce.com/mikem/arduino/RadioHead/classRH__RF69.html

//RH_RF69 driver(15, 16); // For RF69 on PJRC breakout board with Teensy 3.1
//RH_RF69 rf69(4, 2); // For MoteinoMEGA https://lowpowerlab.com/shop/moteinomega
//RH_RF69 driver(8, 7); // Adafruit Feather 32u4
// Class to manage message delivery and receipt, using the driver declared above
RHReliableDatagram manager(driver, SERVER_ADDRESS);



void setup() 
{
  Serial.begin(9600);
  Serial.println("ILI9343 Test");

  tft.begin();
  tft.setRotation(3);tft.fillScreen(ILI9341_BLACK); tft.setTextSize(3);tft.println("Starting...");delay(1000);
  tft.fillScreen(ILI9341_BLACK);

  while (!Serial) 
    ;
  if (!manager.init())
    Serial.println("init failed");
    // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM (for low power module)
  // No encryption
  if (!driver.setFrequency(868.0))
    Serial.println("setFrequency failed");
  // If you are using a high power RF69 eg RFM69HW, you *must* set a Tx power with the
  // ishighpowermodule flag set like this:
  driver.setTxPower(14, true);
}
uint8_t data[] = "And hello back to you";
// Dont put this on the stack:
uint8_t buf[RH_RF69_MAX_MESSAGE_LEN];


void loop()
{
  if (manager.available())
  {
    // Wait for a message addressed to us from the client
    uint8_t len = sizeof(buf);
    uint8_t from;
    if (manager.recvfromAck(buf, &len, &from))
    {
      Serial.print("got request from : 0x");
      Serial.print(from, HEX);
      Serial.print(": ");
      Serial.println((char*)buf);
      driver.printBuffer("Got:", buf, len);
     

      // Send a reply back to the originator client
      if (!manager.sendtoWait(data, sizeof(data), from))
        Serial.println("sendtoWait failed");

    }
  }
   //tft.setRotation(1);tft.fillScreen(ILI9341_RED); tft.setTextSize(3);tft.println("Test123...");}

When I uncomment

//tft.setRotation(1);tft.fillScreen(ILI9341_RED); tft.setTextSize(3);tft.println("Test123...");

I get this error:

Guru Meditation Error: Core 0 panic’ed (Interrupt wdt timeout on CPU0)
Core 0 register dump:
PC : 0x4008643b PS : 0x00060034 A0 : 0x80086c48 A1 : 0x3ffbe140
A2 : 0x3ffbec34 A3 : 0x0000cdcd A4 : 0xb33fffff A5 : 0x00000001
A6 : 0x00060021 A7 : 0x0000abab A8 : 0x0000cdcd A9 : 0x3ffbe140
A10 : 0x00000003 A11 : 0x00060023 A12 : 0x00060021 A13 : 0x00000020
A14 : 0x00000020 A15 : 0x00000000 SAR : 0x0000001b EXCCAUSE: 0x00000005
EXCVADDR: 0x00000000 LBEG : 0x00000000 LEND : 0x00000000 LCOUNT : 0x00000000
Core 0 was running in ISR context:
EPC1 : 0x400ec436 EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x4008643b

Backtrace: 0x4008643b:0x3ffbe140 0x40086c45:0x3ffbe170 0x40087c43:0x3ffbe190 0x40087919:0x3ffbe1b0 0x4008166e:0x3ffbe1c0 0x400ec433:0x3ffbbff0 0x400d675f:0x3ffbc010 0x40086

Could anyone help me, please?
Or does someone have an alternative without changing the radiohead library?
Thanks!!

I have experienced many Guru Meditation errors when using Adafruit libraries.

The ESP32 has 2 SPI buss's The SPI buses's are HSPI and VSPI. From the pin numbers you are using you are trying to use the VSPI buss.

You will want to include: #include "SPI.h" //This inclusion configures the peripherals in the ESP system. and than you'll want to declare the bussSPIClass SPI1(VSPI); From that point on you can then use the buss like soMPU9250FIFO IMU( SPI1, 15);.

Still Adafruits libraries tend to give Guru meditation error. That

EXCVADDR: 0x00000000

is all 0's https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/fatal-errors.html:

If this address is zero, it usually means that application attempted to dereference a NULL pointer

. You can either find a new tft library that will work, fix the Adafruit library or write your own SPI/device routines.

Hi Idahowalker,
Sorry for the late reply.
Thank you for your fast detailed information.
I’ll try to implement it in my program code in the near future (when I have more freetime…).
Thanks a lot!

Hello Idahowalker,
now I have more time for my hobby 8)
I trieded your inputs in my code but I do no success…
This is my code:

#include <Arduino.h>

//http://www.airspayce.com/mikem/arduino/RadioHead/classRH__RF69.html


/* ESP32                        RFM69W
GND--------------------------GND   (ground in)
VIN--------------------------3.3V  (3.3V in)
interrupt D0 pin GPIO27-------DIO0  (interrupt request out)
SS pin GPIO26----------------NSS   (chip select in)
SCK SPI pin GPIO18-----------SCK   (SPI clock in)
MOSI SPI pin GPIO23----------MOSI  (SPI Data in)
MISO SPI pin GPIO19----------MISO  (SPI Data out) */


// rf69_reliable_datagram_server.pde
// -*- mode: C++ -*-
// Example sketch showing how to create a simple addressed, reliable messaging server
// with the RHReliableDatagram class, using the RH_RF69 driver to control a RF69 radio.
// It is designed to work with the other example rf69_reliable_datagram_client
// Tested on Moteino with RFM69 http://lowpowerlab.com/moteino/
// Tested on miniWireless with RFM69 www.anarduino.com/miniwireless
// Tested on Teensy 3.1 with RF69 on PJRC breakout board
#include <RHReliableDatagram.h>
#include <RH_RF69.h>
#include "SPI.h"    //This inclusion configures the peripherals in the ESP system.
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#define CLIENT_ADDRESS 1
#define SERVER_ADDRESS 2



#define _cs   17  // goes to TFT CS
#define _dc   16  // goes to TFT DC
#define _mosi 23  // goes to TFT MOSI
#define _sclk 18  // goes to TFT SCK/CLK
#define _rst 5    // goes to TFT RESET
// #define _miso     // Not connected
//       3.3V     // Goes to TFT LED  
//       5v       // Goes to TFT Vcc
//       Gnd      // Goes to TFT Gnd   

//SPIClass SPI1(VSPI);      //declare the buss HSPI or VSPI   ?????????????
//MPU9250FIFO IMU( SPI1, 15);   //use the buss ????????????????????

/* The default pins for SPI on the ESP32.
If you use HSPI and you receive reboots or Guru Meditation errors, 
then your SPI device is sending out information during the boot process. 
GPIO13 cannot change states during the boot process. If that the case use VSPI.

HSPI
MOSI = GPIO13
MISO = GPIO12
CLK = GPIO14
CS/SS = GPIO15

VSPI
MOSI = GPIO23
MISO = GPIO19
CLK/SCK = GPIO18
CS/SS = GPIO5  */

// Use hardware SPI
Adafruit_ILI9341 tft = Adafruit_ILI9341(_cs, _dc, _rst);


// If using software SPI change pins as desired
//Adafruit_ILI9341 tft = Adafruit_ILI9341(_cs, _dc, _mosi, _sclk, _rst);


// Singleton instance of the radio driver
//RH_RF69 driver;

// Slave Select is pin 26, interrupt is Pin 27
RH_RF69 driver(26, 27);       // http://www.airspayce.com/mikem/arduino/RadioHead/classRH__RF69.html

//RH_RF69 driver(15, 16); // For RF69 on PJRC breakout board with Teensy 3.1
//RH_RF69 rf69(4, 2); // For MoteinoMEGA https://lowpowerlab.com/shop/moteinomega
//RH_RF69 driver(8, 7); // Adafruit Feather 32u4
// Class to manage message delivery and receipt, using the driver declared above
RHReliableDatagram manager(driver, SERVER_ADDRESS);



void setup() 
{
  Serial.begin(115200);
  Serial.println("ILI9343 Test");

  tft.begin();
  tft.setRotation(3);tft.fillScreen(ILI9341_BLACK); tft.setTextSize(3);tft.println("Starting...");delay(1000);
  tft.fillScreen(ILI9341_BLACK);

  // read diagnostics (optional but can help debug problems)
  uint8_t x = tft.readcommand8(ILI9341_RDMODE);
  Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDMADCTL);
  Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDPIXFMT);
  Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDIMGFMT);
  Serial.print("Image Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDSELFDIAG);
  Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX); 
  delay(10);

  while (!Serial) 
    ;
  if (!manager.init())
    Serial.println("init failed");
    // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM (for low power module)
  // No encryption
  if (!driver.setFrequency(868.0))
    Serial.println("setFrequency failed");
  // If you are using a high power RF69 eg RFM69HW, you *must* set a Tx power with the
  // ishighpowermodule flag set like this:
  driver.setTxPower(14, true);
} 

uint8_t data[] = "And hello back to you";
// Dont put this on the stack:
uint8_t buf[RH_RF69_MAX_MESSAGE_LEN];


void loop()
{
  if (manager.available())
  {
    // Wait for a message addressed to us from the client
    uint8_t len = sizeof(buf);
    uint8_t from;
    if (manager.recvfromAck(buf, &len, &from))
    {
      Serial.print("got request from : 0x");
      Serial.print(from, HEX);
      Serial.print(": ");
      Serial.println((char*)buf);
      driver.printBuffer("Got:", buf, len);
     

      // Send a reply back to the originator client
      if (!manager.sendtoWait(data, sizeof(data), from))
        Serial.println("sendtoWait failed");

    }
  }
  tft.setRotation(1);tft.fillScreen(ILI9341_RED); tft.setTextSize(3);tft.setCursor (10, 10); tft.print("Test123...");
  
}

My esp32 reboot constantly… :confused:
What I’m doing wrong? :frowning:
Someone know a library a tft library (driver ili9341) that will work?
I’m a beginner and I dont´t know how I fix the Adafruit library and how I have to write your own SPI/device routines…
With your help I want to make it and expand my knowledge.
Thanks for any help in advance!!!

Good morning, does anybody have an idea? :confused:

i suspect its the rfm69 interrupt causing spi bus contention.

potential solutions :- 1. use the other spi bus for one of your devices 2. modify tft lib to disable interrupts when its accessing spi bus 3. poll the rfm69 for data ready rather than use interrupts

Thank you racpi. I will try your potential solutions:-)

And, learn how to use the ESP32 SPI API

The SPI master driver governs communications of Hosts with Devices. The driver supports the following features:

Multi-threaded environments Transparent handling of DMA transfers while reading and writing data Automatic time-division multiplexing of data coming from different Devices on the same signal bus

: https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/spi_master.html.

The ESP32 SPI API works really well with the ESP32 and SPI devices. Though it does mean you will be writing your own libraries.

Hay Idahowalker,
thank you for your good input.
Unfortunately I’m not an programmer expert.
Maybe do you have some documents or example how i have to do the esp32 spi api?
I would be very grateful! :slight_smile:
Thank you.

Here is some code that I use to access SPI on the ESP32
The ESP32_SPI_API.h tab

#include <driver/spi_master.h>
#include "sdkconfig.h"
#include "esp_system.h" //This inclusion configures the peripherals in the ESP system.
////////////////////////////////////
 uint8_t GetLowBits();
 int8_t GetHighBits();
 int fReadSPIdata16bits( spi_device_handle_t &h, int address );
 int fWriteSPIdata8bits( spi_device_handle_t &h, int address, int sendData );
 int fInitializeSPI_Devices( spi_device_handle_t &h, int csPin);
int fInitializeSPI_Channel( int spiCLK, int spiMOSI, int spiMISO, spi_host_device_t SPI_Host, bool EnableDMA);

The cpp tab

#include "ESP32_SPI_API.h"
/////////////////////////////
///////////////////////////
uint8_t txData[2] = { };
int8_t rxData[25] = { };
uint8_t low;
int8_t high;
//////
//////////////////////////////////
uint8_t GetLowBits()
{
  return low;
}
int8_t GetHighBits()
{
  return high;
}
////////////////////////////////////////
int fInitializeSPI_Channel( int spiCLK, int spiMOSI, int spiMISO, spi_host_device_t SPI_Host, bool EnableDMA)
{
  esp_err_t intError;
  spi_bus_config_t bus_config = { };
  bus_config.sclk_io_num = spiCLK; // CLK
  bus_config.mosi_io_num = spiMOSI; // MOSI
  bus_config.miso_io_num = spiMISO; // MISO
  bus_config.quadwp_io_num = -1; // Not used
  bus_config.quadhd_io_num = -1; // Not used
  intError = spi_bus_initialize( HSPI_HOST, &bus_config, EnableDMA) ;
  return intError;
}
//////
int fInitializeSPI_Devices( spi_device_handle_t &h, int csPin)
{
  esp_err_t intError;
  spi_device_interface_config_t dev_config = { };  // initializes all field to 0
  dev_config.address_bits     = 0;
  dev_config.command_bits     = 0;
  dev_config.dummy_bits       = 0;
  dev_config.mode             = 3;
  dev_config.duty_cycle_pos   = 0;
  dev_config.cs_ena_posttrans = 0;
  dev_config.cs_ena_pretrans  = 0;
  dev_config.clock_speed_hz   = 7000000;
  dev_config.spics_io_num     = csPin;
  dev_config.flags            = 0;
  dev_config.queue_size       = 1;
  dev_config.pre_cb           = NULL;
  dev_config.post_cb          = NULL;
  spi_bus_add_device(HSPI_HOST, &dev_config, &h);
} // void fInitializeSPI_Devices()
///////////////////////////////////////////////////////////////
int fReadSPIdata16bits( spi_device_handle_t &h, int _address )
{
  uint8_t address = _address;
    esp_err_t intError = 0;
    low=0; high=0;
    spi_transaction_t trans_desc;
    trans_desc = { };
    trans_desc.addr =  0;
    trans_desc.cmd = 0;
    trans_desc.flags = 0;
    trans_desc.length = (8 * 3); // total data bits
    trans_desc.tx_buffer = txData;
    trans_desc.rxlength = 8 * 2 ; // Number of bits NOT number of bytes
    trans_desc.rx_buffer = rxData;
    txData[0] = address | 0x80;
    intError = spi_device_transmit( h, &trans_desc);
    low = rxData[0]; high = rxData[1];
   return intError;
} // void fSendSPI( uint8_t count, uint8_t address, uint8_t DataToSend)
////
int fWriteSPIdata8bits( spi_device_handle_t &h, int _address, int _sendData )
{
  uint8_t address =  _address;
  int8_t sendData = _sendData;
  esp_err_t intError;
  spi_transaction_t trans_desc;
  trans_desc = { };
  trans_desc.addr =  0;
  trans_desc.cmd = 0;
  trans_desc.flags = 0;
  trans_desc.length = (8 * 2); // total data bits
  trans_desc.tx_buffer = txData;
  trans_desc.rxlength = 0 ; // Number of bits NOT number of bytes
  trans_desc.rx_buffer = NULL;
  txData[0] = address  & 0x7F;
  txData[1] = sendData;
  intError = spi_device_transmit( h, &trans_desc);
  return intError;
} // void fWriteSPIdata8bits(  spi_device_handle_t &h, uint8_t address, uint8_t sendData )

Wow 8) , thank you so much Idahowalker!!! I will try to understand and to use your example code.