Using GPS PPS to trim TM4C123 RTC

here are some notes on setting the tm4c123 rtc (real-time clock) using pps (pulse per second) pulses from a gps module

--dave allen wb0taq 20oct23 email me
(forgive my aversion to capital letters. a long-time 'c' programmer, i find them a nuisance.)

since the gps clocks are NTP stratum 0 sources, your humble tm4c123 could be a stratum 1 time source.

GPS modules and PPS

i'm using a cheap (<$10) gps module that has a PPS pin. pulse-per-second. this is the start of an accurate time reference. if you want to try this, make sure you get one with that pin. the modules also sent NMEA messages with gps time and location, but they are sent typically at 9600 baud and lag behind the PPS pulse considerably, up to half a second. so they are accurate to +/- one second, but no more than that.

TM4C RTC

the rtc is adjusted by a 'trim' value (HIBRTCT). every 64 seconds the trim value is used in the 32768hz count for one second. so every 64th pps pulse, the rtc seconds count (HIBRTCC) and subseconds (HIBRTCSS) are saved and compared to those from the previous 64sec. the resulting subsecond difference (plus any difference in the seconds) is the exact number to add to the rtc trim (HIBRTCT). ie, if the difference is, say, -10, then the rtc is running slow, losing time. adding -10 to the trim factor (in effect subtracting 10) will shorten the count and make the rtc run that much faster, so the next 64 seconds will be exactly 'in step'. if the difference is positive, the rtc is running fast, has gained time, so adding that number to the trim increases the count every 64seconds, slowing it down.

GPS NMEA messages

i am also using the NMEA messages from the gps module, received via serial port (uart2 in my case) to set the rtc seconds count (HIBRTCLD load reg). the $GPRMC msg in particular gives both the gps time and date (UTC) in one msg. i only use the time in my rtc, wrapping it at 24hrs, but you could easily use the date too for a 'true' rtc. remember to adjust the gps(UTC) time&date for your timezone.

it's important to note that you cannot adjust the trim every second. i tried that at first and wondered why it had no effect. the rtc applies the trim every 64sec, so you have to wait that long to calculate an adjustment.

the nitty-gritty

i'm using two isrs - interrupt service routines. one triggered by a rising edge of a gpio port (the pps pulse). every 64 pps pulses (pps_count&63==0 or pps_count%64==0) this isr moves the earlier seconds and subseconds values to a "previous" location and records the new seconds (HIBRTCC) and subseconds (HIBRTCSS) from the rtc. the other isr is for reception of chars in the uart2 receive (rx) fifo. it saves a line at a time of serial input from the gps module. when it sees a cr, it looks at the string. if it's $GPRMC, it parses out the gps time and date and tucks them away as ascii chars (hhmmss and ddmmyy). each isr sets its 'event' bit/flag which are looked at in the "main loop" of the pgm, which starts with a wfi (wait for interrupt) for power savings, and there's nothing to do until there is an interrupt.

pps event

the event handling the pps pulse compares the current and previous seconds and subseconds and, if reasonable (between -128 and 128), adds the diff the rtc trim (HIBRTCT) and prints the msg in the pgm output as seen below.

nmea time-date event

the gps/nmea handler (gps time and date) sets the rtc time (HIBRTCLD "load" reg) the first time it runs after startup, and saves that setting (seconds) as the pps current seconds. it saves 0 as the subseconds since the write to HIBRTCLD clears the subseconds in the rtc. (this is probably not necessary since it will be off by a couple seconds and will be discarded anyway.)

program output...
note that the rtc trim (HIBRTCT) defaults to 0x7fff at startup, so 7ff4 is not too far off.

08:45:47 - rtc is set from gps time 14:45:47 minus 6hrs MDT
08:45:53 +28398 +0 1s 28398ss             --first 64sec not really 64sec, ignored
08:46:57 +28370 +28398 0s -28ss-28ad 7ff4 --second time 0sec diff, -28subsec diff, trim adj to 0x7ff4
...
09:21:05 +28369 +28370 0s -1ss-1ad 7ff3 -- -1subsec diff, trim 0x7ff3
09:22:09 +28370 +28369 0s 1ss1ad 7ff4   -- +1subsec diff, trim 0x7ff4
...a hiccup...
09:37:04 +28359 +28370 1s -11ss         --diff 1sec -11subsec -- too big, ignore
09:38:08 +28359 +28359 0s 0ss0ad 7ff4   --trim remains 0x7ff4
...and another
09:47:40 +8612 +28359 4s -19747ss      --another glitch, ignored
09:48:40 +28361 +8612 4s 19749ss       --"opposite" glitch, also ignored
09:49:44 +28361 +28361 0s 0ss0ad 7ff4
09:50:48 +28362 +28361 0s 1ss1ad 7ff5
09:51:52 +28361 +28362 0s -1ss-1ad 7ff4
...
14:20:28 +28363 +28363 0s 0ss0ad 7ff4   --pretty stable after 5+hours, don't ya think?