SPI interface circuit - notro/fbtft GitHub Wiki

This is an interface circuit for connecting a parallel interface LCD display with SPI.

The circuit is based on SpriteMods circuit.

Alternative interface circuit: Guzunty
Variation for the HX8352-a: Proposal for modified SPI interface circuit to support HX8352-a based 3.2" TFT
masoudr powers the chips with 5V instead of 3.3V as I have done. This enables him to use DMA.

8-bit bus
Connect STR to Q2
Skip second 74HC4094

16-bit bus
Connect STR to Q3

                                                                 74HC4094
                                                               +--------------+
                                                               |              |
  MOSI o-------------------------------------------------------| D        QP0 |-------------o DB0
                                                               |              |
  SCLK o---------+-----------------------------------+---------| CP       QP1 |-------------o DB1
                 |                                   |         |              |
   CE0 o------+  |                                   | Vcc o---| OE       QP2 |-------------o DB2
              |  |                                   |         |              |
              |  |      74HC4040                     |         |          QP3 |-------------o DB3
              |  |    +--------------+               |         |              |
              |  |    |              |               |         |          QP4 |-------------o DB4
              |  |    |           Q0 |--             |         |              |
              |  |    |              |               |         |          QP5 |-------------o DB5
              |  |    |           Q1 |--             |         |              |
              |  |    |              |               |         |          QP6 |-------------o DB6
              |  |    |           Q2 |-  8bit  --+---|---------| STR          |
              |  |    |              |           |   |         |          QP7 |-------------o DB7
              |  |    |           Q3 |- 16bit  --+   |         |              |
              |  |    |              |           |   |         |              |
              |  |    |           Q4 |--         |   |         |          QS1 |-----+
              |  |    |              |           |   |         |              |     |
              |  |    |           Q5 |--         |   |         |          QS2 |--   |
              |  +----| CP           |           |   |         |              |     |
              |       |           Q6 |--         |   |         +--------------+     |
              +-------| MR           |           |   |                              |
              |       |           Q7 |--         |   |   +--------------------------+
              |       |              |           |   |   |     
              |       |           Q8 |--         |   |   |       74HC4094
              |       |              |           |   |   |     +--------------+
              |       |           Q9 |--         |   |   |     |              |
              |       |              |           |   |   +-----| D        QP0 |-------------o DB8
              |       |          Q10 |--         |   |         |              |
              |       |              |           |   +---------| CP       QP1 |-------------o DB9
              |       |          Q11 |--         |             |              |
              |       |              |           |     Vcc o---| OE       QP2 |-------------o DB10
              |       +--------------+           |             |              |
              |                                  |             |          QP3 |-------------o DB11
              |                                  |             |              |
              |                                  |             |          QP4 |-------------o DB12
              |                                  |             |              |
              |                                  |             |          QP5 |-------------o DB13
              |                                  |             |              |
              |                                  |             |          QP6 |-------------o DB14
              |                                  +-------------| STR          |
              |                                  |             |          QP7 |-------------o DB15
              |                                  |             |              |
              |                                  |             |              |
              |                                  |             |          QS1 |--
              |                                  |             |              |
              |                                  |             |          QS2 |--
              |                                  |             |              |
              |                                  |             +--------------+
              |                                  |
              |                                  |                 74HC04
              |                                  +-------------------|>o--------------------o WR
              |                                                                                 
              |                                                                      Vcc o--o RD
              |
              +-----------------------------------------------------------------------------o CS

  'dc' o------------------------------------------------------------------------------------o DC/RS

Timing analysis

This is an analysis of the circuits timing constraints (8-bit bus).

Constraints is examined for a SPI speed of 32 MHz.

See appendix for details about the 3.3 V values.

Clock (SPI)

These are connected to the SPI clock:

IC          Symbol         Parameter                        Conditions                 Min  Typ  Max  Unit
-----------------------------------------------------------------------------------------------------------
RPi                         SPI speed                        VCC = 3.3 V                     32        MHz
74HC4040     fmax           maximum operating frequency      VCC = 3.3 V                20   55   -    MHz
74HC4094     fmax           maximum frequency                VCC = 3.3 V                20   58   -    MHz

32 MHz falls within the typical values, and exceeds the minimum values.

STR (74HC4094)

The 74HC4094 clocks in data on the rising edge of the clock.
The 74HC4040 counts on the falling edge of the clock.

On the 4th clock cycle: SCLK goes LOW -> 74HC4040 Q2 goes HIGH -> 74HC4094 STR goes HIGH -> shift register data goes to the outputs.
On the 8th clock cycle: SCLK goes LOW -> 74HC4040 Q2 goes LOW -> 74HC4094 STR goes LOW -> outputs are locked (latched).
If STR is HIGH, QPn changes when CP goes HIGH.

IC          Symbol         Parameter                        Conditions                 Min  Typ  Max  Unit
----------------------------------------------------------------------------------------------------------
RPi          twl            pulse width LOW                  32 MHz                          16        ns
74HC4094     tpd            propagation delay CP to QPn      VCC = 3.3 V                -    34   58   ns
74HC4040     tPHL, tPLH     propagation delay CP to Q0       VCC = 3.3 V                -    25   45   ns

Constraint
STR must go LOW before new data enters into the shift register: RPi twl + 74HC4094 tpd > 74HC4040 ttPHL
Typ: 16 + 34 > 25
Worst case: 16 + 34 > 45

WR (LCD)

Data is latched in on the rising edge of /WR.

After 4 clock cycles: STR goes HIGH -> 74HC04 nA goes HIGH -> 74HC04 nY goes LOW -> /WR goes LOW
After 8 clock cycles: STR goes LOW -> 74HC04 nA goes LOW -> 74HC04 nY goes HIGH -> /WR goes HIGH -> data latches in

SSD1289
-------
Symbol   Parameter                               Min  Typ  Max  Unit
---------------------------------------------------------------------------------------
 tcycle   Clock Cycle Time (write cycle)         100   -    -    ns
 PWL      Pulse Width low (write cycle)           50   -    -    ns
 PWH      Pulse Width high (write cycle)          50   -    -    ns
 tDSW     Data Setup Time                          5   -    -    ns
 tDHW     Data Hold Time                           5   -    -    ns

ILI9325
-------
  18.3.1 Display Parallel 18/16/9/8-bit Interface Timing Characteristics (8080-I system)
Symbol   Parameter                               Min  Typ  Max  Unit
---------------------------------------------------------------------------------------
 twc      Write cycle                             66        -    ns
 twrl     Write Control pulse L duration          15        -    ns
 twrh     Write Control pulse H duration          15        -    ns
 tdst     Write data setup time                   10        -    ns
 tdht     Write data hold time                    10        -    ns

IC          Symbol         Parameter                        Conditions                 Min  Typ  Max  Unit
----------------------------------------------------------------------------------------------------------
74HC04       tpd            propagation delay                VCC = 3.3 V                -    13   25   ns

Constraints
Pulse Width Low and Pulse Width High is both 4 clock cycles long: 4 x SPI speed > 50 ns => SPI speed < 80 MHz
Data Setup Time is the time from the last bit is clocked in and available on the outputs, and to /WR goes HIGH: the 74HC04 inverter propagation delay is enough to satisify this.
Data Hold Time is the time from /WR is HIGH to data can change on the bus: this is 4 clock cycles since STR is LOW for so long: 4x32 > 10ns

Backlight

There is 5 inverters left in the 74HC04 Hex Inverter IC. These can be used to drive a LCD backlight.

  • Backlight pulled to +3.3V. It can deliver 4x25mA = 100mA
  • Backlight pulled to GND. Remove the first inverter and put it in parallel. It can sink 5x20mA = 100mA
  led o-----|>o----+--|>o--+-----o LCD backlight
                   |       |
                   +--|>o--+
                   |       |
                   +--|>o--+
                   |       |
                   +--|>o--+

I tried this on the ITDB02-2.8 display, and it seemed to work fine (I really didn't try to connect it directly to +3.3V).
But on the Sainsmart 3.2 display, this circuit gave a rather dim backlight, compared to +3.3V wired. The backlight draws 46mA at 3.3V, but this circuit delivers only 18mA. I haven't had the time to check if I have a miswiring, or if this is all I can get from this setup.

ITDB02-2.8

The circuit is tested with this display (8-bit). I get ~17fps at 32MHz (parallel ~25 fps).
I haven't updated the itdb28fb driver to support SPI yet, so I use flexfb for now

modprobe fbtft_device name=flexfb gpios=reset:25,dc:24,led:18

modprobe flexfb debug=3 rotate=0 width=240 height=320 regwidth=16 setaddrwin=1 init=-1,0x00E3,0x3008,-1,0x00E7,0x0012,-1,0x00EF,0x1231,-1,0x0001,0x0100,-1,0x0002,0x0700,-1,0x0003,0x1030,-1,0x0004,0x0000,-1,0x0008,0x0207,-1,0x0009,0x0000,-1,0x000A,0x0000,-1,0x000C,0x0000,-1,0x000D,0x0000,-1,0x000F,0x0000,-1,0x0010,0x0000,-1,0x0011,0x0007,-1,0x0012,0x0000,-1,0x0013,0x0000,-2,200,-1,0x0010,0x1690,-1,0x0011,0x0223,-2,50,-1,0x0012,0x000D,-2,50,-1,0x0013,0x1200,-1,0x0029,0x000A,-1,0x002B,0x000C,-2,50,-1,0x0020,0x0000,-1,0x0021,0x0000,-1,0x0030,0x0000,-1,0x0031,0x0506,-1,0x0032,0x0104,-1,0x0035,0x0207,-1,0x0036,0x000F,-1,0x0037,0x0306,-1,0x0038,0x0102,-1,0x0039,0x0707,-1,0x003C,0x0702,-1,0x003D,0x1604,-1,0x0050,0x0000,-1,0x0051,0x00EF,-1,0x0052,0x0000,-1,0x0053,0x013F,-1,0x0060,0xA700,-1,0x0061,0x0001,-1,0x006A,0x0000,-1,0x0080,0x0000,-1,0x0081,0x0000,-1,0x0082,0x0000,-1,0x0083,0x0000,-1,0x0084,0x0000,-1,0x0085,0x0000,-1,0x0090,0x0010,-1,0x0092,0x0600,-1,0x0007,0x0133,-3

Sainsmart 3.2

The circuit is tested with this display (16-bit). I get ~10fps at 16MHz (32MHz didn't work).

modprobe fbtft_device name=flexfb speed=16000000 gpios=reset:25,dc:24

modprobe flexfb debug=3 width=240 height=320 rotate=0 regwidth=16 setaddrwin=2 init=-1,0x00,0x0001,-1,0x03,0xa2a4,-1,0x0c,0x0004,-1,0x0d,0x0308,-1,0x0e,0x3000,-1,0x1e,0x00ea,-1,0x01,0x2b3f,-1,0x02,0x0600,-1,0x10,0x0000,-1,0x11,0x6030,-1,0x07,0x0233,-1,0x0b,0x0039,-1,0x0f,0x0000,-1,0x03,0x0707,-1,0x31,0x0204,-1,0x32,0x0204,-1,0x33,0x0502,-1,0x34,0x0507,-1,0x35,0x0204,-1,0x36,0x0204,-1,0x37,0x0502,-1,0x3a,0x0302,-1,0x3b,0x0302,-1,0x23,0x0000,-1,0x24,0x0000,-1,0x25,0xa000,-1,0x48,0x0000,-1,0x49,319,-1,0x4a,0x0000,-1,0x4b,0x0000,-1,0x41,0x0000,-1,0x42,0x0000,-1,0x44,0xef00,-1,0x45,0x0000,-1,0x46,319,-3

Appendix

Dynamic charateristics

The datasheets doesn't mention values with a 3.3V supply voltage.
In the 74HC User guide theres is a graph: Fig. 7 Propagation delay as a function of supply voltage; Tamb = 25 °C; CL = 50 pF
From this we can find that: VCC = 3.3V gives a factor of ~1.5 relative to 4.5V which is 1

Excerpts

74HC4040
--------
Symbol  Parameter                      Conditions                 Min  Typ  Max  Unit
 fmax    maximum operating frequency    VCC = 2.0 V; CL= 50 pF      6   27   -    MHz
                                        VCC = 4.5 V; CL= 50 pF     30   82   -    MHz
                    Using factor 1.5    VCC = 3.3 V;               20   55   -    MHz



Symbol        Parameter                      Conditions                 Min  Typ  Max  Unit
 tPHL, tPLH    propagation delay CP to Q0     VCC = 2.0 V; CL = 50 pF    -    47  150   ns
                                              VCC = 4.5 V; CL = 50 pF    -    17   30   ns
                          using factor 1.5    VCC = 3.3 V                -    25   45   ns

               propagation delay Qn to Qn+1   VCC = 2.0 V; CL = 50 pF    -    28  100   ns
                                              VCC = 4.5 V; CL = 50 pF    -    10   20   ns
                          using factor 1.5    VCC = 3.3 V                -    15   30   ns



74HC4094
--------
Symbol  Parameter                      Conditions                 Min  Typ  Max  Unit
 tpd     propagation delay CP to QPn    VCC = 2.0 V                -    63  195   ns
                                        VCC = 4.5 V                -    23   39   ns
                   using factor 1.5     VCC = 3.3 V                -    34   58   ns

 fmax    maximum frequency              CP
                                        VCC = 2.0 V                 6   28   -    MHz
                                        VCC = 4.5 V                30   87   -    MHz
                   using factor 1.5     VCC = 3.3 V                20   58   -    MHz

74HC04
------
Symbol  Parameter                      Conditions                 Min  Typ  Max  Unit
 tpd     propagation delay nA to nY     VCC = 2.0 V                -   25    85   ns
                                        VCC = 4.5 V                -    9    17   ns
                   using factor 1.5     VCC = 3.3 V                -   13    25   ns

Datasheets

Test script

I used this script to sort out some miswiring. Must be run as root.
Connect a probe wire to GPIO22. This will be used to test the different signals.
Bug:
The script uses the SPI bus lines as GPIOs. The SPI controller driver spi-bcm2708 stops working because of this.
A reload of the driver didn't solve it for me. A reboot was required.

It is also possible to test with: echo -ne "\xff\x00" > /dev/spidev0.0

import os
import time
import subprocess
import array
import sys

PROBE_GPIO = 22

SCLK_GPIO = 11
MOSI_GPIO = 10
CE0_GPIO = 8


def writef(file, val):
#	print "%s <- %s" % (file, val)
	with open(file, 'w') as f: f.write(val)

def readf(file):
#	print "%s <- %s" % (file, val)
	with open(file, 'r') as f: ret = f.read()
	return ret

class GPIO:
	def __init__(self, num, dir='out'):
		self.num = num
		self.val = 0
		writef("/sys/class/gpio/export", "%s" % num)
		writef("/sys/class/gpio/gpio%s/direction" % num, dir)

	def close(self):
		writef("/sys/class/gpio/gpio%s/direction" % self.num, "in")
		writef("/sys/class/gpio/unexport", "%s" % self.num)

	def get(self):
		return int(readf("/sys/class/gpio/gpio%s/value" % self.num))

	def set(self, val=1):
		if val == 0:
			self.val = 0
		else:
			self.val = 1
		writef("/sys/class/gpio/gpio%s/value" % self.num, "%s" % self.val)
		return self.val

	def clear(self):
		self.set(0)

	def pulse(self):
		if (self.val):
			self.set(0)
			time.sleep(1)
			self.set(1)
		else:
			self.set(1)
			time.sleep(1)
			self.set(0)


class SPI:
	def __init__(self, sclk_gpio, mosi_gpio, ce_gpio, probe_gpio):
		self.sclk = GPIO(sclk_gpio)
		self.mosi = GPIO(mosi_gpio)
		self.ce = GPIO(ce_gpio)
		self.probe = GPIO(probe_gpio, 'in')
		self.ce.set(1)
		self.sclk.set(0)
		self.mosi.set(0)

	def __enter__(self):
		return self

	def __exit__(self, type, value, trace):
		self.close()

	def close(self):
		self.sclk.close()
		self.mosi.close()
		self.ce.close()
		self.probe.close()

	def start(self):
		self.ce.set(0)

	def end(self):
		self.ce.set(1)

	def clock(self, value):
#		print("value: %i" % value)
		ret = self.mosi.set(value)
		self.sclk.set(1)
#		time.sleep(1)
		self.sclk.set(0)
#		time.sleep(1)
		return ret

	def write(self, byte):
#		print "spi.write %s" % bin(byte).ljust(10, '0')
		for i in range(8):
			self.clock( (byte << i) & 0b10000000 )

	def write_buf(self, buf):
#		sys.stdout.write("spi.write_buf: ")
		for byte in buf:
#			sys.stdout.write("%s " % bin(byte).split('b')[1].rjust(8, '0'))
			for i in range(8):
				self.clock( (byte << i) & 0b10000000 )
#		print("")

def test_db(spi, bits):
	found = 0
	first_bit_set = -1
	for i in range(bits):
		val = (1 << i)
		if bits == 16:
			# Write Big Endian
			spi.write_buf( [(val >> 8) & 0xFF, val & 0xFF] )
		else:
			spi.write_buf( [val & 0xFF] )
		if spi.probe.get():
			if first_bit_set == -1:
				first_bit_set = i
#			print "D%i\n" % i
			found += 1
	if found == 0:
		print "No signal found\n"
	elif found > 1:
		print "Multiple bits set\n"

	return first_bit_set

def databus_test():
	global db_width

	print "\nDatabus test"
	print "------------\n"

	with SPI(SCLK_GPIO, MOSI_GPIO, CE0_GPIO, PROBE_GPIO) as spi:
		spi.start()
		for i in range(db_width):
			raw_input("D%i" % i)
			bit = test_db(spi, db_width)
			if bit != i:
				print "Error: Signal is found on D%i\n" % bit

		spi.end()

def rd_test():
	print "\nRD test"
	print "-------\n"

	with SPI(SCLK_GPIO, MOSI_GPIO, CE0_GPIO, PROBE_GPIO) as spi:
		raw_input("RD")
		if not spi.probe.get():
			print("Error: RD should be 1\n")

def clock_pulse_test_wr(spi, wanted_value, start, pulses):
	for i in range(start, start+pulses):
		spi.clock(0)
		if not (spi.probe.get() == wanted_value):
			print("Error: WR should be %i after clockpulse %i\n" % (wanted_value, i))

def wr_test():
	global db_width

	print "\nWR test"
	print "-------\n"

	with SPI(SCLK_GPIO, MOSI_GPIO, CE0_GPIO, PROBE_GPIO) as spi:
		raw_input("WR")
		if not spi.probe.get():
			print("Error: WR should be 1\n")
		spi.start()
		if db_width == 16:
			clock_pulse_test_wr(spi, wanted_value=1, start=0, pulses=7)
			clock_pulse_test_wr(spi, wanted_value=0, start=8, pulses=8)
			clock_pulse_test_wr(spi, wanted_value=1, start=16, pulses=1)
		else:
			clock_pulse_test_wr(spi, wanted_value=1, start=0, pulses=3)
			clock_pulse_test_wr(spi, wanted_value=0, start=4, pulses=4)
			clock_pulse_test_wr(spi, wanted_value=1, start=8, pulses=1)
		spi.end()
		# Aborted transfer
		spi.start()
		for i in range(db_width//2):
			spi.clock(0)
		if spi.probe.get():
			print("Error: WR should be 0 after clockpulse %i\n" % (db_width//2))
		spi.end()
		if not spi.probe.get():
			print("Error: WR should be 1 after aborted transfer\n")

def cs_test():
	print "\nCS test"
	print "-------\n"

	with SPI(SCLK_GPIO, MOSI_GPIO, CE0_GPIO, PROBE_GPIO) as spi:
		raw_input("CS")
		if not spi.probe.get():
			print("Error: CS should be HIGH before transfer\n")
		spi.start()
		if spi.probe.get():
			print("Error: CS should be LOW during transfer\n")
		spi.end()

def signal_test(spi, name, gpio):
	raw_input(name)
	gpio.set(0)
	if spi.probe.get():
		print("Error: %s can't be set LOW\n" % name)
	gpio.set(1)
	if not spi.probe.get():
		print("Error: %s can't be set HIGH\n" % name)

def spi_test():
	print "\nSPI test"
	print "-------\n"

	with SPI(SCLK_GPIO, MOSI_GPIO, CE0_GPIO, PROBE_GPIO) as spi:
		signal_test(spi, "SCLK", spi.sclk)
		signal_test(spi, "MOSI", spi.mosi)
		signal_test(spi, "CE", spi.ce)



def menu():
	print("  0. Run all interface tests")
	print("  1.   Databus test")
	print("  2.   WR test")
	print("  3.   RD test")
	print("  4.   CS test")
	print("  5. SPI test")
	print("  x. Quit")
	print("")
	t = raw_input("  Choice [0] ")

	if t== "x":
		return -1
	if t== "":
		return 0
	else:
		try:
			t = int(t)
		except ValueError:
			print("%r is not known" % t)
			return -1
	return t


def main(argv):
	global db_width
	value = 0b11001101
	
	count = 0

	print("\nTests for SPI to LCD interface circuit https://github.com/notro/fbtft/wiki/SPI-interface-circuit\n")

	print "Probe gpio: %i" % PROBE_GPIO
	print "Move probe to the specified signal pin and press Enter\n\n"

	input = raw_input("Databus width [16] ")
	if input == "":
		input = "16"
	try:
		db_width = int(input)
	except ValueError:
		db_width = 0

	if not db_width in [8,16]:
		print("Error: Only 8 and 16 supported")
		return

	t = menu()
	if t == -1:
		quit()
	if t == 0:
		databus_test()
		wr_test()
		rd_test()
		cs_test()
	elif t == 1:
		databus_test()
	elif t == 2:
		wr_test()
	elif t == 3:
		rd_test()
	elif t == 4:
		cs_test()
	elif t == 5:
		spi_test()
	else:
		print("No such test")

	

if __name__ == '__main__':
	try:
		main(sys.argv[1:])
	except KeyboardInterrupt:
		print("")

piwik