Such Programming

Tinkerings and Ramblings

Mad Computer Science – Part 2 – 7-Segment Driver

In the previous post, I implemented a single decimal digit display that used "hardware" pretty minimally. The digital logic side of the design simply split each bit of a byte to allow a software controlled means of controlling each segment of the display.

In this post I'll expand on this design and explore a few more core concepts in hardware tinkery.

The primary goal for this post is to use the 7-segment displays to view the hexademical values for the binary data we're delivering through the Telnet block. When I send an ASCII `K` to the design, I want to see the `4B` displayed in the simulated displays.

What the Hex

In the last post I had a table for which segments should be lit for `0-9`. I'll need `A-F` as well, so I'll add them to that table.

`0``--543210``3F`
`1``-----21-``06`
`2``-6-432-0``5D`
`3``-6--3210``4F`
`4``-65--21-``66`
`5``-65-3-10``6B`
`6``-6543-10``7B`
`7``----321-``0E`
`8``-6543210``7F`
`9``-65-3210``6F`
`A``-654321-``7E`
`B``-654--10``73`
`C``--543--0``39`
`D``-6-4-210``57`
`E``-6543--0``79`
`F``-6543---``78`

My plan is to make a couple small components to organize my implementation for this. I'll start with a single 7-segment driver that takes a 4-bit (nibble) input and drives 1 segment. Once I have that, I'll combine two of them into 1 block that can drive 2 segments.

I'll start by planning out my driver design, first dropping a display in the schematic and making an input bus.

So now I need to light up the right segments based on the values of 4 inputs. I thought of a few different ways for how this could be done.

Logic Gates, Logically

I decided to see what it'd take to light up segment 6 for the right inputs. I started by looking at which numbers should and should not be lit for this segment.

Should be lit:

`2``0010`
`3``0011`
`4``0100`
`5``0101`
`6``0110`
`8``1000`
`9``1001`
`A``1010`
`B``1011`
`D``1101`
`E``1110`
`F``1111`

Should not be lit

`0``0000`
`1``0001`
`7``0111`
`C``1100`

I don't see any obvious simple pattern for implementing this with logic gates. Since the display is lit 3/4 of the time, my quick implemention idea is to use 4-input `AND` gates with some inverted inputs to match each pattern that should not be lit, and input all of those into a 4-input `NOR` gate.

I'll roughly layout the logic gates and route `0` to the remaining segments for now.

Each gate will match a condition where the segment shouldn't be lit. For when a bit value I'm looking for is `0`, I'll flip that invert on its way into the gate. I'll struggle a little bit to wire things up properly then give it a little bit of manual testing.

"Proper" engineering

While this solution only has 5 gates in my schematic, 4-input gates are basically each made of 3 gates. So this design would take at least 15 gates, before including the inverted bits... which is pretty inefficient. There are better, boolean-mathical ways of addressing this, and the simulator has a bit of tooling to assist in avoiding the maths.

If I add and name an output, and name the inputs, I can ask the analysis tool to do it's thing. It'll generate a truth table for me. At the bottom of that table I can find a simplified function that'll generate the same output. I can also bring up the Karnaugh map, though I don't find it particularly helpful here.

That's still... not exactly small is it?

I'm not particularly interesting in doing that 6 more times, so I'm going to change my approach.

Cheat Codes

Instead of going through all that, I'm going to use a LUT (Look-Up Table) to design this a bit more like the original software-oriented route. I'll toss all of this implementation out the door and wire a new LUT block into the design.

Next, I'll load up a file that contains the hex values of the digits.

``````v2.0 raw
3f
06
5d
4f
66
6b
7b
0e
7f
6f
7e
73
39
57
79
78
``````

Well! That was a heck of a lot quicker and easier. I'll just tweak the inputs and outputs so that I can save this design and use it elsewhere.

Then I'll quickly make a dual-display variant, that simply takes in an 8-bit bus and outputs two segment busses. If I open straight to a new file, the simulator doesn't pick up my other files in the `Components` menu. If I choose a `New embedded Circuit`, it will find those files.

Finally, I'll go back into my Telnet schematic and wire up everything to use my new block. To keep things looking relatively tidy, I'll pre-wire the segments to space things out then collapse those individual signals into 4-bit busses. I'll then split the 8-bit segments out into top and bottom busses. I used the horizontal offset of the `8:4*2` splitters to help me visually remember that S1 is on the left and S0 on the right.

That Darn Impedence

With everything wired up, things do work, but there's a little bit of undesired behavior.

Before and after I send my sequence through the Telnet block, the displays will show a random value due to the inputs that aren't being driven to a valid state for reading.

I need somewhere to latch onto just the valid inputs at just the right times, which is exactly what flip-flops are here for!

Latches and flip-flops are circuits for storing bits of information. This playlist on YouTube covers the standard variants

I generally prefer the D-type flip-flops, as they are simple and good for registers. I just feed my data into `D`, and when `C` transitions from `0` to `1` the value will be stored and output on `Q` until the next rising clock (the opposite values will be output on the inverted `Q`, unused here)

I also added the `AND` gate here so that the flip-flop will only latch to the value when the `av` and clock signals are high. This still leaves me an unexpected result at the end of my sequence.

The problem here is that both the Telnet block and the flip-flop latch when the clock transitions to `1`. Does the Telnet block update fast enough to allow this? Probably not.

Though, if I invert the clock the latching will happen one half-cycle after the Telnet block has updated its value. Giving the Telnet block a little time to change its output before storing it.

There we have it, a decently working hexadecimal display! With the goal complete I'll call it a wrap for this post.

I hope you enjoyed this post, stay tuned for the next one!

Bonus material

While you wait for the next post, here are a couple good videos to check out: