GPS-disciplined firmware for the Evil Mad Scientist Alpha Clock Five, with RTC holdover, automatic Pacific time, and five-letter word mode.
This repository is the maintained replacement for the modified GPS Alpha Clock Five project. The active sketch and every library it compiles are first-class files at the repository root; older experiments remain under source/ for reference only.
- Reads checksum-valid
GPRMCandGNRMCGPS sentences continuously without making the display depend on continuous GPS reception. - Stores UTC in both the DS3231/Chronodot RTC and the in-memory system clock.
- Uses the RTC as the primary clock between GPS corrections. GPS disciplines it after the first valid fix, when drift exceeds two seconds, or after six hours.
- Converts UTC to Pacific local time only at the display, alarm, and calendar-editing boundaries.
- Offers three Pacific-time policies: current automatic spring/fall rules, permanent PST (UTC-8), or permanent PDT (UTC-7).
- Preserves the original clock, alarm, date, seconds, fonts, chime, night-light, and temperature features.
- Blinks the full time separator at 1 Hz (500 ms on, 500 ms off) in every normal clock style. Separator-only redraws are immediate so the blink remains crisp; the alarm-time setting screen keeps a steady separator.
- Displays DS3231 temperature in Fahrenheit with one fractional digit, leaving the next character blank so its upper LED dot reads as the degree symbol (for example,
72.5 °F). In the temperature alternate mode, time is held for about eight seconds and temperature for about seven seconds. Each swap fades to black in about 190 ms and fades the next display in over about 190 ms; transition time is separate from the holds. - Reads the DS3231 temperature once per appearance, bounds every I2C transaction to 25 ms with automatic bus-state recovery, and uses a two-second main-loop watchdog to recover from an unexpected firmware or peripheral stall.
- Includes a selectable five-letter-word display backed by 6,532 words stored in program memory.
- Accepts GPS receivers at 4800 or 9600 baud. Turning GPS off restores Serial1 to the clock's 19200-baud daisy-chain rate.
flowchart LR
GPS["GPS RMC date/time (UTC)"] -->|"validate and parse"| DISC["RTC discipline policy"]
DISC --> RTC["DS3231 RTC (UTC)"]
RTC --> SYS["System clock (UTC)"]
SYS --> POLICY["Pacific policy: AUTO / PST / PDT"]
POLICY --> LOCAL["Display, alarms, and edits"]
GPS serial input is parsed continuously so the small UART buffer does not lose complete NMEA sentences. That does not mean GPS overwrites the RTC every second. The RTC carries time between corrections, and the Time library asks it for a fresh value every five minutes.
On the first boot of this firmware, a one-time EEPROM migration converts an RTC written by the older local-time firmware to UTC. It also initializes the Pacific policy to AUTO and GPS speed to 9600 baud.
| Path | Purpose |
|---|---|
firmware/AlphaClock/ |
Production Arduino sketch and its GPS, time, DST, and RTC modules |
libraries/AlphaFive/ |
Vendored display/hardware library and five-letter word data used by the production build |
libraries/Wire/ |
Project-owned Arduino AVR Wire library with bounded I2C waits and timeout recovery |
firmware-images/ |
Versioned flashable images, including the pre-watchdog rollback build |
scripts/build.ps1 |
Canonical reproducible Windows build entry point |
scripts/test.ps1 |
Firmware-logic and captured-NMEA test entry point |
tests/ |
Python behavior tests and 624 captured RMC sentence fixtures |
old_backup/ |
Programmer exports of the previously installed ATmega644A flash and EEPROM |
source/ |
Historical iterations, upstream examples, documents, and research; never compiled |
docs/ |
TL866II fuse guide and repository artwork |
.build/ |
Generated compiler output; intentionally ignored by Git |
The sketch that is compiled is:
firmware\AlphaClock\AlphaClock.ino
Nothing under source/ participates in the production build.
The build targets an Evil Mad Scientist Alpha Clock Five with:
- ATmega644P (
modelP), Sanguino pinout - external 16 MHz clock
- application-only programming with the ATmega644A in a TL866II-Plus ZIF socket
- 4.3 V brown-out protection for reliable 16 MHz operation
- DS3231/Chronodot-compatible RTC
- NMEA GPS receiver connected to Serial1, normally at 9600 baud
The original product page is preserved at Evil Mad Scientist, and the surviving official upstream source is oskay/AlphaClock.
The checked-in build script is designed for Windows PowerShell and currently expects:
- Arduino IDE 1.8.x installed at
C:\Program Files (x86)\Arduino. - MightyCore installed through Arduino Boards Manager. This project has been verified with MightyCore 2.1.3.
- Python 3 on
PATHto run the tests.
The AlphaFive, timeout-capable Wire, Time, and RTC sources needed by the firmware are already vendored in this repository. Do not install alternate copies into the project build path.
From the repository root:
.\scripts\build.ps1The script invokes Arduino Builder with this fully qualified board name:
MightyCore:avr:644:bootloader=no_bootloader,pinout=sanguino,variant=modelP,BOD=4v3,clock=16MHz_external
The resulting firmware image is:
.build\AlphaClock\AlphaClock.ino.hex
A verified copy of the current image is retained at firmware-images/watchdog-i2c-2026-09-10/AlphaClock.ino.hex with SHA-256 B508881DA4C26060CFB93D9B8891B49C53C22B7208079FC2ED2D6432A1F91036.
After compiling, the build script verifies the recorded board selection and generated compiler listing. It also prints the expected display refresh rates, MightyCore's fuse recipe, and the hardened TL866II profile for this clock. The generated .hex contains application flash only; it does not configure fuse bytes, lock bits, EEPROM, or the bootloader section.
You may direct generated output elsewhere without changing the repository:
.\scripts\build.ps1 -BuildPath C:\Temp\AlphaClockBuildRun all host-side behavior tests with:
.\scripts\test.ps1The suite exercises captured GP/GN RMC input, checksums and missing fields, Pacific DST boundaries, permanent PST/PDT behavior, and GPS-to-RTC discipline decisions. A passing host test run complements the Arduino compile; it does not replace testing on the physical clock.
build.ps1 compiles the firmware but does not write it to the microcontroller. The supported deployment workflow removes the ATmega644A from the clock, places it in the TL866II-Plus DIP40 ZIF socket, and programs .build\AlphaClock\AlphaClock.ino.hex. There is no serial flashing connection in the current setup.
The programming method matters:
- The generated image starts at application address zero and is written directly through the ZIF programmer. A serial bootloader is not used for flashing; historical FTDI uploads are no longer part of the supported workflow.
- A ZIF/universal programmer changes fuses and lock bits independently of application flash. For the watchdog-hardened image, use low
0xFF, high0xDF, extended0xFC, lock0xFF. - High
0xDFresets directly to application address zero, disables JTAG, and leaves the watchdog under software control. Extended0xFCenables 4.3 V brown-out protection. In the TL866II interface, a checked box means the fuse bit is programmed as0. - The previous
FF / 9A / FF / CFprofile is retained in the fuse guide as historical recovery evidence, but it resets through a historical boot section and disables brown-out detection. Do not use it with the new watchdog-hardened image. - The physical chip is normally an ATmega644A, while the firmware intentionally compiles for the code-compatible ATmega644P target. This follows the official Alpha Clock Five programming guidance. An ISP or universal programmer must still use the physical ATmega644A device signature.
See TL866II-Plus fuse settings for the decoded checkbox list, screenshot, ZIF procedure, and recovery notes. Do not copy high, extended, or lock values from an unrelated Sanguino board; those bytes also control reset location, EEPROM preservation, JTAG, brown-out behavior, and programming locks.
The firmware that preceded watchdog and I2C hardening is preserved as Git tag pre-watchdog-2026-09-10 and as a ready-to-flash image under firmware-images/pre-watchdog-2026-09-10/. That rollback image also starts at application address zero and can be used with the new app-only fuse profile.
Before powering the clock permanently:
- Connect the RTC and its backup battery.
- Connect the GPS receiver to Serial1 with the correct voltage level and baud rate.
- Flash the firmware and let the GPS obtain valid UTC date/time.
- Open configuration and confirm
GPSis9600(or4800for that receiver). - Set
PACIF/MODEtoAUTO,PST, orPDT.
Hold + and - together for about two seconds to enter configuration. Use the Alarm and Time buttons to move among settings and +/- to change a value. The existing firmware exposes clock format, night light, alarm sound/tone, font, display style, date, seconds, alternate display, Pacific policy, GPS mode, and related preferences.
The project-specific settings are:
| Menu | Choices | Meaning |
|---|---|---|
PACIF / MODE |
AUTO |
Current U.S. Pacific rules: second Sunday in March through first Sunday in November |
PST |
Permanent standard time, UTC-8; never changes seasonally | |
PDT |
Permanent daylight time, UTC-7; never changes seasonally | |
GPS |
OFF |
Stop GPS parsing and restore Serial1 to 19200 baud |
4800 |
Parse GPS NMEA at 4800 baud | |
9600 |
Parse GPS NMEA at 9600 baud; project default | |
TIME / AND.. |
WORDS |
Alternate the time with a random five-letter word every seven seconds |
Selections are saved in EEPROM and survive a restart. If Pacific time law changes, choose permanent PST or PDT; GPS and RTC storage remain UTC and require no other change.
The production AlphaFive library includes 6,532 five-letter words in program memory. Select TIME / AND.. → WORDS to enable the feature. The word list is compiled into the firmware; no SD card or runtime file is required.
With the documented toolchain, the production build currently uses approximately:
- 51,818 bytes of flash (79% of 65,536 bytes)
- 2,077 bytes of static RAM (50% of 4,096 bytes), leaving 2,019 bytes for local variables
Exact output can change slightly with compiler or MightyCore versions.
arduino-builder.exe was not found
Install Arduino IDE 1.8.x in the expected location, or update $arduinoIde in scripts/build.ps1 for your installation.
MightyCore was not found
Install MightyCore in Arduino Boards Manager. The script searches %LOCALAPPDATA%\Arduino15\packages\MightyCore\hardware\avr and chooses the newest installed version.
The clock runs but never corrects from GPS
Confirm receiver wiring, GPS baud, NMEA output, antenna visibility, and that RMC sentences are present. The parser accepts GPRMC and GNRMC, requires a valid checksum, and uses both valid (A) and warning (V) RMC status for UTC time when all date/time fields are complete. SAVED only confirms that a menu setting was written to EEPROM; a GPS discipline briefly lights the far-right indicator and prints UTC time disciplined from GPS on the 19200-baud main serial port.
If the same fixed-9600-baud GPS previously worked but stops after universal-programmer use, check display timing and the numeric fuse readback before changing the parser. UART baud derives from the MCU clock. With the correct 16 MHz operation, startup words last about 750 ms each and the colon is on for 500 ms and off for 500 ms. Restore the confirmed programmer profile if those timings are wrong.
Local time is exactly one hour wrong
Check PACIF / MODE. AUTO follows seasonal rules, while PST and PDT deliberately remain fixed year-round.
The display goes black and buttons stop responding
The hardened firmware limits RTC/I2C waits to 25 ms and resets the I2C hardware after a timeout. It also reads temperature only once per temperature appearance instead of on every 10 ms display pass. If the main loop still stops completing, the two-second watchdog resets the controller automatically. A watchdog recovery is reported as Recovered from watchdog reset. on the 19200-baud main serial port at startup.
If the clock repeatedly restarts, measure the regulated 5 V rail. The required 4.3 V brown-out fuse intentionally holds the MCU in reset when its supply is unsafe for reliable 16 MHz operation.
The startup words are very slow and the display visibly flutters
This combination almost always means the program was compiled for 16 MHz but the microcontroller is running at a divided clock rate. The display driver uses Timer2 at 31.25 kHz and normally completes a full bright-mode display frame about 417 times per second. If CKDIV8 is accidentally programmed, the frame rate falls to about 52 Hz, and extra-dim mode falls to about 14 Hz. Arduino timing also becomes eight times slow, so each nominal 750 ms startup word lasts about six seconds.
Run .\scripts\verify-build.ps1 to verify the compiled artifact, then read the microcontroller's numeric fuse bytes. For the watchdog-hardened TL866II-Plus build, compare them with low 0xFF, high 0xDF, extended 0xFC, and lock 0xFF. Correcting the compile flag alone cannot repair fuses changed during chip programming. See the fuse guide and official Alpha Clock Five firmware instructions.
The first boot changes the displayed hour
The migration assumes the previous firmware stored Pacific local time in the RTC and converts that value to UTC once. After migration, all future local conversion is performed only for display and alarms.
source/ contains the valid iterations and reference material recovered from this computer. It is intentionally not a second build tree. The large bundled Processing 4 runtime formerly found in the five-letter-word research directory was deleted because it was an unmodified development-tool distribution with no project-specific material. Nested .git metadata is also not part of this repository.
See source/README.md for an inventory.
old_backup/ contains the raw flash, EEPROM, and combined/default exports read from the clock before installing the current firmware. They are recovery references, not production build output. See old_backup/README.md before using them with a programmer.
The Alpha Clock firmware and AlphaFive library carry their original copyright and GPL notices in the source headers. The timeout-capable Wire source retains its Arduino copyright and LGPL notice. The GPS additions retain their author notice, and the SCOWL-derived word data has separate attribution and license terms in libraries/AlphaFive/README-SCOWL.txt. Those file-level notices govern their respective material; no new blanket license is asserted here.