SPI problems

Status
Not open for further replies.

Skiddy

Well-known member
Good evening;

since I am new to programming, very likely I am missing something. I have just added a 2.2" TFT display https://www.pjrc.com/store/display_ili9341.html to my project and now am experiencing difficulties with the data transfer of the temperature measurement. The display itself works fine and the temperature measurement does too, as long as not both are running. The temperature measurement somehow gets clobbered on the SPI bus by the TFT display use of the SPI bus.

Code:
// MAX31865_RTD trial with PJRC 2.2" TFT display

#include <MAX31865.h>
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

#define TFT_DC 20
#define TFT_CS  9

// Use hardware SPI
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

// PT1000 / PT100 board from Charles Hallard (http://hallard.me)
//    -------------------------------------------
//    3V3 (!not 5V) -->  NRF Connector pin 8 (VCC)
//    GND           -->  NRF Connector pin 1 (GND)
//    CS: pin 10   -->  NRF Connector pin 7 (CSN)
//    MOSI: pin 11 -->  NRF Connector pin 6 (MOSI)
//    MISO: pin 12 -->  NRF Connector pin 4 (MISO) 
//    SCK: pin 13  -->  NRF Connector pin 3 (SCK)
//    -------------------------------------------

#define RTD_CS_PIN 10

MAX31865_RTD rtd( MAX31865_RTD::RTD_PT100, RTD_CS_PIN, 390 ); // PT100 configuration

float RTD_PT_1 = 0;                            // Global storage for RTD temperature measurement 1
float PTxxx_OHM = 0;                          // Global storage for PT resistance 1

const int TFT_DC_PIN = 20;
const int TFT_CS_PIN = 9;
const int RTD_PIN = 10;

void setup() {
  Serial.begin(115200);                              // Set up serial port

  pinMode (RTD_PIN, OUTPUT);
  pinMode (TFT_DC_PIN, OUTPUT);
  pinMode (TFT_CS_PIN, OUTPUT);  
  digitalWrite (RTD_PIN, HIGH);
  digitalWrite (TFT_DC_PIN, HIGH);
  digitalWrite (TFT_CS_PIN, HIGH);  
  
  SPI.setSCK(14);                                       // SCK pin default
  SPI.begin();                                             // Setup and begin SPI library:
  SPI.setClockDivider(SPI_CLOCK_DIV16);    // SPI speed to SPI_CLOCK_DIV16 (1MHz)
  SPI.setDataMode(SPI_MODE3);                 // MAX31865 works in MODE1 or MODE3

  rtd.configure( true, true, false, true, MAX31865_FAULT_DETECTION_NONE, true, true, 0x0000, 0x7fff ); // MAX31865 configuration
  
  delay(5000);                                           // Delay any further action for 5 seconds
  }
                
  void loop(){

  // ******************** RTD reading ********************
  digitalWrite (RTD_PIN, LOW);
  rtd.read_all();
  PTxxx_OHM =rtd.resistance();
  RTD_PT_1 = rtd.temperature( );
  digitalWrite (RTD_PIN, HIGH);
  // ************** end RTD no-fault handling *************   

  digitalWrite (TFT_DC_PIN, LOW);
  digitalWrite (TFT_CS_PIN, LOW);
/*   
  tft.begin();
  tft.setRotation(1);  
  tft.fillScreen(ILI9341_BLACK);  
  tft.setCursor(0, 0);
  tft.setTextColor(ILI9341_RED);    tft.setTextSize(4);
  tft.println("Temperature");
  tft.setTextSize(6);
  tft.println();   
  tft.println(RTD_PT_1, 2);
*/  
  digitalWrite (TFT_DC_PIN, HIGH);
  digitalWrite (TFT_CS_PIN, HIGH);  

  // ASCII dump printing on USB port
  
  Serial.print("PT100 resistance   ");
  Serial.print(PTxxx_OHM);
  Serial.print("     Temperature   ");
  Serial.println(RTD_PT_1);

  delay(2000);
  }

With the code for the TFT display commented out, it works fine, providing this data:

PT100 resistance 110.25 Temperature 26.32
PT100 resistance 110.25 Temperature 26.32
PT100 resistance 110.25 Temperature 26.32
PT100 resistance 110.25 Temperature 26.32
PT100 resistance 110.23 Temperature 26.29
PT100 resistance 110.25 Temperature 26.32
PT100 resistance 110.23 Temperature 26.29
PT100 resistance 110.25 Temperature 26.32
PT100 resistance 110.22 Temperature 26.26
PT100 resistance 110.23 Temperature 26.29

However if the I am using the complete code, this data is transferred:

PT100 resistance 110.27 Temperature 26.39
PT100 resistance 76.54 Temperature -59.50
PT100 resistance 75.02 Temperature -63.32
PT100 resistance 76.54 Temperature -59.50
PT100 resistance 75.02 Temperature -63.32
PT100 resistance 75.02 Temperature -63.32
PT100 resistance 76.54 Temperature -59.50

Note that the very first transfer is always correct!
 
Last edited:
Perhaps those two devices' libraries are not using "SPI Transactions", an add-on to libraries, developed by Paul of PJRC. It solves most problems where one SPI port needs to be concurrently used by 2+ device interfaces, each with a different chip select bit. And the tricky problem of an interrupt handler assuming that on any interrupt, it is OK to use the SPI port.

As a newbie, you might be better off asking if the two devices you are using have drivers/libraries using SPI Transactions. First, determine if SPI Transactions is needed at all ... these two devices might use the SPI port in ping-pong fashion, never concurrently in an interrupt handler.

Question would go to the experts here
 
Last edited:
General advice from the old fart which I am: Never use a library without having fully read and understood its source code! That's the only way to make sure that 2 libraries provided by different manufacturers will not interfere, or if they do, you'll know what to do to solve occurring problems.
 
Use the ILI9341_t3 library. It definitely supports SPI transactions, and it's much faster than Adafruit's lib. It has GFX built in, so you don't need that lib.

I don't see any link or info to the MAX31865 lib...
 
Just exchanging the Adafruit_GFX.h and Adafruit_ILI9341.h libraries for the ILI9341_t3 library without any further mods displayed the same problem. Having read something earlier in a different forum about SPI library incompatibles, I added this small modification just before the RTD function is called in the loop as well.

SPI.setClockDivider(SPI_CLOCK_DIV16); // SPI speed to SPI_CLOCK_DIV16 (1MHz)
SPI.setDataMode(SPI_MODE3); // MAX31865 works in MODE1 or MODE3

The temperature is now being read and transferred correctly, it is no longer being clobbered.

Code:
// MAX31865_RTD trial with PJRC 2.2" TFT display

#include <MAX31865.h>
#include "SPI.h"
#include "ILI9341_t3.h"

#define TFT_DC 20
#define TFT_CS  9

// Use hardware SPI
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);

// PT1000 / PT100 board from Charles Hallard (http://hallard.me)
//    -------------------------------------------
//    3V3 (!not 5V) -->  NRF Connector pin 8 (VCC)
//    GND           -->  NRF Connector pin 1 (GND)
//    CS: pin 10   -->  NRF Connector pin 7 (CSN)
//    MOSI: pin 11 -->  NRF Connector pin 6 (MOSI)
//    MISO: pin 12 -->  NRF Connector pin 4 (MISO) 
//    SCK: pin 13  -->  NRF Connector pin 3 (SCK)
//    -------------------------------------------

#define RTD_CS_PIN 10

MAX31865_RTD rtd( MAX31865_RTD::RTD_PT100, RTD_CS_PIN, 390 ); // PT100 configuration for 
// MAX31865_RTD rtd( MAX31865_RTD::RTD_PT1000, RTD_CS_PIN, 3900 ); // PT1000 configuration

float RTD_PT_1 = 0;                            // Global storage for RTD temperature measurement 1
float PTxxx_OHM = 0;                           // Global storage for PT resistance 1

const int TFT_DC_PIN = 20;
const int TFT_CS_PIN = 9;
const int RTD_PIN = 10;


void setup() {
  Serial.begin(115200);                              // Set up serial port

  pinMode (RTD_PIN, OUTPUT);
  pinMode (TFT_DC_PIN, OUTPUT);
  pinMode (TFT_CS_PIN, OUTPUT);  
  digitalWrite (RTD_PIN, HIGH);
  digitalWrite (TFT_DC_PIN, HIGH);
  digitalWrite (TFT_CS_PIN, HIGH);  
  
  SPI.setSCK(14);                                    // SCK pin default
  SPI.begin();                                       // Setup and begin SPI library:
  SPI.setClockDivider(SPI_CLOCK_DIV16);              // SPI speed to SPI_CLOCK_DIV16 (1MHz)
  SPI.setDataMode(SPI_MODE3);                        // MAX31865 works in MODE1 or MODE3

  rtd.configure( true, true, false, true, MAX31865_FAULT_DETECTION_NONE, true, true, 0x0000, 0x7fff ); // MAX31865 configuration
  
  delay(5000);                                       // Delay any further action for 5 seconds so the memory etc can be set up internally                                     // Generate the high voltage from the 3.3v line internally
  }
                
  void loop(){

  // ******************** RTD reading ********************
  SPI.setClockDivider(SPI_CLOCK_DIV16);              // SPI speed to SPI_CLOCK_DIV16 (1MHz)
  SPI.setDataMode(SPI_MODE3);                        // MAX31865 works in MODE1 or MODE3
  digitalWrite (RTD_PIN, LOW);
  rtd.read_all();
  PTxxx_OHM =rtd.resistance();
  RTD_PT_1 = rtd.temperature( );
  digitalWrite (RTD_PIN, HIGH);
  // ************** end RTD no-fault handling *************   

  digitalWrite (TFT_DC_PIN, LOW);
  digitalWrite (TFT_CS_PIN, LOW);
   
  tft.begin();
  tft.setRotation(1);  
  tft.fillScreen(ILI9341_BLACK);  
  tft.setCursor(0, 0);
  tft.setTextColor(ILI9341_RED);    tft.setTextSize(4);
  tft.println("Temperature");
  tft.setTextSize(6);
  tft.println();   
  tft.println(RTD_PT_1, 2);
  
  digitalWrite (TFT_DC_PIN, HIGH);
  digitalWrite (TFT_CS_PIN, HIGH);  

  // ASCII dump printing on USB port
  
  Serial.print("PT100 resistance   ");
  Serial.print(PTxxx_OHM);
  Serial.print("     Temperature   ");
  Serial.println(RTD_PT_1);

  delay(2000);
  }

Very likely SPI transactions in ILI9341_t3 therefore will solve it as well, however may not be effective within the MAX31865.h library.

Thanks for the guidance, it now comes down to cleaning up.
 
Oh, not good. That library isn't using SPI transactions, AND it's configuring the SPI port to mode 3.

https://github.com/hallard/arduino-...les/Read_Temperature/Read_Temperature.ino#L52

Almost everything else uses mode 0. The ILI9341 libs also use a much faster clock speed. After using other SPI-based libs, the SPI port will no longer have the settings that library requires. This is exactly the sort of problem SPI transactions solve!

As a quick kludge, you could try putting these 2 lines before *every* call to that library. Or at least all the ones that might happen after you've done anything with the display.

Code:
  SPI.setClockDivider( SPI_CLOCK_DIV16 );
  SPI.setDataMode( SPI_MODE3 );

Maybe file a new issue on that library, requesting the author to consider adding SPI transactions.
 
In the meantime I have incorporated the ILI9341_t3 library in my main program. I have also added the kludge as shown above to it. All is well and it works wonderfully. The next step will be to add a micro SD card when they arrive. If they show a similar problem, I will at least know where to start.

Thanks all
 
Last edited:
Status
Not open for further replies.
Back
Top