Benutzer-Werkzeuge

Webseiten-Werkzeuge


public:projects:stratum1-raspi

Raspberry Pi 4 Stratum-1 NTP Server using Uputronics GPS+RTC Rev. 6.4

Overview

This guide describes the deployment of a dedicated Stratum-1 NTP server based on:

* Raspberry Pi 4 Model B * Raspberry Pi OS Lite (Debian Trixie) * Uputronics GPS+RTC Expansion Board Rev. 6.4 * u-blox NEO-M8N GNSS receiver * RV3028 RTC * PPS synchronization via GPIO18 * Chrony * GPSD

The resulting appliance provides:

* Stratum-1 NTP service * PPS-disciplined system clock * RTC-backed startup time * IPv4 and IPv6 support * Fully headless operation

Hardware

Component Description
SBC Raspberry Pi 4 Model B
RAM 1 GB
Storage 16 GB microSD
GNSS Board Uputronics GPS+RTC Expansion Board Rev. 6.4 - including:
- GNSS Receiver u-blox NEO-M8N
- RTC Micro Crystal RV3028-C7
- PPS GPIO18

Important Revision Information

Uputronics GPS+RTC Rev. 6.4 DOES NOT use a DS3231 RTC.

The board uses a Micro Crystal RV3028-C7 RTC at I²C address 0x52.

Many older online guides still reference DS3231 (0x68) and are not applicable to Revision 6.4.

Operating System Installation

Install:

* Raspberry Pi OS Lite * 64-bit version * Debian Trixie based release

Add network configuration needed and make it accessible via SSH.

Time Zone

Configure local timezone:

sudo timedatectl set-timezone Europe/Berlin

Verify:

timedatectl

Expected:

Time zone: Europe/Berlin (CEST, +0200)
RTC in local TZ: no

RTC should remain in UTC.

Raspberry Pi Configuration

Edit:

/boot/firmware/config.txt

Recommended configuration:

enable_uart=1
 
dtparam=i2c_arm=on
dtparam=rtc=off
 
dtoverlay=i2c-rtc,rv3028,addr=0x52
dtoverlay=pps-gpio,gpiopin=18
 
dtoverlay=disable-wifi
dtoverlay=disable-bt
 
gpu_mem=16
 
camera_auto_detect=0
display_auto_detect=0
 
hdmi_blanking=2 

Why these settings?

Setting Purpose
enable_uart=1 Enables GPS serial interface
dtparam=i2c_arm=on Enables I²C bus
dtoverlay=i2c-rtc,rv3028 Loads RTC driver
dtoverlay=pps-gpio Enables PPS on GPIO18
disable-wifi Disables unused Wi-Fi
disable-bt Disables unused Bluetooth
gpu_mem=16 Minimizes GPU memory allocation
hdmi_blanking=2 Disables HDMI output

Install Required Packages

sudo apt update
 
sudo apt install 
chrony 
gpsd 
gpsd-clients 
pps-tools 
i2c-tools 
minicom 
util-linux-extra 

Verify RTC

Scan the I²C bus:

sudo i2cdetect -y 1

Expected:

40: -- -- 42 ...
50: -- -- UU ...

Meaning:

Address Device
0x42 u-blox NEO-M8N
0x52 RV3028 RTC

Verify RTC device:

ls -l /dev/rtc*

Expected:

/dev/rtc
/dev/rtc0

Read RTC:

sudo hwclock -r

Verify PPS

Check PPS device:

ls -l /dev/pps0

Expected:

/dev/pps0

Run PPS test:

sudo ppstest /dev/pps0

Expected:

source 0 - assert ...
source 0 - assert ...
source 0 - assert ...

One PPS pulse per second should be visible.

Verify GPS

Open serial console:

sudo minicom -b 115200 -o -D /dev/serial0

Expected NMEA output:

$GNRMC
$GNGGA
$GNGSA

Example:

$GNGGA,174143.00,...
$GNRMC,174143.00,...

A valid GNSS fix should report:

* 3D FIX * Latitude / Longitude * UTC Time * Multiple satellites

Typical values observed:

Satellites visible: 24
Satellites used: 14

Lessons Learned

gpsd autodetection did not reliably establish a 3D fix.

Explicitly configuring GPSD for 115200 baud resolved the issue immediately.

GPSD Configuration

Edit:

/etc/default/gpsd

Configuration:

START_DAEMON="true"
USBAUTO="false"

DEVICES="/dev/serial0"

GPSD_OPTIONS="-n -s 115200"
OPTIONS="" 

Explanation

Option Purpose
-n Start reading GPS immediately
-s 115200 Force receiver baud rate
/dev/serial0 Stable Raspberry Pi serial alias

Enable GPSD

sudo systemctl enable gpsd
sudo systemctl restart gpsd

Verify:

sudo systemctl status gpsd --no-pager

Expected:

gpsd -n -s 115200 /dev/serial0

Verify GPSD

cgps -s

Expected:

3D FIX

and a valid:

* Position * UTC time * Satellite list

Chrony Configuration

Backup original configuration:

sudo cp /etc/chrony/chrony.conf \
           /etc/chrony/chrony.conf.orig

Edit:

/etc/chrony/chrony.conf

Example configuration:

driftfile /var/lib/chrony/chrony.drift

logdir /var/log/chrony

refclock SHM 0 refid GPS precision 1e-1 offset 0.0 delay 0.2

refclock PPS /dev/pps0 lock GPS refid PPS prefer

server ntp1.example.net iburst
server ntp2.example.net iburst
server ntp3.example.net iburst

allow 192.168.0.0/16
allow fd00::/8

local stratum 10

makestep 1.0 3

rtcsync

leapsectz right/UTC 

Restart Chrony

sudo systemctl restart chrony

Verify:

sudo systemctl status chrony --no-pager

Verify Synchronization

Display active sources:

chronyc sources -v

Expected:

#- GPS
#* PPS

Meaning:

rtc-gps#~: sudo chronyc sources -v

  .-- Source mode  '^' = server, '=' = peer, '#' = local clock.
 / .- Source state '*' = current best, '+' = combined, '-' = not combined,
| /             'x' = may be in error, '~' = too variable, '?' = unusable.
||                                                 .- xxxx [ yyyy ] +/- zzzz
||      Reachability register (octal) -.           |  xxxx = adjusted offset,
||      Log2(Polling interval) --.      |          |  yyyy = measured offset,
||                                \     |          |  zzzz = estimated error.
||                                 |    |           \
MS Name/IP address         Stratum Poll Reach LastRx Last sample               
===============================================================================
#- GPS                           0   4   377     8    +51ms[  +51ms] +/-  200ms
#* PPS                           0   4   377     8   +689ns[ +706ns] +/-  299ns
Symbol Description
#* PPS Active Stratum-1 source
#- GPS GPS source used to lock PPS
- External NTP server

Verify Tracking

chronyc tracking

Expected:

Reference ID    : PPS
Stratum         : 1
Leap status     : Normal

Verify NTP Service

ss -lunp | grep :123

Expected:

udp 0.0.0.0:123
udp [::]:123

DNS Configuration

Example systemd-resolved configuration:

Create:

/etc/systemd/resolved.conf.d/internal.conf

Contents:

[Resolve]
DNS=192.0.2.53
DNS=2001:db8::53
 
DNS=192.0.2.54
DNS=2001:db8::54
 
FallbackDNS=1.1.1.1
FallbackDNS=2606:4700:4700::1111
 
Domains=~example.lan 

Apply:

sudo systemctl restart systemd-resolved

Verify:

resolvectl status

Store Current Time in RTC

Once Chrony has synchronized to PPS:

sudo hwclock -w

Verify:

sudo hwclock -r

Performance Results

Measured on:

* Raspberry Pi 4 Model B (1 GB) * Raspberry Pi OS Lite (Debian Trixie) * Uputronics GPS+RTC Expansion Board Rev. 6.4

Observed values after synchronization:

Stratum         : 1
Reference       : PPS
Satellites Seen : 24
Satellites Used : 14

Chrony source status:

#* PPS +/- 152ns
#- GPS +/- 200ms

Tracking example:

System time     : 0.000000020 seconds slow
Root delay      : 0.000000001 seconds
Root dispersion : 0.000018754 seconds

Boot Validation

After a reboot verify:

timedatectl
 
ls -l /dev/rtc*
 
sudo hwclock -r
 
sudo systemctl status gpsd
 
chronyc tracking
 
chronyc sources -v 

Expected:

* RTC available * GPSD running * PPS active * Stratum 1 restored automatically

Troubleshooting

RTC not detected

Verify:

sudo i2cdetect -y 1

Expected:

42
UU

Remember:

Rev. 6.4 uses RV3028 at address 0x52.
It does NOT use a DS3231.

PPS missing

Verify:

ls -l /dev/pps0
 
sudo ppstest /dev/pps0 

Check:

dtoverlay=pps-gpio,gpiopin=18

GPSD running but no fix

Verify baud rate:

GPSD_OPTIONS="-n -s 115200"

Check GPS reception:

cgps -s

Chrony does not select PPS

Verify:

chronyc sources -v

Ensure:

refclock PPS /dev/pps0 lock GPS refid PPS prefer

is present in chrony.conf.

CheckMK: local plugin

e.g.: /usr/lib/check_mk_agent/local/ntp_chrony (make it executable: chmod +x)

#!/bin/sh
 
PATH=/usr/sbin:/usr/bin:/sbin:/bin
 
SERVICE_NAME="chrony"
 
# chrony service
if systemctl is-active --quiet chrony || systemctl is-active --quiet chronyd; then
    echo "0 chrony_service - Chrony service is running"
else
    echo "2 chrony_service - Chrony service is NOT running"
    exit 0
fi
 
TRACKING="$(chronyc tracking 2>/dev/null)"
SOURCES="$(chronyc sources -v 2>/dev/null)"
 
if [ -z "$TRACKING" ]; then
    echo "2 chrony_status - chronyc tracking failed"
    exit 0
fi
 
STRATUM="$(echo "$TRACKING" | awk -F: '/^Stratum/ {gsub(/ /,"",$2); print $2}')"
REFID="$(echo "$TRACKING" | awk -F: '/^Reference ID/ {gsub(/^ /,"",$2); print $2}')"
LEAP="$(echo "$TRACKING" | awk -F: '/^Leap status/ {gsub(/^ /,"",$2); print $2}')"
 
# Stratum
if [ -z "$STRATUM" ]; then
    echo "2 chrony_stratum - Could not determine stratum"
elif [ "$STRATUM" -le 2 ]; then
    echo "0 chrony_stratum stratum=$STRATUM Stratum $STRATUM, reference: $REFID"
elif [ "$STRATUM" -le 4 ]; then
    echo "1 chrony_stratum stratum=$STRATUM Stratum $STRATUM, reference: $REFID"
else
    echo "2 chrony_stratum stratum=$STRATUM Stratum $STRATUM too high, reference: $REFID"
fi
 
# Leap status
if [ "$LEAP" = "Normal" ]; then
    echo "0 chrony_leap - Leap status normal"
else
    echo "2 chrony_leap - Leap status: $LEAP"
fi
 
# Active source
ACTIVE_SOURCE="$(echo "$SOURCES" | awk '$1 ~ /\*/ {print $2; exit}')"
 
if [ -n "$ACTIVE_SOURCE" ]; then
    echo "0 chrony_source - Active source: $ACTIVE_SOURCE"
else
    echo "2 chrony_source - No active chrony source selected"
fi
 
# Peer/source count
GOOD_SOURCES="$(echo "$SOURCES" | awk '$1 ~ /^[#^=][*+]/ {count++} END {print count+0}')"
 
if [ "$GOOD_SOURCES" -ge 1 ]; then
    echo "0 chrony_sources good_sources=$GOOD_SOURCES Good usable sources: $GOOD_SOURCES"
else
    echo "1 chrony_sources good_sources=0 No combined/selected sources found"
fi
 
# Stratum 1 specific checks
if [ "$STRATUM" = "1" ]; then
 
    # PPS expected on Stratum 1 if /dev/pps0 exists
    if [ -e /dev/pps0 ]; then
        if timeout 3 ppstest /dev/pps0 2>/dev/null | grep -q "assert"; then
            echo "0 pps_status - PPS pulses detected"
        else
            echo "2 pps_status - PPS device exists but no pulses detected"
        fi
    else
        echo "1 pps_status - Stratum 1 but /dev/pps0 not found"
    fi
 
    # GPS fix via gpspipe
    if command -v gpspipe >/dev/null 2>&1; then
        MODE="$(timeout 3 gpspipe -w -n 10 2>/dev/null | awk -F'"mode":' '/"class":"TPV"/ {split($2,a,","); print a[1]; exit}')"
 
        case "$MODE" in
            3)
                echo "0 gps_fix - GPS 3D fix"
                ;;
            2)
                echo "1 gps_fix - GPS 2D fix only"
                ;;
            1)
                echo "2 gps_fix - GPS no fix"
                ;;
            *)
                echo "1 gps_fix - GPS fix status unknown"
                ;;
        esac
    else
        echo "1 gps_fix - gpspipe not installed"
    fi
 
    # PPS should be active source
    echo "$REFID" | grep -q "PPS"
    if [ $? -eq 0 ]; then
        echo "0 chrony_pps_source - PPS is active reference"
    else
        echo "2 chrony_pps_source - Stratum 1 but active reference is not PPS: $REFID"
    fi
fi

Final Result

The completed appliance provides:

* Stratum-1 NTP service * PPS-disciplined system clock * GNSS time source * RTC-backed startup time * IPv4 support * IPv6 support * Headless operation * Minimal resource usage

The system automatically restores full Stratum-1 operation after reboot without manual intervention.

public/projects/stratum1-raspi.txt · Zuletzt geändert: von gerson

Seiten-Werkzeuge