Skip to content

Commit 9a7f7ac

Browse files
authored
hd44780: Restructure to implement conn/display/TextDisplay. Refine to use GPIO.Group (#91)
* Add support for Adafruit I2C/SPI Backpack * Add support for PCF857x Backpacks * Add support for conn/gpio/Group * Implement conn/display/TextDisplay * Add examples * Cleanups * Change backlight implementation
1 parent bc9678a commit 9a7f7ac

11 files changed

+2972
-150
lines changed

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ require (
1212
github.com/mattn/go-colorable v0.1.13
1313
golang.org/x/image v0.23.0
1414
periph.io/x/conn/v3 v3.7.2
15-
periph.io/x/host/v3 v3.8.3
15+
periph.io/x/host/v3 v3.8.4
1616
)
1717

1818
require (

go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
1717
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
1818
periph.io/x/conn/v3 v3.7.2 h1:qt9dE6XGP5ljbFnCKRJ9OOCoiOyBGlw7JZgoi72zZ1s=
1919
periph.io/x/conn/v3 v3.7.2/go.mod h1:Ao0b4sFRo4QOx6c1tROJU1fLJN1hUIYggjOrkIVnpGg=
20-
periph.io/x/host/v3 v3.8.3 h1:v90ozCFDWgEyfNElZ+JnOvq0jAdW0vmgjCUy8dYXDds=
21-
periph.io/x/host/v3 v3.8.3/go.mod h1:uKrIpfXjELwHkwGBNe6aos//XiQ/3uxDa1P2BmLV6Ok=
20+
periph.io/x/host/v3 v3.8.4 h1:QNleTythDd0k6Chu0n+ISrJFlf3LFig9oNbtOIkxoCc=
21+
periph.io/x/host/v3 v3.8.4/go.mod h1:hPq8dISZIc+UNfWoRj+bPH3XEBQqJPdFdx218W92mdc=

hd44780/README.md

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Hitachi HD44780 Package
2+
3+
## Overview
4+
5+
The Hitachi HD44780 is an LCD driver chip. It's used in a variety of text LCD
6+
displays. The datasheet is available here:
7+
8+
https://www.sparkfun.com/datasheets/LCD/HD44780.pdf
9+
10+
Generally, there are three kinds of displays that use this chip.
11+
12+
1. A raw display. This is a board with a row of pin connectors at the top. It's
13+
made for interfacing directly to GPIO pins. This is the most complicated method
14+
of using the LCD because you have to wire a minimum of 6 GPIO pins (4 data, 1
15+
reset, 1 enable) and 2 power pins to make it work.
16+
17+
There are also complex initialization routines that have to be performed. This
18+
is further complicated by having specific initialization calls depending upon
19+
whether the device is connected to 4 data lines, or 8 data lines.
20+
21+
2. A backpack display. With this type of LCD display, an I2C, serial, or SPI
22+
interface is provided. This type of display is easier because there are fewer
23+
pins, but the complex intialization remains. Examples of backpack interfaces
24+
include The Adafruit I2C/SPI backpack (MCP23008/74HC595D), the generic
25+
LCDXXXX/PCF8547T backpack, etc.
26+
27+
3. The third and final variety is the "Intelligent" display. These displays have
28+
a micro-controller that is connected to the LCD chip. Typically these intelligent
29+
displays support multiple I/O methods and the micro-controller handles the
30+
LCD initialization/communication.
31+
32+
Examples of this kind of display would be the SparkFun SerLCD display, the
33+
MatrixOrbital LK2047T, the AdaFruit USB+Serial Backpack etc.
34+
35+
## Interfacing Notes
36+
37+
The driver package is designed to use the gpio.Group interface. This allows
38+
the LCD driver to be agnostic about the physical connection between the display
39+
and the host device. Any host/expander that supports the
40+
periph.io/x/conn/v3/gpio.Group interface can be used to easily drive the LCD
41+
display.
42+
43+
## Hardware Notes
44+
45+
DO NOT attempt to source VCC for the unit backlight, or sink VCC to ground.
46+
The backlight draws ~250ma of current which exceeds the current capability
47+
of GPIO pins. It will permanently damage your device. If you would like to
48+
control the backlight, connect a GPIO pin through a 1K Ohm resistor to a
49+
transistor (2N2222 or equivalent).
50+
51+
## Troubleshooting
52+
53+
If nothing displays at all, check the contrast. Adjust the contrast control
54+
until the 5x7 dot grid on the display is visible.
55+
56+
If the first row contains blocks of dots, and the other rows are blank, then
57+
the initialization of the device failed. Check IO pins are connected properly.
58+
59+
If the text is garbled, verify the gpio.Group is configured and the IO Pins
60+
are connected to the right pins of the LCD display.

hd44780/af_i2c_backpack.go

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2025 The Periph Authors. All rights reserved.
2+
// Use of this source code is governed under the Apache License, Version 2.0
3+
// that can be found in the LICENSE file.
4+
5+
package hd44780
6+
7+
import (
8+
"periph.io/x/conn/v3/gpio"
9+
"periph.io/x/conn/v3/i2c"
10+
"periph.io/x/conn/v3/spi"
11+
"periph.io/x/devices/v3/mcp23xxx"
12+
"periph.io/x/devices/v3/nxp74hc595"
13+
)
14+
15+
const (
16+
// Name is the LCD pin name, and the integer value is the GPIO
17+
// number (not physical) of the MCP23008 I2C GPIO Expander.
18+
d4 = 3
19+
d5 = 4
20+
d6 = 5
21+
d7 = 6
22+
rsPin = 1
23+
enablePin = 2
24+
backlightPin = 7
25+
)
26+
27+
// This function returns a display configured to use the Adafruit I2C/SPI LCD Backpack.
28+
//
29+
// # Product Information
30+
//
31+
// https://www.adafruit.com/product/292
32+
//
33+
// The I2C side of this backpack uses an MCP23008 I/O expander. This function
34+
// creates an MCP23008 device with the required pin configuration. To use this,
35+
// get an I2C bus, and call this function with the bus, i2c address, number of
36+
// rows, and columns.
37+
func NewAdafruitI2CBackpack(bus i2c.Bus, address uint16, rows, cols int) (*HD44780, error) {
38+
mcp, err := mcp23xxx.NewI2C(bus, mcp23xxx.MCP23008, address)
39+
if err != nil {
40+
return nil, err
41+
}
42+
gr := *mcp.Group(0, []int{d4, d5, d6, d7, rsPin, enablePin, backlightPin})
43+
reset, _ := gr.ByOffset(4).(gpio.PinOut)
44+
enable, _ := gr.ByOffset(5).(gpio.PinOut)
45+
bl := gr.ByOffset(6).(gpio.PinOut)
46+
return NewHD44780(gr, reset, enable, NewBacklight(bl), rows, cols)
47+
}
48+
49+
// This function returns a display configured to use the SPI side of the Adafruit
50+
// I2c/SPI backpack. The SPI side uses a 74HC595 Serial->Parallel shift register.
51+
func NewAdafruitSPIBackpack(conn spi.Conn, rows, cols int) (*HD44780, error) {
52+
chip, err := nxp74hc595.New(conn)
53+
if err != nil {
54+
return nil, err
55+
}
56+
// The SPI side has the same pins but in reverse order from the I2C side.
57+
gr, _ := chip.Group(d7, d6, d5, d4)
58+
rs := chip.Pins[rsPin]
59+
e := chip.Pins[enablePin]
60+
bl := chip.Pins[backlightPin]
61+
return NewHD44780(gr, rs, e, NewBacklight(bl), rows, cols)
62+
}

hd44780/backlight.go

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2025 The Periph Authors. All rights reserved.
2+
// Use of this source code is governed under the Apache License, Version 2.0
3+
// that can be found in the LICENSE file.
4+
5+
package hd44780
6+
7+
import (
8+
"fmt"
9+
10+
"periph.io/x/conn/v3/display"
11+
"periph.io/x/conn/v3/gpio"
12+
)
13+
14+
// A monochrome backlight Implements display.Backlight It uses a single
15+
// GPIO Pin to turn the backlight on or off.
16+
type GPIOMonoBacklight struct {
17+
blPin gpio.PinOut
18+
}
19+
20+
// Given a GPIO pin that turns the backlight on/off, construct a monobacklight
21+
// to use with HD44780.
22+
func NewBacklight(blPin gpio.PinOut) *GPIOMonoBacklight {
23+
return &GPIOMonoBacklight{blPin: blPin}
24+
}
25+
26+
// Turn the display backlight on or off.
27+
func (bl *GPIOMonoBacklight) Backlight(intensity display.Intensity) (err error) {
28+
if intensity == 0 {
29+
err = bl.blPin.Out(gpio.Low)
30+
} else {
31+
err = bl.blPin.Out(gpio.High)
32+
}
33+
return err
34+
}
35+
36+
func (bl *GPIOMonoBacklight) String() string {
37+
return fmt.Sprintf("%#v", bl)
38+
}
39+
40+
var _ display.DisplayBacklight = &GPIOMonoBacklight{}

0 commit comments

Comments
 (0)