Skip to content

Commit 7369743

Browse files
authored
Merge pull request dhylands#40 from davidwilby/onion_omega
add onion omega interface and test code
2 parents 69251c2 + 910f6fd commit 7369743

File tree

2 files changed

+227
-0
lines changed

2 files changed

+227
-0
lines changed

lcd/onion_lcd_gpio.py

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
"""Implements a HD44780 character LCD connected via Onion Omega GPIO pins."""
2+
3+
from lcd_api import LcdApi
4+
from time import sleep
5+
6+
# https://docs.onion.io/omega2-docs/gpio-python-module.html#gpio-python-module
7+
# requires a python3 modification of the current standard onionGpio (as of 2021-11-20)
8+
from onionGpio import OnionGpio
9+
10+
class GpioLcd(LcdApi):
11+
"""Implements a HD44780 character LCD connected via ESP32 GPIO pins."""
12+
13+
def __init__(self, rs_pin, enable_pin, d0_pin=None, d1_pin=None,
14+
d2_pin=None, d3_pin=None, d4_pin=None, d5_pin=None,
15+
d6_pin=None, d7_pin=None, rw_pin=None, backlight_pin=None,
16+
num_lines=2, num_columns=16):
17+
"""Constructs the GpioLcd object. All of the arguments must be onionGpio.OnionGpio
18+
objects which describe which pin the given line from the LCD is
19+
connected to.
20+
21+
When used in 4-bit mode, only D4, D5, D6, and D7 are physically
22+
connected to the LCD panel. This function allows you call it like
23+
GpioLcd(rs, enable, D4, D5, D6, D7) and it will interpret that as
24+
if you had actually called:
25+
GpioLcd(rs, enable, d4=D4, d5=D5, d6=D6, d7=D7)
26+
27+
The enable 8-bit mode, you need pass d0 through d7.
28+
29+
The rw pin isn't used by this library, but if you specify it, then
30+
it will be set low.
31+
"""
32+
self.rs_pin = rs_pin
33+
self.enable_pin = enable_pin
34+
self.rw_pin = rw_pin
35+
self.backlight_pin = backlight_pin
36+
self._4bit = True
37+
if d4_pin and d5_pin and d6_pin and d7_pin:
38+
self.d0_pin = d0_pin
39+
self.d1_pin = d1_pin
40+
self.d2_pin = d2_pin
41+
self.d3_pin = d3_pin
42+
self.d4_pin = d4_pin
43+
self.d5_pin = d5_pin
44+
self.d6_pin = d6_pin
45+
self.d7_pin = d7_pin
46+
if self.d0_pin and self.d1_pin and self.d2_pin and self.d3_pin:
47+
self._4bit = False
48+
else:
49+
# This is really 4-bit mode, and the 4 data pins were just
50+
# passed as the first 4 arguments, so we switch things around.
51+
self.d0_pin = None
52+
self.d1_pin = None
53+
self.d2_pin = None
54+
self.d3_pin = None
55+
self.d4_pin = d0_pin
56+
self.d5_pin = d1_pin
57+
self.d6_pin = d2_pin
58+
self.d7_pin = d3_pin
59+
self.rs_pin.setOutputDirection(0)
60+
if self.rw_pin:
61+
self.rw_pin.setOutputDirection(0)
62+
self.enable_pin.setOutputDirection(0)
63+
self.d4_pin.setOutputDirection(0)
64+
self.d5_pin.setOutputDirection(0)
65+
self.d6_pin.setOutputDirection(0)
66+
self.d7_pin.setOutputDirection(0)
67+
if not self._4bit:
68+
self.d0_pin.setOutputDirection(0)
69+
self.d1_pin.setOutputDirection(0)
70+
self.d2_pin.setOutputDirection(0)
71+
self.d3_pin.setOutputDirection(0)
72+
if self.backlight_pin is not None:
73+
self.backlight_pin.setOutputDirection(0)
74+
75+
# See about splitting this into begin
76+
77+
sleep(0.020) # Allow LCD time to powerup
78+
# Send reset 3 times
79+
self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)
80+
sleep(0.005) # need to delay at least 4.1 msec
81+
self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)
82+
sleep(0.001)
83+
self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)
84+
sleep(0.001)
85+
cmd = self.LCD_FUNCTION
86+
if not self._4bit:
87+
cmd |= self.LCD_FUNCTION_8BIT
88+
self.hal_write_init_nibble(cmd)
89+
sleep(0.001)
90+
LcdApi.__init__(self, num_lines, num_columns)
91+
if num_lines > 1:
92+
cmd |= self.LCD_FUNCTION_2LINES
93+
self.hal_write_command(cmd)
94+
95+
def hal_pulse_enable(self):
96+
"""Pulse the enable line high, and then low again."""
97+
self.enable_pin.setValue(0)
98+
sleep(1/1E6)
99+
self.enable_pin.setValue(1)
100+
sleep(1/1E6) # Enable pulse needs to be > 450 nsec
101+
self.enable_pin.setValue(0)
102+
sleep(100/1E6) # Commands need > 37us to settle
103+
104+
def hal_write_init_nibble(self, nibble):
105+
"""Writes an initialization nibble to the LCD.
106+
107+
This particular function is only used during initialization.
108+
"""
109+
self.hal_write_4bits(nibble >> 4)
110+
111+
def hal_backlight_on(self):
112+
"""Allows the hal layer to turn the backlight on."""
113+
if self.backlight_pin:
114+
self.backlight_pin.setValue(1)
115+
116+
def hal_backlight_off(self):
117+
"""Allows the hal layer to turn the backlight off."""
118+
if self.backlight_pin:
119+
self.backlight_pin.setValue(0)
120+
121+
def hal_write_command(self, cmd):
122+
"""Writes a command to the LCD.
123+
124+
Data is latched on the falling edge of E.
125+
"""
126+
self.rs_pin.setValue(0)
127+
self.hal_write_8bits(cmd)
128+
if cmd <= 3:
129+
# The home and clear commands require a worst
130+
# case delay of 4.1 msec
131+
sleep(0.005)
132+
133+
def hal_write_data(self, data):
134+
"""Write data to the LCD."""
135+
self.rs_pin.setValue(1)
136+
self.hal_write_8bits(data)
137+
138+
def hal_write_8bits(self, value):
139+
"""Writes 8 bits of data to the LCD."""
140+
if self.rw_pin:
141+
self.rw_pin.setValue(0)
142+
if self._4bit:
143+
self.hal_write_4bits(value >> 4)
144+
self.hal_write_4bits(value)
145+
else:
146+
# unlike machine.Pin, onionGpio.OnionGpio.setValue needs us to convert to 0s & 1s ourselves
147+
self.d3_pin.setValue(int(bool(value & 0x08)))
148+
self.d2_pin.setValue(int(bool(value & 0x04)))
149+
self.d1_pin.setValue(int(bool(value & 0x02)))
150+
self.d0_pin.setValue(int(bool(value & 0x01)))
151+
self.hal_write_4bits(value >> 4)
152+
153+
def hal_write_4bits(self, nibble):
154+
"""Writes 4 bits of data to the LCD."""
155+
self.d7_pin.setValue(int(bool(nibble & 0x08)))
156+
self.d6_pin.setValue(int(bool(nibble & 0x04)))
157+
self.d5_pin.setValue(int(bool(nibble & 0x02)))
158+
self.d4_pin.setValue(int(bool(nibble & 0x01)))
159+
self.hal_pulse_enable()
160+
161+
def hal_sleep_us(self, usecs):
162+
"""Sleep for some time (given in microseconds)."""
163+
time.sleep(usecs/1E6) # Uses the standard python library time module for onion omega

lcd/onion_lcd_gpio_test.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"""Implements a HD44780 character LCD connected via Onion Omega GPIO pins."""
2+
3+
from onion_lcd_gpio import GpioLcd
4+
from time import sleep, clock #Note: clock removed in python 3.8 (however onion distributes python 3.4)
5+
6+
# https://docs.onion.io/omega2-docs/gpio-python-module.html#gpio-python-module
7+
# requires a python3 modification of the current standard onionGpio (as of 2021-11-20)
8+
from onionGpio import OnionGpio
9+
10+
# Wiring used for this example:
11+
# tested with Onion omega2+
12+
#
13+
# 1 - Vss (aka Ground) - Connect to one of the ground pins on you pyboard.
14+
# 2 - VDD - I connected to VIN which is 5 volts when your pyboard is powered via USB
15+
# 3 - VE (Contrast voltage) - I'll discuss this below
16+
# 4 - RS (Register Select) connect to gpio pin 2 (as per call to GpioLcd)
17+
# 5 - RW (Read/Write) - connect to ground
18+
# 6 - EN (Enable) connect to gpio pin 3 (as per call to GpioLcd)
19+
# 7 - D0 - leave unconnected
20+
# 8 - D1 - leave unconnected
21+
# 9 - D2 - leave unconnected
22+
# 10 - D3 - leave unconnected
23+
# 11 - D4 - connect to gpio pin 0 (as per call to GpioLcd)
24+
# 12 - D5 - connect to gpio pin 1 (as per call to GpioLcd)
25+
# 13 - D6 - connect to gpio pin 6 (as per call to GpioLcd)
26+
# 14 - D7 - connect to gpio pin 19 (as per call to GpioLcd)
27+
# 15 - A (BackLight Anode) - Connect to VIN
28+
# 16 - K (Backlight Cathode) - Connect to Ground
29+
#
30+
# On 14-pin LCDs, there is no backlight, so pins 15 & 16 don't exist.
31+
#
32+
# The Contrast line (pin 3) typically connects to the center tap of a
33+
# 10K potentiometer, and the other 2 legs of the 10K potentiometer are
34+
# connected to pins 1 and 2 (Ground and VDD)
35+
#
36+
# See: https://docs.onion.io/omega2-docs/using-gpios.html#boot-pins
37+
# for more info on which pins can be used freely
38+
# note that pins must be in gpio mode, see the onion docs
39+
#
40+
#
41+
42+
43+
def test_main():
44+
"""Test function for verifying basic functionality."""
45+
print("Running test_main")
46+
lcd = GpioLcd(rs_pin=OnionGpio(2),
47+
enable_pin=OnionGpio(3),
48+
d4_pin=OnionGpio(0),
49+
d5_pin=OnionGpio(1),
50+
d6_pin=OnionGpio(6),
51+
d7_pin=OnionGpio(19),
52+
num_lines=2, num_columns=16)
53+
lcd.putstr("It Works!\nSecond Line\nThird Line\nFourth Line")
54+
sleep(3)
55+
lcd.clear()
56+
count = 0
57+
while True:
58+
lcd.move_to(0, 0)
59+
lcd.putstr("%7d" % (int(round(clock(),6)*1E6) // 1000))
60+
sleep(1)
61+
count += 1
62+
63+
if __name__ == '__main__':
64+
test_main()

0 commit comments

Comments
 (0)