I’m making a digital clock. It’s an analog-style interface but with 132 RGB LEDs at each tick. Software-side, I needed to rewrite the existing DS1307 RTC libraries that communicate with the Arduino’s microcontroller, since they didn’t do data verification for valid times, and they relied on communicating with the module every second, putting a massive strain on the microcontroller. I solved these problems by offloading the timekeeping effort to the microcontroller, giving it a data structure I designed for it to update. The RTC could then be a backup of the time the microcontroller could read from whenever it powers up. Hardware-wise, I designed my own PCB to create a neat and compact space for all the components.
The Idea
Imagine an analog clock. Each tick on the analog clock would instead be replaced with an RGB LED (meaning 132 LEDs to cover seconds, minutes, and hours). A microcontroller would be used to control lights, while a real-time clock (RTC) could do the timekeeping.
Okay, but Why?
For fun, honestly. Aside from being able to build something I think is pretty neat, the real fun is being able to take the principles and skills I learned and put them into practice. At the same time, it lets me write all about the design process of it as I go along, from initial theorycrafting, all the way to soldering it all together.
The LED
I could use any LED out there, but I wanted to work with the WS2812B. You might be familiar with these since these are a very popular RGB LED. You can find these as strips online pretty easily and cheaply, and I considered using those since they were so easy and cheap to find. The problem with that idea was that if I wanted to lay things out in a space-efficient way, strips would force me to make a very large circle. In addition, it wouldn’t look very great as a finished product. So, let’s try something different. I had these individual LED modules. They were much smaller, so, laying these out shouldn’t be bad size-wise. The question now is, exactly how big would a circle of 60 of these things be?
Lesson 1: High School Geometry Is Useful
I knew the approximate diameter of these modules, 9.4 mm. I then envisioned the PCB of the modules being a square with 9.4 mm sides. I then remembered high school geometry, specifically, regular polygons. I can think of the problem like laying out a 60-sided polygon with 9.4 mm sides. By using an appropriate calculator, I was able to get the answer I was looking for – the inradius from the center to the nearest tip of any given module in the circle would need to be about at least 89.68 mm. Add another 18.8 mm, the length of two entire modules, and this leads to a radius of 108.48 mm. This represents the radius of the smallest circle that would be able to surround all of these modules. This number is important since it defined how big the frame the wooden frame I intended to house the LEDs would need to be. In this case, I would need a square board that has at least 216.96 mm (or about 8.54 inch) sides. And, the hardware store has square plywood pieces that were 12 inches by 12 inches. I’d have more than enough room to give the modules space! Success, right? Well, kind of. I quickly mocked up a design in Adobe Illustrator to laser cut a housing from plywood, but thinking about it, I was dissatisfied. My new problem was the wiring. First, wiring all the modules would be tedious. Second, my wiring job might be subject to failure, be it accidental shorts, joints that don’t hold well to the board, etc. Third, without the frame, the modules would be prone to movement, again, putting my solder joints under mechanical stress. Fourth, I’d need to figure out a way to solder the first module’s data in pad to the microcontroller. Fifth, it’s recommended to hookup power to various points along the strip to ensure enough power reaches all the modules. And, on top of these problems, I was wondering if the size could be any smaller still. The only way to find out was to start over and go back to the drawing board.
Keeping the Time
There are two problems a traditional desk clock has. The smaller of the two problems is that when you update the time on these clocks, you always have to increment one unit at a time. So, if you go one unit over the time you want to set it to, you have to press the button 59 more times. And hope you don’t do that again in the process. So, I opted to add the extra button that lets you increment and decrement a unit at a time. The second of the two problems is semi-related – for those who’ve played around with an Arduino, you might be aware that the Arduino itself could keep and update the time all on its own. Sure, that could work, but say the Arduino loses power somehow. What happens when you power it back up?I planned on plugging this thing in like a regular digital clock, but if the power went out, the microcontroller would lose its memory on what the time was. It’d need to power up to a default state, like the lovely blinking 12:00 am you see above, before being set again by the user. That isn’t terrible, but, I wanted to design something as hassle-free as possible. Enter the DS1307 real-time clock.
The DS1307 is a simple time-keeping chip. It’s low power, has 64×8 memory (64 bytes of memory), and is able to keep track of seconds, minutes, hours, date of the month, month, day of the week, and year with leap year all that way to the year 2100 all on its own. It only needs two wires to communicate with a microcontroller via I2C. If the power goes out, an onboard backup battery can keep the chip running and keeping the time, so by the time the power comes back on, the microcontroller could set itself without my intervention. Best of all, a ready-to-use module can be had for a little under a dollar on eBay or Aliexpress. There’s a catch, however.
Lesson 2: Memory Is Cheap, Reads Are Expensive, Documentation Is Everything
If you look online for libraries that can interface with the DS1307 with Arduino, you’ll find a good load of them. So, I don’t need to even write a library, right? Well, not exactly. The code out there doesn’t prevent you from setting illogical times. Here’s the problem – looking in page 8 of the linked documentation, the DS1307 when set with illogical time and date entries puts the device in undefined operation. Which basically means, you’re going into uncharted waters if you do that. That’s not a good thing. The chip itself can’t stop you from doing that, however, so we have to be careful.
Second, example code demonstrating the timekeeping relies on reading from the DS1307 every second. Here’s the problem – reads are expensive, in terms of time. To put why that is, basically, when the microcontroller and the RTC communicate with each other, they need to handshake, specify what the microcontroller intends to do, and transfer whatever information needs to be transferred one word at a time with acknowledgements in between. But worst of all, each word needs to be literally spelled out one bit at a time. I describe how I2C communication works in more detail here. In the end, the microcontroller would be so busy doing this every second, it wouldn’t be able to handle any other tasks, like, take inputs from buttons, or updating the LED display. And, the library still doesn’t stop users from trying to set illogical times. So, let’s use data structures and good object oriented programming practices to solve the problem.
First, I made a library with a data structure that was compliant with the DS1307’s expectations of time – that is, seconds and minutes go from 0 to 59, hours go from 0 to 23, days of the week go from 1 to 7, months go from 1 to 12, and years go from 2000 to 2100. Days are a bit different, since they are month and year dependent. A user is only able to have access to setters and getters of the object, and could not manipulate any data directly. This goes together with doing checks to ensure the data is logical. Together, any data overwrites are guaranteed to be correct, preventing scenarios where the RTC is running in an undefined state. Next, I created a simple interface to increment the time by a second by overloading the increment operator. In the background, it’s doing a lot of checks, but, hey, that’s the joy of abstraction – it works. Finally, I looked into the documentation to give access to all the features of the chip, including enabling/disabling the oscillator and accessing the other bytes of memory.
Lesson 3: It’s a Good Time to Learn Something New
I’ve wanted to find an excuse to learn how to design and get a PCB manufactured, and I realized that this would be a great project to do just that. So, I downloaded Eagle and got to work learning.
Eagle is computer-aided design software for electronics design. There are two “views” your design exists in. First is schematic view, the kind of blueprint of your project. Here, you can place all your parts and get a general sense of connectivity.
The second is board view, where you actually put your parts on a board and route the connections together.
When making the schematic, some parts (for example, the push-button switches and capacitors) exist in default Eagle libraries. Other parts (for example, the Arduino Nano and WS2812B) are part of libraries ready to download online. In my case, the WS2812B came from Adafruit’s library while the Arduino Nano came from element14 (after some modification). But then there are some parts that you’ll just need to make on your own (for example, the DS1307 timekeeping module). Eagle also has some neat tools in the form of User Language Programs (ULPs), which automate some tasks (for example, arranging the LEDs and capacitors about a circle.
The board you see above is the proof of concept I have of the much larger board I’ve made. Since I haven’t soldered bare WS2812Bs, and since this is the first board I designed, I wanted to be sure my design works at small scale before committing all 132 LEDs in the bigger design.
This tentative final board is 200 mm by 200 mm, but I can lop off the extra bits off the sides and get the size down to 170 mm by 170 mm. Comparing this to the initial design of wiring a bunch of individual modules together, the PCB would be a little over 61% the area of the initial idea.
To Be Continued…
As of now, I’m waiting for the PCBs and parts to come in.
Update (10/26/2018)
The prototype PCBs came in, and they look pretty slick! Still waiting on some headers and SMT capacitors before I start assembling these together.