Around 2013 I bought several used Avago HDSP-2112 display modules. However, it took until 2021 until I implemented a prototype with an old Raspberry Pi.
The special thing about these modules is the technology: the modules are suitable for a DIL-28 socket with a pitch of 2.54 mm and contain eight characters with a matrix of 5×7 LEDs each, which is only about 5 mm high. Several modules can also be mounted next to each other in order to build longer lines of text. In addition to this model, there are also other colors:
- HDSP-2110: orange
- HDSP-2111: yellow
- HDSP-2112: red (high efficiency)
- HDSP-2113: green
The series HDSP-250x provide a bit larger characters with a height of about 7 mm. Besides the different dimension those modules are otherwise pin compatible and functionally identical. Besides that there is also a variant HDSP-253x which has a slightly more compact packaging and a similar pinout fitting a smaller DIL-30 footprint. However the control of the HDSP-253x is identical to the other models.
The following information are based on what I found as PDF at RS Components. Since Avago and Boradcom merged, the modules are now produced by Broadcom where you also find a documentation: product information Broadcom HDSP-2112.
Technical data
The operating voltage is +5 volts and the module uses TTL levels. Input voltages below 0.8 volts are interpreted as “low” or “0”, levels above 2.4 volts as “high” or “1”. Therefore controlling the module using the GPIO ports of a Raspberry Pi or Arduino resp. Atmel AVR is no problem at all.
Depending on how many LEDs light up the power requirement is about 400 mA (430 mA with 160 LEDs turned on) which is about 2 watts at 5 volts
Additional technical details:
- Clock frequency of the controller: 57 kHz (minimum 28 kHz)
- Refresh rate of the display: 256 Hz (minimum 128 Hz)
- Blink rate of flashing characters: clock frequency of the controller devided by 28672, usually about 2 Hz (minimum 1 Hz)
Packaging and pinout
The module can be put into a DIL-28 socket. The position of pin 1 as marked by a slanted corner. In addition there are two pins missing in the top row. You can also put multiple modules next to each other to display longer lines of text.
Pin | Function | Pin | Function |
---|---|---|---|
1 | RST | 28 | D7 |
2 | FL | 27 | D6 |
3 | A0 | 26 | D5 |
4 | A1 | 25 | D4 |
5 | A2 | 24 | D3 |
6 | A3 | 23 | D2 |
7 | N.C. | 22 | – |
8 | N.C. | 21 | – |
9 | N.C. | 20 | D1 |
10 | A4 | 19 | D0 |
11 | CLS | 18 | RD |
12 | CLK | 17 | CE |
13 | WR | 16 | GND (logic) |
14 | VDD | 15 | GND (supply) |
Description of the pin functions
In the following description 1 is used for “high” and 0 for “low”.
Pin | Function | Description | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | RST (Reset) |
If this input is 0, the module will be reset. | ||||||||||||||||||||||||||||||
11 | CLS (Clock Select) |
If this input is 1, the clock for the controller is generated internally and output on CLK.
If this input is 0, a clock signal is expected on CLK. This can be used with multiple modules to use the clock signal of one main module for multiple other modules. |
||||||||||||||||||||||||||||||
12 | CLK (Clock) |
Depending on the signal at CLS this pin is either the output of the clock signal or used as input. | ||||||||||||||||||||||||||||||
17 | CE (Chip Enable) |
This input needs to be 0 to control the module. If CE is 1, read and write operations will be ignored.
This can be used to run multiple modules with a common address and data bus. In this case only one module at a time must be activated using CE. |
||||||||||||||||||||||||||||||
13 | WR (Write) |
If this input is 0 all data from D0-D7 will be written to the address which is put in at A0-A5.
WR must not be 0 together with RD. This would lead to undefined results. |
||||||||||||||||||||||||||||||
18 | RD (Read) |
If this input is 0, D0-D7 will output the data from the location at the adress which is put in at A0-A5.
RD must not be 0 together with WR. This would lead to undefined results. |
||||||||||||||||||||||||||||||
2 | FL (Flash) |
If this input is 0 you can write to the “Flash RAM” . The adress is put in at A0-A2 and defines the position of the character. With D0 you can define if the character should blink (1) or not (0). D1-D7 and A4/A5 will then be ignored.
To output text or write user defined characters, FL must be 1. |
||||||||||||||||||||||||||||||
3-6, 10 | A0-A4 | Adress bus as input to write and read data.
Together with FL the adresses define which part of the memory is accessed (“-” means “will be ignored”):
|
||||||||||||||||||||||||||||||
19-20, 23-28 | D0-D7 | Data bus as input to write data (WR at 0 and RD at 1) or as output to read data (WR at 1 and RD at 0). |
Control
The general method to write data to the display is as following:
- Set WR to 1,
- Set RD to 1 (if you only want to write data, you can also connect this input permanently to VDD).
- Set CE to 0 to activate the module (if you run only one module you can also connect this input permanently to GND).
- Set FL, A0-A4 and D0-D7 as needed.
- Set WR to 0 for a short time so the data will be used and the set WR back to 1.
You find the exact timing requirements in the documentation of the manufacturer.
As a rough orientation: after activating the module with CE there must be a pause of 160 ns before writing data using WR. Writing data takes at least 100 ns and afterwards there is a pause of 20 ns needed before you can write data again. On a Raspberry Pi with Python I used a pause of 0.0001 seconds and had no problems with that.
Writing text (character RAM)
To write text, FL must be 1 – otherwise you would write to the”Flash RAM” beschreibt. The position of the character will be defined using A0-A2. A3 and A4 must be 1. With D0-D7 you set the code of the character to write and execute the write process.
↓ | CE | FL | RD | WR | A4 | A3 | A2 | A1 | A0 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 1 | 1 | 1 | 1 | 1 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 |
2 | 0 | 1 | 1 | 0 | 1 | 1 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 |
3 | 0 | 1 | 1 | 1 | 1 | 1 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 |
The character code is defined as following: 0-31 (0x00-0x1f) are special characters, 32-127 (0x20-0x7f) correspond to ASCII, 128-143 (0x80-0x8f) select one of 16 user defined characters and the values 144-255 (0x90-0xff) are not defined.
D0-D3 → D4-D7 ↓ |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | ◄ | ¿ | x̄ | ñ | Ñ | α | β | γ | ∆ | η | θ | λ | μ | π | σ | Σ |
1 | τ | φ | Ω | Å | å | Ä | ä | Ö | ö | Ü | ü | → | √ | ² | £ | ¥ |
2 | ! | “ | # | $ | % | & | ‘ | ( | ) | * | + | , | – | . | / | |
3 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? |
4 | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
5 | P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ↑ | _ |
6 | ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
7 | p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | ▒ |
8 | ① | ② | ③ | ④ | ⑤ | ⑥ | ⑦ | ⑧ | ⑨ | ⑩ | ⑪ | ⑫ | ⑬ | ⑭ | ⑮ | ⑯ |
Following is the table from the datasheet of the manufacturer:
Control blinking of individual characters (Flash RAM)
When you set FL to 0, you write to the “Flash RAM” using A0-A2 and D0. This way individual characters on the display can be displayed blinking. A0-A2 defines the character position (0-7) and D0 if the character should blink (1) or not (0). All other address and data lines are ignored.
↓ | CE | FL | RD | WR | A4 | A3 | A2 | A1 | A0 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 1 | 1 | – | – | 1/0 | 1/0 | 1/0 | – | – | – | – | – | – | – | 1/0 |
2 | 0 | 0 | 1 | 0 | – | – | 1/0 | 1/0 | 1/0 | – | – | – | – | – | – | – | 1/0 |
3 | 0 | 0 | 1 | 1 | – | – | 1/0 | 1/0 | 1/0 | – | – | – | – | – | – | – | 1/0 |
Write user defined characters (UDC RAM)
To write user defined characters you first have to tell the module which character to write. For this you set FL to 1 and A3 and A4 to 0. With D0-D3 you defined the character to write (0-15). All other address and data lines are ignored.
↓ | CE | FL | RD | WR | A4 | A3 | A2 | A1 | A0 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 1 | 1 | 1 | 0 | 0 | – | – | – | – | – | – | – | 1/0 | 1/0 | 1/0 | 1/0 |
2 | 0 | 1 | 1 | 0 | 0 | 0 | – | – | – | – | – | – | – | 1/0 | 1/0 | 1/0 | 1/0 |
3 | 0 | 1 | 1 | 1 | 0 | 0 | – | – | – | – | – | – | – | 1/0 | 1/0 | 1/0 | 1/0 |
After this write access you can defined the content of the character by setting A3 to 1 und A4 to 0 setzt. A0-A2 define the row of the character matrix to write and D0-D4 das Bitmuster for this line. D5-D7 are ignored since the characters are only 5 pixels wide.
↓ | CE | FL | RD | WR | A4 | A3 | A2 | A1 | A0 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 1 | 1 | 1 | 0 | 1 | 1/0 | 1/0 | 1/0 | – | – | – | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 |
2 | 0 | 1 | 1 | 0 | 0 | 1 | 1/0 | 1/0 | 1/0 | – | – | – | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 |
3 | 0 | 1 | 1 | 1 | 0 | 1 | 1/0 | 1/0 | 1/0 | – | – | – | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 |
Change display settings using the “control word register”
The display has a number of settings which you can change if need. For this you set FL to 1, A3 to 0 und A4 to 1. All other address lines are ignored.
↓ | CE | FL | RD | WR | A4 | A3 | A2 | A1 | A0 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 1 | 1 | 1 | 1 | 0 | – | – | – | 1/0 | 1/0 | – | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 |
2 | 0 | 1 | 1 | 0 | 1 | 0 | – | – | – | 1/0 | 1/0 | – | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 |
3 | 0 | 1 | 1 | 1 | 1 | 0 | – | – | – | 1/0 | 1/0 | – | 1/0 | 1/0 | 1/0 | 1/0 | 1/0 |
The “control word register” is defined as following:
Bits | Function |
---|---|
D0-D2 | Display brightness:
000: 100% |
D3 | 0: Flash not active. 1: Flash active. The characters will blink according to the setting in the Flash RAM. |
D4 | 0: Blink not active. 1: Blink aktive. The whole display will blink. |
D5 | Without function when writing.
When reading this will report the result of the self test: 0: Self test failed |
D6 | 0: Normal operation 1: Start self test, result will be reported at D5. |
D7 | 0: Normal operation 1: Clear content of Character RAM and Flash RAM. |
Test setup with a Raspberry Pi
To check wether my old displays still work, I created a test installation with a Raspberry Pi on a “Dish” by Adafruit.
Important: the input RD of the display should be connected permanently to +5 V to make sure that the module uses the data lines D0-D7 only as input! Otherwise the GPIO ports of the Raspbery Pi could be damaged!
Following is the control of a single display. Further below I have extended this to multiple displays.
To control the module I created a Python script. You have to make sure that all GPIO ports are usable as outputs – this means that you should disable all interface options like SPI, ICC and the serial interface with raspi-config
before you run the script.
The module is connected as following:
Pin | Function | Connection | Pin | Function | Connection |
---|---|---|---|---|---|
1 | RST | see text | 28 | D7 | GPIO 9 |
2 | FL | +5V | 27 | D6 | GPIO 10 |
3 | A0 | GPIO 7 | 26 | D5 | GPIO 22 |
4 | A1 | GPIO 8 | 25 | D4 | GPIO 27 |
5 | A2 | GPIO 25 | 24 | D3 | GPIO 17 |
6 | A3 | GPIO 24 | 23 | D2 | GPIO 4 |
7 | N.C. | – | 22 | – | |
8 | N.C. | – | 21 | – | |
9 | N.C. | – | 20 | D1 | GPIO 3 |
10 | A4 | GPIO 23 | 19 | D0 | GPIO 2 |
11 | CLS | +5 V | 18 | RD | +5 V |
12 | CLK | – | 17 | CE | GND |
13 | WR | GPIO 15 | 16 | GND (logic) | GND |
14 | VDD | +5 V | 15 | GND (supply) | GND |
A R/C circuit is used to get the module into a defined state when powering on: a condensator with 220 nF from RST to GND, a resistor with 100k from RST to +5 V and a diode parallel to the resistor with its cathode connected to +5 V and which is used to discharge the condensator faster when the power supply is turned off:
The wiring is defined at the beginning of the following Python script and can be changed if needed. The script will demonstrate the following steps:
- Initializing the GPIO ports.
- Reducing the display brightness to 13%.
- Defining two user defined characters.
- Output of the text “Hello” followed by a smiley which was created as individual character.
- Output of a scrolling textes with an additional user defined character.
The code is only for demonstration. Feel free to use it for your own applications.
Update 2021-05-22:
The function io_init()
did not set the WR to 1 which could lead to an undefined behaviour for the first write access. I fixed this – so setting the display brightness now works with only call call after powering the device up.
The function hdsp_send_text()
originally contained the unneccessary output of eight space characters to blank the display before writing the text which could lead to a flickering display. I removed that since this function already extends the text to eight characters by adding spaces if needed.
#!/usr/bin/python # Testing a HDSP-2112 display with a Raspberry Pi # An example by Arno Welzel (https://arnowelzel.de) # # Prerequisites: # # Make sure, all GPIO pins are usable as outputs. # If needed disable SPI, IC2, UART etc. in raspi-config first. # # The following pin numbers are BMC based, change if needed. import time import RPi.GPIO as GPIO HDSP_WR = 15 HDSP_A0 = 7 HDSP_A1 = 8 HDSP_A2 = 25 HDSP_A3 = 24 HDSP_A4 = 23 HDSP_D0 = 2 HDSP_D1 = 3 HDSP_D2 = 4 HDSP_D3 = 17 HDSP_D4 = 27 HDSP_D5 = 22 HDSP_D6 = 10 HDSP_D7 = 9 E_PULSE = 0.0001 def io_init(): GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(HDSP_WR, GPIO.OUT) GPIO.setup(HDSP_A0, GPIO.OUT) GPIO.setup(HDSP_A1, GPIO.OUT) GPIO.setup(HDSP_A2, GPIO.OUT) GPIO.setup(HDSP_A3, GPIO.OUT) GPIO.setup(HDSP_A4, GPIO.OUT) GPIO.setup(HDSP_D0, GPIO.OUT) GPIO.setup(HDSP_D1, GPIO.OUT) GPIO.setup(HDSP_D2, GPIO.OUT) GPIO.setup(HDSP_D3, GPIO.OUT) GPIO.setup(HDSP_D4, GPIO.OUT) GPIO.setup(HDSP_D5, GPIO.OUT) GPIO.setup(HDSP_D6, GPIO.OUT) GPIO.setup(HDSP_D7, GPIO.OUT) GPIO.output(HDSP_WR, GPIO.HIGH) def hdsp_send_byte(data, adr): GPIO.output(HDSP_D0, GPIO.LOW) GPIO.output(HDSP_D1, GPIO.LOW) GPIO.output(HDSP_D2, GPIO.LOW) GPIO.output(HDSP_D3, GPIO.LOW) GPIO.output(HDSP_D4, GPIO.LOW) GPIO.output(HDSP_D5, GPIO.LOW) GPIO.output(HDSP_D6, GPIO.LOW) GPIO.output(HDSP_D7, GPIO.LOW) GPIO.output(HDSP_A0, GPIO.LOW) GPIO.output(HDSP_A1, GPIO.LOW) GPIO.output(HDSP_A2, GPIO.LOW) GPIO.output(HDSP_A3, GPIO.LOW) GPIO.output(HDSP_A4, GPIO.LOW) if data & 0x01 == 0x01: GPIO.output(HDSP_D0, GPIO.HIGH) if data & 0x02 == 0x02: GPIO.output(HDSP_D1, GPIO.HIGH) if data & 0x04 == 0x04: GPIO.output(HDSP_D2, GPIO.HIGH) if data & 0x08 == 0x08: GPIO.output(HDSP_D3, GPIO.HIGH) if data & 0x10 == 0x10: GPIO.output(HDSP_D4, GPIO.HIGH) if data & 0x20 == 0x20: GPIO.output(HDSP_D5, GPIO.HIGH) if data & 0x40 == 0x40: GPIO.output(HDSP_D6, GPIO.HIGH) if data & 0x80 == 0x80: GPIO.output(HDSP_D7, GPIO.HIGH) if adr & 0x01 == 0x01: GPIO.output(HDSP_A0, GPIO.HIGH) if adr & 0x02 == 0x02: GPIO.output(HDSP_A1, GPIO.HIGH) if adr & 0x04 == 0x04: GPIO.output(HDSP_A2, GPIO.HIGH) if adr & 0x08 == 0x08: GPIO.output(HDSP_A3, GPIO.HIGH) if adr & 0x10 == 0x10: GPIO.output(HDSP_A4, GPIO.HIGH) time.sleep(E_PULSE) GPIO.output(HDSP_WR, GPIO.LOW) time.sleep(E_PULSE) GPIO.output(HDSP_WR, GPIO.HIGH) def hdsp_send_text(text): text = text.ljust(8,' ') for i in range(8): hdsp_send_byte(ord(text[i]), 0x18+i) def hdsp_scroll_text(text): text = ' '+text+' ' for i in range(len(text)-7): hdsp_send_text(text[i:i+8]) time.sleep(0.25) def hdsp_send_udc(character, matrix): hdsp_send_byte(character, 0x00) adr = 0x08 for line in matrix: byte = 0 bit = 0x10 for pos in range(5): if line[pos:pos+1] == '*': byte = byte | bit bit >>= 1 hdsp_send_byte(byte, adr) adr += 1 if __name__ == '__main__': # initialize GPIOs io_init() # set brightness to 13% hdsp_send_byte(0x06,0x10); # Define custom characters hdsp_send_udc( 0, [ '*...*', '.....', '..*..', '..*..', '.....', '*...*', '.***.']) hdsp_send_udc( 1, [ '..***', '..***', '..**.', '..**.', '.....', '..**.', '..**.']) # do some stuff hdsp_send_text('Hello '+str(b'\x80')) time.sleep(4) hdsp_scroll_text('Scrolling text and custom characters '+str(b'\x81')+str(b'\x81')+str(b'\x81'))
Control multiple displays
After the setup as described above, the Raspberry Pi 1 still has two free GPIO ports which I used to control two displays parallel. For this all data- and adresslines as well as the reset circuit are connected to both displays. CE will not be connected to GND any longer but each display to its own GPIO port to control them individually. It’s also recommened to connect the CLS input of one display to GND and connect CLK of both displays. This way the clock of both displays is sychronized.
The extended cabling in detail:
Pin | Function | Display 1 | Display 2 | Pin | Function | Display 1 | Display 2 |
---|---|---|---|---|---|---|---|
1 | RST | siehe Text | 28 | D7 | GPIO 9 | GPIO 9 | |
2 | FL | +5V | +5V | 27 | D6 | GPIO 10 | GPIO 10 |
3 | A0 | GPIO 7 | GPIO 7 | 26 | D5 | GPIO 22 | GPIO 22 |
4 | A1 | GPIO 8 | GPIO 8 | 25 | D4 | GPIO 27 | GPIO 27 |
5 | A2 | GPIO 25 | GPIO 25 | 24 | D3 | GPIO 17 | GPIO 17 |
6 | A3 | GPIO 24 | GPIO 24 | 23 | D2 | GPIO 4 | GPIO 4 |
7 | N.C. | – | – | 22 | – | – | |
8 | N.C. | – | – | 21 | – | – | |
9 | N.C. | – | – | 20 | D1 | GPIO 3 | GPIO 3 |
10 | A4 | GPIO 23 | GPIO 23 | 19 | D0 | GPIO 2 | GPIO 2 |
11 | CLS | GND | +5 V | 18 | RD | +5 V | +5 V |
12 | CLK | CLK Display 2 | CLK Display 1 | 17 | CE | GPIO 18 | GPIO 11 |
13 | WR | GPIO 15 | GPIO 15 | 16 | GND (logic) | GND | GND |
14 | VDD | +5 V | +5 V | 15 | GND (supply) | GND | GND |
For the cabling I now use solid wires. This makes the whole construction less fragile and the cables can be laid out flat:
Following this scheme you can control even more displays, however there are only enough GPIO pins available on my old Raspberry Pi 1 for three displays. For more displays you may use a shift register which just needs three outputs and can be cascaded.
I extended the Python script so creating user defined characters and text output uses both displays:
#!/usr/bin/python # Testing two HDSP2112 modules combined as one # 16 character display with a Raspberry Pi # An example by Arno Welzel (https://arnowelzel.de) # # Prerequisites: # # Make sure, all GPIO pins are usable as outputs. # If needed disable SPI, IC2, UART etc. in raspi-config first. # # The following pin numbers are BMC based, change if needed. import time import RPi.GPIO as GPIO HDSP_WR = 15 HDSP_A0 = 7 HDSP_A1 = 8 HDSP_A2 = 25 HDSP_A3 = 24 HDSP_A4 = 23 HDSP_D0 = 2 HDSP_D1 = 3 HDSP_D2 = 4 HDSP_D3 = 17 HDSP_D4 = 27 HDSP_D5 = 22 HDSP_D6 = 10 HDSP_D7 = 9 HDSP_CE0 = 18 HDSP_CE1 = 11 E_PULSE = 0.0001 def io_init(): GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(HDSP_WR, GPIO.OUT) GPIO.setup(HDSP_A0, GPIO.OUT) GPIO.setup(HDSP_A1, GPIO.OUT) GPIO.setup(HDSP_A2, GPIO.OUT) GPIO.setup(HDSP_A3, GPIO.OUT) GPIO.setup(HDSP_A4, GPIO.OUT) GPIO.setup(HDSP_D0, GPIO.OUT) GPIO.setup(HDSP_D1, GPIO.OUT) GPIO.setup(HDSP_D2, GPIO.OUT) GPIO.setup(HDSP_D3, GPIO.OUT) GPIO.setup(HDSP_D4, GPIO.OUT) GPIO.setup(HDSP_D5, GPIO.OUT) GPIO.setup(HDSP_D6, GPIO.OUT) GPIO.setup(HDSP_D7, GPIO.OUT) GPIO.setup(HDSP_CE0, GPIO.OUT) GPIO.setup(HDSP_CE1, GPIO.OUT) GPIO.output(HDSP_CE0, GPIO.HIGH) GPIO.output(HDSP_CE1, GPIO.HIGH) GPIO.output(HDSP_WR, GPIO.HIGH) def hdsp_send_byte(chip, data, adr): if chip == 0: GPIO.output(HDSP_CE0, GPIO.LOW) GPIO.output(HDSP_CE1, GPIO.HIGH) elif chip == 1: GPIO.output(HDSP_CE0, GPIO.HIGH) GPIO.output(HDSP_CE1, GPIO.LOW) GPIO.output(HDSP_D0, GPIO.LOW) GPIO.output(HDSP_D1, GPIO.LOW) GPIO.output(HDSP_D2, GPIO.LOW) GPIO.output(HDSP_D3, GPIO.LOW) GPIO.output(HDSP_D4, GPIO.LOW) GPIO.output(HDSP_D5, GPIO.LOW) GPIO.output(HDSP_D6, GPIO.LOW) GPIO.output(HDSP_D7, GPIO.LOW) GPIO.output(HDSP_A0, GPIO.LOW) GPIO.output(HDSP_A1, GPIO.LOW) GPIO.output(HDSP_A2, GPIO.LOW) GPIO.output(HDSP_A3, GPIO.LOW) GPIO.output(HDSP_A4, GPIO.LOW) if data & 0x01 == 0x01: GPIO.output(HDSP_D0, GPIO.HIGH) if data & 0x02 == 0x02: GPIO.output(HDSP_D1, GPIO.HIGH) if data & 0x04 == 0x04: GPIO.output(HDSP_D2, GPIO.HIGH) if data & 0x08 == 0x08: GPIO.output(HDSP_D3, GPIO.HIGH) if data & 0x10 == 0x10: GPIO.output(HDSP_D4, GPIO.HIGH) if data & 0x20 == 0x20: GPIO.output(HDSP_D5, GPIO.HIGH) if data & 0x40 == 0x40: GPIO.output(HDSP_D6, GPIO.HIGH) if data & 0x80 == 0x80: GPIO.output(HDSP_D7, GPIO.HIGH) if adr & 0x01 == 0x01: GPIO.output(HDSP_A0, GPIO.HIGH) if adr & 0x02 == 0x02: GPIO.output(HDSP_A1, GPIO.HIGH) if adr & 0x04 == 0x04: GPIO.output(HDSP_A2, GPIO.HIGH) if adr & 0x08 == 0x08: GPIO.output(HDSP_A3, GPIO.HIGH) if adr & 0x10 == 0x10: GPIO.output(HDSP_A4, GPIO.HIGH) time.sleep(E_PULSE) GPIO.output(HDSP_WR, GPIO.LOW) time.sleep(E_PULSE) GPIO.output(HDSP_WR, GPIO.HIGH) def hdsp_send_text(text): text = text.ljust(16,' ') for i in range(8): hdsp_send_byte(0, ord(text[i]), 0x18+i) for i in range(8,16): hdsp_send_byte(1, ord(text[i]), 0x18+i-8) def hdsp_scroll_text(text): text = ' '+text+' ' for i in range(len(text)-15): hdsp_send_text(text[i:i+16]) time.sleep(0.25) i += 1 def hdsp_send_udc(character, matrix): hdsp_send_byte(0, character, 0x00) hdsp_send_byte(1, character, 0x00) adr = 0x08 for line in matrix: byte = 0 bit = 0x10 for pos in range(5): if line[pos:pos+1] == '*': byte = byte | bit bit >>= 1 hdsp_send_byte(0, byte, adr) hdsp_send_byte(1, byte, adr) adr += 1 if __name__ == '__main__': # initialize GPIOs io_init() # set brightness to 13% hdsp_send_byte(0, 0x06, 0x10); hdsp_send_byte(1, 0x06, 0x10); # Define custom characters hdsp_send_udc( 0, [ '*...*', '.....', '..*..', '..*..', '.....', '*...*', '.***.']) hdsp_send_udc( 1, [ '..***', '..***', '..**.', '..**.', '.....', '..**.', '..**.']) # do some stuff hdsp_send_text('Hello '+str(b'\x80')) time.sleep(4) hdsp_scroll_text('Scrolling text and custom characters '+str(b'\x81')+str(b'\x81')+str(b'\x81'))
Controlling a display with an Arduino Micro
Using an Arduino is also possible as long as you use a model which has enough digital outputs like the Arduino Micro.
Below is the code for the Arduino Micro. I use Visual Studio Code and PlatformIO for the Arduino, but it should also work with the Arduino IDE if you omit the first line #include <Arduino.h>
. At beginning the code also indicates how the outputs of the Arduino are used.
Even the breadboard test setup only contains one display, the code can also be used for two displays if you adjust send_text()
and scroll_text()
to use a buffer with 16 characters instead of only 8.
Important: the function for creating user-defined characters does not work with an array of strings but assumes that you pass a single string with exactly 35 characters (for 7 lines with 5 dots). So that you can see how the characters will look later, you can also split this up into several lines of 5 characters each in the source code. If the character matrix is not exactly 35 characters long, the code will not work!
#include <Arduino.h> int hdsp_a0 = 10; int hdsp_a1 = 11; int hdsp_a2 = 12; int hdsp_a3 = A0; int hdsp_a4 = A1; int hdsp_d0 = 2; int hdsp_d1 = 3; int hdsp_d2 = 4; int hdsp_d3 = 5; int hdsp_d4 = 6; int hdsp_d5 = 7; int hdsp_d6 = 8; int hdsp_d7 = 9; int hdsp_wr = A2; int hdsp_ce0 = A3; int hdsp_ce1 = A4; int e_pulse = 1; void send_udc(int character, const char* matrix); void setup() { pinMode(hdsp_a0, OUTPUT); pinMode(hdsp_a1, OUTPUT); pinMode(hdsp_a2, OUTPUT); pinMode(hdsp_a3, OUTPUT); pinMode(hdsp_a4, OUTPUT); pinMode(hdsp_d0, OUTPUT); pinMode(hdsp_d1, OUTPUT); pinMode(hdsp_d2, OUTPUT); pinMode(hdsp_d3, OUTPUT); pinMode(hdsp_d4, OUTPUT); pinMode(hdsp_d5, OUTPUT); pinMode(hdsp_d6, OUTPUT); pinMode(hdsp_d7, OUTPUT); pinMode(hdsp_ce0, OUTPUT); pinMode(hdsp_ce1, OUTPUT); pinMode(hdsp_wr, OUTPUT); digitalWrite(hdsp_ce0, HIGH); digitalWrite(hdsp_ce1, HIGH); digitalWrite(hdsp_wr, HIGH); send_udc(0, "*...*" "....." "..*.." "..*.." "....." "*...*" ".***." ); send_udc(1, "..***" "..***" "..**." "..**." "....." "..**." "..**." ); } void send_byte(int chip, int data, int adr) { if(chip == 0) { digitalWrite(hdsp_ce0, LOW); digitalWrite(hdsp_ce1, HIGH); } else { digitalWrite(hdsp_ce0, HIGH); digitalWrite(hdsp_ce1, LOW); } if(data & 0x01) digitalWrite(hdsp_d0, HIGH);else digitalWrite(hdsp_d0, LOW); if(data & 0x02) digitalWrite(hdsp_d1, HIGH);else digitalWrite(hdsp_d1, LOW); if(data & 0x04) digitalWrite(hdsp_d2, HIGH);else digitalWrite(hdsp_d2, LOW); if(data & 0x08) digitalWrite(hdsp_d3, HIGH);else digitalWrite(hdsp_d3, LOW); if(data & 0x10) digitalWrite(hdsp_d4, HIGH);else digitalWrite(hdsp_d4, LOW); if(data & 0x20) digitalWrite(hdsp_d5, HIGH);else digitalWrite(hdsp_d5, LOW); if(data & 0x40) digitalWrite(hdsp_d6, HIGH);else digitalWrite(hdsp_d6, LOW); if(data & 0x80) digitalWrite(hdsp_d7, HIGH);else digitalWrite(hdsp_d7, LOW); if(adr & 0x01) digitalWrite(hdsp_a0, HIGH);else digitalWrite(hdsp_a0, LOW); if(adr & 0x02) digitalWrite(hdsp_a1, HIGH);else digitalWrite(hdsp_a1, LOW); if(adr & 0x04) digitalWrite(hdsp_a2, HIGH);else digitalWrite(hdsp_a2, LOW); if(adr & 0x08) digitalWrite(hdsp_a3, HIGH);else digitalWrite(hdsp_a3, LOW); if(adr & 0x10) digitalWrite(hdsp_a4, HIGH);else digitalWrite(hdsp_a4, LOW); delay(e_pulse); digitalWrite(hdsp_wr, LOW); delay(e_pulse); digitalWrite(hdsp_wr, HIGH); } void send_text(const char* text) { int n=strlen(text); if(n>8) n=8; char buf[]=" "; strncpy(buf, text, n); for(int i=0; i<8; i++) { send_byte(0, buf[i], 0x18+i); } } void scroll_text(const char* text) { String output; output.concat(" "); output.concat(text); output.concat(" "); for(unsigned int i=0; i<output.length()-7; i++) { const char *outputBuf = output.c_str(); send_text(&outputBuf[i]); delay(250); } } void send_udc(int character, const char *matrix) { if (strlen(matrix) < 35) { return; } send_byte(0, character, 0x00); send_byte(1, character, 0x00); int adr = 0x08; for (int line=0; line<7; line++) { char byte = 0; char bit = 0x10; for (int pos=0; pos<5; pos++) { if(matrix[line*5+pos] == '*') { byte = byte | bit; } bit >>= 1; } send_byte(0, byte, adr); send_byte(1, byte, adr); adr++; } } void loop() { send_byte(0, 0x06, 0x10); send_text("Hello!"); delay(4000); scroll_text("Scrolling text and custom characters \x81\x81\x81"); delay(1000); }