Correct way to use same SPI pins with different SPI master and Slave libraries? T3.6

Status
Not open for further replies.

DougMcK

Well-known member
Greetings,

I have a fairly large program that I can build to use the TSPISlave library to operate as an SPI slave. This works fine.

I can also build the program to use the ILI9341_t3n, and SPIN, libraries using the T3.6 as a SPI master to drive an SPI tft display over the same pins. That too works fine.

These two functions are never required at the same time, but I now have a use case where it would be useful to have a single build of the code, and switch from one of these uses of the SPI port to the other. Taking a naive approach and simply trying to start the tft display library after using the slave library hangs at tft.begin().

Is there a generally accepted "correct" way to do stuff like this? Should these libraries have a way of gracefully letting go of the hardware resources? I guess I'll start digging into the libraries and figure it out but I thought I would ask for general guidance.
Cheers
Doug
 
Quick FYI - My later versions of ILI9341_t3n no longer needs/uses SPIN library. Decide to excise it from there.

As for TSPISlave library, I have not tried it. My quick look through the code looks like a bunch of stuff is setup on constructor and I don't see anything like a begin/end.

That is everything is done at the creation of the object. Maybe the library owner (@tonton81) might have some suggestions.
 
you can't use master and slave on same bus at same time, or switch, well, you can switch but you need to change the whole bus configuration to do so every time. better to use 2 spi busses

if you still deem it necessary to use a single bus, you need to disable the interrupt of the spi slavr before changing the spi port settings, then rerun spi.begin() before using tft functions, then, copy paste the spi slave setup from source to your sketch and activate the slave through the sketch manually. unfortunately i never added a begin because the constructor was sufficient enough to activate the bus in slave mode

if the tft lcd talks back on the spi bus, thats bad for slave mode since it may see both devices accessing it
 
you can't use master and slave on same bus at same time, or switch, well, you can switch but you need to change the whole bus configuration to do so every time. better to use 2 spi busses

Yeah, I realize that, and the system doesn't ever have a need for using these two modes at close to the same time. This is a piece of hardware that uses the SPI Slave mode for a one-time calibration and then, in some configurations may use SPI master mode for controlling a display. Indeed, the use cases have evolved since the system was designed a few years ago. The goal is to avoid having a change of pinout so that hardware that's deployed with customers isn't now of a different revision than I'm building today.

For me, it's fine for the system to wake up in SPI slave mode (in case it needs calibration) and then, if necessary, reconfigure the bus if it receives the command that tells it that it's actually got a display hooked onto these pins. Less than elegant, perhaps, but definitely fit-for-purpose.

cheers
Doug
 
if the slave is ready though to accept calibration data from another mcu the tft SI/SO lines may interfere in the data process, even if only one of it's line is tri-stated, so data corruption will be creeping your way, unless you decided to shut off the devices before switching to slave mode :)
 
if the slave is ready though to accept calibration data from another mcu the tft SI/SO lines may interfere in the data process, even if only one of it's line is tri-stated, so data corruption will be creeping your way, unless you decided to shut off the devices before switching to slave mode :)

No, that's not a problem. The use case is quite different. The system header that contains this bus has one cable plugged in for a calibration process, or for use in certain use cases, and a different cable plugged in for use with the display. There really is no hardware problem with the way the bus is used, and I'm just trying to rationalize the software so that it can switch between the different use cases (that happen minutes or hours apart).
 
you should be able to copy the relevant spi bus block in tspislave and run that in your sketch to switch to slave, but just need to run spi.begin after to control the lcd then
 
you should be able to copy the relevant spi bus block in tspislave and run that in your sketch to switch to slave, but just need to run spi.begin after to control the lcd then

I'm not in front of the system right now, but I thought I had already done that. I had the system start in SPI Slave mode, as normal, and then attempted to start the LCD SPI system, which resulted in a hang. But, I'll need to look at that again. If that should work fine I'll spend some time on it.
 
ok, I'll check that. Thx

Hmm, it looks like more head-scratching is required. Here's a minimal test program that I've been using to look at this. With either SPISLAVE or TFT_DISP defined, things are fine. If both are defined, which is a proxy for the use case I'm interested in, the code hangs on the tft.begin() statement.
The behavior is the same with or without SPI.begin() or SPI1.begin(). I was hoping that would overwrite the SPISLAVE setup.

Any pointers? Doug

Code:
#define SPISLAVE
#define TFT_DISP

#include <SPI.h>

#ifdef SPISLAVE
  #include "TSPISlave.h" // for SPI receive on SPI1
  uint8_t SPI1_miso = 1;
  uint8_t SPI1_mosi = 0;
  uint8_t SPI1_sck = 32;
  uint8_t SPI1_cs = 31;
  uint8_t SPI1_spimode = 8;  //8 bit transfers.
  TSPISlave mySPI = TSPISlave(SPI1, SPI1_miso, SPI1_mosi, SPI1_sck, SPI1_cs, SPI1_spimode);
#endif

#ifdef TFT_DISP
  #include "ILI9341_t3n.h" //display
  #define TFT_DC 6 // 0xe4  was 6 , 31
  #define TFT_CS 31 // 0xe5
  #define TFT_SCK 32 // 0xe2
  #define TFT_MISO 1 // 0xe3
  #define TFT_MOSI 0 // 0xe1
  #define TFT_RESET 7
  //ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RESET, TFT_MOSI, TFT_SCK, TFT_MISO, &SPIN1);
  ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RESET, TFT_MOSI, TFT_SCK, TFT_MISO);
#endif

void setup() {
  Serial.begin(19200);
  delay(100);
  Serial.println("In Setup");
  delay(100);
#ifdef TFT_DISP
      SPI.begin();
      tft.begin();      
      tft.setRotation(3);   // rotation ranges from 0 to 4
      tft.fillScreen(ILI9341_BLACK);
      tft.setCursor(40, 40);
      tft.setTextColor(ILI9341_YELLOW);
      tft.setTextSize(2);
      tft.println("Hello World!");
#endif
}

void loop() {
  delay(1000); Serial.println("Loop");
}
 
try to disable slave's NVICIRQ before modifying it for master, maybe it's stuck in there when the peripheral transitions and it's not handled
 
try to disable slave's NVICIRQ before modifying it for master, maybe it's stuck in there when the peripheral transitions and it's not handled

That seemed to work in my test program. Thx. I shall get back to fiddling around with the real program.
 
Status
Not open for further replies.
Back
Top