<?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>2022-09-04T02:11:14Z</modified>
<tagline>Photos, electronics, cnc, and more</tagline>
<author><name>Jeff Epler</name><email>jepler@unpythonic.net</email></author>
<entry>
<title>Recent keyboard deeds</title>
<issued>2022-09-04T02:11:14Z</issued>
<modified>2022-09-04T02:11:14Z</modified>
<id>https://gamma.unpythonic.net/01662257474</id>
<link rel="alternate" type="text/html" href="https://gamma.unpythonic.net/01662257474"/>
<content type="text/html" mode="escaped">

I made several USB HID keyboard conversions recently.  They all use
CircuitPython. The hardware setup is not documented as none are worthy of being
called finished projects at this point, but the source code gives an idea what
connections are needed. One or more of these may be the subject of a future
Adafruit Learning System Guide.

&lt;p&gt;Click a triangle to see the full code as an embedded github gist. (Note: if you're viewing this in a RSS reader, you may have to click through to get the embeds.  Sorry!)

&lt;p&gt;&lt;h2 id=&quot;1&quot;&gt;Commodore 16 Keyboard&lt;/h2&gt;
Used an Adafruit KB2040.  Gratuitous use of asyncio. The keymap needs work to be usable, but it's a good start. &lt;a href=&quot;https://gist.github.com/jepler/92de22b404657be27c0743186ae6e9f6&quot;&gt;Direct gist link&lt;/a&gt;.

&lt;p&gt;&lt;details&gt;
&lt;script src=&quot;https://gist.github.com/jepler/92de22b404657be27c0743186ae6e9f6.js&quot;&gt;&lt;/script&gt;
&lt;/details&gt;

&lt;p&gt;&lt;h2 id=&quot;2&quot;&gt;IBM XT &amp;quot;Model F&amp;quot; Keyboard&lt;/h2&gt;
Used an Adafruit QT PY RP2040.  This layout is AWFUL, the &amp;quot;beloved&amp;quot; iteration
of the Model F was for AT computers, with a layout a lot more like a modern
keyboard (aside from the placement of the Esc and Ctrl keys anyway) &lt;a href=&quot;https://gist.github.com/jepler/28fd82ad63050f95a11a04f52cfde4aa&quot;&gt;Direct gist link&lt;/a&gt;.

&lt;p&gt;&lt;details&gt;
&lt;script src=&quot;https://gist.github.com/jepler/28fd82ad63050f95a11a04f52cfde4aa.js&quot;&gt;&lt;/script&gt;
&lt;/details&gt;

&lt;p&gt;&lt;h2 id=&quot;3&quot;&gt;Tandy 1000 Keyboard&lt;/h2&gt;
&lt;details&gt;
Used an Adafruit Feather RP2040.  The trickiest, as caps lock and num lock are
handled in the firmware; and there are some real oddities about the layout compared to the keyboards we're used to.  This keyboard also needed the most clean-up but mechanically it's 100%.  &lt;a href=&quot;https://gist.github.com/jepler/b78ef195c1b8377d6f7eae148d8f29af.js&quot;&gt;Direct gist link&lt;/a&gt;.

&lt;p&gt;&lt;details&gt;
&lt;script src=&quot;https://gist.github.com/jepler/b78ef195c1b8377d6f7eae148d8f29af.js&quot;&gt;&lt;/script&gt;
&lt;/details&gt;
</content>
</entry>
<entry>
<title>Where should CircuitPython go in 2022?</title>
<issued>2022-01-05T03:44:20Z</issued>
<modified>2022-01-05T03:44:20Z</modified>
<id>https://gamma.unpythonic.net/01641354260</id>
<link rel="alternate" type="text/html" href="https://gamma.unpythonic.net/01641354260"/>
<content type="text/html" mode="escaped">

&lt;h2 id=&quot;1&quot;&gt;Looking back at 2021&lt;/h2&gt;

&lt;p&gt;Some of &lt;a href=&quot;https://gamma.unpythonic.net/01609601436&quot;&gt;the goals&lt;/a&gt; I proposed for 2021 have been
accomplished, yay!
&lt;ul&gt;
&lt;li&gt; Support at least one new microcontroller family (I may have known the RP2040 was coming when I said that)
&lt;li&gt; Partially addressed the problem of the time required to build CircuitPython core with changes to GitHub CI
&lt;li&gt; circup and bundlefly greatly ease the problem of gathering items from the bundles for a particular application
&lt;li&gt; In the Adafruit Learn System, we got much more systematic about how programs and their assets are organized
&lt;li&gt; The bluetooth workflow is in the wild and people are using it, such as with the PyLeap app for Apple phones.
&lt;/ul&gt;

&lt;p&gt;At a personal level, I accomplished one of the goals I listed, which was to improve my skills at 3D modeling and in particular I have become reasonably competent at part design using FreeCAD.

&lt;p&gt;Some items we made progress on, but there's always room for further improvement:
&lt;ul&gt;
&lt;li&gt;Continue to help people grow into the roles of reviewer and contributor
&lt;li&gt;JP's CircuitPython Parsec and Scott and FoamyGuy's livestreams are great, but I'm sure there's room for more &quot;how to&quot; video content around CircuitPython.
&lt;/ul&gt;

&lt;p&gt;Some big pieces of progress we made that I didn't even anticipate (but wish I had) were
&lt;ul&gt;
&lt;li&gt; Getting up to date with MicroPython, and then continuing to merge in their new releases
&lt;li&gt; Releasing asyncio support for CircuitPython
&lt;li&gt; Adding typing stubs to the core and types to many libraries in the bundle to work better in advanced IDEs
&lt;/ul&gt;

&lt;p&gt;&lt;h2 id=&quot;2&quot;&gt;Looking forward to 2022&lt;/h2&gt;

&lt;p&gt;I'm not a big picture visionary about where the project should head. Lots of
times it's modest or even invisible changes that give me the most satisfaction.

&lt;p&gt;I look forward to implementing new drivers for hardware I wouldn't have dreamed
of working on (reading from old DOS floppy drives, perfect example), adapting
old algorithms into CircuitPython (let's do more image processing or maybe
start doing audio processing), and finding small efficiency improvements and
firmware size savings when they're needed.

&lt;p&gt;I want to both learn more about and improve asyncio. A personal project goal
would be to have an interactive display that continues to update &amp;amp; respond
to input even while doing wifi requests. I don't think this works right now
(I could be wrong), and I don't know how much is needed in order to make it
work.

&lt;p&gt;I look forward to hearing all about the projects you (yes, you) are planning to
do in 2022; let's figure out if CircuitPython is the right coding language for
those projects, and if it's not let's figure out if there are sensible
additions that will make it work.
</content>
</entry>
<entry>
<title>Hybrid Keyboard Descriptor supports Boot & NKRO</title>
<issued>2021-07-13T21:05:45Z</issued>
<modified>2021-07-13T21:05:45Z</modified>
<id>https://gamma.unpythonic.net/01626210345</id>
<link rel="alternate" type="text/html" href="https://gamma.unpythonic.net/01626210345"/>
<content type="text/html" mode="escaped">
&lt;b&gt;Updated 2021-09-25&lt;/b&gt;: For compatibility with CircuitPython 7.0.0.

&lt;p&gt;
&lt;a href=&quot;https://blog.adafruit.com/2021/05/16/n-key-rollover-nkro-with-usb-keyboards/&quot;&gt;It has been suggested&lt;/a&gt; that it's possible to have both N-key rollover (NKRO)
and be compatible with computer early boot screens (BIOS/UEFI/etc) by ensuring
that the first 8 bytes of the report are compatible with the standard keyboard
protocol.

&lt;p&gt;On the &lt;a href=&quot;https://gamma.unpythonic.net/01625944378&quot;&gt;heels of my earlier experience&lt;/a&gt; with how easy
CircuitPython 7 made it to try a custom descriptor for NKRO, I tried
implementing this too.  And it works!  On a sample of one Dell notebook
computer, the hybrid descriptor can navigate in the boot menu but also enjoys
full NKRO once Linux has booted.

&lt;p&gt;You have to configure the descriptor in &lt;tt &gt;boot.py&lt;/tt&gt;
and then use the HybridKeyboard class in your code.  It is compatible
with the adafruit_hid.keyboard.Keyboard class, except that if you ask it
to press more than 6 keys in a row, it doesn't throw an exception!

&lt;p&gt;The original NKRO descriptor is also in this &lt;tt &gt;boot.py&lt;/tt&gt;, in case you want to
try both and compare how they work for you; &lt;tt &gt;code.py&lt;/tt&gt; is intended to
auto-select the correct interface class.  Remember that you need to fully restart the Feather when modifying &lt;tt &gt;boot.py&lt;/tt&gt;!

&lt;p&gt;The first file below is &lt;tt &gt;boot.py&lt;/tt&gt; and the second is &lt;tt &gt;code.py&lt;/tt&gt;, and the code is designed for an Adafruit Feather RP2040 with custom 4x5 keypad, &lt;a href=&quot;https://learn.adafruit.com/desk-calculator-with-circuitpython&quot;&gt;detailed in a Learning System guide&lt;/a&gt;.

&lt;p&gt;&lt;script src=&quot;https://gist.github.com/jepler/3f507711de499fa4f3cb756680bea927.js&quot;&gt;&lt;/script&gt;


&lt;p&gt;&lt;br&gt;</content>
</entry>
<entry>
<title>Quick CircuitPython Driver for ES100 WWVB Receiver</title>
<issued>2021-06-24T01:43:49Z</issued>
<modified>2021-06-24T01:43:49Z</modified>
<id>https://gamma.unpythonic.net/01624499029</id>
<link rel="alternate" type="text/html" href="https://gamma.unpythonic.net/01624499029"/>
<content type="text/html" mode="escaped">

I picked up an &lt;a href=&quot;https://www.universal-solder.ca/product/universal-solder-everset-es100-wwvb-bpsk-atomic-clock-starter-kit/&quot;&gt;ES100 WWVB receiver kit&lt;/a&gt;
and wrote a quick &amp;amp; dirty library to interact with it in CircuitPython.

&lt;p&gt;I'm not super thrilled with how the chip works; I imagined that the
date &amp;amp; time registers would act like an RTC after a successful reception,
but instead they just mark the second when reception &amp;amp; decoding completed
and are cleared to zero as soon as a new reception attempt is kicked off.

&lt;p&gt;Still, I'll have to figure out a clock to put it inside.  I am still
thinking of doing an edge-lit display version of the Roman Solar Clock,
so maybe that's where it'll go.

&lt;p&gt;The library is &lt;tt &gt;&lt;a href=&quot;https://media.unpythonic.net/emergent-files/01624499029/jepler_es100.py&quot;&gt;jepler_es100.py&lt;/a&gt;&lt;/tt&gt; and the example is &lt;tt &gt;&lt;a href=&quot;https://media.unpythonic.net/emergent-files/01624499029/code_es100.py&quot;&gt;code_es100.py&lt;/a&gt;&lt;/tt&gt; (rename to code.py).
I ran it on a Feather nRF52840 Expess with CircuitPython 6.3, but it should
work on a range of boards.

&lt;p&gt;Because the ES100 just locks up the I2C bus if you &amp;quot;repeated-start&amp;quot; it, I had
to use my custom rolled register library instead of &lt;tt &gt;adafruit_register&lt;/tt&gt;.
I did build it on top of &lt;tt &gt;adafruit_bus_device&lt;/tt&gt;.

&lt;p&gt;&lt;p&gt;&lt;b&gt;Files currently attached to this page:&lt;/b&gt;
&lt;table cellpadding=5 style=&quot;width:auto!important; clear:none!important&quot;&gt;&lt;col&gt;&lt;col style=&quot;text-align: right&quot;&gt;&lt;tr bgcolor=#eeeeee&gt;&lt;td&gt;&lt;a href=&quot;https://media.unpythonic.net/emergent-files/01624499029/code_es100.py&quot;&gt;code_es100.py&lt;/a&gt;&lt;/td&gt;&lt;td&gt;1.1kB&lt;/td&gt;&lt;/tr&gt;&lt;tr bgcolor=#dddddd&gt;&lt;td&gt;&lt;a href=&quot;https://media.unpythonic.net/emergent-files/01624499029/jepler_es100.py&quot;&gt;jepler_es100.py&lt;/a&gt;&lt;/td&gt;&lt;td&gt;3.3kB&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;p&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>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>
</feed>
