Sometimes when you’ve been buried deep in a subject, you lose track of where you were before the journey began. This article series plunges into the process of an absolute novice designing, assembling, and programming a very basic clock. About half of it will be narrative, talking about the process, the other half will focus on the technical details. While I do try to keep it readable, I’ve been in the project so long that I’ve lost track of the point of view from the outside.

In the first draft of this opening article, I ended up with a rambling stream of consciousness mess that didn’t meet my standards for submission. So yeah, it was pretty bad. I will, however, shamelessly reuse the opening paragraphs.

Recently, I realized that I have been inadvertently doing a series, albeit an irregular one, where I would write about my attempts to learn a topic or skill. Only one of these was an instructor-led attempt, though I am hesitant to seize the title of autodidact, simply because these are hobbyist level dalliances. It would be technically correct for some topics, and isn’t that the best kind of correct?

Largely, I learn by doing. I select a goal, develop a plan to reach that goal, implement the plan, the revise the plan when it inevitably runs into issues resulting from my initial ignorance. In my current learning project, my ambitious goal is to design and build some electronic device which uses Nixie tubes for output. We’re nowhere near using those stylish vacuum tubes. The exact nature of this device has varied in my mind’s eye as I address my own knowledge gaps. I know that as it stands now, I do not possess the skills needed to do most of that, even if I’d set the function in stone.

So, what’s a man to do?

Clearly, I must start by addressing what I know I don’t know but will need to know. What I did instead was go on a spending bender for electrical components, and now I have to work around the sunk costs. Otherwise, I’d feel like such a fool. So, now I need a plan. The vague destination project doesn’t cut it. So I picked an intermediate goal. I’d ordered a bunch of electrical components with no real rhyme or reason beyond “These might be useful in future learning projects.” I got resistors, capacitors, a stack of shift registers, IC sockets, some protoboards, jumper wire, and five MSP430F2003 microcontrollers.

The MSP430-series is another family of chips from Texas Instruments. Unlike the shift registers, these are much more complex, being essentially a computer on a chip, containing a CPU, a timer source, RAM, non-volatile storage, and all that jazz. They’re designed for low-power applications and optimized for not guzzling electricity. This may sound like quite a jump from poking at a shift register, but I have a strong background in bigger computers and programming. So I’m working my way towards understanding circuits from both directions.

In a practical level, all the MSP430 will be doing for the time being is taking over from the Raspberry Pi I used before. That is, running code to push 1s and 0s down the wires. But what am I going to do to learn? Well, among the components I bought was a four-digit, seven-segment display, you know, the kind you find on a regular digital clock. So, I’ll make a clock. Unfortunately, or fortunately, it wasn’t so simple. They do sell real-time clock chips which do all the work even to the point of maintaining the calendar and accounting for things like leap years. Yeah, maybe later. I’m here to learn. I’ll be using the MSP430’s internal timer to drive the clock, but it knows nothing about time.

What are the components of this project? A: Figure out how to light up the lights on the display. B: Figure out how to get a regular interval counter from the MSP430 timer. C: Make the MSP430 output the value from B to the display. D: Figure out how to let the user set the time. Spoiler, it proved to be more effort than I originally expected. For the buttons, the wiring side is so trivial, but the code is where the catch is.

I also did these steps out of order. Why? Well, after placing the order for the lot of components, I started looking into how to get code onto the MSP430. If I was a masochist, I could write my own program to push ones and zeroes of assembly code over two or four pins… but I am less interested in reverse engineering that communication protocol than I am in getting the project working. Texas Instruments makes a series of developer boards which can be used to flash the memory on the microcontroller, and even debug the code by reading the memory, interrupting code execution on the chip, etc. These are the ‘Launchpad’. There are a number of different versions, but I ordered one off Amazon which fit the F2003 version.

Because I am a sucker who is still paying for Prime, the Launchpad arrived two days later, well before the larger shipment containing the F2003s. At first, I started to fret, because the socket was pre-populated with a larger chip than the F2003s I’d ordered. After a moment, I found the “supported microcontrollers” section of the documentation and the mile long list of chips it worked with. It had come with a MSP430G2553 chip, but did support the F2003s I had coming. In terms of capacity, the G2553 dwarfed the F2003, having more of, well, everything. It was, however, code compatible with the lightweight F2003s. So I could get started with my software before my hardware arrived.

Aaaand, we ran into the first self-inflicted difficulty.

You see, that G2553 shipped with demo code pre-installed, and I wanted to make a backup of the contents just in case. I went around from utility to utility looking for something to get the data off the chip. Along the way I downloaded two development environments, USB drivers for the Launchpad, and finally, a utility that let me dump arbitrary ranges of memory off the chip. I got a bunch of binary I had no clue how to interpret. Fine, I had my backup. I could flash it back using the same utility. So, lets get some of my own code on there.

I found an annoying quirk. The protocol used to load data onto the Microcontrollers is a remnant of the days of yore when every desktop PC had a nine-pin serial port. It had been translated to create virtual COM ports on the USB connection. This being that USB driver I previously mentioned. But the whole thing doesn’t play nice with the Windows USB stack for USB3 ports. Well, guess what most of my system had? This was an intermittent problem I would notice later. As it stood, I found one of the development environments couldn’t find the Launchpad. I ended up using the TI-developed software, as it did manage to find the Launchpad.

If I were doing this industrially, Texas Instruments’ Code Composer Studio would be expensive, but the free, hobbyist license will work for code below a certain size. I think that size is 16KB – which is as much as the G2553 can hold at full capacity, and sixteen times the F2003’s 1KB limit. So I’ll be good. I just needed the C header files for the hardware. This was included with example code from Texas Instruments. And a lovely export attestation page.

Laws and Regulations.

Huh. So, the header files and example code for a $2 Microcontroller are subject to export restrictions because of potential use in weapons development?

Okay then.

Well, In the example code was the C source code for the demo software the G2553 was delivered with. So I would literally never need the binary dump I made. Oh well.

Now that I could get code into the chip, I fell down the rabbit hole of learning the nuances of C-code for embedded systems. The first thing I did was write a version of the shift register test code that switched between versions at the press of a button. This would actually form the core of the code for the clock later, since the updates to the state of the output were done based upon interrupts generated by the chip’s internal timer.

What is an interrupt? In short, it’s an event not caused by the normal sequence of code. It could be anything from the internal timer ticking over, to a change in state of an external I/O pin, to a catastrophic system issue. We’re not delving into catastrophic system issues at this point, but interrupts are essential for anything that is going to be interacting with the real world. A user pushing a button doesn’t want to wait for the code to get around to checking the state of that button if that code has anything else it needs to do and might miss the button press all together. As for interrupts from the internal timer, it will trigger them on regular intervals which you have to configure at the start of your code. Eventually I’ll get around to tuning that to be an actual second long, but for the time being, regular intervals is good enough.

This article is getting way too long, it ran well past the word count of the shift register article, which was already pretty big, so I’m breaking it up. We’ll stop here, having completed Step B and ready to go back to Step A when the hardware makes its appearance.