[Elixir/Nerves] Character LCD with serial interface (I2C)
Tags: elixir, nerves, lcd, i2c
Published: 2021-01-19 03:07:00

As a [Nerves](https://www.nerves-project.org/documentation) IoT framework hobbyist, I enjoy learning the very basics of the electronics through writing [Elixir](https://elixir-lang.org/) programs that run on my Raspberry Pis.
Today I will talk about the [HD44780 Character LCD display](https://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller) with the serial interface. There are multiple ways to use the serial interface between an LCD and a Raspberry Pi, but here I will use a [typical inexpensive I2C piggyback board](http://www.handsontec.com/dataspecs/module/I2C_1602_LCD.pdf) as an example.

## Hardware

Here are the items I prepared:

- [Raspberry Pi Zero W](https://www.google.com/search?q=Raspberry+Pi+Zero+W&tbm=isch)
  - This can be any [target device that the Nerves project supports](https://hexdocs.pm/nerves/targets.html).
- [Micro SD card](https://www.google.com/search?q=Micro%20SD%20card&tbm=isch)
  - We will burn our firmware on a micro SD card.
- [16x2 LCD display with I2C serial interface](https://www.amazon.com/s?k=i2c+16x2+lcd+module)
  - Typically this is less than US$10 and it is pre-assembled.
  - Many inexpensive I2C boards use [8-Bit I/O Expander PCF8574](https://www.nxp.com/docs/en/data-sheet/PCF8574_PCF8574A.pdf) but please check what I/O expander yours uses.
  - [Handson Technology I2C Serial Interface 1602 LCD Module User Guide](http://www.handsontec.com/dataspecs/module/I2C_1602_LCD.pdf) summarizes the typical specifications of the PCF8574-based I2C module.
- Four [female-to-female jumber wires](https://www.google.com/search?q=female+to+female+jumper+wires&tbm=isch)

## Software

- [Nerves](https://www.nerves-project.org/documentation) - IoT platform built with Elixir
- [elixir-circuits/circuits_i2c](https://github.com/elixir-circuits/circuits_i2c) - Communicate over I2C from Elixir
- [mnishiguchi/lcd_display](https://github.com/mnishiguchi/lcd_display) - Use character liquid crystal display (LCD) in Elixir

## Wiring and connections

| I2C module | Raspberry Pi                                   |
| ---------- | ---------------------------------------------- |
| 5V         | [5V Power](https://pinout.xyz/pinout/5v_power) |
| GND        | [Ground](https://pinout.xyz/pinout/ground)     |
| SDA        | [SDA](https://pinout.xyz/pinout/pin3_gpio2)    |
| SCL        | [SCL](https://pinout.xyz/pinout/pin5_gpio3)    |

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

## Demo Nerves project

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/5wu4g4vwqcgh6kyxhlx2.gif)

Clone the demo project

```
$ git clone git@github.com:mnishiguchi/lcd_display.git
$ cd lcd_display/examples/nerves_hello_lcd
```

Set necessary environment variables. The demo project assumes you will [use WIFI](https://hexdocs.pm/vintage_net/cookbook.html#wifi) so two WIFI related values (ssid and psk) are required to be set. The `MIX_TARGET` environment variable can be any [target tag 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
```

Create firmware.

```sh
$ mix firmware
```

Insert the SD card into your host machine (e.g. laptop) and run the following command to burn the firmware to that SD card.

```
$ mix firmware.burn
```

Insert that SD card into your target board (e.g. Raspberry Pi) and power it on.

### Connect to your target board

Check the connection.

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

For the other supported commands, please refer to [`LcdDisplay.HD44780.Driver` documentation](https://hexdocs.pm/lcd_display/LcdDisplay.HD44780.Driver.html#content).

Here is the command I use for testing the LCD. It runs various commands one after another.

```
iex(1)> NervesHelloLcd.hello_pcf8574
```

## Some mistakes I made

### I thought all I2C boards were the same

Different products out there may use a differnt I/O expander internally.

At first, I was under the impression that all the I2C boards would do exactly the same thing. That is not true at all. There is no gurantee the same program works for all the serial interface boards.

[Embarrasingly, I posted to the Adafruit Forum saying the products I purchased might be defective, blindly using my old code for other I2C module](https://forums.adafruit.com/viewtopic.php?f=19&t=173685).

So the lesson I learned is even if two products look similar, it is a good idea to still check what I/O expander is mounted on a board and check the pin assignment between the I/O expander and the LCD display.

### I underestimated the desoldering

I totally underestimated the difficulty level of desoldering. I messed up two LCDs. First of all, desoldering itself is difficult to me at least. Secondly, a solder sucker can peel the printed metal sheet. I do not know the name of it, but I mean by the metal bits on which we solder to connect the header pins.

The lesson I learned is to avoid desoldering whenever possible.

### I connected only the Red LED pin for the backlight

Many I2C boards only support one pin for the backlight, using pins 1 to 16.

For the 16-pin standard LCDs, there is no issue, but for the 18-pin RGB LCDs, the pin #16 is for the Red LED. So the backlight can always be red if only that pin is connected not the Green and the Blue pins. I should have use a standard LCD, not the RGB one.

The lesson I learned is to make plans before using the RGB LCD.

## Other serial interfaces

They say [SparkFun Qwiic Connect System](https://www.sparkfun.com/qwiic) makes the I2C connection easy.

The USB port can be used for connecting a LCD.

Here are my study notes on [HD44780 LCD, I/O expanders, I2C interface etc](https://dev.to/mnishiguchi/hd44780-lcd-i-o-expanders-i2c-interface-etc-476e) in case they may be helpful for somebody.