Files
Nick Craig-Wood a53a39922b hd44780: add a mode to work with boards where the RW pin is grounded
On some HD44780 boards (eg the Keyestudio LCD1602 expansion shield),
the RW pin isn't brought out and is permanently grounded.

This means that the board can't be read from, and in particular the
busy status can't be read.

This patch adapts the package to work with boards like these.

To signal this to the package, set the RW pin to machine.NoPin.

The package will then disallow all reading and use adjustable timing
based writing. The timing can be adjusted the configuration.
2021-03-26 18:03:15 +01:00

158 lines
3.1 KiB
Go

package hd44780
import (
"errors"
"machine"
)
type GPIO struct {
dataPins []machine.Pin
en machine.Pin
rw machine.Pin
rs machine.Pin
write func(data byte)
read func() byte
}
func newGPIO(dataPins []machine.Pin, en, rs, rw machine.Pin, mode byte) Device {
pins := make([]machine.Pin, len(dataPins))
for i := 0; i < len(dataPins); i++ {
dataPins[i].Configure(machine.PinConfig{Mode: machine.PinOutput})
pins[i] = dataPins[i]
}
en.Configure(machine.PinConfig{Mode: machine.PinOutput})
rs.Configure(machine.PinConfig{Mode: machine.PinOutput})
rw.Configure(machine.PinConfig{Mode: machine.PinOutput})
rw.Low()
gpio := GPIO{
dataPins: pins,
en: en,
rs: rs,
rw: rw,
}
if mode == DATA_LENGTH_4BIT {
gpio.write = gpio.write4BitMode
gpio.read = gpio.read4BitMode
} else {
gpio.write = gpio.write8BitMode
gpio.read = gpio.read8BitMode
}
return Device{
bus: &gpio,
datalength: mode,
}
}
// SetCommandMode sets command/instruction mode
func (g *GPIO) SetCommandMode(set bool) {
if set {
g.rs.Low()
} else {
g.rs.High()
}
}
// WriteOnly is true if you passed rw in as machine.NoPin
func (g *GPIO) WriteOnly() bool {
return g.rw == machine.NoPin
}
// Write writes len(data) bytes from data to display driver
func (g *GPIO) Write(data []byte) (n int, err error) {
if !g.WriteOnly() {
g.rw.Low()
}
for _, d := range data {
g.write(d)
n++
}
return n, nil
}
func (g *GPIO) write8BitMode(data byte) {
g.en.High()
g.setPins(data)
g.en.Low()
}
func (g *GPIO) write4BitMode(data byte) {
g.en.High()
g.setPins(data >> 4)
g.en.Low()
g.en.High()
g.setPins(data)
g.en.Low()
}
// Read reads len(data) bytes from display RAM to data starting from RAM address counter position
// Ram address can be changed by writing address in command mode
func (g *GPIO) Read(data []byte) (n int, err error) {
if len(data) == 0 {
return 0, errors.New("length greater than 0 is required")
}
if g.WriteOnly() {
return 0, errors.New("Read not supported if RW not wired")
}
g.rw.High()
g.reconfigureGPIOMode(machine.PinInput)
for i := 0; i < len(data); i++ {
data[i] = g.read()
n++
}
g.reconfigureGPIOMode(machine.PinInput)
return n, nil
}
func (g *GPIO) read4BitMode() byte {
g.en.High()
data := (g.pins() << 4 & 0xF0)
g.en.Low()
g.en.High()
data |= (g.pins() & 0x0F)
g.en.Low()
return data
}
func (g *GPIO) read8BitMode() byte {
g.en.High()
data := g.pins()
g.en.Low()
return data
}
func (g *GPIO) reconfigureGPIOMode(mode machine.PinMode) {
for i := 0; i < len(g.dataPins); i++ {
g.dataPins[i].Configure(machine.PinConfig{Mode: mode})
}
}
// setPins sets high or low state on all data pins depending on data
func (g *GPIO) setPins(data byte) {
mask := byte(1)
for i := 0; i < len(g.dataPins); i++ {
if (data & mask) != 0 {
g.dataPins[i].High()
} else {
g.dataPins[i].Low()
}
mask = mask << 1
}
}
// pins returns current state of data pins. MSB is D7
func (g *GPIO) pins() byte {
bits := byte(0)
for i := uint8(0); i < uint8(len(g.dataPins)); i++ {
if g.dataPins[i].Get() {
bits |= (1 << i)
}
}
return bits
}