"8th" - Embedded and more (part 3) - interfacing the 7-segment


This is the third in a series of articles exploring how to use 8th with embedded as well as desktop and server systems, in an integrated project. The first in the series is here, and the previous edition is here. It also lists prerequisites, such as requiring the Hobbyist edition of 8th.


Last time, we assembled the basic hardware (the LM75A sensor), connected it to the Raspberry Pi, and showed you how to talk to the sensor using the I2C interface words built-in to 8th. This time we're going to add a seven-segment LED display from Adafruit Industries.

Hooking up (safely)

I'll skip the details of assembling the Adafruit 7-segment display, since it's quite simple. What's less simple is interfacing it with 8th, since there is (or, rather, "was") no interface library for the device in 8th. It was therefore necessary to convert the Adafruit Python-based interface library to 8th; more on that in a bit.

First, you'll want to ensure that you've got the device assembled and connected correctly. So do that now.

Once you've seen that you've got things working properly, you can get the 8th code for this post, and unzip it on your Raspberry Pi.

You light up my life (or at least, my LEDs!)

As I mentioned above, I had to convert the Adafruit Python LED interface code (from the GitHub repository) to 8th. The two files we needed to convert were the Holtek HT16K33 LED driver and the 7-segment I2C driver. If you compare the Python and 8th code, you should be able to see the parallels. The 8th code is in the file libs/dev/7seg, and is accessed from the main code by including it with needs dev/7seg.

In Python, a new class is created as is usual in Python. In 8th, we simply create an array whose elements hold the information we need. We could have created a user-defined data-type, but I judged that overkill for such a simple bit of code. In keeping with 8th's usual practice, the array holding the device information is left on the stack by each word operating on it, to leave it available for the next word.

Low level: HT16K33

The 8th version of the low-level HT16K33 driver is initialized with LED:init, which takes an i2c bus number, and an i2c device address as its parameters, and returns an array. The array contains two items: the 8th I2C hardware handle for the LED device, and the backing-store buffer. That buffer is 16 bytes, and marked writable. Failure to make it writable would mean that a new buffer would be created when any modification to the current one was made. That's not useful in our case, since we want the backing-store to change, and this buffer is the LED backing-store. The device gets sent the buffer using the word "write-display", when the LEDs should be updated. You must pass the array from "init" to any interface words operating on the LEDs.

Note the use of "namespaces" in 8th: the low-level HT16K33 words are in the "LED" namespace, so "init" is really "LED:init".

High level: 7seg

The namespace "7seg" contains the higher-level code which you're more likely to use. The "7seg:init" word takes three parameters: "invert", "bus#", and "i2caddr" (the parameters are not actually named, they are pushed on the stack in the order given), and the result is an array containing a LED array and the "map" item which converts input characters into a bitmap to be shown.

Again, the code is roughly parallel to the equivalent Adafruit Python code. The high-level words most useful to the programmer, are "clear", which blanks the display, and the "print-*" words. The data.8th sample uses the "7seg:print-float" word to display the temperature.

Once you've unpacked the file 'allcode.zip' you can run it by changing directories to the 'data' folder and then running the 'data.8th' file:8th data.8th.

The output to the console will be similar to the previous version's output, but you should see the LEDs light up and display the current temperature (in ºC)

The modifications to 'data.8th' from our previous version are few and simple:

  1. needs dev/7seg
  2. add a variable to store the handle: var 7SEG
  3. intialize the LED: false 1 LED:DEFAULT_ADDRESS 7seg:init 7SEG !
  4. write to the LED: 7SEG @ over 1 true 7seg:print-float drop
  5. add a frivolous "intro-screen" which scrolls 'o' on the LEDs


The 8th code as presented is functional, and a relatively straightforward translation of the Python code. It is not, however, particularly efficient nor particularly representative of 8th (or Forth). In particular, bits of code are replicated in different places. Typically, those bits would be "factored out" into separate words. Some of the code could be rearranged to be more compact and probably more efficient; however, one goal was to show how to translate Python into 8th (since so much Python code is available).

More resources

This article is not intended to be a tutorial on how to use 8th: for that, you can see the tutorials, the manual, the forum, or you can start here: 8th - a Gentle Introduction to a Modern Forth.

Next time...

The next installment will deal with the server-side of our little project. Until then, enjoy 8th and may the Forth be with you!