Using second SPI beside Arduino GFX powered TFT Display

Hi together,
after a long time I found some time to get back to my ESP32.
I'm trying to measure a Temperatur using a MAX31865 and plot it on a 2,8" TFT Display. I'm able to measure the temperatur OR plot something on the display. But when I initilaize the display i'm getting only a constant temperature of 988,79°. This Is my code.Any help would great. Many thanks in advance.


#include <Wire.h> //Arduino Uno; SDA = A4, SCL = A5
#include <SPI.h>
#include <Arduino_GFX_Library.h>

// Pins for SPI bus for the display
#define TFT_CLK 40  //SPI Clock
#define TFT_DA 41   //SPI Data (MOSI)
#define TFT_DC  39   //Data/Command
#define TFT_CS 42    //Chip select
#define TFT_RST 37   //Reset
Arduino_DataBus *bus = new Arduino_ESP32SPI(TFT_DC, TFT_CS,TFT_CLK, TFT_DA);
Arduino_GFX *tft = new Arduino_ILI9341(bus, TFT_RST, 0, false);

// define SPI for MAX31865
#define TEMP_CS 10
#define TEMP_MOSI 11
#define TEMP_CLK 12
#define TEMP_MISO 13
#define VSPI FSPI
SPIClass *TempSPI = NULL;
//SPIClass TempSPI = SPIClass(VSPI);


//Variables for the PT100 boards
double resistance;
uint8_t reg1, reg2; //reg1 holds MSB, reg2 holds LSB for RTD
uint16_t fullreg; //fullreg holds the combined reg1 and reg2
double temperature;
//Variables and parameters for the R - T conversion
double Z1, Z2, Z3, Z4, Rt;
double RTDa = 3.9083e-3;
double RTDb = -5.775e-7;
double rpoly = 0;

//--Display---------------------------------------------



const int chipSelectPin = TEMP_CS;

void setup()
{
  TempSPI = new SPIClass(VSPI);
  TempSPI->begin(TEMP_CLK, TEMP_MISO, TEMP_MOSI, TEMP_CS);
  Serial.begin(115200); //Start serial

  pinMode(chipSelectPin, OUTPUT); //because CS is manually switched  

  tft->begin();
}

void loop()
{
  readRegister();
  convertToTemperature();
  delay(1000);
}



void convertToTemperature()
{
  Rt = resistance;
  Rt /= 32768;
  Rt *= 430; //This is now the real resistance in Ohms

  Z1 = -RTDa;
  Z2 = RTDa * RTDa - (4 * RTDb);
  Z3 = (4 * RTDb) / 100;
  Z4 = 2 * RTDb;

  temperature = Z2 + (Z3 * Rt);
  temperature = (sqrt(temperature) + Z1) / Z4;

  if (temperature >= 0)
  {
    Serial.print("Temperature: ");
    Serial.println(temperature); //Temperature in Celsius degrees
    return; //exit
  }
  else
  {
    Rt /= 100;
    Rt *= 100; // normalize to 100 ohm

    rpoly = Rt;

    temperature = -242.02;
    temperature += 2.2228 * rpoly;
    rpoly *= Rt; // square
    temperature += 2.5859e-3 * rpoly;
    rpoly *= Rt; // ^3
    temperature -= 4.8260e-6 * rpoly;
    rpoly *= Rt; // ^4
    temperature -= 2.8183e-8 * rpoly;
    rpoly *= Rt; // ^5
    temperature += 1.5243e-10 * rpoly;

    Serial.print("Temperature: ");
    Serial.println(temperature); //Temperature in Celsius degrees
  }
  //Note: all formulas can be found in the AN-709 application note from Analog Devices
}


void readRegister()
{
  TempSPI->beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE1));
  digitalWrite(chipSelectPin, LOW);

  TempSPI->transfer(0x80); //80h = 128 - config register
  TempSPI->transfer(0xB0); //B0h = 176 - 10110000: bias ON, 1-shot, start 1-shot, 3-wire, rest are 0
  digitalWrite(chipSelectPin, HIGH);

  digitalWrite(chipSelectPin, LOW);
  TempSPI->transfer(1);
  reg1 = TempSPI->transfer(0xFF);
  reg2 = TempSPI->transfer(0xFF);
  digitalWrite(chipSelectPin, HIGH);

  fullreg = reg1; //read MSB
  fullreg <<= 8;  //Shift to the MSB part
  fullreg |= reg2; //read LSB and combine it with MSB
  fullreg >>= 1; //Shift D0 out.
  resistance = fullreg; //pass the value to the resistance variable
  //note: this is not yet the resistance of the RTD!

  digitalWrite(chipSelectPin, LOW);

  TempSPI->transfer(0x80); //80h = 128
  TempSPI->transfer(144); //144 = 10010000
  TempSPI->endTransaction();
  digitalWrite(chipSelectPin, HIGH);

  Serial.print("Resistance: ");
  Serial.println(resistance);
}


Have you checked to see if the display tri-states MISO when it's not selected? It's the first thing I'd check.

Better SPI Bus Design in 3 Steps

I'm not shure if I understand what you mean. But the MISO signal remains the same. I checked it with the oscilloscope.

What did you not understand in the comprehensive explanation contained in the provided link?

Ah I did not noticed the link.
Very good explanation! But I'm trying to use two different SPI for each device. Tristating should not be a problem. Until I add the line:

tft->begin();

I'm getting valid temperatures via the serial interface. So I think it's not a connection problem.

have you checked your pin usage against esp32-pinout-reference-gpios
you are using separate SPI interfaces for the two devices so they should not interfere with each other
did you test each device using a separate programs with the pin configurations of the code in post 1?
can you give a link to the TFT?
EDIT: which ESP32 are you using? original, S3, C6, ???

Yes I checked the Pinout of ther ESP32 board. It should work. It's an S3-Wroom-1 Bord with two USB-C conectors. Here you can find a Pinout: Pinout ESP32-S3-Wroom-1. And yes if I only use one device it is working with the pins defined in the code I posted.
I can use the max31865 without problems until I add the tft begin command. Since then the temperatur is an invalid constant value. I checked all signals of the temeprature SPI interface with the oscilloscope and they look the same as before. The tft works allone and with the MAx31865 as it should.
The TFT is a piece like that: 2,8" TFT

Suspect a conflict over pin usage, so carefully check the details in each of the libraries.

this was also my gues. unfortunately I do not understand everthing 100%. I checked the Arduino_ESP32SPI.cpp and the Arduino_IL9341.cpp of the GFX for Arduino library. Maybe the problem is the FSPI or HSPI definition. I do not understand how to define it. I think I need some experts help.

from post 1 noticed the order of initialization is

void setup()
{
  TempSPI = new SPIClass(VSPI);
  TempSPI->begin(TEMP_CLK, TEMP_MISO, TEMP_MOSI, TEMP_CS);
  Serial.begin(115200); //Start serial

  pinMode(chipSelectPin, OUTPUT); //because CS is manually switched  

  tft->begin();
}

what happens if you call tft->begin(); before TempSPI->begin()?

Wow, that's awesome. That was the problem. Changing the order during initialization solved it. Thanks for the suggestion. What a lovely Christmas present. I would love it if someone could explain to me why that is.

Merry Christmas!

as a quick test I connected a ILI9341 display and a RFM95 LoRa module to a ESP32-S3-DevKitC-1 with SPI connections similar to your post 1

#define TFT_CLK 40//12  //SPI Clock
#define TFT_DA 41//11   //SPI Data (MOSI)
#define TFT_DC  39//9//39   //Data/Command
#define TFT_CS 42//10//42    //Chip select
#define TFT_RST 37//3//37   //Reset

// ESP32S3 SCK pin GPIO12  to RFM95_pin SCK
// ESP32S3 MISO pin GPIO13  to RFM95_pin MISO
// ESP32S3 MOSI pin GPIO11  to RFM95_pin MOSI
// ESP32S3 pin GPIO 10   to RFM95 SS
// ESP32S3 pin GPIO8   to RFM95 Reset
// ESP32S3 pin GPIO9   to RFM95 DIO0 

found similar problem to your post 1

  1. if I initialize the RFM95 then TFT the TFT works OK but the RFM95 receives no data packets
  2. if I initialize the TFT then RFM95 the TFT and RFM95 both work OK with the TFT displaying data and the RFM95 receiving data packets

EDIT: repeated test using the Adafruit_ILI9341 library - order of initialization did not matter - both modules worked OK

Hi again!
Since I managed to operated two SPI interfaces in parallel to connect MAX31865 Boards and the TFT Display I became megalomaniac. I tried to init a third SPI interface to make the touch function of the screan run. Unfortunately the third SPI seems not to work as I can't see any edges with the oscilloscope. Does anyone ever used three SPI in parallel with the ESP32? This Is my code so far. Of course it can be optimized.


#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h> //Arduino Uno; SDA = A4, SCL = A5
#include <SPI.h>
#include <Arduino_GFX_Library.h>
#include <sheme.h>
#include <XPT2046_Touchscreen.h>

// Pins for SPI bus for the display
#define TFT_CLK 40  //SPI Clock
#define TFT_DA 41   //SPI Data (MOSI)
#define TFT_DC  1   //Data/Command
#define TFT_CS 2    //Chip select
#define TFT_RST 37   //Reset

#define WHITE   0xFFFF
#define BLACK   0x0000
Arduino_DataBus *bus = new Arduino_ESP32SPI(TFT_DC, TFT_CS,TFT_CLK, TFT_DA);
Arduino_GFX *tft = new Arduino_ILI9341(bus, TFT_RST, 0, false);

// define SPI for MAX31865
#define TEMP_CS 10
#define TEMP_MOSI 11
#define TEMP_CLK 12
#define TEMP_MISO 13
#define VSPI FSPI
SPIClass *TempSPI = NULL;
//SPIClass TempSPI = SPIClass(VSPI);

// define Touchscreen SPI pins
#define XPT2046_IRQ 20   // T_IRQ
#define XPT2046_MOSI 47  // T_DIN
#define XPT2046_MISO 21  // T_OUT
#define XPT2046_CLK 36   // T_CLK
#define XPT2046_CS 35    // T_CS
SPIClass *TouchSPI = NULL;
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240

XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);

const char* SSID = "##############";
const char* PSK = "###############";
const char* MQTT_BROKER = "###.###.#.###";
WiFiClient espClient;
PubSubClient client(espClient);

char ResolTempPuffer_1_1_string[7]={0};
char ResolTempPuffer_1_3_string[7]={0};


//Variables for the PT100 boards
double resistance; 
double Temperature[8] ={0,0,0,0,0,0,0,0};
double Old_Temperature[8] ={0,0,0,0,0,0,0,0};
float ResolTempPuffer_1_1 = 0, ResolTempPuffer_1_1_old = 0, ResolTempPuffer_1_3 = 0, ResolTempPuffer_1_3_old = 0;

uint8_t PowerFlowHeater = 0, Old_PowerFlowHeater = 0;
uint8_t PowerPump = 0, Old_PowerPump = 0;
uint16_t Offset = 10;
uint8_t Turn = 1; 
uint8_t NumberOfPT100 = 2;
//uint8_t chipSelectPin;
uint8_t X1 = 40, X2 = 200, X3 = 130;
uint8_t Y = 45; 
uint8_t OffSet = 35, OffSet2 = 22;

int x, y, z;

//--Display---------------------------------------------


const int ChipSelectPin[8] ={10,9,46,3,8,18,17,16};
const int chipSelectPin_1 = 10;
const int chipSelectPin_2 = 9;

void setup()
{
  Serial.begin(115200);
  setup_wifi();
  client.setServer(MQTT_BROKER, 1883);
  client.setCallback(MQTTreceive);

  tft->begin();
  tft->setRotation(1);
  TouchSPI = new SPIClass(); // Software SPI
  TouchSPI->begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
  TempSPI = new SPIClass(VSPI);
  TempSPI->begin(TEMP_CLK, TEMP_MISO, TEMP_MOSI, TEMP_CS);
  Serial.begin(115200); //Start serial
  for (uint8_t n = 0; n < 8; n++){
    pinMode(ChipSelectPin[n], OUTPUT); //because CS is manually switched 

  }
  // prepare Screen once
  FillWholeScreen(BLACK);
  tft->drawBitmap(0,0, epd_bitmap_Sheme,320,240,WHITE);

}

void loop()
{
  if (!client.connected()) {
    while (!client.connected()) {
      client.connect("FlowHeaterESP32");
      client.subscribe("Flowheater/Puffer_1_1_Temperature");
      client.subscribe("Flowheater/Puffer_1_3_Temperature");
      delay(100);
    }
  }
    client.loop();


  // read all 8 Temperature Sensors
  for (uint8_t n = 0; n < 8; n++){
    resistance = readRegister(ChipSelectPin[n]);
    Temperature[n] = convertToTemperature(resistance);
    //Serial.printf("Temperature %d:",n);
    //Serial.println(Temperature[n]); //Temperature in Celsius degrees
  }

  //Delete all Values
  // left row
  tft->setTextSize(1);
  tft->setTextColor(BLACK);
  tft->setCursor(X1, Y);
  tft->print(ResolTempPuffer_1_1_old);
  tft->setCursor(X1, Y + OffSet);
  tft->print(Old_Temperature[0]);
  tft->setCursor(X1, Y + 2*OffSet);
  tft->print(ResolTempPuffer_1_3_old);
  tft->setCursor(X1, Y + 3*OffSet);
  tft->print(Old_Temperature[1]);
  // rigth row
  tft->setCursor(X2, Y);
  tft->print(Old_Temperature[2]);
  tft->setCursor(X2, Y + OffSet);
  tft->print(Old_Temperature[3]);
  tft->setCursor(X2, Y + 2*OffSet);
  tft->print(Old_Temperature[4]);
  tft->setCursor(X2, Y + 3*OffSet);
  tft->print(Old_Temperature[5]);
  // Temperatures ans Power of the Flowheater 
  tft->setCursor(X3, Y + OffSet);
  tft->print(Old_Temperature[6]);
  tft->setCursor(X3, Y + OffSet + OffSet2);
  tft->printf("%u %%",Old_PowerFlowHeater);
  tft->setCursor(X3, Y + OffSet + 2*OffSet2);
  tft->print(Old_Temperature[7]);
  tft->setCursor(X3, Y + OffSet + 3*OffSet2);
  tft->printf("%u %%",Old_PowerPump);

  
  // Print new Values
  tft->setTextSize(1);
  tft->setTextColor(WHITE);
  // left row 
  tft->setCursor(X1, Y);
  tft->print(ResolTempPuffer_1_1);
  tft->setCursor(X1, Y + OffSet);
  tft->print(Temperature[0]);
  tft->setCursor(X1, Y + 2*OffSet);
  tft->print(ResolTempPuffer_1_3);
  tft->setCursor(X1, Y + 3*OffSet);
  tft->print(Temperature[1]);
  // rigth row
  tft->setCursor(X2, Y);
  tft->print(Temperature[2]);
  tft->setCursor(X2, Y + OffSet);
  tft->print(Temperature[3]);
  tft->setCursor(X2, Y + 2*OffSet);
  tft->print(Temperature[4]);
  tft->setCursor(X2, Y + 3*OffSet);
  tft->print(Temperature[5]);
  // Temperatures ans Power of the Flowheater 
  tft->setCursor(X3, Y + OffSet);
  tft->print(Temperature[6]);
  tft->setCursor(X3, Y + OffSet + OffSet2);
  tft->printf("%u %%",PowerFlowHeater);
  tft->setCursor(X3, Y + OffSet + 2*OffSet2);
  tft->print(Temperature[7]);
  // Power of the Pump
  tft->setCursor(X3, Y + OffSet + 3*OffSet2);
  tft->printf("%u %%",PowerFlowHeater);


  // store old Values for deleting
    for (uint8_t i = 0; i < 8; i++){
      Old_Temperature[i] = Temperature[i];
    }

  delay(200);
    if (touchscreen.tirqTouched() && touchscreen.touched()) {
    // Get Touchscreen points
    TS_Point p = touchscreen.getPoint();
    // Calibrate Touchscreen points with map function to the correct width and height
    x = map(p.x, 200, 3700, 1, SCREEN_WIDTH);
    y = map(p.y, 240, 3800, 1, SCREEN_HEIGHT);
    z = p.z;

    printTouchToSerial(x, y, z);


    delay(100);
  }
}



double convertToTemperature(double resistance_read)
{
  double Z1, Z2, Z3, Z4, Rt;
  double RTDa = 3.9083e-3;
  double RTDb = -5.775e-7;
  double rpoly = 0;
  double temp;
  Rt = resistance_read;
  Rt /= 32768;
  Rt *= 430; //This is now the real resistance in Ohms

  Z1 = -RTDa;
  Z2 = RTDa * RTDa - (4 * RTDb);
  Z3 = (4 * RTDb) / 100;
  Z4 = 2 * RTDb;

  temp = Z2 + (Z3 * Rt);
  temp = (sqrt(temp) + Z1) / Z4;

  if (temp >= 0)
  {
    // Serial.print("Temperature: ");
    // Serial.println(temp); //Temperature in Celsius degrees
    return temp; //exit
  }
  else
  {
    Rt /= 100;
    Rt *= 100; // normalize to 100 ohm

    rpoly = Rt;

    temp = -242.02;
    temp += 2.2228 * rpoly;
    rpoly *= Rt; // square
    temp += 2.5859e-3 * rpoly;
    rpoly *= Rt; // ^3
    temp -= 4.8260e-6 * rpoly;
    rpoly *= Rt; // ^4
    temp -= 2.8183e-8 * rpoly;
    rpoly *= Rt; // ^5
    temp += 1.5243e-10 * rpoly;

    // Serial.print("Temperature: ");
    // Serial.println(temp); //Temperature in Celsius degrees
  }
  //Note: all formulas can be found in the AN-709 application note from Analog Devices
  return temp;
}


double readRegister(uint8_t chipSelectPin)
{
  double resist; 
  uint8_t reg1, reg2; //reg1 holds MSB, reg2 holds LSB for RTD
  uint16_t fullreg; //fullreg holds the combined reg1 and reg2
  TempSPI->beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE1));
  digitalWrite(chipSelectPin, LOW);

  TempSPI->transfer(0x80); //80h = 128 - config register
  TempSPI->transfer(0xB0); //B0h = 176 - 10110000: bias ON, 1-shot, start 1-shot, 3-wire, rest are 0
  digitalWrite(chipSelectPin, HIGH);

  digitalWrite(chipSelectPin, LOW);
  TempSPI->transfer(1);
  reg1 = TempSPI->transfer(0xFF);
  reg2 = TempSPI->transfer(0xFF);
  digitalWrite(chipSelectPin, HIGH);

  fullreg = reg1; //read MSB
  fullreg <<= 8;  //Shift to the MSB part
  fullreg |= reg2; //read LSB and combine it with MSB
  fullreg >>= 1; //Shift D0 out.
  resist = fullreg; //pass the value to the resistance variable
  //note: this is not yet the resistance of the RTD!

  digitalWrite(chipSelectPin, LOW);

  TempSPI->transfer(0x80); //80h = 128
  TempSPI->transfer(144); //144 = 10010000
  TempSPI->endTransaction();
  digitalWrite(chipSelectPin, HIGH);

  // Serial.print("Resistance: ");
  // Serial.println(resist);
  return resist;
}

void FillWholeScreen(uint16_t color)
{
  for (uint16_t x = 0; x < 320; x++)
  {
    for (uint8_t y = 0; y < 240;y++)
    {
      tft->drawPixel(x,y,color);
    }
  }
}

void setup_wifi() {
    WiFi.begin(SSID, PSK);
 
    while (WiFi.status() != WL_CONNECTED) {
        delay(100);
    }
    
    Serial.println(WiFi.localIP());
}

void MQTTreceive(char* topic, byte* payload, unsigned int length){

  // ResolTempPuffer_1_1
  if (strcmp(topic,"Flowheater/Puffer_1_1_Temperature") == 0){
    ResolTempPuffer_1_1_old = ResolTempPuffer_1_1;
    for (int i = 0; i < length-3; i++){ // only consider the numbers
      ResolTempPuffer_1_1_string[i]= char(payload[i]);
    }
    ResolTempPuffer_1_1_string[4] = {'\0'};
    ResolTempPuffer_1_1 = atof(ResolTempPuffer_1_1_string);
    if (ResolTempPuffer_1_1 != ResolTempPuffer_1_1_old){
      //Output_Power1_Update = true;
    }
    Serial.println(ResolTempPuffer_1_1_string);
  }
  // ResolTempPuffer_1_3
  if (strcmp(topic,"Flowheater/Puffer_1_3_Temperature") == 0){
    ResolTempPuffer_1_3_old = ResolTempPuffer_1_3;
    for (int i = 0; i < length-3; i++){ // only consider the numbers
      ResolTempPuffer_1_3_string[i]= char(payload[i]);
    }
    ResolTempPuffer_1_3_string[4] = {'\0'}; 
    ResolTempPuffer_1_3 = atof(ResolTempPuffer_1_3_string);
    if (ResolTempPuffer_1_3 != ResolTempPuffer_1_3_old){
      //Output_Power1_Update = true;
    }
    Serial.println(ResolTempPuffer_1_3_string);
  }
}

void printTouchToSerial(int touchX, int touchY, int touchZ) {
  Serial.print("X = ");
  Serial.print(touchX);
  Serial.print(" | Y = ");
  Serial.print(touchY);
  Serial.print(" | Pressure = ");
  Serial.print(touchZ);
  Serial.println();
}

Meanwhile I learned that the first two SPI interfaces of the ESP32 are used internally for memory access and should not be used. I found nothing about software SPI, so the task is to operate the TFT-Display and the Touch Controller at the same SPI bus.

As you are using Arduino IDE, and probably all your libraries make use of SPIClass to use the SPI bus, you must initialize the graphic using "Arduino_HWSPI" instead of "Arduino_ESP32SPI".

It happens because Arduino_ESP32SPI uses a kind of bit-banging method, and then it will be hard to share the bus with other devices using SPIClass

"Arduino_HWSPI", by default, uses the default SPI object to handle it, so you can rather pass it as a parameter to the touch driver and the other device, or create an other SPIClass to make it work.

And you forgot to start the touchscreen with touchscreen.begin(TouchSPI);, thats why you were not able to use the 3rd SPI bus.

If you want to use the shared SPI, you would simply use touchscreen.begin();

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