<?xml version="1.0" encoding="utf-8"?>
<feed version="0.3" xmlns="http://purl.org/atom/ns#">
<link rel="alternate" type="text/html" href="https://gamma.unpythonic.net/"/>

<title>Jeff Epler's blog</title>
<modified>2021-10-30T21:12:03Z</modified>
<tagline>Photos, electronics, cnc, and more</tagline>
<author><name>Jeff Epler</name><email>jepler@unpythonic.net</email></author>
<entry>
<title>Use printf() in Arduino programs</title>
<issued>2021-10-30T21:12:03Z</issued>
<modified>2021-10-30T21:12:03Z</modified>
<id>https://gamma.unpythonic.net/01635628323</id>
<link rel="alternate" type="text/html" href="https://gamma.unpythonic.net/01635628323"/>
<content type="text/html" mode="escaped">


&lt;p&gt;Are you happiest with printf() debugging?  Do circumstances lead to you
writing &amp;quot;arduino code&amp;quot; because it's just about the easiest way to set up
an embedded software project that's not to different from C(++)?  I have
something for you.

&lt;p&gt;I've only tested it on a sample of 1 board (the &lt;a href=&quot;https://www.adafruit.com/product/3857&quot;&gt;Adafruit Feather
M4 Express&lt;/a&gt;) but I suspect that
it works on a wide variety of &lt;strong&gt;arm-based&lt;/strong&gt; (or, actually,
newlib-based) boards.

&lt;p&gt;Long story short, put the following code in your &lt;strong&gt;.ino&lt;/strong&gt;
file, call &lt;code&gt;Serial.begin()&lt;/code&gt; as usual, then use 
&lt;code&gt;printf(...)&lt;/code&gt; and &lt;code&gt;fprintf(stderr, ...)&lt;/code&gt; just
like you would anywhere.  The only caveat I've discovered so far is that
printing floating-point numbers didn't work for me.

&lt;p&gt;&lt;pre&gt;
// This bridges from stdio output to Serial.write
#include &amp;lt;errno.h&amp;gt;
#undef errno
extern int errno;
extern &quot;C&quot; int _write(int file, char *ptr, int len);
int _write(int file, char *ptr, int len) {
    if (file &amp;lt; 1 || file &gt; 3) {
        errno = EBADF;
        return -1;         
    }                
     
    if (file == 3) { // File 3 does not do \n -&gt; \r\n transformation
        Serial.write(ptr, len);
        return len;
    }
     
    // color stderr
    static bool stderr_flag;    
    bool is_stderr = (file == 2);
    if (is_stderr != stderr_flag) {
        if (is_stderr) {
            Serial.write(&quot;\033[95m&quot;);
        } else {
            Serial.write(&quot;\033[0m&quot;);
        }
        stderr_flag = is_stderr;
    }

    int result = len;
    for (; len--; ptr++) {
        int c = *ptr;
        if (c == '\n')
            Serial.write('\r');
        Serial.write(c);
    }
    return result;
}

extern &quot;C&quot; int write(int file, char *ptr, int len);
int write(int file, char *ptr, int len) __attribute__((alias(&quot;_write&quot;)));
&lt;/pre&gt;
</content>
</entry>
<entry>
<title>Pi Zero W USB Proxy</title>
<issued>2020-09-07T14:31:40Z</issued>
<modified>2020-09-07T14:31:40Z</modified>
<id>https://gamma.unpythonic.net/01599489100</id>
<link rel="alternate" type="text/html" href="https://gamma.unpythonic.net/01599489100"/>
<content type="text/html" mode="escaped">

&lt;img src=&quot;https://media.unpythonic.net/emergent-files/01599489100/IMG_20200907_093946.jpg&quot;&gt;

&lt;p&gt;I'm not sure exactly what to call it, but here's a little something I set
up this weekend.

&lt;p&gt;On my Linux desktop, I have occasional problems where being stopped at the
debugger prompt for a plugged-in USB device hoses the whole computer.
The problem waxes and wanes but on a particularly frustrating day 
I decided that maybe a Pi was the answer to the problem.

&lt;p&gt;Using screen I can access the USB-serial devices on the pi, and using sshfs
I can access the files.  If the whole pi freezes, I can just reboot it
with essentially no harm done.

&lt;p&gt;I selected a Pi Zero W with a Zero4U hub and Adafruit MiniPiTFT 1.14&amp;quot; attached.
To a base raspbian lite system I added some software, including tio, udiskie,
screen, and Adafruit Blinka; enabled ssh access and disk mounting by the pi
user, and set up GNU screen and my custom script for the LCD which is
(confusingly) also called screen.

&lt;p&gt;The screen shows information about each of the 4 USB connectors.
In brackets &amp;quot;S&amp;quot; is shown if there is a serial device; &amp;quot;D&amp;quot; is shown if there's a partitioned disk, &amp;quot;d&amp;quot; if there's an unpartitioned disk; and &amp;quot;M&amp;quot; is shown if it is mounted.  After that, the device name is shown.

&lt;p&gt;Automount can be toggled with the B button (silk screen 23) and any non-mounted disks can be mounted with the A button (silk screen 24)

&lt;p&gt;So far I've only used it lightly, but if it prevents a single crash of my
desktop, it will be worth it.

&lt;p&gt;This isn't a detailed guide so a lot of the setup is omitted.  However, here are the scripts that are the essential parts:

&lt;p&gt;&lt;script src=&quot;https://gist.github.com/jepler/ee50fca98455f26379e5e0ab24ce6ed4.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;&lt;script src=&quot;https://gist.github.com/jepler/ae71dffd3aeb4cb6a11a12e8773ee373.js&quot;&gt;&lt;/script&gt;
</content>
</entry>
<entry>
<title>Some notes on the Si5351a</title>
<issued>2020-08-18T01:55:16Z</issued>
<modified>2020-08-18T01:55:16Z</modified>
<id>https://gamma.unpythonic.net/01597715716</id>
<link rel="alternate" type="text/html" href="https://gamma.unpythonic.net/01597715716"/>
<content type="text/html" mode="escaped">

&lt;pre&gt;
Si5351 &quot;XA&quot; can be driven by a clock signal (25/27 MHz, 1Vpp)
    source: [2] p23, figure 14

Internet commenters report success driving it with a much wider frequency range
as well as successfully exceeding the specified PLL range.  Inputs from 3MHz to
146MHz and PLL frequencies from 168 to 1168MHz were tested.
    source: [1]

intermediate PLL frequency:
    600 to 900 MHz [3] p2
    divider range 15 + 0/1048575 .. 90
    &quot;integer divide&quot; FBA_INT flag is for _EVEN_ integers [3] p4

multisynth:
    valid dividiers are 4, 6, 8, 8 + 1/1048575 ... 2048
    &quot;integer divide&quot; FBA_INT flag is for _EVEN_ integers [3] p6
&lt;/pre&gt;
 
 &lt;p&gt;[1]: &lt;a href=&quot;http://www.simonsdialogs.com/2018/11/si5351a-any-frequency-cmos-clock-generator-and-vco-specifications-myths-and-truth/&quot;&gt;http://www.simonsdialogs.com/2018/11/si5351a-any-frequency-cmos-clock-generator-and-vco-specifications-myths-and-truth/&lt;/a&gt;&lt;br&gt;
 [2]: &lt;a href=&quot;https://www.silabs.com/documents/public/data-sheets/Si5351-B.pdf&quot;&gt;https://www.silabs.com/documents/public/data-sheets/Si5351-B.pdf&lt;/a&gt; (rev 1.3)&lt;br&gt;
 [3]: &lt;a href=&quot;https://www.silabs.com/documents/public/application-notes/AN619.pdf&quot;&gt;https://www.silabs.com/documents/public/application-notes/AN619.pdf&lt;/a&gt; Manually Generating an Si5351 Register Map rev 0.8

&lt;p&gt;</content>
</entry>
<entry>
<title>Si5351 Frequency Planner in Python</title>
<issued>2020-08-16T18:05:50Z</issued>
<modified>2020-08-16T18:05:50Z</modified>
<id>https://gamma.unpythonic.net/01597601150</id>
<link rel="alternate" type="text/html" href="https://gamma.unpythonic.net/01597601150"/>
<content type="text/html" mode="escaped">

The Si5351 and related clock generators are very flexible, but they are a bit cumbersome to &amp;quot;program&amp;quot;.

&lt;p&gt;The basic design of the Si5351 is that an incoming frequency is first
multiplied to create a high internal frequency (nominally in the range from 600MHz to 900MHz), then divided to create an output frequency.  The multipliers and dividers have restrictions on their ranges, there are just 2 PLLs but 3 output clocks, and certain types of configurations (e.g., &amp;quot;divisor is an integer multiple of 2&amp;quot;) are said to give lower jitter outputs than others.

&lt;p&gt;The datasheet advising users on how to create their own register values is very complicated and some of the parts resist comprehension even after multiple readings.  Thie chip maker Silicon Labs provides a graphical closed source Windows program for generating register maps, though some internet commenters regard it as buggy.

&lt;p&gt;This program represents my own effort to create a frequency planner.  It
neglects some datasheet rules, mostly related to output frequencies above 50MHz
or so.  It tries to
&lt;ul&gt;
&lt;li&gt; Favor lower-jitter configurations where possible
&lt;li&gt; Favor making the first-listed frequency as accurate as possible
&lt;li&gt; Try each combination of ways to allocate output clocks to the PLLs
&lt;li&gt; Obey the datasheet restrictions as I've understood them
&lt;li&gt; Do all arithmetic as infinite precision arithmetic, not floating point
&lt;/ul&gt;
It does not
&lt;ul&gt;
&lt;li&gt; Implement the divisor rules for extremely fast clocks
&lt;li&gt; Implement the divisor rules for higher numbered outputs on 20QFN packages
&lt;/ul&gt;

&lt;p&gt;For exact input clocks such as 25MHz, it is surprisingly hard to find a
&amp;quot;plausible&amp;quot; frequency that is inexact, and even harder to find a &amp;quot;plausible&amp;quot;
frequency that is less exact than your reference clock.  I didn't actually find
a case where the error is not much smaller than the frequency stability of any
reference I'd plausibly have access to.

&lt;p&gt;(Of course, if you measure your reference clock as 25MHz + 13.37Hz and plug
that in as the --input-freq then almost everything is related to that clock
inexactly, so the fact that the clocks will still be really, really close to
the requested value is very nice.)

&lt;p&gt;It does &lt;strong&gt;not&lt;/strong&gt; directly create a register map, but the
values shown are easy enough to convert to the form used in the CircuitPython
adafruit_si5151 library.
Sadly, as CircuitPython does not support the fractions module, it's not currently feasible to run this code on a CircuitPython board directly controlling the si5351 chip.

&lt;p&gt;Example:

&lt;p&gt;Generate 315M/88 (NTSC colorburst), 4.43361875M (PAL colour carrier), 25.8048M (UART clock) all exactly from a 25MHz reference clock or crystal.  However, the PAL colour carrier will have more jitter since it uses a fractional divisor:

&lt;p&gt;&lt;pre&gt;
$ ./party.py 315M/88 4.43361875M 25.8048M
Input frequency: 25000000 (25000000.0)
Frequency plan score: 10.38

PLL A:
Frequency plan type: Fractional multiplier, double integer divisor (1)
Multiplier = 126/5 (25.2)
Intermediate frequency = 630000000 (630000000.0)

Desired output frequency: 39375000/11 (3579545.4545454546)
Divider = 176 (176.0)
Exact
r_divider = 0 (/ 1)


PLL B:
Frequency plan type: Fractional multiplier, fractional divisor (5)
Multiplier = 12059443/500000 (24.118886)
Intermediate frequency = 602972150 (602972150.0)

Desired output frequency: 17734475/4 (4433618.75)
Divider = 136 (136.0)
Exact
r_divider = 0 (/ 1)

Desired output frequency: 25804800 (25804800.0)
Divider = 12059443/516096 (23.366666279141864)
Exact
r_divider = 0 (/ 1)
&lt;/pre&gt;

&lt;p&gt;Generate pi MHz from a 25MHz reference clock or crystal (error: 27.8 nano Hz)
&lt;pre&gt;
$ ./party.py 3.1415926535898M
Input frequency: 25000000 (25000000.0)
Frequency plan score: 1.00

PLL A:
Frequency plan type: Fractional multiplier, fractional divisor (5)
Multiplier = 24 (24.0)
Intermediate frequency = 600000000 (600000000.0)

Desired output frequency: 15707963267949/5000000 (3141592.6535898)
Divider = 40306053/211042 (190.98593171027568)
Actual output frequency: 42208400000000/13435351 (3141592.653589772)
Relative Error: -8.83757e-15
Absolute Error: 2.78e-08Hz
r_divider = 0 (/ 1)
&lt;/pre&gt;

&lt;p&gt;The source is available &lt;a href=&quot;https://gist.github.com/jepler/e2354d64009948c041f6610468cdf655&quot;&gt;in a github gist&lt;/a&gt;:

&lt;p&gt;&lt;script src=&quot;https://gist.github.com/jepler/e2354d64009948c041f6610468cdf655.js&quot;&gt;&lt;/script&gt;
</content>
</entry>
<entry>
<title>Quad CharliePlex FeatherWing hack</title>
<issued>2020-07-18T13:21:10Z</issued>
<modified>2020-07-18T13:21:10Z</modified>
<id>https://gamma.unpythonic.net/01595078470</id>
<link rel="alternate" type="text/html" href="https://gamma.unpythonic.net/01595078470"/>
<content type="text/html" mode="escaped">
&lt;img src=&quot;https://media.unpythonic.net/emergent-files/01595078470/charlie920.jpg&quot;&gt;

&lt;p&gt;Adafruit makes these neat &amp;quot;&lt;a href=&quot;https://learn.adafruit.com/adafruit-15x7-7x15-charlieplex-led-matrix-charliewing-featherwing/overview&quot;&gt;CharlieWing&lt;/a&gt;&amp;quot; displays that allow you to control a 15x7 LED matrix using the
I2C bus.  I2C uses two signal wires (called SDA and SCL, for Serial DAta and
Serial CLock), and can connect multiple devices as long as they have different
addresses.

&lt;p&gt;I noticed that the &lt;a href=&quot;https://learn.adafruit.com/i31fl3731-16x9-charliplexed-pwm-led-driver&quot;&gt;bigger brother of this device&lt;/a&gt;, with a whopping 144 LEDs, could be configured for 4 different I2C addresses, while this one could only be configured for 2.

&lt;p&gt;Or could it?</content>
</entry>
<entry>
<title>Minimal Time-Zone Handling for CircuitPython</title>
<issued>2020-07-17T21:37:17Z</issued>
<modified>2020-07-17T21:37:17Z</modified>
<id>https://gamma.unpythonic.net/01595021837</id>
<link rel="alternate" type="text/html" href="https://gamma.unpythonic.net/01595021837"/>
<content type="text/html" mode="escaped">
&lt;img src=&quot;https://media.unpythonic.net/emergent-files/01595021837/zones960.png&quot;&gt;

&lt;p&gt;For my clock, I want automatic handling of Daylight Saving Time.  However,
CircuitPython doesn't build in any distinction between local and UTC time, and
fitting in the entire Python3 datetime module or an Olson time zone database is
simply not going to happen.  What can we do that is simple enough to fit, but
can represent the reality of timezones where I live?</content>
</entry>
<entry>
<title>Calibrating the DS3231 and PCF8523 RTCs</title>
<issued>2020-07-16T18:22:35Z</issued>
<modified>2020-07-16T18:22:35Z</modified>
<id>https://gamma.unpythonic.net/01594923755</id>
<link rel="alternate" type="text/html" href="https://gamma.unpythonic.net/01594923755"/>
<content type="text/html" mode="escaped">
&lt;img src=&quot;https://media.unpythonic.net/emergent-files/01594923755/frequency.jpg&quot;&gt;

&lt;p&gt;The &lt;a href=&quot;https://www.adafruit.com/product/3028&quot;&gt;DS3231&lt;/a&gt; and &lt;a href=&quot;https://www.adafruit.com/product/2922&quot;&gt;PCF8523&lt;/a&gt; real time clocks (RTCs) can
both be calibrated by writing various register values.  To follow the
calibration procedures you'll need a frequency counter you trust, with at least
6 digits to calibrate the PCF8523 and 7 digits to calibrate the DS3231.  (It
also has to operate at the comparatively low frequency of 32.768kHz; a common
inexpensive 8-digit frequency counter such as the &amp;quot;SANJIAN STUDIO&amp;quot; has a
minimum of 100kHz so it's not usable for this purpose)  I use an old HP 5315B
universal counter that has been calibrated against GPS time.</content>
</entry>
<entry>
<title>Helpful Scripts for CircuitPython & Real Time Clocks (RTCs)</title>
<issued>2020-07-16T15:12:26Z</issued>
<modified>2020-07-16T15:12:26Z</modified>
<id>https://gamma.unpythonic.net/01594912346</id>
<link rel="alternate" type="text/html" href="https://gamma.unpythonic.net/01594912346"/>
<content type="text/html" mode="escaped">
&lt;img src=&quot;https://media.unpythonic.net/emergent-files/01594912346/rtcboards.jpg&quot;&gt;

&lt;p&gt;I have used two different RTCs in the Feather form factor.  One has
the &lt;a href=&quot;https://www.adafruit.com/product/2922&quot;&gt;PCF8523&lt;/a&gt;, and the other
has the &lt;a href=&quot;https://www.adafruit.com/product/3028&quot;&gt;DS3231&lt;/a&gt;.  The former has an SD card slot while the latter has higher precision including a temperature-compensated crystal oscillator.</content>
</entry>
</feed>
