-
Notifications
You must be signed in to change notification settings - Fork 495
SPI interface circuit
Work in progress...
This is an interface circuit for connecting a parallel interface LCD display with SPI.
The circuit is based on SpriteMods circuit.
74HC4094
+--------------+
| |
MOSI o-------------------------------------------------------| D QP0 |-------------o DB0
| |
SCLK o---------+---------------------------------------------| CP QP1 |-------------o DB1
| | |
CSn o------+ | Vcc o---| OE QP2 |-------------o DB2
| | | |
| | 74HC4040 | QP3 |-------------o DB3
| | +--------------+ | |
| | | | | QP4 |-------------o DB4
| | | Q0 |-- | |
| | | | | QP5 |-------------o DB5
| | | Q1 |-- | |
| | | | | QP6 |-------------o DB6
| | | Q2 |-------------+-----------| STR |
| | | | | | QP7 |-------------o DB7
| | | Q3 |-- | | |
| | | | | | |
| | | Q4 |-- | | QS1 |--
| | | | | | |
| | | Q5 |-- | | QS2 |--
| +----| CP | | | |
| | Q6 |-- | +--------------+
+-------| MR | |
| | Q7 |-- |
| | | | 74HC04
| | Q8 |-- +-----------------|>o--------------------o WR
| | |
| | Q9 |-- Vcc o--o RD
| | |
| | Q10 |--
| | |
| | Q11 |--
| | |
| +--------------+
|
|
+-----------------------------------------------------------------------------o CS
This is an analysis of the circuits timing constraints.
Constraints is examined for a SPI speed of 32 MHz.
See appendix for details about the 3.3 V values.
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, but fails the minimum values.
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
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
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--+
The circuit is tested with this display. 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
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
- 74HC4040 12-stage binary ripple counter
- 74HC4094 8-stage shift-and-store bus register
- 74HC04 Hex inverter
I used this script to sort out some miswiring. Must be run as root.
import os
import time
import subprocess
# put a backslash before 007. Markdown messes it up.
def beep():
if subprocess.call(["echo", "-ne", "007"]) != 0:
raise OSError
def writef(file, val):
# print "%s <- %s" % (file, val)
with open(file, 'w') as f: f.write(val)
class GPIO:
def __init__(self, num):
self.num = num
self.val = 0
writef("/sys/class/gpio/export", "%s" % num)
writef("/sys/class/gpio/gpio%s/direction" % num, "out")
def close(self):
writef("/sys/class/gpio/gpio%s/direction" % self.num, "in")
writef("/sys/class/gpio/unexport", "%s" % 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):
beep()
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):
self.sclk = GPIO(sclk_gpio)
self.mosi = GPIO(mosi_gpio)
self.ce = GPIO(ce_gpio)
self.ce.set(1)
self.sclk.set(0)
self.mosi.set(0)
def close(self):
self.sclk.close()
self.mosi.close()
self.ce.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):
for i in range(8):
spi.clock( (byte << i) & 0b10000000 )
# echo "11" > /sys/class/gpio/unexport; echo "10" > /sys/class/gpio/unexport; echo "8" > /sys/class/gpio/unexport
SCLK = 11
MOSI = 10
CE0 = 8
value = 0b11001101
count = 0
# Setup
value &= 0xFF
spi = SPI(SCLK, MOSI, CE0)
# Clear contents of shift register
spi.write(0)
print("\nPress ENTER on each step to proceed\nOnly changing signals is shown")
print("\nByte to transfer: %s" % bin(value))
# Start Transmit
print("\n => SCLK = 0, MOSI = 0, CS=1")
print("\n => 74HC4040 Q2 = 0\n")
raw_input("Initiate transfer by lowering CE(CS)")
spi.start()
print("\n => CS=0\n")
raw_input("Set MOSI=1 and take SCLK HIGH")
bit = (value << count) & 0b10000000
spi.mosi.set(bit)
count += 1
spi.sclk.set(1)
print("\n => SCLK=1, MOSI=1\n")
raw_input("Take SCLK LOW")
spi.sclk.set(0)
print("\n => SCLK=0\n")
for i in range(3):
bit = (value << count) & 0b10000000
if bit: bit = 1
count += 1
raw_input("Clock out bit: %i" % bit)
spi.clock(bit)
print("\n => 74HC4040 Q2 = 1 => 74HC4094 STR = 1 => Shift register content is available on the outputs")
print(" => 74HC04 1A = 1 => WR = 0 => Display ready to receive data\n")
for i in range(4):
bit = (value << count) & 0b10000000
if bit: bit = 1
count += 1
raw_input("Clock out bit: %i" % bit)
spi.clock(bit)
print("\n => 74HC4040 Q2 = 0 => 74HC4094 STR = 0 => Shift register outputs is frozen (latched)")
print(" => 74HC04 1A = 0 => WR = 1 => Data latched in\n")
raw_input("Stop transfer by raising CE")
spi.end()
print("\n => CS=1\n")
raw_input("Release GPIOs")
spi.close()
print("\n => All pins floating\n")