mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-07-26 10:38:41 +00:00
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.
This commit is contained in:
committed by
deadprogram
parent
41d6a4c3fa
commit
a53a39922b
+11
-1
@@ -57,9 +57,16 @@ func (g *GPIO) SetCommandMode(set bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
g.rw.Low()
|
||||
if !g.WriteOnly() {
|
||||
g.rw.Low()
|
||||
}
|
||||
for _, d := range data {
|
||||
g.write(d)
|
||||
n++
|
||||
@@ -89,6 +96,9 @@ 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++ {
|
||||
|
||||
+60
-9
@@ -11,9 +11,23 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// These are the default execution times for the Clear and
|
||||
// Home commands and everything else.
|
||||
//
|
||||
// These are used if RW is passed as machine.NoPin and ignored
|
||||
// otherwise.
|
||||
//
|
||||
// They are set conservatively here and can be tweaked in the
|
||||
// Config structure.
|
||||
DefaultClearHomeTime = 80 * time.Millisecond
|
||||
DefaultInstrExecTime = 80 * time.Microsecond
|
||||
)
|
||||
|
||||
type Buser interface {
|
||||
io.ReadWriter
|
||||
SetCommandMode(set bool)
|
||||
WriteOnly() bool
|
||||
}
|
||||
|
||||
type Device struct {
|
||||
@@ -28,6 +42,9 @@ type Device struct {
|
||||
|
||||
cursor cursor
|
||||
busyStatus []byte
|
||||
|
||||
clearHomeTime time.Duration // time clear/home instructions might take
|
||||
instrExecTime time.Duration // time all other instructions might take
|
||||
}
|
||||
|
||||
type cursor struct {
|
||||
@@ -35,14 +52,18 @@ type cursor struct {
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Width int16
|
||||
Height int16
|
||||
CursorBlink bool
|
||||
CursorOnOff bool
|
||||
Font uint8
|
||||
Width int16
|
||||
Height int16
|
||||
CursorBlink bool
|
||||
CursorOnOff bool
|
||||
Font uint8
|
||||
ClearHomeTime time.Duration // time clear/home instructions might take - use 0 for the default
|
||||
InstrExecTime time.Duration // time all other instructions might take - use 0 for the default
|
||||
}
|
||||
|
||||
// NewGPIO4Bit returns 4bit data length HD44780 driver. Datapins are LCD DB pins starting from DB4 to DB7
|
||||
//
|
||||
// If your device has RW set permanently to ground then pass in rw as machine.NoPin
|
||||
func NewGPIO4Bit(dataPins []machine.Pin, e, rs, rw machine.Pin) (Device, error) {
|
||||
const fourBitMode = 4
|
||||
if len(dataPins) != fourBitMode {
|
||||
@@ -52,6 +73,8 @@ func NewGPIO4Bit(dataPins []machine.Pin, e, rs, rw machine.Pin) (Device, error)
|
||||
}
|
||||
|
||||
// NewGPIO8Bit returns 8bit data length HD44780 driver. Datapins are LCD DB pins starting from DB0 to DB7
|
||||
//
|
||||
// If your device has RW set permanently to ground then pass in rw as machine.NoPin
|
||||
func NewGPIO8Bit(dataPins []machine.Pin, e, rs, rw machine.Pin) (Device, error) {
|
||||
const eightBitMode = 8
|
||||
if len(dataPins) != eightBitMode {
|
||||
@@ -68,6 +91,8 @@ func (d *Device) Configure(cfg Config) error {
|
||||
if d.width == 0 || d.height == 0 {
|
||||
return errors.New("width and height must be set")
|
||||
}
|
||||
d.clearHomeTime = cfg.ClearHomeTime
|
||||
d.instrExecTime = cfg.InstrExecTime
|
||||
memoryMap := uint8(ONE_LINE)
|
||||
if d.height > 1 {
|
||||
memoryMap = TWO_LINE
|
||||
@@ -186,7 +211,7 @@ func (d *Device) SendCommand(command byte) {
|
||||
d.bus.SetCommandMode(true)
|
||||
d.bus.Write([]byte{command})
|
||||
|
||||
for d.Busy() {
|
||||
for d.busy(command == DISPLAY_CLEAR || command == CURSOR_HOME) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,7 +220,7 @@ func (d *Device) sendData(data byte) {
|
||||
d.bus.SetCommandMode(false)
|
||||
d.bus.Write([]byte{data})
|
||||
|
||||
for d.Busy() {
|
||||
for d.busy(false) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,13 +232,39 @@ func (d *Device) CreateCharacter(cgramAddr uint8, data []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
// Busy returns true when hd447890 is busy
|
||||
func (d *Device) Busy() bool {
|
||||
// busy returns true when hd447890 is busy
|
||||
// or after the timeout specified
|
||||
func (d *Device) busy(longDelay bool) bool {
|
||||
if d.bus.WriteOnly() {
|
||||
// Can't read busy flag if write only, so sleep a bit then return
|
||||
if longDelay {
|
||||
// Note that we sleep like this so the default
|
||||
// time.Sleep is time.Sleep(constant) as
|
||||
// time.Sleep(variable) doesn't seem to work on AVR yet
|
||||
if d.clearHomeTime != 0 {
|
||||
time.Sleep(d.clearHomeTime)
|
||||
} else {
|
||||
time.Sleep(DefaultClearHomeTime)
|
||||
}
|
||||
} else {
|
||||
if d.instrExecTime != 0 {
|
||||
time.Sleep(d.instrExecTime)
|
||||
} else {
|
||||
time.Sleep(DefaultInstrExecTime)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
d.bus.SetCommandMode(true)
|
||||
d.bus.Read(d.busyStatus)
|
||||
return (d.busyStatus[0] & BUSY) > 0
|
||||
}
|
||||
|
||||
// Busy returns true when hd447890 is busy
|
||||
func (d *Device) Busy() bool {
|
||||
return d.busy(false)
|
||||
}
|
||||
|
||||
// Size returns the current size of the display.
|
||||
func (d *Device) Size() (w, h int16) {
|
||||
return int16(d.width), int16(d.height)
|
||||
|
||||
Reference in New Issue
Block a user