[Dprglist] Comparing Raspberry Pi's hardware PWM vs. external clock
Kipton Moravec
kip at kdream.com
Fri Mar 12 08:28:58 PST 2021
It looks like nobody else responded, but thanks for this information. I
have not played with the PWM but people have used it to generate RF
signals in the VHF band.
When using NTP a friend of mine discovered the Raspberry Pi crystal did
change frequency based on temperature, in a repeatable way. Somehow he
compensated for the temperature and got a better clock and as a result a
better Stratum 1 Time Server.
Kip
On 3/4/21 3:17 PM, Murray Altheim via DPRGlist wrote:
> Here's my report comparing an external clock vs. an internal hardware
> clock on a Raspberry Pi.
>
>
> # Executive Summary ...................................................
>
> There doesn't seem to be any notable difference between using the
> internal (PWM) hardware clock of a PI vs. an external microcontroller
> in terms of either precision or accuracy, not that would affect usage
> of either as a system clock for a robot.
>
> The internal hardware clock may be considered a more elegant solution,
> but requires more significant Linux skills to set up and configure.
> This can be ameliorated by providing suitable documentation and
> example code. This solution was shown to display intermittently but
> very infrequent lags whose source has not yet been determined -- these
> may be entirely in the test harness, so have been discounted.
>
> As hardware, the external clock is relatively simple to set up but as
> has been mentioned here previously, kinda "wastes" an entire micro-
> controller for what is admittedly a simple task. Given the hardware
> cost is very low this waste is mostly aesthetic, but also includes the
> physical space taken on a robot, additional power usage and hardware
> complexity.
>
> Given their respective pros and cons, both seem to be viable solutions.
> Design elegance is an important consideration, but must be balanced
> against the respective hardware and software skills and experience of
> the person doing the implementation.
>
>
> # Detailed Summary ....................................................
>
> The tests were run on my KD01 robot using a Raspberry Pi 3 B+ and a
> bench power supply.
>
> I ran two separate types of tests, one with a hardware (Raspberry Pi PWM)
> clock, the second with an external clock whose 20Hz pulse comes from a
> C++ program running on a Cortex-M4 (Adafruit Itsy Bitsy M4 Express)
> mounted
> on the robot. The details on setting up the hardware clock can be found
> inside the hw_clock.py file (listed below).
>
> Each of these test types was run three ways:
>
> 1. no system load (apart from the ssh session)
> 2. light system load (running 'sudo apt update' once during the test)
> 3. high load, running "stress --cpu 4", a temperature monitor with fan
> script, the 'top' system monitor, and three ssh sessions
>
> Each test was run 5 times (the hardware clock low load 10x), at 1000
> clock
> cycles per test, each cycle a 20Hz/50ms clock loop. The output is
> log-printed
> to sysout. The test results are listed below.
>
> The external clock seems to consistently run about 0.1ms slow, but
> with very
> low variability even under stress.
>
> The internal hardware clock reacts more to system load and on some
> occasions
> (particularly under the 'sudo apt update' load) sometimes gets a
> significant
> bump (extreme case was 16ms), but very infrequently and so far not
> repeatable.
> Over many runs of 1000 cycles this happened maybe three or four times,
> but
> it's notable that this did occur.
>
> The external clock is more more precise but less accurate. The C++ clock
> loop is actually set for 50000 microseconds (and this of course shows
> up on
> the M4's serial monitor as "50000ns") but something between that clock
> and
> it showing up in the Python program is consistently creating that
> 0.1ms lag.
> I'm not going to worry about this as it would not cause any problem
> when used
> as a system clock. The external clock solution shows no discernible
> reaction
> to system load that can't be ascribed to the test harness. The
> downside of
> the external clock is that it requires the setup of a separate
> microcontroller
> board, and C++ programming of that board.
>
> The internal hardware clock is, to a very small degree, more accurate but
> less precise, and more prone to system loads, though in general probably
> not problematic. I haven't determined what causes the infrequent,
> intermittent
> lags in timing.
>
> The downside of using the internal hardware clock is that its
> configuration
> is lost upon each reboot, meaning that it's (software-wise) more
> complicated
> to set up and maintain. There are a number of ways of running a
> root-permission
> program on boot (e.g., rc.local, systemd, etc.); if someone has the
> Linux OS
> skills to do this it's not hard to do. OTOH, for someone without the
> software
> skills but having hardware skills, setting up an external
> microcontroller with
> a simple 20Hz timing loop in C++ is not hard to do. YMMV.
>
> I suspect that for both external and internal clocks, the displayed
> timing
> lags are likely due to the test program being affected by the system
> load,
> not the clocks themselves, since both the external and internal clocks
> display some lag and we know that the external clock is entirely
> independent.
>
> So this last point is what I was really trying to determine: that the
> internal
> hardware clock of the Pi is (so far as I can ascertain) entirely
> independent
> on system load. I could use either external or internal clock and be
> assured
> of reasonable, reliable timing. I've already got the Itsy Bitsy
> installed and
> functional so I could leave it there. Or figure out how to run a short
> Python
> or bash script to re-establish the hardware PWM timer on reboot. I've
> written
> two methods into the HardwareClock class, check_boot_config() and
> configure(),
> which resp. checks to see if /boot/config.txt has been modified to
> support a
> PWM clock, and then to see if the PWM clock is actually running. The
> latter
> must be run as sudo, but this call could be made by a startup script.
> I'll
> need to make a change so that if called in that way it actually exits
> rather
> than running the clock, but I'll be doing that in an update soon.
>
> The code for the tests and library classes may be found at:
>
> https://github.com/ifurusato/ros/blob/master/ext_clock_test.py
> https://github.com/ifurusato/ros/blob/master/lib/ext_clock.py
> https://github.com/ifurusato/ros/blob/master/hw_clock_test.py
> https://github.com/ifurusato/ros/blob/master/lib/hw_clock.py
>
> As noted above, when the hw_clock.py is run as root it will establish and
> start the clock, which currently keeps running rather than exiting.
> I've not
> determined whether I like this behaviour or not, but this may change
> in the
> near future.
>
>
> # test results
> .................................................................
>
> # external clock, no load:
> ....................................................
> Δ 50.10200; err: 0.10200; max err: 0.26000; mean: 50.10078; max
> vari: 0.00216
> Δ 50.11900; err: 0.11900; max err: 0.69500; mean: 50.09706; max
> vari: 0.01953
> Δ 50.00400; err: 0.00400; max err: 0.63300; mean: 50.09290; max
> vari: 0.01522
> Δ 50.09700; err: 0.09700; max err: 0.24800; mean: 50.09582; max
> vari: 0.00346
> Δ 50.11000; err: 0.11000; max err: 0.80300; mean: 50.10728; max
> vari: 0.02050
>
> # external clock, low load:
> ...................................................
> Δ 50.09900; err: 0.09900; max err: 0.42900; mean: 50.09946; max
> vari: 0.00766
> Δ 50.10700; err: 0.10700; max err: 1.74600; mean: 50.08970; max
> vari: 0.10963
> Δ 50.09900; err: 0.09900; max err: 0.74500; mean: 50.09298; max
> vari: 0.03481
> Δ 50.08800; err: 0.08800; max err: 0.75500; mean: 50.09696; max
> vari: 0.01975
> Δ 50.09500; err: 0.09500; max err: 0.68500; mean: 50.09910; max
> vari: 0.01608
>
> # external clock, high load:
> ..................................................
> Δ 50.11500; err: 0.11500; max err: 0.15700; mean: 50.11342; max
> vari: 0.00039
> Δ 50.11500; err: 0.11500; max err: 0.15500; mean: 50.11678; max
> vari: 0.00010
> Δ 50.08400; err: 0.08400; max err: 0.19500; mean: 50.11086; max
> vari: 0.00043
> Δ 50.12000; err: 0.12000; max err: 0.97100; mean: 50.11776; max
> vari: 0.02985
> Δ 50.09600; err: 0.09600; max err: 0.20100; mean: 50.10798; max
> vari: 0.00045
>
> # hardware clock, no load:
> ....................................................
> Δ 50.00400; err: 0.00400; max err: 0.35500; mean: 50.00110; max
> vari: 0.01178
> Δ 50.00200; err: 0.00200; max err: 0.78000; mean: 50.00150; max
> vari: 0.06192
> Δ 50.03500; err: 0.03500; max err: 1.55600; mean: 50.00242; max
> vari: 0.11057
> Δ 50.00000; err: 0.00000; max err: 0.23600; mean: 50.00090; max
> vari: 0.00706
> Δ 50.00800; err: 0.00800; max err: 0.21400; mean: 50.00118; max
> vari: 0.00805
>
> # hardware clock, low load:
> ...................................................
> Δ 49.96800; err: -0.03200; max err: 0.21500; mean: 50.00224; max
> vari: 0.00586
> Δ 50.10900; err: 0.10900; max err: 6.71900; mean: 50.00814; max
> vari: 1.91167
> Δ 50.04900; err: 0.04900; max err: 1.35400; mean: 50.00202; max
> vari: 0.09144
> Δ 49.99100; err: -0.00900; max err: 1.05200; mean: 50.00136; max
> vari: 0.09587
> Δ 49.96600; err: -0.03400; max err: 0.68800; mean: 50.00162; max
> vari: 0.02198
> Δ 50.00300; err: 0.00300; max err: 2.26600; mean: 50.00174; max
> vari: 0.21424
> Δ 49.99200; err: -0.00800; max err: 9.11900; mean: 50.00222; max
> vari: 3.45226
> Δ 50.00700; err: 0.00700; max err: 0.64700; mean: 50.00004; max
> vari: 0.03155
> Δ 49.90500; err: -0.09500; max err: 0.49400; mean: 50.00238; max
> vari: 0.01838
> Δ 49.98100; err: -0.01900; max err: 0.38800; mean: 50.00296; max
> vari: 0.01134
>
> worst case (unexplained):
> Δ 49.90700; err: -0.09300; max err: 19.67400; mean: 50.00384; max
> vari: 15.84047
>
> # hardware clock, high load:
> ..................................................
> Δ 49.99300; err: -0.00700; max err: 0.85000; mean: 50.00248; max
> vari: 0.02417
> Δ 50.01000; err: 0.01000; max err: 0.24200; mean: 50.00284; max
> vari: 0.00341
> Δ 50.01100; err: 0.01100; max err: 4.27400; mean: 50.00352; max
> vari: 0.72376
> Δ 50.00500; err: 0.00500; max err: 0.27800; mean: 49.99622; max
> vari: 0.00419
> Δ 50.00500; err: 0.00500; max err: 0.18600; mean: 50.00202; max
> vari: 0.00250
>
> # legend:
> ................................................................
> Δ: delta: elapsed time (ms) for this cycle
> err: error for this cycle
> max err: maximum error over 1000 cycles
> mean: mean delta over 1000 cycles
> max vari: maximum variance over 1000 cycles
>
> ...........................................................................
>
> Murray Altheim <murray18 at altheim dot com> =
> = ===
> http://www.altheim.com/murray/ === ===
> = = ===
> In the evening
> The rice leaves in the garden
> Rustle in the autumn wind
> That blows through my reed hut.
> -- Minamoto no Tsunenobu
>
> _______________________________________________
> DPRGlist mailing list
> DPRGlist at lists.dprg.org
> http://lists.dprg.org/listinfo.cgi/dprglist-dprg.org
More information about the DPRGlist
mailing list