The timekeeping aspect of this project is going to be very simple. While the GPS clock project had granularity down to the 10th-of-a-second, which required some interpolation, this clock will only require one second granularity. There will be a need to keep a sub-second timer, but we'll get to that later. Getting time from a GPS receiver requires handling the serial I/O as well as the PPS output from the receiver. We can use the PPS as an interrupt to create the leading edge of the tick and beep sounds (so that they're as accurate as possible) as well as marking the second-start for synchronizing the software activities.
Like all of the time-talkers that have come before, we want to use sampled audio rather than attempting to use voice synthesis. The limited vocabulary of the clock makes that the path of least resistance. 8 kHz 12 bit PCM audio provides "telephone" quality level for the audio. The bad news is that the 32 kB of flash available is obviously insufficient for the number of samples required. Storing the audio on an SD card not only gives us a nearly infinite (for our purposes) amount of storage, but by using FAT storage, we can configure the card quite easily. This also potentially allows field replacement of the samples, so that people could customize the voice (even the language) however they like.
We use the same XMega32E5 controller we used in the v5 variant of the GPS clock. The XMega32E5 has a 2 channel DAC that we can use to play back the audio samples from the SD card. We can use one of the timers configured for 8 kHz as a clock for the DMA controller to trigger updating the current DAC value so that playback can be done largely in the background (we have to double-buffer SD card reads to insure the playback remains seamless, but that's only 1k of RAM out of the 4k available).
The actual audio format is 10 second blocks. Every second is marked by a 10 ms "tick" and every 10 seconds there will be a 3/4 second beep. The leading edges of these are synchronized to the PPS of the GPS receiver using the PPS ISR. We configure one of the timers to output a 1 kHz square wave on one of the pins of the controller, and we simply turn that output on early in the PPS ISR and in the outer loop turn it off either 10 ms or 750 ms after the second.
The audio circuitry takes the 1 kHz square wave output and runs it through an RC low-pass filter. Then it is mixed with the output of the DAC and the sum fed into an audio amplifier and speaker.
The SD card slot is simply connected to the SPI interface. The directory layout is top level directories "ZONE" "HOUR" "MINUTE" "SECOND". Inside of each of the hour, minute and second directory are files named 0-60 (0-24 for hours, and only every 10 for seconds), each of which are an audio snippet. Inside of "ZONE" are files with two letter names, the first of which is a timezone (Pacific, Mountain, Central, Eastern, Alaskan, Hawaiian), the second of which is either S for standard or D for daylight. There will also be a "U" for UTC. Every 10 seconds, the playback consists of the appropriate ZONE file, then hour, minute and second. The intended scripting is "At the tone, Coordinated Universal time will be 23 hours, 59 minutes, 50 seconds." The first second of each 10 second block is reserved for the previous block's mark tone. Seconds 2 through 6 are for the "ZONE" file, then one second for each of the time files, which means the whole thing should end just before the 9th second.
There is a simple set of DIP switches on the board to configure the desired timezone. The system simply continuously generates the audio stream, and the speaker is turned on with a momentary push-button. The push-button will be an input to the controller and the firmware will toggle an enable pin on the audio amplifier. This design allows for autonomous audio output in the future for hourly chimes.