[Elixir Nerves] Hello to LCD display

[Elixir Nerves] Hello to LCD display

When we learn a new programming language, usually the first thing we do is to print the "Hello world" text. It seems like the equivalent in the IoT is to blink an LED. After I was successful in blinking an LED, I got curious about how to change the brightness of an LED. Then I started to think about actually printing the "Hello world" text somehow.

Many ways to output text

I had tons of electronic parts at hand from the starter kit I purchased when I first started playing with the IoT framework Nerves and Raspberry Pi. So it was a great opportunity for me to learn how to use them. Here are some options I came up with:

Eventually I want to do them all but for now I decided to use a Character LCD Display with I2C interface. Some determiners are:

  • LCD Character Display with I2C interface requires only 4 wires
  • LEDs requires so many wires and it seems messy
  • Web and mobile interfaces are practical but I wanted to learn electronics now


I googled around and watched tons of Youtube vidoes to learn the basics. Here are some of the resources I found helpful:

There was nothing difficult about the wiring; however, many tutorials just use certain libraries that communicates with an LCD when it comes to the programming. Many are written in C, C++ or Python.

On the other hand, I had trouble finding a good Elixir library for controling an LCD, other than Elixir Circuits. The ExLCD library does deal with LCDs; however as of writing it has not been maintained for many years and depends on old dependencies.

At first I forked ExLCD and attempted to build on it. Then I realized that there is nothing special in communicating with an LCD as I learned more about the Hitachi HD44780 LCD. All I need is to understand what its datasheet says. I decided to write my own from scratch, borrowing ideas from other libraries.

Some key things are:

  • what each LCD pin does (RS, En, D4-D7)
  • how to initialize the display
  • 4-bit mode vs 8-bit mode
  • instruction mode vs data mode
  • how to send instruction
  • how to send data
  • the pin assignment between the I/O expander (e.g. PCF8574, MCP23008 etc) and the LCD
  • the basics of I2C

Experiments by trial and error

I did experiments using a playground Nerves app. After all, all I needed was:

  • understand roughly what the HD44780 datasheet says
  • understand the pin assignment between the I/O expander and the LCD
  • understand how to switch on/off the output of the I/O expander through I2C interface

I took me a while to be able to show the "Hello" text because I did not do the above-mentioned. It was frustrating when I saw a random text on the display.

Once I was able to show the "Hello" text on the display, I wrote tests, improved the code and refactored incrementally. I realized my experimental app can be split into:

Demo app

Prepare hardware


Burn firmware to an SD card

Set necessary environment variables. Here is a list of target tags that Nerves supports.

$ export WIFI_SSID=_____  # your WIFI id
$ export WIFI_PSK=______  # your WIFI password
$ export MIX_TARGET=rpi0  # your target board

Install dependencies.

$ mix deps.get

Here are some firmware-related commands.

$ mix help | grep firmware

mix burn                   # Write a firmware image to an SDCard
mix firmware               # Build a firmware bundle
mix firmware.burn          # Build a firmware bundle and write it to an SDCard
mix firmware.gen.script    # Generates a shell script for pushing firmware updates
mix firmware.image         # Create a firmware image file
mix firmware.metadata      # Print out metadata for the current firmware
mix firmware.patch         # Build a firmware patch
mix firmware.unpack        # Unpack a firmware bundle for inspection
mix upload                 # Uploads firmware to a Nerves device over SSH

Create firmware.

$ mix firmware

Insert the SD card into your host machine.

Burn the firmware to that SD card.

$ mix firmware.burn

Insert the SD card into your target board.

Power your target board on.

Connect to your target board

Check the connection by pinging.

$ ping nerves.local

SSH into your target board, then interactive Elixir shell will start.

$ ssh nerves.local

Interactive Elixir (1.11.2) - press Ctrl+C to exit (type h() ENTER for help)
Toolshed imported. Run h(Toolshed) for more info.
RingLogger is collecting log messages from Elixir and Linux. To see the
messages, either attach the current IEx session to the logger:


or print the next messages in the log:



Run RingLogger.attach then log messages will be outputted.

Follow the instructions in mnishiguchi/lcd_display README to show "Hello" text.



It was a great experience for me to learn I2C allows me to communicate with a peripheral quite easily just reading the datasheets carefully. Reading the datasheet is super important.

I put together my study note on HD44780 LCD, I/O expanders, I2C interface etc as a separate post.