[Elixir/Nerves] Hello to LCD display
Tags: elixir, nerves, i2c, lcd
Published: 2020-12-17 15:06:49

[日本語](https://qiita.com/mnishiguchi/items/f93aafcdcf284db28475) | English

## Introduction

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](https://dev.to/mnishiguchi/elixir-nerves-pulse-width-modulation-pwm-for-led-mj2). 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](https://www.nerves-project.org/) 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:

- Place many [LEDs](https://www.google.com/search?q=leds&tbm=isch) to make the hello text
- [Seven-segment display](https://en.wikipedia.org/wiki/Seven-segment_display)
- [Dot Matrix LED](https://en.wikipedia.org/wiki/Dot-matrix_display)
- [LCD Character Display](https://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller)
- Web interface
- Mobile interface

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

## Research

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

- [Hitachi HD44780 LCD controller datasheet](https://cdn-shop.adafruit.com/datasheets/HD44780.pdf)
- [Hitachi HD44780 LCD controller
  | Wikipedia](https://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller)
- [How a Character LCD works Part 1 by The 8-Bit Guy | Youtube](https://youtu.be/hZRL8luuPb8)
- [How to Use Character LCD Module | elm-chan.org](http://elm-chan.org/docs/lcd/hd44780_e.html)
- [Difference between interfacing character 16×2 lcd in 4-bit and 8-bit mode with microcontroller | engineersgarage.com](https://www.engineersgarage.com/knowledge_share/lcd-in-4-bit-mode-and-8-bit-mode/)
- [Character LCDs | learn.adafruit.com](https://learn.adafruit.com/character-lcds)
- [I2C Serial Interface 1602 LCD Module User Guide](http://www.handsontec.com/dataspecs/module/I2C_1602_LCD.pdf)

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.

- [fdebrabander/Arduino-LiquidCrystal-I2C-library](https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library)
- [dbrgn/RPLCD](https://github.com/dbrgn/RPLCD)
- [adafruit/Adafruit_CircuitPython_CharLCD](https://github.com/adafruit/Adafruit_CircuitPython_CharLCD)
- etc

On the other hand, I had trouble finding a good Elixir library for controling an LCD, other than [Elixir Circuits](https://elixir-circuits.github.io/). The [ExLCD](https://github.com/cthree/ex_lcd) 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](https://www.nxp.com/docs/en/data-sheet/PCF8574_PCF8574A.pdf), [MCP23008](https://ww1.microchip.com/downloads/en/DeviceDoc/MCP23008-MCP23S08-Data-Sheet-20001919F.pdf) 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](https://cdn-shop.adafruit.com/datasheets/HD44780.pdf) 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:

- [a library that knows how to communicate with an LCD](https://github.com/mnishiguchi/lcd_display); and
- [a demo app that demonstrates how to use the library](https://github.com/mnishiguchi/lcd_display/tree/main/examples/nerves_hello_lcd)

## Demo app

![](https://user-images.githubusercontent.com/7563926/103111408-b550d680-461a-11eb-8140-48adefe99eb2.gif)

### Prepare hardware

- A target board (e.g. [Raspberry Pi](https://www.google.com/search?q=Raspberry%20Pi&tbm=isch))
- [Micro SD card](https://www.google.com/search?q=Micro%20SD%20card&tbm=isch)
- [LCD display (16x2)](https://www.google.com/search?q=16x2+LCD+display&tbm=isch)
- [I2C interface module](https://www.google.com/search?q=Char+LCD+display+I2C&tbm=isch)
- female to female Jumper wires

Connect:

- 5V to [5V Power](https://pinout.xyz/pinout/5v_power)
- GND to [Ground](https://pinout.xyz/pinout/ground)
- SDA to [SDA](https://pinout.xyz/pinout/pin3_gpio2)
- SCL to [SCL](https://pinout.xyz/pinout/pin5_gpio3)

[![](https://user-images.githubusercontent.com/7563926/102290618-65358e00-3f0f-11eb-9031-ecd5227af653.png)](https://pinout.xyz/)

### Burn firmware to an SD card

Set necessary environment variables. [Here is a list of target tags that Nerves supports.](https://hexdocs.pm/nerves/targets.html)

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

Install dependencies.

```sh
$ mix deps.get
```

Here are some firmware-related commands.

```sh
$ 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.

```sh
$ 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.

```sh
$ 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:

  RingLogger.attach

or print the next messages in the log:

  RingLogger.next

iex(1)>
```

Run `RingLogger.attach` then log messages will be outputted.

Follow the instructions in [mnishiguchi/lcd_display README](https://github.com/mnishiguchi/lcd_display#usage) to show "Hello" text.

![nerves_hello_lcd_20201213_185620](https://user-images.githubusercontent.com/7563926/102028171-ba8a6780-3d76-11eb-94f4-f82272fc3063.gif)

## Conclusion

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](https://dev.to/mnishiguchi/hd44780-lcd-i-o-expanders-i2c-interface-etc-476e) as a separate post.

[![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F240349%2F5ef22bb9-f357-778c-1bff-b018cce54948.png?ixlib=rb-1.2.2&auto=format&gif-q=60&q=75&w=1400&fit=max&s=c746dae99633be5b9eadf524d7a7b191)](https://nerves-jp.connpass.com/)