LED display HDSP-211x

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.

HDSP-211x layout

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”):

Memory area FL A4 A3 A2-A0
Flash RAM 0 Character position
UDC adress 1 0 0
UDC RAM 1 0 1 Row number
Control word register 1 1 0
Character RAM 1 1 1 Character position
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:

  1. Set WR to 1,
  2. Set RD to 1 (if you only want to write data, you can also connect this input permanently to VDD).
  3. Set CE to 0 to activate the module (if you run only one module you can also connect this input permanently to GND).
  4. Set FL, A0-A4 and D0-D7 as needed.
  5. 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 ¿ ñ Ñ α β γ η θ λ μ π σ Σ
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%
001: 80%
010: 53%
011: 40%
100: 27%
101: 20%
110: 13%
111: 0%

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
1: Self test OK

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.

HDSP-2112, Test mit Raspberry Pi

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:

HDSP-2112, R/C circuit for reset

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:

  1. Initializing the GPIO ports.
  2. Reducing the display brightness to 13%.
  3. Defining two user defined characters.
  4. Output of the text “Hello” followed by a smiley which was created as individual character.
  5. 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:

HDSP-2112, Test with two displays and Raspberry Pi

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.

HDSP-2112 mit Arduino Micro

Following is the sketch for the Arduino IDE. In the beginning there is also the definition how the outputs of the Arduino are being used. I did not include custom characters in this script, but you should get the idea.

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 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);
}

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(int i=0; i<output.length()-7; i++) {
    const char *outputBuf = output.c_str();
    send_text(&outputBuf[i]);
    delay(250);
  }
}

void loop()
{
  send_byte(0, 0x06, 0x10);
  send_text("Hello!");
  delay(4000);
  scroll_text("This is an HDSP-2112 controlled by an Arduino Micro.");
  delay(1000);
}