Best Practice for five device SPI on Teensy 3.6

Status
Not open for further replies.

tboicey

New member
I'm porting a project from Arduino DUE to Teensy 3.6.

The project has five SPI displays.

The board has a single capacitive touch screen TFT (the Adafruit ILI9341 one: https://www.adafruit.com/products/1947) and four ILI9163 displays identical to: http://henrysbench.capnfatz.com/hen...ays/arduino-1-44-in-spi-tft-display-tutorial/

I had it working with point-to-point wiring on the Due. All of the screens are on the same SPI pins and I just chose CS pins based on whatever was available and nearby on the PCB.

With that success, I (foolishly?) had a board made with the Teensy 3.6 footprint and the same pin assignments. No go.

I seem to be running into problems with only certain pins being suitable for SPI, especially CS. I've scratched and patched the PCB to move enough lines around to get the large screen and two small screens working., hacking a bit blindly with the Teensy 3.6 pinout card and various SPI libraries, and various forum posts and rumours. But I can't seem to find pins that will CS the other two screens.

I think I need to start over again.

Would anyone suggest what SHOULD work, as far as pin assignments and suggested libraries? How I should wire the five screens to run them all on a Teensy 3.6?

Performance is nice but not paramount.

2016-11-18 21.56.35.jpg
 
Were there proper pullups on all the CS's : five displays and touch?

There is a good Teensy library for the ILI9163 that you might run the those from a SPI1? I only ever did one - but as I saw it there was support for multiples. I'm not sure it requires the 'DMA compatible' CS pins like the ILI9341.
 
There may not be enough information here to give you any complete answers.


ILI9341: If you use the optimized library ili9341_t3, it requires two hardware SPI CS pins. One for the DC pin and another for the CS pin. My variation on this library: https://github.com/KurtE/ILI9341_t3n
Allows you to use all three SPI busses on T3.6. I also made it such that it would work with only 1 hardware CS pin, which needs to be the DC pin.

I don't know enough about the ILI9163 displays and drivers available. For higher speed my guess would be Sumotoys driver: https://github.com/sumotoy/TFT_ILI9163C
But I am guessing that it is based using some of the same stuff as the ili9341_t3 and requires hardware CS and DC pins.

What I did with my ili9341_t3n library was to move all of the hardware SPI specific stuff out of that library and into another library I called SPIN, which setup classes for the different SPI busses, which then allowed me in my apps to give a pointer to which one that display should use. It also tries to take care of some other issues like SPI0 has a 4 item queue, where SPI1 and SPI2 have a 1 item queue. Note: this took work in my main code to handle as well, as there is code that would do things like push three commands onto the queue (query pixel) and then pop the three responses, which won't work...

Probably would not be hard to make a version of the ..63 library to do the same.

The sort of confusing things about hardware CS pins, is that while I believe the T3.6 has something like 10 pins that can be CS pins. Some of them are duplicates of others. That is like with the signal MISO0 which is by default on pin 12, it can alternatively be on pin 7 or pin 28. This is true for CS pins as well. That is pin 10 is a CS0, which signal is actually (spi0_PCS0). And likewise that same signal is on pin 26. I believe there are 6 unique CS channels on SPI0. What is means, that for those apps that are using the underlying hardware SPI cs capabilities, like the ILI9341_t3 library, the program can not use both 10 and 26.

Not sure if that helps answer?
 
That github link has a link to the newest release version: sumotoy/TFT_ILI9163C/tree/Pre-Release-1.0p7. I may be wrong - but I don't think the DMA usable control lines are required on that one - it does write only so MISO isn't used.

Here is the Thread for that work by sumotoy: ILI9163C-128x128-TFT-driver
Hi defragster:
From the link you mentioned if you look at the header file: https://github.com/sumotoy/TFT_ILI9163C/blob/Pre-Release-1.0p7/TFT_ILI9163C.h at starting about line 515, you will see that is using the SPI FIFO queue code out of Pauls ili9341_t3 code. So again this will require the Hardware SPI pins for CS and DC pins. My guess is you should be able to share the DC pin across all of the displays and have a different CS pin for each one.

What pins might work? Here are the pins for the different SPI0 CS pin channels

Channel: Pins
0: 2, 10, 26
1: 6, 9,
2: 20, 23
3: 21, 22
4: 15
5: 45

Fixed table (pin 20)
 
Last edited:
Thank you all for replies!

Current status: I've tied the RESET line for all screens high, and compiled with the basic SPI.h from Arduino. I assume it's just bit banged and it works for all screens on any pins.

So everything works and the performance isn't terrible, but I will certainly pursue improvements.

From this thread comments, I am going to try isolating the ili9341 onto the main SPI bus and attempt KurtE's library. If that makes the large TFT fast then I'll see what I can gain from the small ones with the other SPI bus. The little screens have so few pixels though, performance is never that bad

I spent the evening tearing the useful parts off the first PCB I mangled and I'm starting fresh tomorrow on a new one.

Hurray for PCBcart's fast prototyping five pack!
 
tboicey - indeed putting keeping the FAST DMA driving the ILI9341 would show the most reward - even combined the other four ILI9163's have fewer pixels to update. And they do run well. I was getting 200+ fps updating twin bar graphs when I modified the one example to minimize update area.

KurtE - Thanks for detailed/look correction. I wonder if there is awareness or #ifdef in sumotoy code to skip the DMA and fallback to standard pins?

Question: The card shows #20 as a valid CS0. Did you transpose that with another of your listed alternatives? The lone #23 doesn't show CS0.
#45 of course is a bottom pad.
 
Defragster - As for sumotoys code, as far as I know it does not use DMA, but simply the SPI fifo code. For the fun of it, I might try making a SPIN version of it. However I don't have any of the displays to test it out. I could probably order one through Amazon or Ebay, but don't have any need for them... But if someone would like to try it out...

As for what pin does what, I took a little time this morning and wrote a soon to be example SPIN program, which hopefully enumerates each of the SPI busses a Teensy has, and prints out which pins are CS along with their channel, plus which ones are MISO, MOSI and SCK pins. My library added pin checs for the MISO, MOSI, SCK, like the underlying SPI library does for CS... I keep thinking about doing a Pull Request to add these to the actual SPI objects.

Here is an example output for T3.6:
Code:
Spin - print processor SPI Pin information
Teensy 3.6 - 64 pins

Serial pin information for BUSS 0
2: CS0-0
6: CS0-1
7: MOSI
8: MISO
9: CS0-1
10: CS0-0
11: MOSI
12: MISO
13: SCK
14: SCK
15: CS0-4
20: CS0-2
21: CS0-3
22: CS0-3
23: CS0-2
26: CS0-0
27: SCK
28: MOSI
39: MISO

Serial pin information for BUSS 1
0: MOSI
1: MISO
5: MISO
6: CS1-0
20: SCK
21: MOSI
31: CS1-0
32: SCK
58: CS1-1
59: MOSI MISO
60: SCK
61: MOSI MISO
62: CS1-0
63: CS1-2

Serial pin information for BUSS 2
43: CS2-0
44: MOSI
45: MISO
46: SCK
51: MISO
52: MOSI
53: SCK
54: CS2-1
55: CS2-0
*** End SPIN - Enter anything to repeat ***
So yep I missed mentioning pin 20 :eek: Also not showing pin 45... So might need to check to see if need fix in CORES for this

Edit: I thought I saw this before (pin 45), Actually updated needed in SPI project, Pull Request #20 (Sept 6)
 
Last edited:
KurtE - at least I had valid focus on the pin# - (can you put pin 20 in the right place in post #5?) - even if I keep conflating/confusing the DMA with FIFO.

I have some of those 128x128's - they are a nice size for some output and are quite fast - not much bigger than an SSD1306 but more pixels and color, and a few more wires - and about the same cost. Though of course TFT not as wide angle and more power that the OLED.
 
Posting #5 updated.

Sorry this may be a little off topic

I ordered 1 of the displays from Amazon, should arrive in about a week.

I started playing around with modifying sumotoys library to see how hard it would be to convert to spin. Actually it looks like he has already started to add SPI1 support. I first started editing in one before it had any support for it, but then noticed when I cloned the library that there is some support. So create new branch to try on.

I see that the current stuff to add SPI1 support is starting the same way my playing with the ILI9341 display code and hated adding code that looked like:
Code:
		void writecommand_cont(const uint8_t c) __attribute__((always_inline)) {
			#if defined(__MK20DX128__) || defined(__MK20DX256__)
				KINETISK_SPI0.PUSHR = c | (pcs_command << 16) | SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT;
			#else
				if (_useSPI == 0){
					KINETISK_SPI0.PUSHR = c | (pcs_command << 16) | SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT;
				} else if (_useSPI == 1){
					KINETISK_SPI1.PUSHR = c | (pcs_command << 16) | SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT;
				}
			#endif
			waitFifoNotFull();

So I setup SPIN to be able to use virtual functions versus doing if/else if/else testing in everyplace. Especially when you add in SPI2. Another thing that helps, is if you keep a pointer to the appropriate SPI register structure, then you can convert the above to:

Code:
		void writecommand_cont(uint8_t c) __attribute__((always_inline)) {
			_pkinetisk_spi->PUSHR = c | (pcs_command << 16) | SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT;
			_pspin->waitFifoNotFull();
		}


But as he already has some support I may hold off until I get the display and try playing with it.
 
You should have bought at least two :) Though E-Bay is cheaper. I wonder what color pin holder version you'll get? I only saw a black(?) one on Amazon.

Just re-read the henry's bench page and saw the link to the older sumotoy library - didn't read that close before.

Not sure when sumotoy will be back online - may you saw this post:
I had a surgical operation in July and still not 100% ok, I'm late with everithing, when I'm ok I will take care of all libraries, sorry but before I cannot even use keyboard!
to get back to his awesome work - but for optimal performance/options I think getting that code to work would help the OP know the options.
 
As you said - I might have saved about $1 They only had 1.

I may play some more. Hope Sumotoy is feeling better!
 
Not sure if to post here or over on SumoToys thread, or new thread.

But I built a version, with SPIN, that is defined for all the T3.x boards. In my Fork, I created a new branch based off of sumotoys T64-T66 branch (https://github.com/KurtE/TFT_ILI9163C/tree/SPIN-version), that so far at least compiles (at least bigtest) where I added reference to SPIN.h

WARNING: I have not run this at all, So no idea of how many places I missed or screwed up ;) My one display shipped last night, probably from China, and should get here within a week.

But if someone beats me to it who understands this stuff that would be great.

My comments on the commit:
This is a test version of this library, that uses my (KurtE) SPIN
library to remove some of the differences between SPI, SPI1, and SPI2 on
the new processor boards. A lot of this comes from my ILI9341_t3n
version of the Pauls fast version.

In this version, I use SPIN for all T3.x boards. SPin has in it code to
know which pins are valid for MOSI, MISO, SCK and I use that instead of
hard coding.

I added an optional SPIN object pointer to the constructor, so you can
directly say which SPI buss it is on (like my ILI.._t3n), but an
addition, I added some code that if the pins passed in are not valid on
the main SPIN object and SPIN1 and SPIN2, exists, (Update: and the
passed in pins are valid on one of those busses)
it updates to use
those objects instead.

Also like my ILI9341_t3n class, I default MOSI an SCK to pins 255 and
code checks if they are that, to not set the MOSI or SCK on the buss,
but just use the default (or current) ones.

Also code in place that allows the code to work if DC is on an hardware
CS pin for the proper buss, but the CS pin is not. Sumotoy already had
this for SPI1 case as there is only 1 valid one unless you use the
SDCard pins.

Warning: This compiles, but I have not yet tested as I don't have the
hardware. Should have a display hopefully within the week.
 
problems using SPIN1 on 3.6

Hi,

I'm trying to use SPIN1 with ILI9341_t3n on Teensy 3.6
ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, &SPIN1);

if I use &SPIN my screen works and I can communicate with my program via serial interface. If I use &SPIN1 monitor does not work and serial communication stops working. I use pins 7,8,14 for SPIN0 and 0,1,32 for SPIN1. Any suggestions? The most puzzling for me is the loss of serial communication.
 
If you don't need the ILI9163 (128x128) displays to run as fast as the main display, you might move them to i2c instead of spi. I've used dig-ole displays in the past, and their displays support i2c, spi, or serial uart programming depending on how you set a solder jumper. I've only used them via serial uart, but they do support i2c. Here is a link for their 128x128 TFT display: http://www.digole.com/index.php?productID=1215.

The programming for the display is higher level (draw line, draw circle, write text, etc.) and you don't need to buffer the contents of the display memory in the microprocessor memory.

Note, in hooking up i2c devices on the Teensy, you will need separate pull-up resistors between each of the SDA and SCL pins (18/19)
 
Last edited:
Hi,

I'm trying to use SPIN1 with ILI9341_t3n on Teensy 3.6
ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, &SPIN1);

if I use &SPIN my screen works and I can communicate with my program via serial interface. If I use &SPIN1 monitor does not work and serial communication stops working. I use pins 7,8,14 for SPIN0 and 0,1,32 for SPIN1. Any suggestions? The most puzzling for me is the loss of serial communication.
What pins are you using for CS and DC? At least DC needs to be valid hardware CS pin on the appropriate buss, preferably both, but only one valid CS channel on spi1 unless you use pins of Sdcard
 
What pins are you using for CS and DC? At least DC needs to be valid hardware CS pin on the appropriate buss, preferably both, but only one valid CS channel on spi1 unless you use pins of Sdcard

I use these pins for &SPIN1(TFT) : 21(mosi), 5(miso), 30(cs), 20(sck), 31(dc). With this configuration TFT works, but serial communication over USB port is broken. If I use
&SPIN(TFT) : 7(mosi), 8(miso), 10(cs), 14(sck), 9(dc) both TFT and USB serial communication works. I want to use SPI0 with spi4teensy3 to control peripherals, though. Originally I have tried &SPIN1(TFT) : 0(mosi), 1(miso), 30(cs), 32(sck), 31(dc), neither TFT nor USB communication works...
 
Hi leonid,

Not sure what is going on, that would cause USB not to work. If you have not already done so, you might sync up my libraries to the current updates (up on github\kurte).

There were some versions where I may(probably) had some versions which did Serial.print of some debug information. Hopefully that is turned off up on github.
 
Hi KurtE,

I uploaded the latest library and recompiled the code. TFT stopped working (was working with a few weeks older version), but USB serial still does not work. As soon as I declare SPIN and proper pins USB serial works. Why would of USB serial stop working if ILI9341_t3n is not properly initialized (which it should not according to your code if pins are incorrect)?
 
Could you upload example, so I can try tomorrow?

I attached a code which shows the problem. The attached file "ILI9341_t3.h" is needed for font library "ILI9341_fonts" to be properly compiled. When "DAC20_22-NOV-2016.ino" is compiled as is (&SPIN with 7(mosi),8(miso),10(cs),14(sck), 9(dc), a screen is updated to show some stuff, and a simple command in serial monitor "?\n" should generate a "DAC20-v2" response. Also white "?" is echoed on the TFT.

If I now switch to SPI1 pins in hardware and software
Code:
/*
#define TFT_DC      9   // 9 
#define TFT_CS      10  // 10
#define TFT_RST    255  // 255 = unused, connect to 3.3V
#define TFT_MOSI    7   // 11 || 7
#define TFT_MISO    8   // 12 || 8
#define TFT_SCLK    14  // 13 || 14
*/
#define TFT_DC      31 
#define TFT_CS      30
#define TFT_RST    255  // 255 = unused, connect to 3.3V
#define TFT_MOSI    21
#define TFT_MISO    15 
#define TFT_SCLK    20

and change &SPIN to &SPIN1 in
Code:
ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, &SPIN);

TFT is not initialized any more and there is no response to serial "?" command.

Thanks in advance for your help.
 

Attachments

  • DAC20_22-NOV-2016.ino
    8.6 KB · Views: 226
  • ILI9341_t3.h
    25 bytes · Views: 244
leonid: The problem is pin 15 is not a valid MISO pin for SPI1. Pins 1 and 5 are. Sometimes I think the library could be updated to still sort of work in this case. But some things would fail, like readPixel...

Anyway I also put updates in the ili9341_t3n library that if the begin fails, like it did to print out some information to help figure out why. Probably should change begin to a bool and return false, but probably no one would check anyway.

I did not actually put the display in this configuration yet, but at least USB works. The reason it probably did not, is because the SPI is not properly setup because of the error and probably some graphic function hung
 
leonid: The problem is pin 15 is not a valid MISO pin for SPI1. Pins 1 and 5 are. Sometimes I think the library could be updated to still sort of work in this case. But some things would fail, like readPixel...

Anyway I also put updates in the ili9341_t3n library that if the begin fails, like it did to print out some information to help figure out why. Probably should change begin to a bool and return false, but probably no one would check anyway.

I did not actually put the display in this configuration yet, but at least USB works. The reason it probably did not, is because the SPI is not properly setup because of the error and probably some graphic function hung

Thanks for checking it. MISO pin was 5 at the beginning of my tests and morphed into 15 some time later, that's where the screen stopped working... But serial comm did not work with SPI1 from the onset, I'll test it when come home. BTW, at the very beginning I tried 0,1,31,32 pins for SPI1 and it also stopped USB communication. Does USB uses RX1 & TX1?
 
No USB does not use any of the IO pins. My guess is when you saw this, the display was not initialized properly and so function probably just hung, and as such never got to your code that reads from the USB.

Update: Put in code, that if MOSI and SCK are valid, that the display operations will work. It leaves MISO to the default pin (or to current setting if called elsewhere)
It also traps calls, like readPixel, readRect and bails on those...

With this I have your program above working, except I commented out some include files and substituted fonts to Arial as to not need to install other font files.
 
Last edited:
Status
Not open for further replies.
Back
Top