Driving lots of TFT SPI screens at high speed - Page 1
Forum section: electronics / projects

author: DavidMenting
author_rank: Contributor
timestamp: August 26, 2014, 08:02:24 am
content: For a nice project I'm working on I'm attempting to drive a large(-ish) number of 2.2" TFT SPI screens.It's a second revision of this project:In the new revision we're running 16 screens on a Raspberry Pi via SPI.The 2.2" screens have an ili9341 driver IC on board. Communication with the screens is done via 3 wire SPI, plus an additional Reset and Data/Command line. I have been able to drive three screens hooked up directly to the Raspberry Pi's GPIO connector at a clock rate of 42MHz.I have no experience in dealing with high speed signals and large fanouts, so going from 3 to 16 screens is something I could use some advice on.The main question is: how do ensure the 42MHz SPI signals end up at the screens reliably?The Raspberry Pi is capable of driving 8mA and the ili1941 specifies 1µA input current, so drive strength should not be an issue.The screens will be positioned approx. 200mm from the Raspberry Pi. If I fan out directly from the Raspberry Pi that is 3.2m worth of cable, so I expect transmission line issues to come into play. What sort of cables and connectors should I use? How should I approach termination? And can I smartly apply buffers to mitigate the problem, for instance by splitting the 16 screens into blocks of 4 or daisy chaining?I have seen the iPod screen project by Mike and really liked his approach, but I'd like to steer clear of embedding a microcontroller with every screen. I have ordered a bunch of buffer logic IC's to experiment, but could use any expert advice.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 26, 2014, 08:41:51 am
content: There are a few approaches, but first ask yourself if it needs to run as fast as 42MHz. Slowing things down will make life easier. Ground inductance is probably your biggest problem.Only the clock and data need worrying about - as long as you leave sufficient settling time, CS and reset won't be an issue. If possible, try to live without readback if you can. If you really need it, e.g. for a ready signal, do readback at a slower clock rate.If you want something that will be robust and reasonably flexible in terms of length, I'd put the clock and data over LVDS, which would require a tx/rx pair per display, and should have plenty of margin.You could use multiple discrete LVDS drivers, but another option would be to use an FPGA, as it will probably have sufficient drivers in one chip. the coding would be trivial.With carefully chosen drivers and cabling, and a good ground (at least every other core in a ribbon cable, maybe an additional heavy core to reduce inductance) , you might just get away with single ended drivers (ACT+damping resistor), but at that frequency my gut feeling is it will be marginal as soon as you go over about 100mm.If this approach can be made to work then you can probably share drivers - e.g. one driver, with 4 seperate damping resistors to 4 displays.You may also be able to do a half-way solution using AC series Cmos to drive differential signals, and LVDS receivers at the far end.Take a look at the line driver section on TI's website to get an idea of what solutions & standards are out there - I'm sure there will be something useful.For a 1-off, your time is going to be worth more than parts cost, so if you can find a solution that's a good fit in terms of channel count and bandwidth, it would be better to go with that than fiddle around with cheapskate options.And obviously make sure your clock/data phasing is such that it gives you the maximum headroom for jitter.You definitely want to have relatively few displays per driver - if nothing else this makes it easier to test, so once you have one driver working with, say, 4 displays, you can have good confidence it will work on the full system as it is just more copies of the same setup.

author: DavidMenting
author_rank: Contributor
timestamp: August 26, 2014, 08:56:09 am
content: Quote from: mikeselectricstuff on August 26, 2014, 08:41:51 amThanks, Mike, for having a look. Slowing down the clock significantly is not an option. I'll be using a microcontroller to manage the chip selects so that every consecutive video frame from the Raspberry Pi ends up on the next screen. That means I need to get a fairly high framerate in order to update all sixteen screens in about a second or so.QuoteYup, I'm ignoring the MISO dataQuoteBased on your iPod Nano videos I ordered a MachXO dev board but soon realised I don't want to invest my time in learning a HDL.QuoteGood one, having four drivers for four displays each makes sense.Would a clock fanout buffer (for instance:http://www.ti.com/product/cdclvc1104) make life easier?

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 26, 2014, 09:19:52 am
content: QuoteAs I said, the coding is trivial - you would have to learn almost nothingThe main VHDL code would literally beclkout1<=clkin;datout1<=datin;clkout2<=clkin;datout2<=datin;etc.Of course if you wanted to get more into it you could also implement your CS steering in the FPGA as well petty easily.One reason that this could be a good solution is that the Lattice XO2 board is a ready-made solution that probably do the whole job at the transmit end without you needing to build a 1-off 4 layer PCB . You'd need to look at pinout details but you may literally be able to just plug 40 way ribbon cable connectors into the headers and split the cable up to each display.One annoyance is that the pinout on each connector is slightly different, but there are plenty of grounds.QuoteNot looked at that - you need to look at devices in the right frequency ballpark, and with a good permutations of channels per package to suit your numbers.My gut feeling would be to go straight to LVDS, as this is the most likely to "just work"

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 26, 2014, 10:48:11 am
content: Another thought - if the links to the LCDs can be PCBs rather than cables, you may have a better chance with a simple single-ended solution as you can have a nice well-controlled groundplane, and may even be able to do it without a receiver at the far end.

author: Kjelt
author_rank: Super Contributor
timestamp: August 26, 2014, 12:32:15 pm
content: Mike just a thought, since it is only a single product , would tiny coax cables with SMB connectors not also work or is that overkill?

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 26, 2014, 12:40:57 pm
content: Quote from: Kjelt on August 26, 2014, 12:32:15 pmoverkill - LVDS would be fine - we're only talking 200mm distance

author: nctnico
author_rank: Super Contributor
timestamp: August 26, 2014, 04:05:48 pm
content: Lets see if I understand: there are 16 displays with 20cm in between so the total length of the bus is 320cm?At 42MHz this is definitely transmission line territory. You could arrange a bus consisting of a clock pair and a data pair. You can have 2 lower frequency frame sync signals. One which indicates the data enable, the other one to tell the data should go to the next display. In that case each display should have a flipflop. The 'next display' signal is the clock for that flipflop, the data enable the input. This way the displays act as a shift register shifting the data enable from one display to another. You could use ethernet connectors and standard ethernet cables (easy to buy). If you use 6 wires for clock, data and frame syncs you have 2 wires left for ground. I'd use high speed RS485 drivers at 3.3V for this system. LVDS may not be tolerant enough for variations in ground level.One thing to look out for is impedance matching. Ethernet cable has a typical differential impedance of 100 Ohms. The PCB traces should therefore be layout as a differential pair as well. Also the length of stubs to the bus should be limited. Preferably 0. At the beginning and end of the bus the clock and data pairs must be terminated. It is a good idea to use AC termination to reduce current consumption.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 26, 2014, 04:12:07 pm
content: Quote from: nctnico on August 26, 2014, 04:05:48 pmLooking at the video, I was assuming it was a radial arrangement, with all the screens in a circle, at a similar distance from the controller.

author: zapta
author_rank: Super Contributor
timestamp: August 26, 2014, 04:21:55 pm
content: Will this help you?http://www.analog.com/static/imported-files/data_sheets/ADG738_739.pdf(you will need to drive only a few displays at a time, as you do now).BTW, very nice project.

author: DavidMenting
author_rank: Contributor
timestamp: August 26, 2014, 09:46:55 pm
content: Quote from: nctnico on August 26, 2014, 04:05:48 pmThe 16 screens are positioned in a circle approx. 300mm in diameter. If I would wire all screens point to point to the middle that would mean a total of 2.4m wire in 16 sections of 150mm, but that arrangement doesn't make sense.It's not yet determined how the bus has to run.Breaking it up into logical blocks of four would result in something like this:The line from the Raspberry Pi would fan out to 4 buffers, every line being around 100mm long. Every buffer then fans out to four screens. Seems doable with single-ended signaling, right?Another option would be to daisy chain all drivers. The wire to the first screen will be around 150mm long, with sections of ±40mm between screens:In that arrangement I would need to send the Reset and D/C signals through the buffers as well to account for propagation delay, which gives me fairly bulky connectors short cable runs.Hmm, so many options... How to choose?

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 26, 2014, 11:24:44 pm
content: Definitely the star arrangement - ensures all delays are similar, and also you can protoype one section and have good confidence the others will work.If using LVDS you need one buffer per display - single ended you can probably use one buffer, then 4 individual damping resistors to drive each bus. An advantage of single-ended is you can use the same buffers for the other signals. Probably worth prototyping this as it's simple and cheap, but make sure you have a good solid ground joining the ends - e.g. 20mm wide copper tape.

author: DavidMenting
author_rank: Contributor
timestamp: August 27, 2014, 11:59:03 am
content: Running all eight signals through an octal buffer sounds tempting. That makes life easier with routing as well. I'll try that first before going the LVDS route. Are the 74xx244 and 74xx541 3-state octal buffer/line driver the parts I should be looking at?You mention 4 individual damping resistors near the buffers. In a low-speed world the two schematics below would be the same (taking Rstvalues into account), but I guess things are different when the frequencies go up, right?

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 27, 2014, 12:13:23 pm
content: The point is you're damping each line - obviously the buffers and resistors are at the raspi end - you may also want some parallel termination at the far end. maybe use a HCT or ACT buffer run from 5V, so if you have equal series and parallel termination, the 2.5v resulting amplitude will be ok for what I assume will be 3.3v logic on the display.

author: nctnico
author_rank: Super Contributor
timestamp: August 27, 2014, 02:35:31 pm
content: With the short distances between the displays the star arrangement would allow to use a flexible PCB. If you use 0.5mm PCB material it is flexible enough to bend it. That way you could use right angle male/female headers to connect the boards. Needing 10 or more connections wouldn't be a problem. You may need to glue a 'stiffener' to the board where the components are but you could also use the frame for that purpose.

author: DavidMenting
author_rank: Contributor
timestamp: August 28, 2014, 09:20:29 pm
content: Flex PCB is nice, but is probably not needed. The TFT screens have an attached flat flex PCB that can be flipped to form a right angle connection. The TFT connectors will be directly soldered to the board as I haven't been able to find any 14 pin 0.8mm flat flex ZIF sockets in stock anywhere.My plan now is to create four PCBs each holding the octal buffer, the connectors for four TFTs and some passives for termination/decoupling like so (top view):Any thoughts on connectors I could use to connect the Raspberry Pi to the four boards? I'll have to make a little PCB to break out the Raspberry Pi's GPIO ports anyway, so might as well select a suitable connector right away. I'm looking at 8 signal lines plus power and ground(s).I've been reading up on routing high speed signals. Especially this application report by Ti onHigh Speed Layout Guidelineswas very informative.

author: nctnico
author_rank: Super Contributor
timestamp: August 28, 2014, 10:09:38 pm
content: How about standard ribbon/flatcable and 2.54mm headers? Or... how about making one PCB which accomodates both the displays and Raspberry pi board? A PCB with a diameter of 30cm is well within standard assembly size.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 28, 2014, 10:47:29 pm
content: You want the buffers waaaay closer to the pi than that. pi->buffer->long distance->tft

author: jmole
author_rank: Regular Contributor
timestamp: August 29, 2014, 03:26:50 am
content: Quote from: mikeselectricstuff on August 28, 2014, 10:47:29 pmyep. I've had no issues running ~30MHz single-ended, ground-terminated SPI-esque signals to 8 devices distributed over a meter using paralleled SN74LVC3G34 buffers (i.e. tie all inputs together, and all outputs together), and good termination resistors at the end of each line. For 90-100 ohms @ 3.3-5V, a 1206 will usually do. No need for source termination, as long as you've got a good ground plane, or you use a ribbon cable with GND/signal/GND/signal/etc.Another trick, if you're running the same clock (or any fast signal) to all devices, is to add a resistor equal to the line impedance between the transmission line and the device, as close to the transmission line as possible. This acts as a sort of low-pass filter at the inputs, reduces EMI from stubs going to devices, and improves noise margins.

author: DavidMenting
author_rank: Contributor
timestamp: August 29, 2014, 07:50:52 am
content: Quote from: nctnico on August 28, 2014, 10:09:38 pmI've been thinking about that as well, but having separate modules that can be tested separately are a great plus. Also, time and budget don't allow for a large PCB like that. If possible, I'd like to stay within the limits of the cheap Chinese PCB services (Seeed/Dirty/iTead) meaning several boards of < 15x5cm for instance.Quote from: mikeselectricstuff on August 28, 2014, 10:47:29 pmOuch, that means a far larger PCB or an extra set of buffers. pi -> buffer -> 100mm cable -> buffer -> 80mm pcb trace -> tftThe Pi seems happy to drive three of these screens paralleled through 150mm unterminated ribbon cable (each) at 42MHz though, which makes me think the output drivers of the Pi aren't that bad at all.Quote from: jmole on August 29, 2014, 03:26:50 amI'm still new to termination. With 'good termination resistors at the end of each line' you mean a 120? resistor from the input of the device to ground? Any advantage of doing that as opposed to source termination (as that is easier to route in my case)QuoteSo that would be buffer -> transmission line -> 120? resistor -> device input(I'm using 120? as an example value here)

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 29, 2014, 08:27:22 am
content: Quote from: DavidMenting on August 29, 2014, 07:50:52 amPCB at Pi end with buffers -> Ribbon cable. -> small PCBs with connectors at screen endQuoteDepending on the buffer, it's usually good to have a series resistor on the output to control edge rates - definitely put it on the PCB - you can always fit a 0R link.At the TFT end, allow for a resistor to ground.

author: bktemp
author_rank: Super Contributor
timestamp: August 29, 2014, 08:33:01 am
content: I would use simple approach:Some buffers right at the source to distribute both clock and data signals. A typical ribbon cable with data and gnd signales interleaved has an impedance of about 100 ohms. A series resistor of about 68 ohms at the driver matches the impedance to the cable and dampens the reflected signal. This works quite well for short cables up to about 100MHz even with no termination at the end.Since 42MHz is way out of spec for the ILI9341 the best solution would be an fpga to distribute the interleaved data to several displays and drive each at a much lower data rate.

author: jmole
author_rank: Regular Contributor
timestamp: August 30, 2014, 04:57:26 am
content: Is the same signal going to all TFTs? Or do you need daisy chain/variation?

author: DavidMenting
author_rank: Contributor
timestamp: August 30, 2014, 07:00:54 am
content: Quote from: jmole on August 30, 2014, 04:57:26 amYes, it's the same signal. The individual chip selects determine which screen shows what. The ili9341 has a built-in graphics buffer so the screen keeps displaying the same image until it receives a new one.Quote from: bktemp on August 29, 2014, 08:33:01 amI don't mind running stuff a bit faster than the specsHowever, looking into it it seems a clock cycle is specified to be at least 150ns = 6.6MHz max in the datasheet. I'm not the only one running them so far out of specs and have yet to find any negative effects of that.I'd like to steer clear of FPGA solutions as I have no experience with them. Also, I'd need a lot of buffer storage per frame: 320 x 240 x 16 bits = 1228800 bytes = 150kB.

author: nctnico
author_rank: Super Contributor
timestamp: August 30, 2014, 09:31:59 pm
content: Quote from: DavidMenting on August 29, 2014, 07:50:52 amIf you ask they are most probably able to make largers PCBs. I have not tried that myself but I know other members have had succes.

author: DavidMenting
author_rank: Contributor
timestamp: September 02, 2014, 12:37:22 pm
content: Thanks for all your thoughts so far. I'm going for the modular approach – I sent these puppies in for manufacturing today:The pads at the top connect to the 2.2" TFT. I've added a termination resistor on the SCL and SDI line and some power supply filtering. Now it's time wait for the boards to come in and to focus on the Raspberry Pi's end

author: jmole
author_rank: Regular Contributor
timestamp: September 03, 2014, 12:37:19 am
content: those termination resistors (ideally) need a much lower impedance path to ground. why not add a via between the resistors to the ground plane?Quote from: DavidMenting on September 02, 2014, 12:37:22 pm

author: DavidMenting
author_rank: Contributor
timestamp: September 03, 2014, 08:27:03 am
content: Quote from: jmole on September 03, 2014, 12:37:19 amGood one. I'll have to add that to a second revision, though.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: September 03, 2014, 08:44:06 am
content: Quote from: jmole on September 03, 2014, 12:37:19 amIt's a resistor. Any additional track resistance will just add a tiny fraction more resistance.

author: jmole
author_rank: Regular Contributor
timestamp: September 03, 2014, 12:35:33 pm
content: Quote from: mikeselectricstuff on September 03, 2014, 08:44:06 amyou've got more expertise than I on this, but it seems like the impedance to ground is what matters, not the resistance. It's a short trace, so the stray inductance there is likely pretty negligible, but I'd consider it good practice to terminate the ends of the resistor as close to the ground plane as possible. Seems especially important if you're doing single-ended termination without a resistor at the source, since the current being driven is much higher.

author: DanielS
author_rank: Frequent Contributor
timestamp: September 03, 2014, 01:09:07 pm
content: Quote from: mikeselectricstuff on September 03, 2014, 08:44:06 amAnd a few extra nH of inductance.To reduce the amount of power wasted in termination resistors when the I2C bus is idle, I would use RC termination instead.

author: DavidMenting
author_rank: Contributor
timestamp: September 15, 2014, 07:19:36 am
content: Quote from: DanielS on September 03, 2014, 01:09:07 pmWould that just be a matter of putting a capacitor (100pF?) in series with the resistor?

author: DavidMenting
author_rank: Contributor
timestamp: September 25, 2014, 08:16:15 am
content: Okay, I've taken the plunge and have gone for the Lattice FPGA/CPLD option. Luckily, I found someone who wanted to get me started with the tools and the basics of it.and...It's great!Thanks for the suggestion, Mike.The breakout boards have come in and seem to work perfectly. Here is a setup with six screens hooked up.The Lattice MachXO board splits the CLK, MOSI, RESET and D/C signals using the following Verilog code:Code:assign out_clk[7:0] = {8{spi_clk}} ;assign out_sdi[7:0] = {8{spi_mosi}} ;assign out_dc[7:0] = {8{tft_dc}} ;assign out_res[7:0] = {8{tft_reset}} ;I'm still working on the CS logic that switches to a different screen once an SPI transfer is completed.