Skip to content

Commit 3b24140

Browse files
authored
ili9325: add ILI9325 driver for 8-bit parallel displays (#926)
* ili9325: add ILI9325 driver for 8-bit parallel displays This adds a driver for the ILI9325 TFT controller on an 8-bit parallel bus, with an example for the ITead ITDB02-2.8 Arduino shield. * examples/ili9325: add Lorenz attractor example This adds an example that draws the Lorenz attractor on the ITead ITDB02-2.8 shield. * ili9325: keep WR pulses within the datasheet limits Review of #926 asked for ENTRY_MODE to be written once per rotation, for clearer errors and doc comments, and for a check of the WR pulse width against the ILI9325 AC characteristics. The datasheet V0.43 13.4.1 gives PWLW and PWHW 50 ns min. A DSLogic capture at 400 MS/s on an Arduino M0 at -opt=2 showed WR high of 25 ns between the two bytes of a pixel. WR low was in spec. At the default -opt=z each register store is a call, so the pulses were long only by accident. Inline asm padding gives the same minimum at every opt level. After the change the minimums are 58 ns low and 65 ns high. Traces: https://raw.githubusercontent.com/davecheney/tinygo/pr-assets/drivers926-wr-timing.png
1 parent fa29657 commit 3b24140

11 files changed

Lines changed: 650 additions & 0 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//go:build atsamd21
2+
3+
package main
4+
5+
import "tinygo.org/x/drivers/ili9325"
6+
7+
func newBus() ili9325.Bus {
8+
bus, err := ili9325.NewPortBus(data, wr)
9+
if err != nil {
10+
panic(err)
11+
}
12+
return bus
13+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//go:build !atsamd21
2+
3+
package main
4+
5+
import "tinygo.org/x/drivers/ili9325"
6+
7+
func newBus() ili9325.Bus {
8+
return ili9325.NewPinBus(data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], wr)
9+
}

‎examples/ili9325/itdb02/main.go‎

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Draws a test pattern on the ITead ITDB02-2.8 shield in landscape, with the
2+
// red square in the top left corner.
3+
package main
4+
5+
import (
6+
"image/color"
7+
"machine"
8+
"time"
9+
10+
"tinygo.org/x/drivers"
11+
"tinygo.org/x/drivers/ili9325"
12+
)
13+
14+
var (
15+
data = [8]machine.Pin{machine.D0, machine.D1, machine.D2, machine.D3, machine.D4, machine.D5, machine.D6, machine.D7}
16+
rs = machine.ADC5
17+
wr = machine.ADC4
18+
cs = machine.ADC3
19+
rst = machine.ADC2
20+
)
21+
22+
var (
23+
black = color.RGBA{0, 0, 0, 255}
24+
white = color.RGBA{255, 255, 255, 255}
25+
red = color.RGBA{255, 0, 0, 255}
26+
green = color.RGBA{0, 255, 0, 255}
27+
blue = color.RGBA{0, 0, 255, 255}
28+
)
29+
30+
func main() {
31+
out := machine.PinConfig{Mode: machine.PinOutput}
32+
for _, p := range append(data[:], rs, wr, cs, rst) {
33+
p.Configure(out)
34+
}
35+
36+
display := ili9325.New(newBus(), rs, cs, rst)
37+
display.Configure(ili9325.Config{Rotation: drivers.Rotation90})
38+
39+
w, h := display.Size()
40+
display.FillScreen(black)
41+
display.FillRectangle(0, 0, 40, 40, red)
42+
display.FillRectangle(w-40, 0, 40, 40, green)
43+
display.FillRectangle(0, h-40, 40, 40, blue)
44+
display.FillRectangle(w-40, h-40, 40, 40, white)
45+
46+
// Only redraw the strips that change, so the square doesn't flicker.
47+
x, y, dx := int16(40), h/2-20, int16(4)
48+
display.FillRectangle(x, y, 40, 40, green)
49+
for {
50+
if x+dx < 40 || x+dx > w-80 {
51+
dx = -dx
52+
}
53+
if dx > 0 {
54+
display.FillRectangle(x, y, dx, 40, black)
55+
display.FillRectangle(x+40, y, dx, 40, green)
56+
} else {
57+
display.FillRectangle(x+40+dx, y, -dx, 40, black)
58+
display.FillRectangle(x+dx, y, -dx, 40, green)
59+
}
60+
x += dx
61+
time.Sleep(10 * time.Millisecond)
62+
}
63+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//go:build atsamd21
2+
3+
package main
4+
5+
import "tinygo.org/x/drivers/ili9325"
6+
7+
func newBus() ili9325.Bus {
8+
bus, err := ili9325.NewPortBus(data, wr)
9+
if err != nil {
10+
panic(err)
11+
}
12+
return bus
13+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//go:build !atsamd21
2+
3+
package main
4+
5+
import "tinygo.org/x/drivers/ili9325"
6+
7+
func newBus() ili9325.Bus {
8+
return ili9325.NewPinBus(data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], wr)
9+
}

‎examples/ili9325/lorenz/main.go‎

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Draws the Lorenz attractor on the ITead ITDB02-2.8 shield. A 3000 point
2+
// trail traces the attractor while the view slowly rotates around the z axis.
3+
package main
4+
5+
import (
6+
"image/color"
7+
"machine"
8+
"math"
9+
10+
"tinygo.org/x/drivers"
11+
"tinygo.org/x/drivers/ili9325"
12+
)
13+
14+
var (
15+
data = [8]machine.Pin{machine.D0, machine.D1, machine.D2, machine.D3, machine.D4, machine.D5, machine.D6, machine.D7}
16+
rs = machine.ADC5
17+
wr = machine.ADC4
18+
cs = machine.ADC3
19+
rst = machine.ADC2
20+
)
21+
22+
const (
23+
trail = 3000
24+
sigma = 10
25+
rho = 28
26+
beta = 8.0 / 3
27+
dt = 0.006
28+
scale = 5.2
29+
)
30+
31+
var (
32+
black = color.RGBA{0, 0, 0, 255}
33+
palette [64]color.RGBA
34+
px, py [trail]int16
35+
)
36+
37+
func main() {
38+
out := machine.PinConfig{Mode: machine.PinOutput}
39+
for _, p := range append(data[:], rs, wr, cs, rst) {
40+
p.Configure(out)
41+
}
42+
43+
display := ili9325.New(newBus(), rs, cs, rst)
44+
display.Configure(ili9325.Config{Rotation: drivers.Rotation90})
45+
display.FillScreen(black)
46+
47+
for i := range palette {
48+
palette[i] = hue(float32(i) / float32(len(palette)))
49+
}
50+
for i := range px {
51+
px[i] = -1
52+
}
53+
54+
w, h := display.Size()
55+
cx, cy := float32(w/2), float32(h-6)
56+
x, y, z := float32(0.1), float32(0), float32(0)
57+
theta := float64(0)
58+
cos, sin := float32(1), float32(0)
59+
for i := 0; ; i++ {
60+
dx := sigma * (y - x)
61+
dy := x*(rho-z) - y
62+
dz := x*y - beta*z
63+
x += dx * dt
64+
y += dy * dt
65+
z += dz * dt
66+
67+
if i%64 == 0 {
68+
theta += 0.004
69+
cos, sin = float32(math.Cos(theta)), float32(math.Sin(theta))
70+
}
71+
sx := int16(cx + (x*cos-y*sin)*scale)
72+
sy := int16(cy - z*4.4)
73+
74+
j := i % trail
75+
if px[j] >= 0 {
76+
display.SetPixel(px[j], py[j], black)
77+
}
78+
zi := int(z * 1.3)
79+
if zi < 0 {
80+
zi = 0
81+
}
82+
display.SetPixel(sx, sy, palette[zi%len(palette)])
83+
px[j], py[j] = sx, sy
84+
}
85+
}
86+
87+
// hue returns a fully saturated colour for h in [0, 1).
88+
func hue(h float32) color.RGBA {
89+
h6 := h * 6
90+
f := h6 - float32(int(h6))
91+
up, down := uint8(255*f), uint8(255*(1-f))
92+
switch int(h6) % 6 {
93+
case 0:
94+
return color.RGBA{255, up, 0, 255}
95+
case 1:
96+
return color.RGBA{down, 255, 0, 255}
97+
case 2:
98+
return color.RGBA{0, 255, up, 255}
99+
case 3:
100+
return color.RGBA{0, down, 255, 255}
101+
case 4:
102+
return color.RGBA{up, 0, 255, 255}
103+
default:
104+
return color.RGBA{255, 0, down, 255}
105+
}
106+
}

0 commit comments

Comments
 (0)