over-engineering what should be a simple device
To make the experience fit your profile, pick a username and tell us what interests you.
In the last update I got the clock ticking, but it was not doing so accurately (I was able to notice it lose a half hour over the course of a couple days), and the firmware/verilog running on it was a bit of a mess
the first order of business was cleaning up the code repo. This was just some organization and some simple changes to the verilog top level to get it to work on the new FPGA. As part of this clean up I added UART support to the device's firmware, so now it blasts the number of seconds since it was powered up (I call this the clock's epoch (i.e. like the unix epoch)) out over the UART. I also added a software directory and some host side python scripts to allow me to calibrate the clock.
Specifically I wrote two scripts:
z_1_rtc_host.py counts the number of seconds that the clock has accumulated or lost since the program was started. It works by comparing the clock's internal epoch to the unix time stamp reported by my computer (since the clock starts at 0 when you power it up the script normalizes both time stamps to the t=0 being the time that the program started). The output of the script is just a simple .csv with one column showing how long the measurement has been running for, and the other showing how many seconds the clock has lost (negative number), or accumulated (positive number).
plot_error.py just plots the .csv file with the number of seconds (according to my computer) that the experiment ran for as the independent variable. With no tuning I got a graph that looked like this:
This image is mostly pretty bad, after ~60kSec the clock was ~900Sec slow, or in other words it lost about 15 minutes in only 16.66 hours, which is far from usable. This is a deviation of about 1.5%. That being said, the graph is very linear, which means that the observed error is systematic, and can therefore be calibrated out, at least in theory.
I went ahead and calculated a corrected master frequency based on the slope of the line in the last image, and replaced the nominal OCXO master frequency with the calculated OCXO master frequency in the main divider module, and reran the experiment:
Obviously this is a lot better, but not perfect. Now the clock is running ~0.15% fast, so in the ~22kSec I ran the second experiment for the clock still manged to pick up ~33Sec, or about half a minute in just over 6 hours. Still not usable. While the observed error is still linear, and can therefore be corrected for I figured that it was probably indicating an underlying flaw in the verilog responsible for counting the pulses coming from the master oscillator.
So, after some messing around I went back to my initial simulations and was able to spot a doozy of a bug. IDK how I missed it the first time around, but here it is:
this is the output of the divider test bench (link), showing the signals responsible for synchronizing the master oscillator to the FPGA's internal clock, and then producing a single clock pulse that can be used to increment the counting logic. Basically trig is the master oscillator, and trig_edge_pulse should be a one FPGA clock pulse that corresponds to the rising edge of the master oscillator, however, if you look just before the 1us (and 2us) mark you can see that trig_edge_pulse is missing a master oscillator edge! this is bad news!
It seems like the error occurs only when the the external trigger coincides with the rising edge of the FPGA clk. Thus the solution was to add another synchronization step as follows:
here we see that there is a trig_edge_pulse on every rising edge of the trigger signal!...Read more »
in my last post I described the new revisions to the main PCB. They have arrived and I've successfully populated a v3.3 board.
here's a comparison shot of all 3 versions of the PCB:
from top to bottom we have: v3.1, v3.2, and v3.3.
Basically everything is identical across all three version except the FPGA, v3.1 is designed to work with a 32QFN lmcxo2-1200hc part (the same as in the tinyFPGA Ax1), v3.2 is designed to include an entire tinyFPGA board, and v3.3 uses a 100TQFP lmcxo2-2000hc part.
As you'll recall I was unable to order more of the 1200hc parts and so I had to switch to the 2000hc part, which is unfortunately an order of magnitude more than I really need, but its at least in stock, and a package that I can solder. I basically designed the v3.2 as as back up in case the v3.3 didn't work, so I started bringup with the v3.3.
Assembly of the v3.3 board was pretty straightforward. Since the micro and FTDI circuits were exactly the same, they went together no problem. I did run out of capacitors though, and had to harvest some 0603 0.1uF from an old v1 board. Soldering on the 100TQFP was a pain, since I don't have a proper hot air station, but I got there in the end, all though I spent a lot of time hunting down and individually reflowing bad solders. I also had a nasty intermittently disconnected cold solder on one of the headers that attaches the main board to the display interconnect board, that took a long time to hunt down (I even ended up replacing the micro before figuring out that the intermittancy was due to a bad solder joint, and not a blown micro).
Since I all ready had test code ready to go I was able to confirm that the micro and FTDI chip were up an running pretty quickly. Getting the FPGA configured took some more effort though.
I'm using the tinyFPGA programmer for all of this, which is a little ten dollar USB->JTAG bridge with some software that's designed to make it go with the tinyFPGA Ax1 and Ax2 boards. However, the lmcxo2-2000hc-5tg100i is not one of the chips that is used on the Ax1 and Ax2 boards. I was hoping that it would just work out of the box anyway, but I was not so lucky.
I briefly considered getting the official Lattice JTAG programming cable, but its like $230, and even ebay clones are ~$30. Thus the only cost effective solution was to take a hack at the tinyFPGA programmer software: https://github.com/tinyfpga/TinyFPGA-Programmer-Application
From what I can see the tinyFPGA programming software consists of 3 major parts:
The code base for the gui seems pretty stable, based on the github page, while the cmd interface seems to have had some more work done on it (the gui submodules an old version of the cmd interface).
To make a long story short, the reason that the gui wasn't programming my chip is that once it identifies an adapter it checks the IDCODE of the device that you're trying to program. IDCODEs uniquely identify the part number, and the programmer lets you configure the target if the IDCODE matches the chip used in the tinyFPGA Ax1 or Ax2. After some digging (page 187 of this: https://media.digikey.com/pdf/Data%20Sheets/Lattice%20PDFs/MachX02%20Family%20Handbook.pd ) I was able...Read more »
As mentioned in a previous post the current version (v3.1) of the clock's main PCB didn't work completely. Specifically it caused the FPGA to burn up shortly after being plugged in. This was a pretty mysterious problem, since the FPGA didn't blow immediately, but instead seemed to work for a few minutes (I was even able to configure it once) before starting to draw a lot of current and burning out.
The problem was further compounded by the fact that the particular part number I had specc'd is on back order everywhere, and as a result I was unable to order more parts and do more testing. Additionally the parts I was initially testing with were in unknown condition, since they were originally bought for/built into the first hardware version that I started over a year ago, and hadn't been stored very carefully in the interim. Finally, it's possible that the flux I used during assembly was dodgy (all though this may just be paranoia).
Therefore it's time for some new board revisions.
Before starting on the next version I had to validate as much of the existing design as I could. I was quickly able to get the ATmega up and get it displaying stuff on the display thanks to some old code I had from the first pass at the project. I was also able to confirm that the ATmega ought to be able to talk to my verilog, provided I could get it running on a non-exploded FPGA. This was mostly covered in this log.
The final thing to validate was the FTDI UART/USB bridge. In the original (v1.0) design I had trouble getting the FTDI chip to survive for very long, likely due to a lack of USB protection, and so I had never written code to test bidirectional serial comms.
Fortunately the USB protection on the v3.1 board seems to be sufficient, and I was able to hack together some test code to confirm that I can send bits to the ATmega, and it can send bits back to me. (no picture here since it would just be a screengrab of `minicom` or `cu`).
Thus, I felt ready to begin designing new PCBs. Ideally, the device would use the LMCXO2-1200HC-4SG32C, which is exactly the FPGA in the tinyFPGA Ax2 devboard. Unfortunately the 1200HC is sold out everywhere, and so I needed an alternative. There are two obvious options
Option 1 is obviously simpler and quicker, but doesn't give me the nerd-cred of having successfully embedded an FPGA on a PCB I've designed. Option 2 is certainly the hard road, but also presents a better learning opportunity (and maybe a better resume item :) )
At any rate it wasn't a clear decision, and so I decided to just do both options 1 and 2. Which takes a little longer, but doesn't cost much more since JLCPCB lets you batch PCB orders. Thus, option 1 became PCB v3.2, and option 2 became PCB v3.3.
As a refresher this is the schematic for v3.1:
and this is the schematic for v3.2:
as you can see the v3.2 is a pretty simple replacement of the FPGA+support circuitry with the tinyFPGA-Ax2 module. The only other difference is the bank of 0R jumpers that are used to optionally connect some signals from the micro to the FPGA. Originally I had intended to just use the breakout pins to connect the micro and the FPGA, but the jumpers were easy to add, and will make the final design look a little neater.
For the v3.3 I needed to pick a chip I could actually order. After scraping through digikey and mouser, the cheapest (when considering shipping cost) similar chip I could order was the LCMXO2-2000HC-5TG100I, which is almost the same as the LCMXO2-1200HC-4SG32C, with a couple key differences:
basically the new chip is...Read more »
As mentioned in a previous project log, there's something up (idk what) with the FPGA circuit on the clock's main board and I fried my last two FPGAs. Unfortunately the Lattice part I had designed around is no longer available so I can't debug the current version of the board.
My plan is to redesign the PCB around a slightly different Lattice FPGA that is still in stock, but first I wanted to confirm that I have a minimum viable FPGA configuration and minimum viable firmware for the micro.
I had developed some example code and a mostly working FPGA config the last time I was working on this project so it was mostly a case of wiring in my TinyFPGA dev board in place of the busted FPGA on the PCB and uploading all of my test code. The hardware setup looks like this:
In the setup above the tinyFPGA devboard (on the breadboard) is counting pulses from the master oscillator (silver can near the AC plug in the image above), dividing the master frequency down to 1Hz, and then incrementing an epoch register every second. The ATmega (in the clock on the PCB) just periodically polls the FPGA for the current value in the epoch register over SPI, and then throws that value up on the display. So this test setup confirms the following:
As the image below demonstrates, this was mostly a success:
here the clock is showing that the FPGA has counted 64'h1C (?'d28) seconds since the clock was turned on. Since the master frequency is 20MHz this means that the FPGA has counted 28*20 = 560 million edges, and reported this over a spi connection.
In theory all of the code/logic to do this all ready existed in a working state from the last time I was working on this project, but it took a while to remember how it all went together. (mysteriously I also had interrupts misconfigured in the 'good' version of the code, which took way too long to debug). But this means that we have a known starting point to begin working on changing the FPGA to a part that is actually available, which is what the next couple of project logs will discuss.
As you probably guessed from the title of this post, dear reader, there is some qualification to the success described above. And that is that the clock is really really inaccurate right now, and the FPGA occasionally loses the state of the epoch register and rolls over to 0x0 prematurely.
There is an obvious problem with the above setup that certainly contributes to (and may be the source of) the above problem; that is that the 20MHz master frequency signal is being dumped right into a breadboard in order to connect to the tinyFPGA. This is suboptimal to say the least. Hopefully a shorter more direct connection between the OCXO and the FPGA will reduce parasitic capacitences and improve the accuracy a little. However there are still other possible sources of error:
despite these qualifications,...Read more »
The display (this is the exact part used) is on the front of the clock and the main PCB is deep inside, and so some wiring needs to happen.
The display interface board is a little chunk of perfboard that connects wires coming from the display to the correct microcontroller pins, and sits right on top of the main board like so:
The board itself is very simple, it just has some wires, a trim pot, and a diode. The trimmer is used to set the display contrast, and the diode drops the 3v3 supply by ~0.7v for the display back light which is not rated for 3v3. Here's a pic of the interconnect board popped out of its socket:
the shorted jumper is for the back light power, so that I can have it enabled or disabled. I might eventually connect the back light to something (switch or micro pin, etc) so I left a connector.
Since I'm probably going to have to order V4 boards for this project I might also make a pcb for the interconnect board, and the master oscillator carrier board, which are both just perfboard right now. we'll see.
Electronics need to go in a box so they don't get dusty. When I started this project in 2019 I didn't have a 3D printer and so the case was built out of some aluminum duct work and scrap wood. There are pictures at the bottom of this post.
I spent most of 2020 working on my undergraduate capstone project, and due to the G L O B A L P A N D E M I C it was all done remotely. In practice this was a good excuse to buy a 3D printer since it was "for school".
Now that I have a 3D printer it makes sense that I would 3D print my electronics enclosures. So that's what I'm doing.
The largest component in the clock is the mains to 3v3 power supply which is a 3v3 meanwell RS-15 series unit. Datasheet [pdf]. As such I designed around the power supply. I like my projects to be easy to work on so I designed the case in 3 parts: a bottom and top cover that bolt together and sandwich a midframe assembly between them. The midframe holds all of the electronics and can be removed from the rest of the case simply by taking the top cover off. Some exploded views of the case:
There is a recess for the USB port on the left side, power input on the rear, the display on the front, and some cooling holes on the bottom. Eventually I'll also add some kind of feet as well so that the power supply gets some airflow.
The design is all done in FreeCAD, and thus far I've been printing in in PLA+ on my Ender 3. Since the top of the midframe contains a lot of interconnect wires that I didn't include in the CAD model I've held off printing the top until the project is more complete since I'm pretty sure that the top cover will require some redesigning.
In its current state the case+electronics looks like this:
The bottom cover:
and some shots of the mostly assembled midframe and electronics:
In my last post I discussed some of the problems I had with the version 1 hardware at the end of 2019. There were enough issues with the hardware that I decided that it would be worth redoing the board and so I started a version 2 design, but didn't get very far before school started again and I had to put the project on hold.
In 2020 I started working on my undergraduate capstone project, and the combination of capstone work and regular school work/internship work meant that I didn't end up having enough time to work on this project for all of 2020.
After finishing school in April of 2021 I had some more free time again and dug out this project and reevaluated what I'd completed so far.
Rather than moving forward with the V2 hardware design, which wasn't well developed and had been rushed at the end of 2019 I decided to start fresh with a V3 hardware design that would address many of the issues I faced with the V1 hardware.
I ended up making the following changes and simplifications to the V1/2 designs:
With these simplifications in mind I went ahead and redesigned the board with the same parts as the version 1 design from 2 years ago. The final schematic is as follows:
I ordered and assembled the boards which looked like this:
This board was largely a success!
However, there was one big issue... The FPGA kept dying on me. I was able to get two soldered down, and powered up, but after a few minutes they would short out and burn. Before it burned up I was even able to configure one of the FPGAs successfully, which contributes to the mystery.
Further confounding debugging this issue is the current parts shortage. I blew up all of the spare FPGAs I had left over from when I bought parts in 2019, and now they're out of stock everywhere. :(
I tried to check some of the obvious stuff to see if I could figure out a reason that the FPGAs were burning, but I wasn't able to come up with anything
Unfortunately I wasn't able to check anything else electrical. However, I also had some paranoid Ideas about what could be wrong:
I'm specifically suspicious of the flux since its not actually proper electronics flux, its just hardware store plumbing flux. I have...Read more »
The first version of this project's hardware was developed in the fall of 2019. Due to how my school/co-op cycle worked I only had time to work on this project between September and December 2019. Since four months wasn't really enough time to get things done properly I rushed a lot of stuff, specifically the v1 PCB design, and as a result it didn't really work properly. Therefore this post will explain (one method of) how not to build a digital real time clock.
To begin prototyping I basically just connected some devboards on a breadboard. Recalling the block diagram in my last post The initial prototype implemented the various blocks as follows:
for testing purposes this was just the output of my function generator. This is not nearly accurate enough to meet my time keeping specification, but it did let me work on developing the RTL for the counting logic.
This was implemented with a TinyFPGA Ax2 devboard. This is a very barebones (and easy to use) dev board for the Lattice LMXO2-1200HC-4SG32C, which is a basic fpga/cpld in Lattice's machXO2 family of devices. This part was selected entirely based on the fact that the TinyFPGA dev board was readily available to me, and reasonably well documented. Probably there are better ways to select parts for a project, but oh well.
The time computation was handled with an ESP32-WROOM32D devkit-c development board. This was selected since I had it in my parts box all ready and I all ready knew how to put micropython on the ESP32.
Display and Set/Reset logic:
I basically ignored this for the earliest prototype, and just had all of my i/o via the devkit-c's USB serial port.
A recreation of the initial prototype:
The initial prototype was mostly used to develop the RTL for the FPGA. I spare the gory details of the exact counting logic implementation (the code is on github here if you really care), and just summarize how the counting logic works.
Basically, the RTL runs off of the FPGA's internal resonator which is faster than the master oscillator frequency (FPGA clk ~80MHz, master oscillator ~10 to 20MHz), and every tick it checks to see if the output of the master oscillator has risen. If it has then the FPGA increments a register. when the value in this register is equal to the master oscillator's nominal frequency we know that one second has elapsed, and a signal is generated to increment the Seconds Register. The Seconds Register holds an epoch (some absolute number of seconds since a known time), and is the basis of the time count. I use a 64 bit register to hold the unix epoch because the universe began on 01 Jan 1971.
The other part of the RTL is a state machine that implements a simple SPI protocol that allows a bus-master to query the FPGA for the current value of the epoch, and to allow the bus-master to load a new epoch into the seconds register.
There was also some non-sense with external triggers that I abandoned part way through. (the idea was basically to allow the FPGA to measure the time that elapsed between two trigger signals)
The above is all well and good, but it glosses over two important details:
Issue 1. turned out to be important since I want to be able to synthesize a 1Hz signal from non power of 2 master oscillator signals. The solution is pretty straightforward though. Basically I just pipelined the divider so that the first stage is a reliable rollover counter with a width equal to the largest power of two less than the MO's nominal frequency, and the second stage, which is now much...Read more »
This project actually began in the fall of 2019. I needed to learn verilog for an internship (they only taught me VHDL in school), and so I was messing around with a couple different FPGA dev boards (Terasic DE10-Lite, and the TinyFPGA AX2). Eventually I figured it would be fun to try and make a PCB with an FPGA on it, since I'd never done that before.
Since I didn't want to just make a dev board I needed a project, and I thought it would be cool to try and make a freestanding digital real time clock.
I also had some other requirements:
In order to meet these objectives I came up with the following architecture:
This is the ticking heart of the clock. It would be cool to build my own very accurate oscillator, but that's a project unto itself. It would also be cool to use a surplus rubidium frequency standard as the master oscillator, but that would also be a bit of an undertaking. Therefore to keep things simple (for now) I decided to use a prebuilt oscillator module (more discussion about the specific part later). However, I'd like to keep the counting logic oscillator agnostic, in order to ensure that its easy to swap out the oscillator at a later date.
every tick of the oscillator needs to be counted, and every 1/f ticks the counting logic should increment a seconds register. This is the FPGA part of this project.
Could I compute time and date from a seconds register, drive a display, read some buttons, and deal with a UART/USB connection from an FPGA? yeah probably. Do I want to? not particularly. Therefore all of these tasks will be carried out by a microcontroller.
should be something nice and friendly to read, preferably with some flexibility since I want to display strings like:
"PST: 19:32.57, 12 NOV 2022"
in a way that doesn't require learning how to decode an array of blinking LEDs.
Finally I need a way to set the time that the clock displays. Since the Time computation is going to be handled in a microcontroller, the set reset interface needs to talk to the microcontroller. I decided that the easiest way to set the time would be over a USB serial port since then I could write a little utility that would synchronize the clock to current time of the computer that its plugged into.
In the next post I'll talk about the parts I picked, and the version 1 hardware design.
Become a member to follow this project and never miss any updates