[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