10/01/2019 at 12:23 •
Just a quick video outlining some software improvements I've made such as fixing that stuck segment bug and adding brightness adjustment. Still need to figure out how to activate and set alarms using the user interface without making it cumbersome.
09/23/2019 at 19:06 •
Here's a quick demo and assembly video that recaps the hardware side of things:
Ok, with that out of the way we'll now go into some more detail about the software works. The software has a few main tasks going on that all have to run simultaneously. First the atmega328P has to generate the higher voltage for the tube and it does this using timer1 running at ~62.5kHz (adjusting the duty from 50-95% will boost the open circuit voltage from ~30-120V, respectively). Luckily the load (the vfd tube) wont really change drastically during operation so I just run the boost converter open loop, although closing the loop would be simple enough by adding some code to the interrupt.
Additionally we need a method to automatically update the multiplexing to all the digits. This is done in the timer2 interrupt which is configured to fire off at 2kHz. In this interrupt we do a couple of things. First off, similar to my word and discrete 8 digit LED clocks, the interrupt will step though one digit each iteration and set the correct segments to send. Data is sent serially via the SPI peripheral so that we don't have to waste time manually bit-banging pins to send the required 20 bits to update the next digit. Actually an odd aside, since the mcu only deals in 8 bit spi packets at a time we end up having to send 3 bytes (24 bits) and the first 4 bits just end up being discarded.
So now we have high voltage and data going to the tube driver. All we have left to do is read button inputs, talk to the real time clock and make fun beeps/boops when a button is pressed. I originally wanted to generate the beeps of adjustable frequency using timer0 but found out that's what the arduino library uses to generate delays and messing with that would be slightly annoying. So instead I just look for a buzzer flag that any function can set to control the buzzer and if it's set then in the interrupt it toggles the buzzer pin. Since it can only toggle it once per interrupt period then the frequency ends up being half that of the interrupt which is 1kHz (a suitably loud but not too annoying frequency for a beep).
The real time clock is also controlled via SPI, but I was a bit lazy on this one and just included the library file I wrote before for bit-banging the signalling (I definitely could have shared the data and clock with the max6921 driver chip though and just given the rtc a separate chip select). We have lots of free pins so why not.
For the button pins, I thought of having a separate pin change interrupt to read them, but instead I simply reused the timer interrupt to poll the buttons at 2kHz and set global flags which any other function can use to react to button presses. Additionally the button flags are also read during the buzzer code in the interrupt to beep when any button is pressed for a bit of user feedback.
So that's about everything in terms of software. There is one major bug I've found where segment A of digit 0 always seems to be set and I've tracked it down to the display mux code in the interrupt so I'll fix that once I get the time.
09/23/2019 at 17:49 •
To start off, thanks to JLCPCB for sponsoring this project as well as providing pcbs to get the ball rolling. JLCPCB Prototype for $2 (Any Color): https://jlcpcb.com
The hardware requirements of this project are fairly simple: two buttons for setting time, a small speaker for delightful beeps and possibly to add alarm functionality in the future, onboard software controllable "high voltage" boost converter to generate ~30-70V from 5V, USB micro power input, battery backed real time clock, and software controllable dc filament drive/driver blanking. I've pretty much done an identical clock in the past using a larger IV-18 tube with the pcb done on protoboard using hand wiring but this time I wanted something that would look more professional.
The design consists of two boards. The first is the main board that contains all the electronics to keep time, generate the necessary tube drive voltage, and control all the multiplexed segments for the display. I wanted to keep the board small, single sided for easy assembly, and yet not go crazy with microscopic surface mount components. The digital parts are for the most part surface mount, but the boost converter components are through hole and suitably spaced for ease of replacement or sourcing suitable alternatives. All the low voltage stuff is condensed to the left hand side, while the higher voltage goodies lie on the right side with the tube header on the very end. I opted to just do dc filament drive as my past experience with the brightness gradient due to dc wasn't bad (especially for small tubes like these) compared to the complication that moving to ac drive would add. Here's the circuit and layout I settled on:
The second board is just a wiring pass through to allow the vfd to be mounted above the main board, and connects via a standard 0.1" pin header and female socket for ease of replacement (just in case the tube burns out or meets an unfortunate end after a rough bump or drop). Here's what it looks like:
I actually had an interesting time figuring out an easy way to calculate the positions of the radial pads. Since eagle does everything in cartesian coordinates making a nice evenly spaced circular arrangement of pads is easier said than done. I'm not familiar with eagle's scripting language yet, so I ended up manually setting the coordinates of each pad, but to make my life easier I wrote up a quick excel spreadsheet to calculate the x and y values for you if you plug in the desired number of pins, radius and angular separation. Hah, and I often hear people say they never use trig after high school, but those equations came in handy for me now! Then all you need to do is plug in the output x and y coordinates into the pad position settings in eagle and they are perfectly aligned! (Caveat: the calculations sometime spit out negative angles and positions in the wrong quadrant, but some common sense of signs when transferring the coordinates will fix those issues quick enough)
This "calculator" ended up being super useful and I will definitely end up using it in future projects with various tubes I intend to use.
After receiving the boards from JLCPCB I quickly assembled them.
It certainly looks the part! There were a few small problems with the circuit though. I accidentally miswired c6 (the large electrolytic cap) to the wrong point (just after the switching transistor instead of the 5V input DOH!) so the boost converter wasn't able to ... erm boost. I cut the trace and off she went, easily generating over 100V off the 5V input. The second issue I ran across is that I wired the blanking input of the max6921 hv driver chip to the atmega's miso pin. This didn't seem like it'd be an issue, but apparently when the atmega is configured as a master SPI device the mico pin is hardwired to be an input and cannot be reconfigured to use as an output. Bummer, but I lifted the max6921 pin and ran a bodge wire the the open A1 output pin of the atmega and all was well. I've already fixed the pcb files for these two errors so don't worry.
Finally with all the hardware properly assembled I could start writing the firmware. In the next log I'll talk a bit about the software and post the assembly/demo video.