<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>John Whittington&apos;s Blog</title>
    <atom:link href="/feed.xml" rel="self" type="application/rss+xml"/>
    <link>https://engineer.john-whittington.co.uk//</link>
    <description>Engineer John Whittington&apos;s personal project blog</description>
    <pubDate>Mon, 12 Feb 2024 16:01:16 +0000</pubDate>
    
      <item>
        <title>Tailwind - Wahoo Headwind BLE Remote with Rust</title>
        <link>/programming/2023/12/11/tailwind-headwind-ble-remote.html</link>
        <guid isPermaLink="true">/programming/2023/12/11/tailwind-headwind-ble-remote.html</guid>
        <description>&lt;p&gt;I recently purchased a &lt;a href=&quot;https://eu.wahoofitness.com/devices/indoor-cycling/accessories/kickr-headwind&quot;&gt;&lt;em&gt;Wahoo Headwind&lt;/em&gt;&lt;/a&gt; as part of my static trainer setup. The device lacks a button remote in favour of App based control. Whilst this works okay in principle, anyone that has used a static trainer knows that in the sweaty heat of the moment trying to use a App is frustrating at best!&lt;/p&gt;

&lt;p&gt;So I decided to use the opportunity to explore using (embedded) Rust on the Nordic nRF series. Developing BLE for Nordic chips involves a reasonably complex toolchain since the BLE stack is a closed-source binary (SoftDevice) and there is a lot of supporting modules. I was intrigued to see what the experience would be like outside of the C &lt;em&gt;Nordic nRF Connect SDK&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://embassy.dev/&quot;&gt;Embassy&lt;/a&gt; have created a &lt;a href=&quot;https://github.com/embassy-rs/nrf-softdevice&quot;&gt;SoftDevice Rust binding generator project&lt;/a&gt; for the nRF series that formed the foundation of my project. Using it also allowed me to learn about many parts of the Rust embedded ecosystem, such as &lt;a href=&quot;https://probe.rs/&quot;&gt;Probe&lt;/a&gt;, the &lt;a href=&quot;https://embassy.dev/&quot;&gt;Embassy&lt;/a&gt; runtime itself and working with &lt;a href=&quot;https://github.com/rust-embedded/embedded-hal&quot;&gt;Rust embedded-hal(s)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/tailwind-wireshark.png&quot; alt=&quot;/assets/img/tailwind-wirkshark.png&quot; /&gt;
&lt;strong&gt;Small snapshot of Wahoo App BLE logging to reverse engineer protocol&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Headwind protocol was fairly easy to reverse engineer using the Android Wahoo App with HCI BLE logging enabled and some other hacking attempts around the internet. I was able to review the action/result using WireShark. The protocol isn’t great in my opinion, using a fixed cyclic update rather than actual notify and seems to lag behind the actual state of the device at times.&lt;/p&gt;

&lt;p&gt;I could have ignored the device state all together but I wanted to keep synchronisation so that I can seamlessly switch control between the App, front-panel and the remote. A press of the remote button will request and assert the change so that the button press will always reflect a change in the actual state of the device.&lt;/p&gt;

&lt;div class=&quot;box&quot;&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/c2azojD2oZM?si=xC57Zcoo9vrkFaW8&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;In all it was a fun project and fills the requirement. Whilst the Rust developer experience surpassed that of using the C SDK - the benefits of a modern language and package manager - it’s not as powerful as the ZephyrOS based toolchain provided by the new Nordic nRF Connect SDK. ZephyrOS is a joy to use, so I’ll take the shortcomings of C (fine with experience/working practices) for now in order to use it. Perhaps as Embassy develops, Nordic will adopt a Rust SDK but I don’t see this happening in the near future. For a simple device like this, I’ll turn to the Rust stack. For a custom fully featured BLE device, I’ll stick to the nRF SDK for now…&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/tuna-f1sh/tailwind&quot;&gt;GitHub Project&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 11 Dec 2023 00:00:00 +0000</pubDate>
      </item>
    
      <item>
        <title>Minnow USB-C DAM Tool</title>
        <link>/electronics/2023/07/30/minnow-usbc-dam-tool.html</link>
        <guid isPermaLink="true">/electronics/2023/07/30/minnow-usbc-dam-tool.html</guid>
        <description>&lt;p&gt;Minnow is a tool for using DAM (Debug Accessory Mode), providing an interface to SWD or JTAG and/or UART from the device. It expands upon &lt;a href=&quot;https://github.com/BitterAndReal/SWD-over-USB-C&quot;&gt;this concept&lt;/a&gt; to include a USB-UART and some utility for use within test rigs. It could be considered SWD over DAM with a sprinkling of &lt;a href=&quot;https://github.com/oxda/usb-cereal&quot;&gt;USB cereal&lt;/a&gt; - unlike usb-cereal it does not use the Chromebook UART mapping in favour of maintaining USB-C rotational symmetry.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Enables and interfaces USB DAM configured in image below; Full SWD or JTAG over USB-C.&lt;/li&gt;
  &lt;li&gt;Provides board designer the option of using RX+ for NRST/RXD and RX- for SWO/TXD - either single-wire trace communication (RTT) or UART.&lt;/li&gt;
  &lt;li&gt;Four configurable GPIO on FT230 for test rig control of UUT: power enable; RX pin control; reset.&lt;/li&gt;
  &lt;li&gt;TagConnect TC2030 and ARM 10-pin header to debugger.&lt;/li&gt;
  &lt;li&gt;USB pass-through or FT230 USB UART to device.&lt;/li&gt;
  &lt;li&gt;VTARGET reference from device or external.&lt;/li&gt;
  &lt;li&gt;Maintains USB-C rotational symmetry.&lt;/li&gt;
  &lt;li&gt;Alternate Mode 3.1+ can still be used in the main application with normal hosts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/minnow-pcb.jpg&quot; alt=&quot;Minnow DAM USB-C DAM Tool PCB&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s the intro for the &lt;a href=&quot;https://github.com/tuna-f1sh/minnow&quot;&gt;README.md&lt;/a&gt;. I’ll expand a bit more on why I made the device here. The debugger over SWD/JTAG is a pre-requisite when developing any custom embedded hardware, and is often required for provisioning said hardware - in volumes below pre-programmed microcontrollers. When designing a PCB, there is often a trade off between ease of debugger attachment and land. I’m a fan of the &lt;a href=&quot;https://www.tag-connect.com/&quot;&gt;TagConnect&lt;/a&gt; system but even that is quite big and really should be reserved for out of form, initial dev boards. Another issue is that once the device is &lt;em&gt;embedded&lt;/em&gt; the debugger header often cannot be accessed. In practice this is generally considered a bonus (security) but it can save the day after a dodgy DFU for example.&lt;/p&gt;

&lt;p&gt;Most devices have a USB-C interface, which supports USB 3.1+ &lt;a href=&quot;https://en.wikipedia.org/wiki/USB-C#Alternate_Mode_2&quot;&gt;Alternate Mode&lt;/a&gt;. The Alternate Mode lines provide 5 lines (2 differential pairs and 1 low-speed signal), which provide a designer up-to 10 additional IO (not used as differential and rotational asymmetry). These pins are used by USB-C &lt;a href=&quot;https://en.wikipedia.org/wiki/USB-C#Alternate_Mode_partner_specifications&quot;&gt;interface protocols&lt;/a&gt; such as DisplayPort, Thunderbolt and HDMI.&lt;/p&gt;

&lt;p&gt;The USB specification even includes one for debugging; &lt;a href=&quot;https://en.wikipedia.org/wiki/USB-C#Debug_Accessory_Mode&quot;&gt;DAM&lt;/a&gt; - what we are talking about here. It’s up-to the designer how to implement it, the specification only covers how to enter DAM. Since the port is normally externally accessible and already taking up board area it’s a nice solution to solve the issues mentioned in the paragraph above.&lt;/p&gt;

&lt;p&gt;Whilst it may not be ideal for the highest security devices - exposing an external interface to debuggers - the SWD/JTAG/readback could still be disabled with fuses in production firmwares (as it should be).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/minnow_swd_dam_pinout.png&quot; alt=&quot;Minnow DAM mode pinout&quot; /&gt;
&lt;strong&gt;&lt;a href=&quot;https://github.com/BitterAndReal/SWD-over-USB-C/blob/main/images/SWD%20over%20USB-C%20Pinout-01.png&quot;&gt;Original reference&lt;/a&gt; modified to include option of UART.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/tuna-f1sh/minnow&quot;&gt;Minnow&lt;/a&gt; implements DAM by defining the &lt;a href=&quot;https://developer.arm.com/documentation/101636/0100/Debug-and-Trace/JTAG-SWD-Interface&quot;&gt;SWD and JTAG&lt;/a&gt; interface over the Alternate Mode differential pairs and VTARGET over SBUS. Since there are four SWD lines and one for VTARGET, USB-C rotational symmetry is maintained 🙏. The Minnow hardware does the job of pulling the CC lines high with the pull-ups defined in the USB specification, so when connected to a supported target SWD is exposed on the 10-pin ARM and TagConnect headers.&lt;/p&gt;

&lt;p&gt;The neat thing is that when the target is connected to other hosts, the DAM lines are out of circuit and the Alternate Modes can be used for a custom protocol. One could have a DisplayPort display for a example, with this Minnow DAM implementation to provide DFU.&lt;/p&gt;

&lt;p&gt;Minnow enables DAM whilst forwarding the standard USB 2.0 differential pairs to the host; SWD can be used at the same time as USB communication in DAM.&lt;/p&gt;

&lt;p&gt;I also added the option of using the &lt;em&gt;extra&lt;/em&gt; SWD lines (NRST and TRACE, not required for programming/debug) for UART. This means the target device can forward a UART over USB-C for provisioning rather than RTT. For this, Minnow includes a FTDI FT230X USB-UART adaptor so no additional tools are required.&lt;/p&gt;

&lt;p&gt;The on-board FT230X’s GPIO can also be used to control power to the target device, reset the device or control something else.&lt;/p&gt;

&lt;p&gt;There is some circuitry required on the target device to support USB DAM and the Minnow configuration (see below). Essentially the target must detect when the CC lines are &lt;strong&gt;both&lt;/strong&gt; pulled up with the values specified in the USB specification. Since normal cables do not connect both CC lines, the Minnow must feature a plug to connect directly to the target.&lt;/p&gt;

&lt;p&gt;The example board uses two op-amps configured as non-inverting amplifiers to buffer this to a logic AND, which enables a 4-channel switch to connect the debug lines to the Alternate Mode pins. It must be honoured with the corrected values as the CC lines are used for all sorts of upstream and downstream control.&lt;/p&gt;

&lt;p&gt;You can find a quick video demo below. The design is open-source but if you’d rather purchase assembled boards or just support my work, PCBAs are on &lt;a href=&quot;https://shop.jbrengineering.co.uk/product/minnow-usb-c-debug-accessory-mode-tool-dam/&quot;&gt;my shop&lt;/a&gt; and &lt;a href=&quot;https://www.tindie.com/products/jbrengineering/minnow-usb-c-debug-accessory-mode-tool-dam/&quot;&gt;Tindie&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/QQiKsJ13bL0&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;/assets/minnow-r2-0-g19cc.pdf&quot;&gt;&lt;img src=&quot;/assets/img/minnow-r2-0-g19cc.png&quot; alt=&quot;Minnow R2 schematic&quot; /&gt;&lt;/a&gt;
&lt;strong&gt;Minnow schematic design. Full source available on &lt;a href=&quot;https://github.com/tuna-f1sh/minnow&quot;&gt;GitHub&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/minnow-usb-dam-schematic.pdf&quot;&gt;&lt;img src=&quot;/assets/img/minnow-usb-dam-schematic.png&quot; alt=&quot;Example DAM mode Minnow target&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example DAM switching on target. Some additional circuitry is required on the target device to implement DAM as per the USB specification; it could be reduced if not concerned about meeting the specification. The additional parts are not any bigger than most other debugging headers however, with the benefit of not requiring a bespoke plug - just a USB-C.&lt;/strong&gt;&lt;/p&gt;
</description>
        <pubDate>Sun, 30 Jul 2023 00:00:00 +0000</pubDate>
      </item>
    
      <item>
        <title>Adding gs_usb Hardware Timestamping to Kernel Module</title>
        <link>/programming/2023/01/07/socketcan-gsusb-timestamping.html</link>
        <guid isPermaLink="true">/programming/2023/01/07/socketcan-gsusb-timestamping.html</guid>
        <description>&lt;p&gt;I recently had to check a CAN node was providing a cyclic message within a 10% threshold of the defined period. Logging the messages, it appeared that it was slipping by as much as 25% at times.&lt;/p&gt;

&lt;p&gt;In addition to a hardware specific logger, I was debugging with a &lt;em&gt;SocketCAN&lt;/em&gt; ‘gs_usb’ compatible tool and wanted to ensure that the host OS was not introducing any timing error.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;SocketCAN&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;candump&lt;/code&gt; has a flag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-H&lt;/code&gt; to enable hardware timestamps; timestamps from the capturing device rather than the host OS stamping upon receipt (software timestamps). When the tool provides a timestamp, it should be much closer to when the transceiver actually received the message&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. Timestamps provided by the host OS may be inaccurate due to preemption by a higher priority task before the USB packet is retrieved; it’s the time it was popped from the USB queue so the period that the OS got around to this is included. &lt;a href=&quot;https://www.kernel.org/doc/html/latest/networking/timestamping.html&quot;&gt;More on the Linux kernel net timestamping options&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My USB CAN tool of choice is and my &lt;a href=&quot;/2021/03/16/entree-usb-c-can-interface.html&quot;&gt;Entree&lt;/a&gt; board, which uses candleLight firmware. The problem was that adding the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-H&lt;/code&gt; flag resulted in zeros. Digging into the firmware, I saw that it does support &lt;a href=&quot;https://github.com/candle-usb/candleLight_fw/blob/f07aed4a5b939408cb9a2c6a8cd7e7edf6daf940/src/main.c#L144&quot;&gt;sending timestamps as part of the gs_usb packet&lt;/a&gt; but that the Linux kernel module did not yet use it.&lt;/p&gt;

&lt;p&gt;The module that required changing was &lt;a href=&quot;https://github.com/torvalds/linux/blob/v5.19/drivers/net/can/usb/gs_usb.c&quot;&gt;gs_usb&lt;/a&gt;. Contributing to something like Linux is probably the most intimidating but also rewarding things to do in open-source. It’s not something that is easy to jump into and so opportunities to actually change some code are few. Additionally, whilst it is mirrored on GitHub the collaboration process is still mailing list based so it’s not just a simple case of opening a PR in a nice web GUI!&lt;/p&gt;

&lt;p&gt;To my benefit, one of the contributors to candleLight is also a maintainer of the CAN modules and was very helpful in pointing me in the right directions. It also meant I already had someone on-board to do the final merge request. Reading the excellent &lt;a href=&quot;https://docs.kernel.org/process/submitting-patches.html&quot;&gt;documentation&lt;/a&gt; first also got me a long way before submitting to the mailing list. In all, the process took around four months from identifying the problem, patching then finally it being merged and release as part of Kernel 6.1. &lt;a href=&quot;https://github.com/torvalds/linux/commit/45dfa45f52e66f8eee30a64b16550a9c47915044&quot;&gt;Here it is in the Linux commit log (GitHub mirror) 😏&lt;/a&gt;. It’s actually quite involved as the timestamp sent is a tick count from a 32 bit timer, which requires a worker to maintain a datetime relative timestamp.&lt;/p&gt;

&lt;p&gt;The process really epitomised why I love open-source:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Was quickly able to pin point what was missing and where by looking at the code. That’s not possible with closed-source tools.&lt;/li&gt;
  &lt;li&gt;The feature wasn’t present but I wanted it and it would benefit others to add it.&lt;/li&gt;
  &lt;li&gt;Good documentation meant setting up a development environment was quick and abiding to contribution guidelines easy.&lt;/li&gt;
  &lt;li&gt;Existing experienced contributors aided but hopefully were not burdened by a new feature being developed by someone else.&lt;/li&gt;
  &lt;li&gt;It all happened asynchronously, remotely and without any meetings in four months to being included in one of the World’s most used software.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;usage-and-difference-illustration&quot;&gt;Usage and Difference Illustration&lt;/h1&gt;

&lt;p&gt;One can check the timestamping capabilities of a tool using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethtool&lt;/code&gt; and a candleLight will now report support for hardware RX and TX.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt; ethtool --show-time-stamping can0
Time stamping parameters for can0:
Capabilities:
        hardware-transmit
        software-transmit
        hardware-receive
        software-receive
        software-system-clock
        hardware-raw-clock
PTP Hardware Clock: none
Hardware Transmit Timestamp Modes:
        on
Hardware Receive Filter Modes:
        all
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;During the development and following the released 6.1 kernel with the updated module, I ran some tests to illustrate the difference between using software and hardware timestamping. Using a STM32F4 device (external oscillator with 72 MHz main clock) configured with the sole job to send a CAN message every 2 ms from the SysTick ISR, I captured on the same interface with both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;candump can0 -l -H&lt;/code&gt; (hardware) and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;candump -l&lt;/code&gt; (software). The plots and statistics are generated using a quick &lt;a href=&quot;https://gist.github.com/tuna-f1sh/2abe421c2547d41e638253e04e509331&quot;&gt;Python script&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Click the graphs to view live but downsampled versions (too slow and large with all datapoints).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/timestamping-box-ds.html&quot;&gt;&lt;img src=&quot;/assets/img/timestamping-comparison.png&quot; alt=&quot;box&quot; /&gt;&lt;/a&gt;
&lt;strong&gt;The box plot at standard zoom is not ideal because the spread is so different between the two. It does visually highlight how much more reliable hardware timestamps are over software ones however.&lt;/strong&gt;
&lt;a href=&quot;/assets/timestamping-scatter-ds.html&quot;&gt;&lt;img src=&quot;/assets/img/timestamping-scatter.png&quot; alt=&quot;scatter&quot; /&gt;&lt;/a&gt;
&lt;strong&gt;One can see that a software &lt;em&gt;timestamp&lt;/em&gt; &amp;gt; n * 2 ms will result in the following n timestamps appearing to be ~0 ms due to the system actually popping all the packets that arrived in the n * 2 ms period and stamping them all in quick succession.&lt;/strong&gt;
&lt;a href=&quot;/assets/timestamping-hist-ds.html&quot;&gt;&lt;img src=&quot;/assets/img/timestamping-hist.png&quot; alt=&quot;histogram&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One can see there is a pronounced difference in the accuracy of the timing; the software timing makes the device appear to be unstable. I did intentionally load the system and it was running in a virtual machine so is a worse case perhaps. It is still clear that if one is doing timing specific tests, hardware timestamps are very important if not critical&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Hardware Timestamps
Max: 2025 µs
Min: 1977 µs
Stddev: 6.8 µs
Variance: 46.6 µs
Largest percentage slip: 1.25%

# Software Timestamps
Max: 7916 µs
Min: 1 µs
Stddev: 113.1 µs
Variance: 12789.7 µs
Largest percentage slip: 295.8%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;In candleLight firmware, it’s when the gs_usb packet is queued - not perfect but good enough for most use cases. The resolution is limited to 1 µs. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;On a non-real-time kernel at least - it would be interesting to test with a real-time one. They should be more stable but could not beat the accuracy of the hardware supplied ones. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Sat, 07 Jan 2023 00:00:00 +0000</pubDate>
      </item>
    
      <item>
        <title>Cyme - System USB Bus and Device Listing</title>
        <link>/programming/2023/01/01/cyme-usb-listing-tool.html</link>
        <guid isPermaLink="true">/programming/2023/01/01/cyme-usb-listing-tool.html</guid>
        <description>&lt;p&gt;&lt;a href=&quot;https://github.com/tuna-f1sh/cyme&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cyme&lt;/code&gt;&lt;/a&gt; is a Rust CLI tool I developed for listing system USB buses and devices - a modern cross-platform alternative to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lsusb&lt;/code&gt;. Here is the README intro:&lt;/p&gt;

&lt;p&gt;The project started as a quick replacement for the barely working lsusb script and is my yearly Rust project to keep up to date! Like most fun projects, it quickly experienced feature creep as I developed it into a cross-platform replacement for lsusb. As a developer of embedded devices, I use a USB list tool on a frequent basis and developed this to cater to what I believe are the short comings of lsusb; verbose dump is too verbose, tree doesn’t contain useful data on the whole, it barely works on non-Linux platforms and modern terminals support features that make glancing through the data easier.&lt;/p&gt;

&lt;p&gt;It’s not perfect as it started out as a Rust refresher but I had a lot of fun developing it and hope others will find it useful and can contribute. Reading around the lsusb source code, USB-IF and general USB information was also a good knowledge builder.&lt;/p&gt;

&lt;p&gt;The name comes from the technical term for the type of blossom on a Apple tree: cyme - it is Apple related and also looks like a USB device tree 😃🌸.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://asciinema.org/a/IwYyZMrGMbXL4g15qDIaUViyM&quot;&gt;&lt;img src=&quot;https://asciinema.org/a/IwYyZMrGMbXL4g15qDIaUViyM.svg&quot; alt=&quot;asciicast demo&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Sun, 01 Jan 2023 00:00:00 +0000</pubDate>
      </item>
    
      <item>
        <title>Ceramic Nixie Tube Clock</title>
        <link>/electronics/fabrication/mechanical/clock/2022/11/01/nixie-clock.html</link>
        <guid isPermaLink="true">/electronics/fabrication/mechanical/clock/2022/11/01/nixie-clock.html</guid>
        <description>&lt;p&gt;It’s been six years since my &lt;a href=&quot;/2016/12/nixie-pipe-modern-day-led-nixie-tube/&quot;&gt;Nixie Pipe project&lt;/a&gt; - my interpretation of a modern day &lt;a href=&quot;https://en.wikipedia.org/wiki/Nixie_tube&quot;&gt;Nixie Tube&lt;/a&gt;. Whilst the project was successful and has merit as an Nixie Tube alternative, an element of the inspiration was perhaps shying away from the electronic design challenge of a &lt;em&gt;real&lt;/em&gt; Nixie Tube project.&lt;/p&gt;

&lt;p&gt;So I decided now was the time to do the fabled project of an Electronic Engineer: a Nixie Tube project. Not to say it’s the most challenging electronics in the world, more that it’s a digestible one for a side-project with some interesting analogue and digital design choices to make; Drop-in hV supply or custom design? Shift registers and MOSFETs, hV LED drivers, hV shift registers or retro Nixie drivers?&lt;/p&gt;

&lt;p&gt;The main interest for me was the hV supply and case design - since the case is where one can make it unique. Like my &lt;a href=&quot;/electronics/fabrication/mechanical/clock/2021/06/16/linear-clock.html&quot;&gt;Linear Clock&lt;/a&gt; I ended up with two designs again! One is a CNC aluminium case with a solar indicator and the other is a 3d printed ceramic case - something I’ve wanted to try for a while.&lt;/p&gt;

&lt;h2 id=&quot;electronics&quot;&gt;Electronics&lt;/h2&gt;

&lt;p&gt;I wanted to design the high-voltage (hV) supply into the controller - rather than pick something off the shelf - as this was one of the more interesting aspects of the project. Using the excellent &lt;a href=&quot;https://hackaday.io/project/162301-high-voltage-nixie-power-supply&quot;&gt;report by Tony&lt;/a&gt; as a reference, the controller features a LT3757EMSE configured as a flyback converter. It’s essentially the application example on pg.32 but with a digital pot in the feedback loop so that the controller can adjust the output voltage as required. I thought it might to be useful to control this to &lt;em&gt;overdrive&lt;/em&gt; the tubes if required or adjust brightness but didn’t use it in the end.&lt;/p&gt;

&lt;p&gt;The converter is most efficient at higher than standard USB input voltages so I added a USB-PD controller. It’s nice to have the option but in practice the clock works fine at USB-2.0 5 V/500 mA - I would probably DNF this circuitry next time.&lt;/p&gt;

&lt;p&gt;The remaining design is something tried and tested for me: SAMD21 microcontroller, DS3232 RTC, logic shifters for WS2812B LEDs and Molex connectors for the touch buttons/IO. I’m happy to report revision 0 of the controller worked without any bodge wires 😁!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/jbr-nixie-in-12-clock-r1.pdf&quot;&gt;JBR Nixie Tube Clock Controller Schematic&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;touch-buttons&quot;&gt;Touch Buttons&lt;/h3&gt;

&lt;p&gt;Every clock needs a way to set it, which offers another area to play! I had a basic idea of how I wanted the case to look at this point and knew I wanted touch pads not buttons. The touch input was initially provided by the &lt;a href=&quot;https://www.nxp.com/docs/en/data-sheet/MPR121.pdf&quot;&gt;MPR121&lt;/a&gt; on an external board. The part is end of life however and so I’ve since developed a direct to GPIO &lt;a href=&quot;https://github.com/tuna-f1sh/RBD_QTouchButton&quot;&gt;solution&lt;/a&gt; using the SAMD21’s QTouch peripheral.&lt;/p&gt;

&lt;p&gt;The touch inputs connect to aluminium (not anodised for conduction unlike the case) touch pads.&lt;/p&gt;

&lt;h3 id=&quot;in-12ab-carrier-modules&quot;&gt;IN-12A/B Carrier Modules&lt;/h3&gt;

&lt;p&gt;With the hV supply on the controller, it didn’t leave much land for lots of through-holes to mount the IN-12 tubes directly. Modules also allow quick replacement in case of burn out so this is the route I went down. The next choice was the switching method.&lt;/p&gt;

&lt;p&gt;I explored shift registers with transistors, shift registers with high voltage sinking etc. but none had the right number of channels to be mounted directly on a module, complicating the routing. I came across the &lt;a href=&quot;https://github.com/dekuNukem/exixe&quot;&gt;Exixie&lt;/a&gt; modules a while back and actually started making some so decided to base my modules on this. I replaced the STM32F0 part for a PCA9685PW - the same control but cheaper and no programming required. For redundancy, the controller and firmware actually supports both the SPI Exixe and I2C PCA9685PW - take that chipageddon!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/jbr-in-12-module-r0.pdf&quot;&gt;JBR IN-12A/B Module Schematic&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/nixie-clock/hardware/DSC_0360.jpg&quot; alt=&quot;&quot; /&gt;
&lt;strong&gt;My IN-12A/B Nixie Tube module. A &lt;a href=&quot;https://www.nxp.com/docs/en/data-sheet/PCA9685.pdf&quot;&gt;PCA9685BS&lt;/a&gt; 16 channel PWD controller, 10 &lt;a href=&quot;https://assets.nexperia.com/documents/data-sheet/BF820W.pdf&quot;&gt;BF820W&lt;/a&gt; NPN high-voltage transistors, RGB LED and passives. It’s footprint matches the Exixe and the addressing of the PCA9685BS allows upto 62 modules, so it’s not going to be a limiter.&lt;/strong&gt;
&lt;img src=&quot;/assets/img/nixie-clock/hardware/DSC_0355.jpg&quot; alt=&quot;&quot; /&gt;
&lt;strong&gt;Low stack headers mean the modules don’t add much stack compared to being soldered straight into controller. I toyed with pin sockets but opted against in favour of better clearances.&lt;/strong&gt;
&lt;img src=&quot;/assets/img/nixie-clock/hardware/DSC_0334.jpg&quot; alt=&quot;&quot; /&gt;
&lt;strong&gt;My controller left to right: &lt;a href=&quot;https://www.analog.com/media/en/technical-documentation/data-sheets/lt3757-3757a.pdf&quot;&gt;LT3757EMSE&lt;/a&gt; configured as a flyback high voltage supply (170 V) with optional digital pot for uC setpoint control. STUSB4500 USB-PD controller for &amp;gt; 5 V input voltage to improve flyback efficiency - will work at USB-2.0 5 V/500 mA too. SAMD21, DS3232 RTC, IO and logic shifters for WS2813B LEDs.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;cases&quot;&gt;Cases&lt;/h2&gt;

&lt;p&gt;With the electronics done, next was the part looked at every day. I went for a fairly simple rectangle with a bit of my own spin; nice radii and smooth lines. Up top are areas for two slightly raised touch pads. On the bottom, a foot tilts the case to an angle that is nearer to one’s eyeline when on a desk.&lt;/p&gt;

&lt;p&gt;Initially I made a resin then aluminium case because these were easy to prototype. Something about ceramic and Nixie Tubes got me going though - maybe because ceramic is often used as a hV isolator? Finding Olaf at &lt;a href=&quot;https://seremik.ch/?lang=en&quot;&gt;Seremik&lt;/a&gt; in Switzerland, he explained how to adapt the design and we made a ceramic version.&lt;/p&gt;

&lt;p&gt;The ceramic one is one I like most. Whilst the solar clock part of the aluminium one is cool, I actually wanted to avoid LEDs in this project. Additionally, having been into ceramics when at school it feels like coming full circle in my life of projects. I actually made it as a 70th birthday present for my mother, to go with all my school ceramic pieces!&lt;/p&gt;

&lt;h3 id=&quot;aluminium-solar-clock&quot;&gt;Aluminium Solar Clock&lt;/h3&gt;

&lt;p&gt;I intended the foot to be made from wood or plastic. Waiting for parts to arrive and wanting to do more with the sun clock function in my &lt;a href=&quot;/electronics/fabrication/mechanical/clock/2021/06/16/linear-clock.html&quot;&gt;Linear Clock&lt;/a&gt;, I ended up making a translucent foot. An LED strip diffuses through the foot, with the &lt;em&gt;sun&lt;/em&gt; (LED) moving from the left to right side throughout the daylight hours - repeating with a &lt;em&gt;moon&lt;/em&gt; hue at night. The LED palette attempts to mirror the sun’s at that coordinate position. It’s best understood watching the &lt;a href=&quot;https://youtu.be/eiXbshH5SjY?t=108&quot;&gt;video&lt;/a&gt; or animation below.&lt;/p&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;img src=&quot;/assets/img/nixie-clock/nixie-clock-solar.gif&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/nixie-clock/aluminium/DSC_0501.jpg&quot; alt=&quot;&quot; /&gt;
&lt;strong&gt;Midday the sun (LED) position is near enough middle.&lt;/strong&gt;
&lt;img src=&quot;/assets/img/nixie-clock/aluminium/DSC_0496.jpg&quot; alt=&quot;&quot; /&gt;
&lt;strong&gt;LED bar and tube illumination off&lt;/strong&gt;
&lt;img src=&quot;/assets/img/nixie-clock/aluminium/DSC_0449.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/assets/img/nixie-clock/aluminium/DSC_0309.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/assets/img/nixie-clock/aluminium/DSC_0317.jpg&quot; alt=&quot;&quot; /&gt;
&lt;strong&gt;In set settings mode the bottom bar is full magenta!&lt;/strong&gt;
&lt;img src=&quot;/assets/img/nixie-clock/aluminium/DSC_0391.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/assets/img/nixie-clock/aluminium/DSC_0388.jpg&quot; alt=&quot;&quot; /&gt;
&lt;strong&gt;The body is anodised, the buttons are not in order to isolate them from the case.&lt;/strong&gt;
&lt;img src=&quot;/assets/img/nixie-clock/aluminium/DSC_0387.jpg&quot; alt=&quot;&quot; /&gt;
&lt;strong&gt;Light diffuser foot. I have the intention of making a wooden foot too.&lt;/strong&gt;
&lt;img src=&quot;/assets/img/nixie-clock/aluminium/DSC_0382.jpg&quot; alt=&quot;&quot; /&gt;
&lt;strong&gt;Clear rear panel to show off the electronics but prevent accidental shocks. Yes I did shock myself more than once 🤦👈…&lt;/strong&gt;
&lt;img src=&quot;/assets/img/nixie-clock/aluminium/DSC_0381.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.dropbox.com/sh/c0p42ch8rv73797/AACrwQgwomrfLwGUCbuhZ-fXa?dl=0&quot;&gt;Dropbox folder with more photos&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;printed-ceramic&quot;&gt;Printed Ceramic&lt;/h3&gt;

&lt;p&gt;Adapting the case for ceramic printing involved a bit of back and fourth. Unlike other 3d printing materials, the wet clay remains wet as it prints. The result is that supports aren’t an option, ruling out even minor overhangs like the radii on the case.&lt;/p&gt;

&lt;p&gt;The front of the case is flat for this reason but I don’t think it takes much away as the imperfect, organic form of the clay adds interest. Talking of the imperfect form, the tube openings have enough tolerance for the tubes to fit and the wavy ceramic finish is not dissimilar to the blown glass tubes. It was hard to get the machined touch buttons in place however, without gaps (or only small ones)!&lt;/p&gt;

&lt;p&gt;Unlike the machined case, which includes PCB mounts and tapped holes for the rear panel, neither were options for the ceramic case. Instead, I created a PCB carrier that is adhered to the ceramic and glued magnets to hold the rear panel.&lt;/p&gt;

&lt;p&gt;Overall I think the outcome is great and it’s near to what I envisaged. I particularly like how the white glaze reflects the glowing tubes.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/nixie-clock/ceramic/DSC_0520.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/assets/img/nixie-clock/ceramic/DSC_0512.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/assets/img/nixie-clock/ceramic/DSC_0491.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/assets/img/nixie-clock/ceramic/DSC_0423.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/assets/img/nixie-clock/ceramic/DSC_0419.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/assets/img/nixie-clock/ceramic/DSC_0413.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/assets/img/nixie-clock/ceramic/DSC_0410.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/assets/img/nixie-clock/ceramic/DSC_0402.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/assets/img/nixie-clock/ceramic/DSC_0394.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/assets/img/nixie-clock/ceramic/DSC_0376.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/assets/img/nixie-clock/ceramic/DSC_0374.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/assets/img/nixie-clock/ceramic/DSC_0368.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/assets/img/nixie-clock/ceramic/DSC_0349.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.dropbox.com/sh/c0p42ch8rv73797/AACrwQgwomrfLwGUCbuhZ-fXa?dl=0&quot;&gt;Dropbox folder with more photos&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;video&quot;&gt;Video&lt;/h2&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/eiXbshH5SjY&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id=&quot;manual&quot;&gt;Manual&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/nixie-clock/JBRNixieTubeClockManual.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;shop&quot;&gt;Shop&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://shop.jbrengineering.co.uk/product/nixie-tube-clock-solar/&quot;&gt;Aluminium Solar Clock&lt;/a&gt;
&lt;a href=&quot;https://shop.jbrengineering.co.uk/product/ceramic-nixie-tube-clock/&quot;&gt;Ceramic Clock&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Tue, 01 Nov 2022 00:00:00 +0000</pubDate>
      </item>
    
      <item>
        <title>Linear Clock</title>
        <link>/electronics/fabrication/mechanical/clock/2021/06/16/linear-clock.html</link>
        <guid isPermaLink="true">/electronics/fabrication/mechanical/clock/2021/06/16/linear-clock.html</guid>
        <description>&lt;p&gt;My latest clock project has been the longest and most challenging to complete. There have been times when I’ve been tempted to can it or thought I’d reached a dead-end but persevered. I had to keep reminding myself that I do these projects primarily for the challenge, to learn new things and to further my knowledge: if it were simple I wouldn’t have started.&lt;/p&gt;

&lt;p&gt;Overall I’m now fairly happy with the outcome - an outcome which resulted in two designs! I’ve tried to compact the development’s interesting points into this post, which also serves as a sort of script for the &lt;a href=&quot;https://www.youtube.com/embed/_xnCBslNjTs&quot;&gt;video blog&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;idea-and-concept&quot;&gt;Idea and Concept&lt;/h2&gt;

&lt;p&gt;I was keen to build a mechanical clock &lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, as my previous designs have been light based. Having worked with flip-dot displays, the sound of a well orchestrated electro-mechanical system is very pleasing and this is something I wanted to achieve. It would also present the multi-domain challenges that I seek.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://www.hodinkee.com/articles/the-eerie-beauty-of-the-apple-watch-solar-face-and-the-anatomy-of-nightfall&quot;&gt;solar Apple Watch face&lt;/a&gt; had drawn my inspiration for a while and I wanted to create a physical clock based on this. I was struggling to develop a nice way to present this however: I’d developed a sun clock based colour temperature of WS2812B LEDs but didn’t want another purely LED clock!&lt;/p&gt;

&lt;p&gt;Ball bearings also peaked my interest and started considering how to build a clock around this, without it becoming a marble run. Again, I wanted sound but not actuation sound; only the sound of the ball rolling. How could I move balls without some form of actuation? Magnets.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/linear-clock-sketch.png&quot; alt=&quot;sketch of clock idea&quot; /&gt;
&lt;strong&gt;Basic form sketch. The idea was two rows: one for fives of minutes and one for ones of hours. A ball in each row would move to indicate the current time using magnets. Combined with the sun clock, the shiny balls would reflect the colour temperature and make for a more interesting display.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At this point, I could design around an array of electromagnets from Aliexpress. I had recently come &lt;a href=&quot;https://hackaday.io/project/39494-pcb-motor&quot;&gt;across PCB motors&lt;/a&gt; however and wanted to explore this. It would also allow for a compact and easy to assemble design. Of course, I wasn’t sure at this stage how well they would work with a gap between the PCB and attracting ball..&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/linear-clock-concept-development.jpg&quot; alt=&quot;image of clock concept development&quot; /&gt;
&lt;strong&gt;An ongoing idea board - it features some later developments. Shows some gauging for the clock sizing and consideration of shared channel 3-phase motor control rather than the independent h-bridge design that I ended up with.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;prototype-one&quot;&gt;Prototype One&lt;/h2&gt;

&lt;p&gt;So I started out designing a &lt;em&gt;Coil Board&lt;/em&gt; and enclosure that would feature tracks above the PCB coils for each row. It would be controlled by a &lt;em&gt;Controller&lt;/em&gt; via an umbilical connection. I opted to separate the boards for a number of reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The &lt;em&gt;Controller&lt;/em&gt; features designs I’ve tried and tested so I was confident I would not need to revise it. It had the most assembly so I could just build it once and move it to &lt;em&gt;Coil Board&lt;/em&gt; revisions.&lt;/li&gt;
  &lt;li&gt;I was less concerned regarding EMF issues; 24 inductors next to the microcontroller didn’t seem nice!&lt;/li&gt;
  &lt;li&gt;It allows for debugging the &lt;em&gt;Coil Board&lt;/em&gt; without the controller. Human in the loop and a power supply if required.&lt;/li&gt;
  &lt;li&gt;There simply wasn’t much space on the &lt;em&gt;Coil Board&lt;/em&gt;. The design was already long with twelve coils and there wasn’t much space in the centre once the LEDs were added and ensuring a good ground plane.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;coil-board-r0&quot;&gt;Coil Board R0&lt;/h3&gt;

&lt;p&gt;In terms of electronics, the &lt;em&gt;Coil Board&lt;/em&gt; was quite simple: a I2C PWM driver (PCA9685PW) per row to control each coil independently via a low-side switch (single direction) and a WS2812B LED strip in centre for sun clock and visual feedback. The challenge was in the coil design and layout.&lt;/p&gt;

&lt;p&gt;I found &lt;a href=&quot;https://github.com/in3otd/spiki&quot;&gt;Spiki&lt;/a&gt; a Python tool for creating KiCad spirals, which I used to create a 26 mm diameter coil with a 0.2 mm trace width. It required some fudging however to morph the output into what I could use for creating rows of coils.&lt;/p&gt;

&lt;p&gt;Since it generated a PCB, I made this into a footprint with some &lt;em&gt;vim&lt;/em&gt; since the KiCad editor does not allow multi-layer footprints. KiCad also does not allow vias in footprints so I ended up with a mix of footprint and layout, which I then used as a pattern using another script to create two rows of twelve coils.&lt;/p&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;img src=&quot;/assets/img/linear-clock/pcb-coil.gif&quot; /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;The four layer PCB coil created with some scripts and vim! I had to layout the vias and tracks manually since these are not allowed in a KiCad footprint and then repeat this as a master pattern. Not before triple checking the current path is always the correct direction so as not to cancel it’s own EMF! The routing is quite tight when one factors in that JLPCB does not allow blind vias.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/see-through-board.png&quot; alt=&quot;R0 full board&quot; /&gt;
&lt;strong&gt;The full copper layout looks pretty cool!&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;controller-r0&quot;&gt;Controller R0&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/big-ball-controller.jpg&quot; alt=&quot;linear clock controller board&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Nothing too special:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;STUSB4500 USB-PD controller for power supply: I’ve used this for a number of projects and it’s great. It keeps the power supply upstream but allows the controller to decide the input power - this was important as I wanted to tune the coil voltage for the maximum current the copper could take once I could measure the actual coil resistance.&lt;/li&gt;
  &lt;li&gt;SAMD21 microcontroller: My go to for Arduino compatibility. I added support for this chip to &lt;a href=&quot;https://github.com/sudar/Arduino-Makefile&quot;&gt;Arduino Makefile&lt;/a&gt; so it strikes the right balance for personal projects between being able to go low-level whilst relying on the Arduino eco-system.&lt;/li&gt;
  &lt;li&gt;Current sense for each row: For protection but I also had the idea that I may be able to detect the ball position based on the change in current due to the induced current in the ball.&lt;/li&gt;
  &lt;li&gt;DS3231 RTC: I could have used the RTC on the SAMD21 but it doesn’t have an easy to use RTC battery solution like the STM32 series. The DS3231 I’ve used in all my clocks so it was low risk.&lt;/li&gt;
  &lt;li&gt;Connected to the &lt;em&gt;Coil Board&lt;/em&gt; via a Molex Pico-Lock system: I love these because they are small but carry high current; the 1 mm pitch/2 circuit is rated for 2.5 A! Each row has it’s own supply cable and I estimated with three coils the peak current would be 1.5 A per row.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;case-r0&quot;&gt;Case R0&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/r0-render.png&quot; alt=&quot;r0 render&quot; /&gt;
&lt;strong&gt;A render of the first design. With the PCBs fabricated in China, I perhaps got a bit ahead of myself waiting for the delivery - this would become the theme of the project!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I wanted a clean design so it’s a simple rounded rectangle - based on the PCB outline - with some indents at the front edge to indicate the positions. The tracks are profile cuts of the ball but offset slightly so the ball only contacts at the edges, in order to reduce friction and help the ball roll between pads.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/split-joined.jpg&quot; alt=&quot;r0 print&quot; /&gt;
&lt;strong&gt;When it came to printing (which I had to do in two halves due to print tray size) I opted to play with the track design. One is a smooth track and the other is wavey. The wavey idea was to create mechanical instability so that the ball would roll to the edge of the coil when the coil was switched off, allowing the next coil to &lt;em&gt;pick it up&lt;/em&gt;. The centre thin section is for the LEDs - too thin and square in this case.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;testing&quot;&gt;Testing&lt;/h3&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;img src=&quot;/assets/img/linear-clock/first-run.gif&quot; /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Testing started well, the coils worked! Control via the PWM controllers from the &lt;em&gt;Controller&lt;/em&gt; also worked.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I got off to a good start: the PCB coils all worked and were controllable via the PWM controllers. PWM driving the coils wasn’t great as in combination with a magnet, they turned into a very unpleasant speaker! Even PWM frequencies above audible created noise. 100% duty solved this, which was ok as I found I had no need to module the driving.&lt;/p&gt;

&lt;p&gt;What didn’t work was a ferrous steel ball, which I had based the design around; 20 mm carbon steel balls. The PCB magnets were too weak (generating ~1.5 mT at the PCB) to even hold a ferrous steel, let alone attract it through the casing. Not deterred, I used a neodymium magnet and this worked great. I can replace the carbon steel balls with neodymium of the same size, simple I thought…&lt;/p&gt;

&lt;p&gt;The first hurdle with using a permanent magnet rather than ferrous steel was that it had poles and this meant single direction current control of the coil was not going to work. With the steel, I had hoped I could just shift the attracting coil down the row and the ball would roll with it. The magnet meant that it would have its poles aligned with the current coil and that the direction of the next coil needed to be the opposite. I turned to some (basic) FEM using &lt;a href=&quot;https://www.femm.info/wiki/MagneticsTutorial&quot;&gt;FEMM&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/linear-clock-two-balls-air-model.png&quot; alt=&quot;FEM model two pcb coil&quot; /&gt;
&lt;strong&gt;FEM model of the PCB coil with balls illustrated but configured as air. One can see that the field lines from the active coil form such that the poles would be inverse on the adjacent pad. Turning on the next coil with the same polarity simply &lt;em&gt;locks&lt;/em&gt; the ball on the other pad; the polarity must switch to attract the ball, something R0 did not allow.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/linear-clock-one-ball-ans.png&quot; alt=&quot;FEM model single ball&quot; /&gt;
&lt;strong&gt;More pretty colours! FEM model of the PCB coil with single neodymium ball. I’m not going to pretend I had to go much beyond the tutorial but I was pleased to find the model matched my measurements for Telsas generated by the PCB coil: ~1.5 mT on the PCB and ~1.0 mT through the case (0.6 mm).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I hoped the wavey track might counter this flaw, by causing the ball to rest between coils it would allow the next coil to &lt;em&gt;pick up&lt;/em&gt; the ball. In practice it was not successful however. I tried a number of profiles but faced a few issues.&lt;/p&gt;

&lt;p&gt;One was the increased material/air gap degrading the holding field strength and also struggling to get the ball stable when held. Another was that the track biasing had to be symmetrical (in order to work both directions) but this meant the ball would not always roll to the correct coil. It’s possible with more effort one could find a track profile but I opted for a different path.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/track-profile-cut.png&quot; alt=&quot;wavey track profile cut&quot; /&gt;
&lt;strong&gt;I could not find a track profile that solved R0’s design flaws. This track had small peaks but also narrowing to make the ball less stable at the coils so that it would carry momentum between coils. The problem was biasing the roll in the correct direction, whilst maintaining bidirectional control.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pondering over other mechanical advantages: inclining the track depending on direction, moving the magnet…all felt like over-complexity and dilution of the idea - I wanted the ball to roll with no apparent assistance.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/electromagnet-build.JPG&quot; alt=&quot;iron core electromagnets&quot; /&gt;
&lt;strong&gt;Another attempt at salvaging the design was using iron core electromagnets. I found the perfect size for the design. Whilst this did hold a carbon steel ball, the air gap was still too large to attract the ball from another coil. At this point I was learning the hard way about reluctance and the magnetic field drop off in air!&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;prototype-two&quot;&gt;Prototype Two&lt;/h2&gt;

&lt;p&gt;Prototype One showed the concept had potential but also flaws so I set out on a second design. The primary updates were to the &lt;em&gt;Coil Board&lt;/em&gt;, the &lt;em&gt;Controller&lt;/em&gt; could remain at R0 - the split paying dividends.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The &lt;em&gt;Coil Board&lt;/em&gt; needed polarity control of the coils.&lt;/li&gt;
  &lt;li&gt;Current sense didn’t really work for position detection; current induced was negligible compared to coil current. I needed a better positioning method.&lt;/li&gt;
  &lt;li&gt;I had realised how important reluctance is and that the coil should be as close to ball as possible.&lt;/li&gt;
  &lt;li&gt;I had measured the coil resistance to be ~20 Ω. Based on the fabricated copper thickness peak 450 mA @ 9 V was about the limit before burn out. I say peak because the coil quickly warms up and thus its resistance increases, reducing the current.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;coil-board-r1&quot;&gt;Coil Board R1&lt;/h3&gt;

&lt;p&gt;The obvious way to get direction control of the coils was to ditch the PWM controller and MOSETS and to use a motor controller IC with internal H-bridges. The design decision here was what controller to use.&lt;/p&gt;

&lt;p&gt;3-phase with three channels? I could wire the coils like a stepper motor rolled out flat and get away with just two controllers. The current demand would be high however as four coils would be on when just one is &lt;em&gt;working&lt;/em&gt;, or eight in order to move (~7.4 A!). It might also corner me in the software control flexibility.&lt;/p&gt;

&lt;p&gt;I decided against this 3-phase, mostly because the current demand would eliminate USB-C and the clock would require a massive PSU. There was the option of not sharing channels, but going down this track I opted to use a simple dual H-bridge IC: the &lt;a href=&quot;https://www.ti.com/lit/ds/symlink/drv8833.pdf&quot;&gt;DRV8833&lt;/a&gt;. I’d used it in a couple of other projects so knew how it worked, plus I liked that it features over-current limiting, clipping current control and fault indication. I would add hall effect sensors at each coil as a magnet position sensor - since I was now using magnetic balls not steel, this was an option.&lt;/p&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;img src=&quot;/assets/img/linear-clock/drv8833-test.gif&quot; /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Testing the DRV8833 control of coils with first board before redesign. I wanted to ensure that the DRV8833 didn’t fault, since the coil could be considered a short-circuit.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The next step was how to independently control each DRV8833. I would have six DRV8833 per row (one per two coils), each with five inputs and one output. A shift register came to my mind first, but would not provide read-back of fault or the hall sensors so I would require another chip just for this. Since the speed or timing of the coil switching was not important, I went for the MCP23017 GPIO expander: three per row, each controlling and reading the state of four coils via the DRV8833 and hall sensors.&lt;/p&gt;

&lt;p&gt;Whilst the &lt;em&gt;Coil Board&lt;/em&gt; was having quite the overhaul, the nice thing about using the GPIO expander was that it could be controlled over I2C and so the PicoLock cable to the &lt;em&gt;Controller&lt;/em&gt; reminded the same. The firmware became a bit more complex, due to addressing the six MCP23017 in order to shift along the coil row but I created an abstraction layer that made this transparent as my first task.&lt;/p&gt;

&lt;h3 id=&quot;development-and-testing&quot;&gt;Development and Testing&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/small-ball-open.jpg&quot; alt=&quot;r1 coil board assembly&quot; /&gt;
&lt;strong&gt;The assembled R1 &lt;em&gt;Coil Board&lt;/em&gt; with DRV8833 H-bridge control via MCP23017 GPIO expanders and hall sensors below each coil is quite pleasing, even if I do say so myself - and only one bodge wire! It’s four layer so there is some hidden complexity below the solder mask.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The updated boards arrived, I assembled and to my joy the system worked! I had polarity control and sensing of all the coils via the &lt;em&gt;Controller&lt;/em&gt;. With the wind in my sails, I set out developing the firmware. My approach to the firmware was to create a coil control abstraction, which a &lt;em&gt;magnets&lt;/em&gt; state machine interfaces with.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;magnets&lt;/em&gt; state machine on a basic level, takes a seek position and moves the magnet to this location. It also constantly tracks the state of the magnet, ensuring that it is always where it should be, if it is missing or if the system is faulting.&lt;/p&gt;

&lt;p&gt;Movement is achieved by enabling the next coil in the direction of the seek position, with the opposite polarity of the current coil. The current coil is disabled and the ball movement is detected by the hall sensors. The movement event causes the state change, this allows the system to detect when the magnet is &lt;em&gt;stuck&lt;/em&gt; and act accordingly. Once moved, the &lt;em&gt;brake&lt;/em&gt; state enables coils either side of the position to help stop the magnet.&lt;/p&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/jUbjE3N4uFo&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Demo of &lt;em&gt;magnets&lt;/em&gt; state machine with LED debugging enabled. Green: hall sensor active; Blue: coil enabled with north polarity; Red: coil enabled with south polarity.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Another state machine &lt;em&gt;linear-time&lt;/em&gt;, controls the clock state and sets the &lt;em&gt;magnets&lt;/em&gt; FSM based on the time. It also controls a configuration state, which allows one to set the time and other run-time parameters.&lt;/p&gt;

&lt;p&gt;Separate to all this is the solar clock I designed that sets the hour position LED colour temperature based on the solar cycle:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;night -&amp;gt; dawn -&amp;gt; sunrise -&amp;gt; day -&amp;gt; sunset &amp;gt; dusk -&amp;gt; night&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;img src=&quot;/assets/img/linear-clock/sunrise.gif&quot; /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Solar cycle showing the sunrise using a blended sky colour palette, emulating each phase of the day. See the &lt;a href=&quot;https://youtu.be/CRLD3K5hQnA?t=68&quot;&gt;demo reel&lt;/a&gt; for a clearer view.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It does this completely offline, based on a set longitude and latitude using the &lt;a href=&quot;https://github.com/buelowp/sunset&quot;&gt;sunset lib&lt;/a&gt; - pretty neat! I created the FastLED colour temperature palettes using sky palettes kindly provided &lt;a href=&quot;http://soliton.vm.bytemark.co.uk/pub/cpt-city/rafi/index.html&quot;&gt;here&lt;/a&gt; that are mapped to each day phase, mixed as they intersect.&lt;/p&gt;

&lt;h4 id=&quot;balls&quot;&gt;Balls…&lt;/h4&gt;

&lt;p&gt;You may have noticed that the above video shows only one magnet…I’m embarrassed to say, I became so focused developing this that I developed the whole thing with only one magnet. I started with one row during bring up and just didn’t think to try the other row since it was just a mirror of the first. I also have the excuse that my original design was without permanent magnets so interaction between rows was not an issue.&lt;/p&gt;

&lt;p&gt;If you haven’t worked it out, the magnetic field of the neodymium magnets is magnitudes (100x) larger than the PCB coil. The air gap between the rows is not enough to prevent 15 mm neodymium magnets interacting with each other 🤦. In hindsight, this is obvious and I may appear an idiot but I guess it’s an example of a design in flux (pun intended!) and becoming too focused on the development once one gets a sniff of success!&lt;/p&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/3JAXp0J8rKA&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;Above was a low point in the project for sure. I took a break, unsure how it could be salvaged. I considered how I could change the magnetic properties of the ball:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Heating the ball in the oven I had read can permanently reduce magnetism of neodymium - not for me or at not enough to make a difference.&lt;/li&gt;
  &lt;li&gt;Hitting the balls I also read can affect a permanent magnet due to change in the crystal alignments. No joy.&lt;/li&gt;
  &lt;li&gt;Making a carrier ball with smaller neodymium magnets at the pole positions. It didn’t really roll well.&lt;/li&gt;
  &lt;li&gt;Permanent magnets not made from neodymium or at least not 100% neodymium to reduce the magnetic field for the same volume. I found one can get &lt;a href=&quot;https://uk.misumi-ec.com/vona2/detail/221006350391/#&quot;&gt;sintered ferrite magnets&lt;/a&gt; that can be tuned to the required field strength. These are nice because they have a mirrored finish unlike a 100% ferrite magnet and are not quite as brittle. They are expensive however!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The carrier ball and sintered magnets did offer a solution. The problem, was the trade off when selecting ball size. A large ball has more inertia and so is harder to control and move - it does offer a larger field strength however, so is more attracted to the coil. I wanted a large ball (15-20 mm) as this was the intended design. Small balls made the clock harder to read from a distance and make a more &lt;em&gt;pingy&lt;/em&gt; sound.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/balls.jpg&quot; alt=&quot;all the balls I tested with&quot; /&gt;
&lt;strong&gt;I now have a lot of magnetic balls. Exploring the different trade offs between ball diameter, inertia and magnetic field strength. I’ve included the 3d printed carrier balls in this photo too.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The ball size also has an impact on the control system/PCB geometry, as the circumference/2 should be a close factor of the coil pitch in order to roll into the next coil with the correct polarity.&lt;/p&gt;

&lt;p&gt;After a lot of testing, the only ball I could get to work reliably on the current design was a 5 mm neodymium. It didn’t look bad but the small balls just felt like too much of a compromise. True to current tech trends, I decided I’d keep it at that but call it ‘Linear Clock Mini’ or something and work on a re-design.&lt;/p&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/CRLD3K5hQnA&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Demo reel of the &lt;em&gt;Mini&lt;/em&gt; design. Whilst the small balls dilute the design somewhat, I still think it has a place in a small room or on a desk.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/linear-clock-mini-1.jpg&quot; alt=&quot;linear clock mini&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;prototype-three&quot;&gt;Prototype Three&lt;/h2&gt;

&lt;p&gt;Not fully satisfied with the Linear Clock Mini. I explored some options for a clock with the original large balls I had designed for.&lt;/p&gt;

&lt;h3 id=&quot;sledge&quot;&gt;Sledge&lt;/h3&gt;

&lt;p&gt;One idea that seemed feasible and would maintain the same exterior was to sandwich a magnet between the case and PCB. The magnet would move along an inner track - driven by the PCB coils - and pull a carbon steel ball above. It would be a multiplier for the PCB coil of sorts.&lt;/p&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;img src=&quot;/assets/img/linear-clock/sledge.gif&quot; /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Sandwiching a flat magnet between the ball track and PCB was something I tested. Here a small magnet is shown to move with a steel ball magnetically attached - the case would sit between the two.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In practice, whilst it did sort of work, the ball would scrape along the track rather than roll. In addition, friction of the magnet in the sandwich and due to the clamping force to the ball meant it wasn’t all that smooth. I also suspected I would encounter issues with magnet size and proximity to the parallel sledge again, due to the size magnet I would require.&lt;/p&gt;

&lt;h3 id=&quot;split&quot;&gt;Split&lt;/h3&gt;

&lt;p&gt;Creating a larger air gap between the rows was the other feasible idea I had and decided to go with. It was guaranteed to work, the challenge was finding the minimum air gap and maintaining a nice design.&lt;/p&gt;

&lt;p&gt;I turned back to my FEM model and back it up with real-world testing to find the minimum air gap such that the PCB coils would overcome the interaction between the two magnets. By stepping the design and moving the gap into the diagonal, the effect on overall width was reduced slightly. The step also creates a better area for the position indicators, LED and easier viewing of both balls when reading at eye level so wasn’t a complete compromise.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/p-linear-clock-split-1.jpg&quot; alt=&quot;split verification&quot; /&gt;
&lt;strong&gt;Verifying the FEM modelled air gap required for a 15 mm sintered ferrite ball, before committing to the design.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;coil-board-r2&quot;&gt;Coil Board R2&lt;/h3&gt;

&lt;p&gt;The R2 schematic matched R1 since it worked - the change was purely mechanical. I created a split and cut lines in order to detach the rows from each other. One might wonder why I didn’t just create symmetrical PCBs for each row. I opted for a single board with cut so that I could use the board in a wide flat design if I desired; I could keep a single connector to the &lt;em&gt;Controller&lt;/em&gt; without changing that design; to minimise changes in the layout/tracking at this stage.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/hardware-debugging.jpg&quot; alt=&quot;hardware debugging&quot; /&gt;
&lt;strong&gt;There were very few hardware issues in the design process. There was one gotcha in the split that did require some hardware debugging: the cut disconnected the top layer ground plane, resulting in the DRV8833s working at low power (5 V/3 A) but not the intended 9 V/3 A. A good lesson that a bad ground return can allow something to work but not work &lt;em&gt;well&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;stepped-case&quot;&gt;Stepped Case&lt;/h3&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;img src=&quot;/assets/img/linear-clock/linear-clock-max-model-overview.gif&quot; /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Overview of the &lt;em&gt;Max&lt;/em&gt; model. I think I made the most of the forced geometry and it did not become too cumbersome. The track features &lt;em&gt;tees&lt;/em&gt; to aid keeping the ball in position.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Prototype Three demanded a completely new enclosure design. Nothing too complex though: again based on the PCB outline to minimise size but with a slope based on the calculated minimum air gap + fudge factor between the rows. I made full use of the slope to make the position indicators clearer with an LED light diffuser between them.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/max-base-machining.jpg&quot; alt=&quot;anodised base for max&quot; /&gt;
&lt;strong&gt;The ferrite balls have a dark gray appearance so for this design, I requested a gray anodising to the aluminium machined base to match.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;it-works&quot;&gt;It Works!&lt;/h3&gt;

&lt;p&gt;I placed the order for the printed top and machined base then crossed my fingers. When they arrived, I was dreading the test but thankfully, it worked! The big balls were controllable through the full clock cycle. The firmware for both designs is the same, apart from some different timing values for the motion due to the different ball inertia.&lt;/p&gt;

&lt;p&gt;There is minor interaction between the rows on both the &lt;em&gt;Mini&lt;/em&gt; and the &lt;em&gt;Max&lt;/em&gt; design - more so on the &lt;em&gt;Mini&lt;/em&gt; in fact. With the motion sensing however, the controller can overcome this. It flips the parallel row to ensure the poles are opposing one another and will re-attempt a move if &lt;em&gt;stuck&lt;/em&gt; - this can be seen in the demo videos. Running at accelerated speed for the demos, this is more apparent as the coils and balls warm up and the control is less effective. I think the repeated movement is almost part of the charm.&lt;/p&gt;

&lt;p&gt;I’m pleased with both designs. The rolling noise is different but pleasing on both; a fast swipe on the &lt;em&gt;Mini&lt;/em&gt; and a grand roll on the &lt;em&gt;Max&lt;/em&gt; due to the increased inertia. Each fits a different space.&lt;/p&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/vNKcjXRv2U8&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Demo reel of the split and stepped &lt;em&gt;Max&lt;/em&gt; design. The increased air gap allows the clock to work with 15 mm balls, which was my original design intent.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/max-open.JPG&quot; alt=&quot;linear clock max open&quot; /&gt;
&lt;strong&gt;The &lt;em&gt;Max&lt;/em&gt; design involves some soldered connections unlike the &lt;em&gt;Mini&lt;/em&gt;. I would probably change the interconnects if I were to revise this, so that both boards connect directly to the &lt;em&gt;Controller&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;final-design-gallery&quot;&gt;Final Design Gallery&lt;/h2&gt;

&lt;h3 id=&quot;mini&quot;&gt;Mini&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/linear-clock-mini-flipdot.jpg&quot; alt=&quot;linear clock mini with flip dot&quot; /&gt;
&lt;img src=&quot;/assets/img/linear-clock/linear-clock-mini-front-4.jpg&quot; alt=&quot;linear clock mini front left&quot; /&gt;
&lt;img src=&quot;/assets/img/linear-clock/linear-clock-mini-front-5.jpg&quot; alt=&quot;linear clock mini front tracks&quot; /&gt;
&lt;img src=&quot;/assets/img/linear-clock/linear-clock-mini-tracks-1.jpg&quot; alt=&quot;linear clock mini tracks&quot; /&gt;
&lt;img src=&quot;/assets/img/linear-clock/linear-clock-mini-rear-1.jpg&quot; alt=&quot;linear clock mini rear&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;max&quot;&gt;Max&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/linear-clock/linear-clock-max-front-1.jpg&quot; alt=&quot;linear clock max front right&quot; /&gt;
&lt;img src=&quot;/assets/img/linear-clock/linear-clock-max-rear-1.jpg&quot; alt=&quot;linear clock max rear&quot; /&gt;
&lt;img src=&quot;/assets/img/linear-clock/linear-clock-max-side-1.jpg&quot; alt=&quot;linear clock max left side&quot; /&gt;
&lt;img src=&quot;/assets/img/linear-clock/linear-clock-max-reflect-2.jpg&quot; alt=&quot;linear clock max balls&quot; /&gt;
&lt;img src=&quot;/assets/img/linear-clock/linear-clock-max-kitchen-3.jpg&quot; alt=&quot;linear clock max kitchen&quot; /&gt;&lt;/p&gt;
&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;mechanical in the non-static sense rather than internal cogs and gears. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Wed, 16 Jun 2021 00:00:00 +0000</pubDate>
      </item>
    
      <item>
        <title>Same Same but Different</title>
        <link>/2021/05/06/same-same-but-different.html</link>
        <guid isPermaLink="true">/2021/05/06/same-same-but-different.html</guid>
        <description>&lt;p&gt;I’ve migrated this blog from Wordpress to Jekyll. Wordpress worked but since I write everything in Markdown before posting it, Jekyll fits into my workflow better. Wordpress become overkill and slow or my needs; it’s not really designed for power users and I didn’t use most the features.  In addition, Wordpress required plug-ins like Jetpack in order to prevent an overwhelming amount of SPAM and I didn’t like having an external analytics tool harvesting data &lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. I’m a proponent of just not having tracking cookies rather than cookie banners that everyone hates - &lt;a href=&quot;https://github.blog/2020-12-17-no-cookie-for-you/&quot;&gt;it’s an easy and intended solution&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On a similar note, I opted not to include or support comments in the migration. Whilst I have enjoyed the discussion and feedback I’ve had with readers over the years, it’s hard to find a good privacy focused comment host. It is a shame to loose this as the public comments often keep posts up to date or add things I may have missed but unless I find a nice and easy to implement static comments system, it’s email only for now.&lt;/p&gt;

&lt;p&gt;The blog is almost ten years old now! Going back through the archives, there is some embarrassing stuff and it’s certainly not representative of my current skill set but I opted to keep them, as a record of my progression as an engineer if nothing else.&lt;/p&gt;

&lt;p&gt;I hope to continue updating this blog with personal projects for at least another ten years. I already have a couple of projects in my backlog I’m excited to write about and the Markdown -&amp;gt; blog post should lower the barrier to this.&lt;/p&gt;

&lt;h2 id=&quot;wordpress-to-jekyll-migration&quot;&gt;Wordpress to Jekyll Migration&lt;/h2&gt;

&lt;p&gt;There are a &lt;a href=&quot;https://nts.strzibny.name/migrating-wordpress-to-jekyll/&quot;&gt;number of posts&lt;/a&gt; around for this so I won’t go too deep. It was not quite as simple as running a plugin however!&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Install the &lt;a href=&quot;https://github.com/benbalter/wordpress-to-jekyll-exporter&quot;&gt;Wordpress to Jekyll exporter plugin&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Find out this doesn’t work on the production site and so export the SQL database and spin up a &lt;a href=&quot;https://hub.docker.com/_/wordpress&quot;&gt;Docker wordpress&lt;/a&gt; container:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;wordpress&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;wordpress&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;always&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;80:80&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;443:443&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;WORDPRESS_DB_HOST&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;db&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# I changed these to match the hosted database (in &apos;db&apos; service too) but not sure it&apos;s required since the wp_config is created for the service&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;WORDPRESS_DB_USER&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;db_user&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;WORDPRESS_DB_PASSWORD&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;db_password&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;WORDPRESS_DB_NAME&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;db_name&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./wp-content/themes/my-theme:/var/www/html/wp-content/themes/my-theme&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# mapping our custom theme to the container&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./wp-content/plugins:/var/www/html/wp-content/plugins&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# map our plugins to the container&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./wp-content/uploads:/var/www/html/wp-content/uploads&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# map our uploads to the container&lt;/span&gt;

    &lt;span class=&quot;na&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;mysql:5.7&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;always&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;db_name&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;MYSQL_USER&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;db_user&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;db_password&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;MYSQL_RANDOM_ROOT_PASSWORD&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;1&apos;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# put the exported .sql database in ./docker/ and it will be imported&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./docker:/docker-entrypoint-initdb.d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;Realise the local site attemps to re-direct http -&amp;gt; https when using ‘/wp-admin’ so:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker &lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; engineer_db_1 bash
mysql &lt;span class=&quot;nt&quot;&gt;--user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;root &lt;span class=&quot;nt&quot;&gt;--password&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;ROOT_PASSWORD &lt;span class=&quot;c&quot;&gt;# where the password is the root password displayed when the serice is started&lt;/span&gt;
use db_name
SELECT &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; from wp_options WHERE option_name &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;home&apos;&lt;/span&gt; OR option_name &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;siteurl&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
UPDATE wp_options SET option_value &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;http://localhost&apos;&lt;/span&gt; WHERE option_name &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;home&apos;&lt;/span&gt; OR option_name &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;siteurl&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;Fix all the exported Markdown post asset links and inline html using a mix of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vim&lt;/code&gt; macros and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fd . _posts/ --type f -e md --exec sed ...&lt;/code&gt;; the exporter does not do this…&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;I didn’t have the time nor inclination to dig into exactly what, but if it’s free… &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Thu, 06 May 2021 00:00:00 +0000</pubDate>
      </item>
    
      <item>
        <title>Entrée USB-C CAN Bus Interface with USB-PD</title>
        <link>/2021/03/16/entree-usb-c-can-interface.html</link>
        <guid isPermaLink="true">/2021/03/16/entree-usb-c-can-interface.html</guid>
        <description>&lt;p&gt;Entrée - like a Canapé but tastier…yes the logo is, and name was, Canapé but I didn’t want to face a &lt;a href=&quot;http://tmsearch.uspto.gov/bin/showfield?f=doc&amp;amp;state=4801:pgy4lj.2.5&quot;&gt;Trademark&lt;/a&gt; dispute over an acute e for a hobby project…&lt;/p&gt;

&lt;p&gt;The Entrée is a USB-C CAN interface. It is a variant of the open source &lt;a href=&quot;https://github.com/HubertD/candleLight&quot;&gt;candleLight&lt;/a&gt; platform and its many spawns. Not only does it add USB-C, it brings new features and CAN/USB controlled USB-PD for powering devices under test.&lt;/p&gt;

&lt;p&gt;This post is a copy and paste of the &lt;a href=&quot;https://github.com/tuna-f1sh/entree&quot;&gt;README.md&lt;/a&gt; - the repository one should be used as the source of truth. I thought I’d share it here for the record, as it is both a useful and interesting project.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/2021/03/entree-plugged-oak.jpg&quot; alt=&quot;Entrée Plugged In&quot; /&gt;
&lt;img src=&quot;/assets/img/uploads/2021/03/entree-backside-oak.jpg&quot; alt=&quot;Entrée Back&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;features&quot;&gt;Features&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Compatiable with:
    &lt;ul&gt;
      &lt;li&gt;gs_usb firmware &lt;a href=&quot;https://github.com/candle-usb/candleLight_fw&quot;&gt;candleLight_fw&lt;/a&gt;; Linux mainline native support.&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://github.com/normaldotcom/cantact-fw&quot;&gt;slcan cantact&lt;/a&gt;; Linux CAN over USART/CDC.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;USB-C connection for use with modern hardware.&lt;/li&gt;
  &lt;li&gt;USB-PD negotiation for powering devices rather than using USB communication interface. Up-to 20 V/1 A can be requested and supplied to a device.&lt;/li&gt;
  &lt;li&gt;Switched control of 120 Ω termination resistor.&lt;/li&gt;
  &lt;li&gt;Switched control of DFU mode and TagConnect 6-pin ISP for use as a development tool.&lt;/li&gt;
  &lt;li&gt;USB-PD profile and device setup using switched internal CAN IDs.&lt;/li&gt;
  &lt;li&gt;USART test points for SLCAN without USB.&lt;/li&gt;
  &lt;li&gt;Two signal connector choices.&lt;/li&gt;
  &lt;li&gt;Small form factor: 55 x 18.5 mm.&lt;/li&gt;
  &lt;li&gt;Silkscreen art 🎨!&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://jbrengineering.co.uk/web-dfu/&quot;&gt;Web-DFU firmware update/selector tool&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;purchase&quot;&gt;Purchase&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://shop.jbrengineering.co.uk/product/entree-usb-c-to-can-interface-with-usb-pd/&quot;&gt;JBR Engineering shop&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.tindie.com/products/22440/&quot;&gt;Tindie&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;usage&quot;&gt;Usage&lt;/h1&gt;

&lt;h2 id=&quot;hardware-connection&quot;&gt;Hardware Connection&lt;/h2&gt;

&lt;p&gt;The primary CAN connection is a &lt;a href=&quot;https://www.digikey.ch/products/en?keywords=WM7622CT-ND&quot;&gt;Molex Picoblade &lt;em&gt;53261-0471&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The connector was selected because they are commonly used on Drones and so Picoblade to 0.1” header cables can also be easily obtained:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://1bitsquared.com/products/black-magic-01in-pin-header-serial-cable&quot;&gt;1 Bit Sqaured Black Magic 0.1” female cable&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alternatively, one can obtain &lt;a href=&quot;https://www.digikey.ch/product-detail/en/molex/0151340402/WM15258-ND/6198148&quot;&gt;pre-crimped female cable assemblies &lt;em&gt;15134-0402&lt;/em&gt;&lt;/a&gt; or &lt;a href=&quot;https://www.digikey.ch/product-detail/en/molex/0510210400/WM1722-ND/242844&quot;&gt;female 4-pin housing &lt;em&gt;51021-04&lt;/em&gt;&lt;/a&gt; for custom cabling.&lt;/p&gt;

&lt;p&gt;A secondary unfitted &lt;a href=&quot;https://www.digikey.ch/products/en?keywords=455-1804-1-ND&quot;&gt;&lt;em&gt;JST SM04B&lt;/em&gt;&lt;/a&gt; (otherwise known as Qwiic/STEMMA) footprint is available on the bottom of the board if one wishes to use those &lt;a href=&quot;https://www.adafruit.com/category/619&quot;&gt;commonly available cables&lt;/a&gt; instead. JST pre-crimped part is &lt;em&gt;A04SR04SR30K152A&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&quot;wiring-example&quot;&gt;Wiring Example&lt;/h3&gt;

&lt;p&gt;Below is a wiring example showing the Entrée Picoblade and JST pinout. A Black Magic 0.1” female header cable is connected to the Picoblade and standard STEMMA QT connected to the secondary JST header. &lt;strong&gt;Note both cable colouring is non-standard due to optimal board layout&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/2021/03/entree-wiring-diagram.png&quot; alt=&quot;Entrée wiring diagram&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;software&quot;&gt;Software&lt;/h2&gt;

&lt;p&gt;A &lt;a href=&quot;https://www.vagrantup.com/&quot;&gt;Vagrant&lt;/a&gt; virtual machine environment is provided in the ./linux-vm folder for those on non-Linux hosts or who want a pre-configured environment. Install Vagrant and VirtualBox and then setup the machine from within the ./linux-vm folder with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vagrant up&lt;/code&gt; command.&lt;/p&gt;

&lt;h3 id=&quot;linux-socketcan&quot;&gt;Linux SocketCAN&lt;/h3&gt;

&lt;p&gt;Entrée comes with &lt;em&gt;candleLight&lt;/em&gt; firmware which is intended for use with a Linux host. Most Linux distributions include the gs_usb driver and can kernel modules by default so getting started is very easy.&lt;/p&gt;

&lt;h4 id=&quot;create-can-network-interface-ref&quot;&gt;Create CAN network interface &lt;a href=&quot;https://elinux.org/Bringing_CAN_interface_up&quot;&gt;[ref]&lt;/a&gt;&lt;/h4&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo ip link set can0 type can bitrate BIT_RATE # where BIT_RATE is the CAN bus speed in b/s
sudo ip link set up can0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;cli&quot;&gt;CLI&lt;/h4&gt;

&lt;p&gt;Install &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;can-utils&lt;/code&gt; using one’s package manager and then various command line tools are available.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cansend can0 999#DEADBEEF   # Send a frame to 0x999 with payload 0xdeadbeef
candump can0                # Show all traffic received by can0
canbusload can0 500000      # Calculate bus loading percentage on can0
cansniffer can0             # Display top-style view of can traffic
cangen can0 -D 11223344DEADBEEF -L 8    # Generate fixed-data CAN messages
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;See the &lt;a href=&quot;https://github.com/linux-can/can-utils/blob/master/README.md&quot;&gt;can-utils README&lt;/a&gt; for more.&lt;/p&gt;

&lt;h4 id=&quot;cangaroo-gui&quot;&gt;Cangaroo GUI&lt;/h4&gt;

&lt;p&gt;The Cangaroo GUI can be compiled for Linux hosts. See &lt;a href=&quot;https://github.com/normaldotcom/cangaroo/&quot;&gt;Cangaroo&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;windows&quot;&gt;Windows&lt;/h3&gt;

&lt;p&gt;To use the default &lt;em&gt;candleLight&lt;/em&gt; firmware on Windows, one can use &lt;a href=&quot;https://github.com/normaldotcom/cangaroo/&quot;&gt;Cangaroo&lt;/a&gt;: &lt;a href=&quot;https://www.dropbox.com/s/dyh9gvt572v8nhn/cangaroo-win32-0363ce7.zip?dl=0&quot;&gt;Pre-compiled Win32 binary&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Alternatively, to use &lt;a href=&quot;#linux-socketcan&quot;&gt;SocketCAN&lt;/a&gt; one can use the pre-configured virtual machine explained at the start of the &lt;a href=&quot;#software&quot;&gt;Software section&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;python&quot;&gt;Python&lt;/h3&gt;

&lt;p&gt;The &lt;a href=&quot;https://python-can.readthedocs.io/en/master/#&quot;&gt;python-can&lt;/a&gt; module supports &lt;em&gt;SocketCAN&lt;/em&gt; (candleLight), &lt;em&gt;slcan&lt;/em&gt; and &lt;em&gt;PCAN&lt;/em&gt; devices so options for all hosts are covered - see the &lt;a href=&quot;https://python-can.readthedocs.io/en/master/configuration.html&quot;&gt;configuration page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Paired with the &lt;a href=&quot;https://pypi.org/project/cantools/&quot;&gt;cantools&lt;/a&gt; module, one has access to powerful CLI tools and scripting for CAN bus operations including use with database definition files.&lt;/p&gt;

&lt;p&gt;Both modules are pre-installed in the Vagrant virtual machine.&lt;/p&gt;

&lt;h2 id=&quot;dip-switches&quot;&gt;DIP Switches&lt;/h2&gt;

&lt;p&gt;The 4 bit DIP switch sets unique runtime settings when in the ‘ON’ position; for normal usage as a CAN bus probe these would be ‘OFF’.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Switch&lt;/th&gt;
      &lt;th&gt;Decimal&lt;/th&gt;
      &lt;th&gt;Set Action&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;Force bootloader for DFU.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;Enable Entrée internal configuration CAN IDs.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;3&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
      &lt;td&gt;Enable VBUS -&amp;gt; VBS always not just when USB-PD profile valid.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;4&lt;/td&gt;
      &lt;td&gt;8&lt;/td&gt;
      &lt;td&gt;Enable 120 ohm CAN_H/CAN_L termination resistor&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; both DFU and ‘Enable VBUS’ will require power cycling the device for the change to be reflected.&lt;/p&gt;

&lt;h2 id=&quot;usb-power-delivery-usb-pd&quot;&gt;USB Power Delivery (USB-PD)&lt;/h2&gt;

&lt;p&gt;The on-board USB-C controller (STUSB4500) is configured for 5 V / 1A power delivery by default (PDO 2). One can configure the controller using the below CAN bus commands when using the &lt;a href=&quot;https://github.com/tuna-f1sh/candleLight_fw&quot;&gt;&lt;strong&gt;candleLight_fw&lt;/strong&gt;&lt;/a&gt; fork and with the &lt;a href=&quot;#dip-switches&quot;&gt;internal CAN IDs switch&lt;/a&gt; set.
Please refer to the &lt;a href=&quot;https://github.com/tuna-f1sh/candleLight_fw&quot;&gt;&lt;strong&gt;candleLight_fw Entrée fork&lt;/strong&gt;&lt;/a&gt; README for usage.&lt;/p&gt;

&lt;h2 id=&quot;firmware&quot;&gt;Firmware&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/tuna-f1sh/candleLight_fw&quot;&gt;&lt;strong&gt;candleLight_fw Entrée fork&lt;/strong&gt;&lt;/a&gt; - &lt;a href=&quot;./bin/entree_fw_101.bin&quot;&gt;[BIN DOWNLOAD]&lt;/a&gt;: Default firmware shipping with Entrée. Works with &lt;a href=&quot;#linux-socketcan&quot;&gt;Linux SocketCAN&lt;/a&gt; and the &lt;a href=&quot;#cangaroo-gui&quot;&gt;Cangaroo&lt;/a&gt; GUI. Includes support for configuration of the on-board STUSB4500 USB-C controller and DFU without setting DIP switch.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/normaldotcom/cantact-fw&quot;&gt;&lt;strong&gt;cantact_slcan&lt;/strong&gt;&lt;/a&gt;: slcand is a USART CAN daemon for Linux, which emulates a CAN network socket over USART. The pre-cursor of the candleLight_fw and gs_usb driver, it offers no real advantage since it is still over USB as a CDC. I’ve found it to drop frames at common bus rates and so do not recommend it. USART pins are exposed however if one wishes to play with slcan over physical USART. A virtual network interface can be created: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo slcand -o -s8 -t hw -S 3000000 /dev/ttyS0&lt;/code&gt; and then used like a &lt;a href=&quot;#linux-socketcan&quot;&gt;SocketCAN&lt;/a&gt; interface.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;update&quot;&gt;Update&lt;/h3&gt;

&lt;h4 id=&quot;web-updater&quot;&gt;Web Updater&lt;/h4&gt;

&lt;p&gt;Use the Web-DFU tool provided here: &lt;a href=&quot;https://www.jbrengineering.co.uk/web-dfu/&quot;&gt;https://www.jbrengineering.co.uk/web-dfu/&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&quot;manual-cli&quot;&gt;Manual CLI&lt;/h4&gt;

&lt;p&gt;Enable the DFU &lt;a href=&quot;#dip-switches&quot;&gt;DIP switch&lt;/a&gt; and then issue the following command with &lt;a href=&quot;http://dfu-util.sourceforge.net/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dfu-util&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo dfu-util -d 0483:df11 -c 1 -i 0 -a 0 -s 0x08000000 -D $FIRMWARE_FILE.bin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$FIRMWARE_FILE.bin&lt;/code&gt; is the firmware file to be updated. Binaires are stored in the ‘./bin’ folder of this repository, so to flash:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo dfu-util -d 0483:df11 -c 1 -i 0 -a 0 -s 0x08000000 -D ./bin/entree_fw.bin # candleLight_fw
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;credits&quot;&gt;Credits&lt;/h1&gt;

&lt;p&gt;The open source CAN community is large and this project adds to that in the true spirit of open source. The &lt;a href=&quot;canable.io&quot;&gt;canable&lt;/a&gt; devices (of which I have many!) started me on my journey into CAN hardware and software development. Entrée fixes areas I felt could be improved upon and brought up-to date.&lt;/p&gt;

&lt;p&gt;Please find links below to projects that have supported the development of the open source CAN ecosystem.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://canable.io&quot;&gt;canable.io&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://wiki.linklayer.com/index.php/CANtact&quot;&gt;CANtact&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/HubertD/candleLight&quot;&gt;candleLight&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/candle-usb/candleLight_fw&quot;&gt;candleLight_fw&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/linux-can/can-utils&quot;&gt;SocketCAN user space utilities&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/torvalds/linux/blob/master/drivers/net/can/slcan.c&quot;&gt;Linux slcan module&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/torvalds/linux/blob/master/drivers/net/can/usb/gs_usb.c&quot;&gt;Linux gs_usb module&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://python-can.readthedocs.io/en/master/&quot;&gt;python-can Python module&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Should get you started down the rabbit hole!&lt;/p&gt;
</description>
        <pubDate>Tue, 16 Mar 2021 00:00:00 +0000</pubDate>
      </item>
    
      <item>
        <title>Game of Life on a Flip-Dot Display</title>
        <link>/2020/04/game-of-life-on-a-flip-dot-display/</link>
        <guid isPermaLink="true">/2020/04/game-of-life-on-a-flip-dot-display/</guid>
        <description>&lt;p&gt;With the passing of John Conway, I decided to add ‘Game of Life’ to a Flip-Dot project I’m working on, in honour of his work.&lt;/p&gt;

&lt;p&gt;I show a couple of random starts, a start from text ‘Hello!’ and a start with some known forms.&lt;/p&gt;

&lt;div class=&quot;box&quot;&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/FjQ4jZS2f9M&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;Physical display is an Alfa-Zeta XY5 28×14. I’m building it into a much larger display (252×56) so I develop with a curses based simulator most of the time. I show Game of Life running in this at the end, the larger area allows for some known persistent patterns at start.&lt;/p&gt;

&lt;p&gt;Uses Python PIL based driver: &lt;a href=&quot;https://github.com/tuna-f1sh/flipdot&quot;&gt;https://github.com/tuna-f1sh/flipdot&lt;/a&gt;&lt;br /&gt;
With custom async display manager, Game of Life functions: &lt;a href=&quot;https://gist.github.com/tuna-f1sh/9e6ff4552f75de3705cae6d3c044b1cc&quot;&gt;https://gist.github.com/tuna-f1sh/9e6ff4552f75de3705cae6d3c044b1cc&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Tue, 28 Apr 2020 11:41:59 +0000</pubDate>
      </item>
    
      <item>
        <title>Pi-Hole and Smokeping using Same lighttpd Service</title>
        <link>/2019/12/pi-hole-and-smokeping-using-same-lighttpd-service/</link>
        <guid isPermaLink="true">/2019/12/pi-hole-and-smokeping-using-same-lighttpd-service/</guid>
        <description>&lt;p&gt;I was having random – or not so random – internet dropouts on a 4G WiFi router. I wanted to ascertain when they occur and if it’s internal wireless or WAN to troubleshoot. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smokeping&lt;/code&gt; is an old but useful tool to capture this as it sits in the background constantly pinging pre-defined servers.&lt;/p&gt;

&lt;p&gt;Since I had a Pi-Hole on the network, this seemed the best tool. Getting the web-portal up and running requires some tinkering however to run as part of the existing Pi-Hole lighttpd web server.&lt;/p&gt;

&lt;p&gt;Turns out the correlation is with trains and rush hour! I live near a train station and as a train comes to the station at peak times, the contention ratio on the 4G mast must go through the roof and my internet crawls…Either that or the electric train lines are EMC bandits!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Warning: Steps below worked on PiHole 4.0 and were captured post-process for my own documentation; it is not a concrete guide and some system knowledge is probably required&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;install-smokeping&quot;&gt;Install Smokeping&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;smokeping
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;smokeping-setup-with-pihole-lighttpd&quot;&gt;Smokeping Setup With Pihole Lighttpd&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# enable cgi&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /usr/share/smokeping/www /var/www/html/smokeping
&lt;span class=&quot;nb&quot;&gt;sudo cp&lt;/span&gt; /var/www/html/smokeping/smokeping.fcgi.dist /var/www/html/smokeping/smokeping.fcgi
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;exec /usr/lib/cgi-bin/smokeping.cgi /etc/smokeping/config&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /var/www/html/smokeping/smokeping.fcgi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;setup-fast-cgi-etclighttpdconf-available10-fastcgiconf&quot;&gt;Setup Fast cgi /etc/lighttpd/conf-available/10-fastcgi.conf&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;fastcgi.server +&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;smokeping.fcgi&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;socket&quot;&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/var/run/lighttpd/fcgi.socket&quot;&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;bin-path&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/usr/share/smokeping/www/smokeping.fcgi&quot;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;lighttpd-enable-mod fastcgi
&lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; /etc/init.d/lighttpd force-reload
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;check-route&quot;&gt;Check Route&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://localhost/smokeping/smokeping.fcgi&quot;&gt;http://localhost/smokeping/smokeping.fcgi&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;redirect-smokeping-route-to-fast-cgi-file&quot;&gt;Redirect Smokeping Route to Fast cgi File&lt;/h2&gt;

&lt;p&gt;In &lt;em&gt;/etc/lighttpd/lighttpd.conf&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$HTTP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~ &lt;span class=&quot;s2&quot;&gt;&quot;^/smokeping/&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
         url.redirect  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^/smokeping/?$&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/smokeping/smokeping.fcgi&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now one can simply navigate to &lt;a href=&quot;pihole.local/smokeping&quot;&gt;pihole.local/smokeping&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 09 Dec 2019 17:10:03 +0000</pubDate>
      </item>
    
      <item>
        <title>Whitterm-220 2.0</title>
        <link>/2019/06/whitterm-220-2-0/</link>
        <guid isPermaLink="true">/2019/06/whitterm-220-2-0/</guid>
        <description>&lt;p&gt;Having used my clever serial terminal – &lt;a href=&quot;/2016/06/whitterm-220-clever-serial-terminal/&quot;&gt;the WT-220&lt;/a&gt; – for a few years now, I’d identified improvements I wanted to make. I was never that pleased with the cobbled together electronics (based on what I had laying around and ability at the time) and with PCB fabrication accessible to hobbyists now thanks to China, I decided the main win would be a Raspberry Pi Hat.&lt;/p&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/wazZxE-fdEo&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;The rear panel wiring made opening the thing up a dread, so this was the main item I wanted to fix. Thinking about how to simplify the connection between the Hat and the RPi, I came around to the idea of ditching the acrylic rear panel entirely in favour of PCB mount upright connectors – the PCB would be electronically and mechanically part of the design.&lt;/p&gt;

&lt;p&gt;As with all good hobby projects, I got quite carried away with adding bells and whistles but the rear panel functionality and resulting WT-220 has been greatly improved overall. It was a nice slow burner project to fill time gaps moving to Switzerland at the start of the year. I enjoy these sorts of projects, cementing knowledge I’ve developed in professional work and exploring ideas one doesn’t always have time for.&lt;/p&gt;

&lt;h1 id=&quot;wt-220-rear-panel-io-hat&quot;&gt;WT-220 Rear Panel IO Hat&lt;/h1&gt;

&lt;div id=&quot;gallery-32&quot; class=&quot;gallery galleryid-1317 gallery-columns-2 gallery-size-large&quot;&gt;
  &lt;figure class=&quot;gallery-item&quot;&gt; 
  
  &lt;div class=&quot;gallery-icon landscape&quot;&gt;
    &lt;a href=&quot;/assets/img/uploads/2019/06/Screenshot-2019-06-30-at-15.29.08.png&quot;&gt;&lt;img src=&quot;/assets/img/uploads/2019/06/Screenshot-2019-06-30-at-15.29.08.png&quot; class=&quot;attachment-large size-large&quot; alt=&quot;WT-220 PCB Front&quot; loading=&quot;lazy&quot; aria-describedby=&quot;gallery-32-1322&quot; srcset=&quot;/assets/img/uploads/2019/06/Screenshot-2019-06-30-at-15.29.08.png 894w, /assets/img/uploads/2019/06/Screenshot-2019-06-30-at-15.29.08-300x187.png 300w, /assets/img/uploads/2019/06/Screenshot-2019-06-30-at-15.29.08-768x478.png 768w&quot; sizes=&quot;(max-width: 580px) 100vw, 580px&quot; /&gt;&lt;/a&gt;
  &lt;/div&gt;&lt;figcaption class=&quot;wp-caption-text gallery-caption&quot; id=&quot;gallery-32-1322&quot;&gt; The hole is for a panel mount USB. &lt;/figcaption&gt;&lt;/figure&gt;&lt;figure class=&quot;gallery-item&quot;&gt; 
  
  &lt;div class=&quot;gallery-icon landscape&quot;&gt;
    &lt;a href=&quot;/assets/img/uploads/2019/06/Screenshot-2019-06-30-at-15.29.36.png&quot;&gt;&lt;img src=&quot;/assets/img/uploads/2019/06/Screenshot-2019-06-30-at-15.29.36.png&quot; class=&quot;attachment-large size-large&quot; alt=&quot;WT-220 PCB Rear&quot; loading=&quot;lazy&quot; srcset=&quot;/assets/img/uploads/2019/06/Screenshot-2019-06-30-at-15.29.36.png 991w, /assets/img/uploads/2019/06/Screenshot-2019-06-30-at-15.29.36-300x183.png 300w, /assets/img/uploads/2019/06/Screenshot-2019-06-30-at-15.29.36-768x468.png 768w&quot; sizes=&quot;(max-width: 580px) 100vw, 580px&quot; /&gt;&lt;/a&gt;
  &lt;/div&gt;&lt;/figure&gt;&lt;figure class=&quot;gallery-item&quot;&gt; 
  
  &lt;div class=&quot;gallery-icon landscape&quot;&gt;
    &lt;a href=&quot;/assets/img/uploads/2019/06/DSC_0050.jpg&quot;&gt;&lt;img src=&quot;/assets/img/uploads/2019/06/DSC_0050-1024x683.jpg&quot; class=&quot;attachment-large size-large&quot; alt=&quot;&quot; loading=&quot;lazy&quot; aria-describedby=&quot;gallery-32-1328&quot; srcset=&quot;/assets/img/uploads/2019/06/DSC_0050-1024x683.jpg 1024w, /assets/img/uploads/2019/06/DSC_0050-300x200.jpg 300w, /assets/img/uploads/2019/06/DSC_0050-768x512.jpg 768w&quot; /&gt;&lt;/a&gt;
  &lt;/div&gt;&lt;figcaption class=&quot;wp-caption-text gallery-caption&quot; id=&quot;gallery-32-1328&quot;&gt; The (hand) populated rear panel. &lt;/figcaption&gt;&lt;/figure&gt;&lt;figure class=&quot;gallery-item&quot;&gt; 
  
  &lt;div class=&quot;gallery-icon landscape&quot;&gt;
    &lt;a href=&quot;/assets/img/uploads/2019/06/DSC_0036.jpg&quot;&gt;&lt;img src=&quot;/assets/img/uploads/2019/06/DSC_0036-1024x683.jpg&quot; class=&quot;attachment-large size-large&quot; alt=&quot;&quot; loading=&quot;lazy&quot; aria-describedby=&quot;gallery-32-1327&quot; srcset=&quot;/assets/img/uploads/2019/06/DSC_0036-1024x683.jpg 1024w, /assets/img/uploads/2019/06/DSC_0036-300x200.jpg 300w, /assets/img/uploads/2019/06/DSC_0036-768x512.jpg 768w&quot; /&gt;&lt;/a&gt;
  &lt;/div&gt;&lt;figcaption class=&quot;wp-caption-text gallery-caption&quot; id=&quot;gallery-32-1327&quot;&gt; 40-pin IDC cable to Raspberry Pi is a much nicer solution than before. &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;

&lt;h2 id=&quot;features&quot;&gt;Features&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;USB-C input for USB-PD high current (3 A) supply to RPi. LEDs indicate detected current profile from UFP. I2C lines made available to SAMD for playing with USB-C device modes.&lt;/li&gt;
  &lt;li&gt;MAX3232 RS232 transceiver provides RS232 level interface to RPi UART and SAMD UART.&lt;/li&gt;
  &lt;li&gt;SAMD21 microcontroller provides boot button control of RPi over I2C and buffered IO (2 0-10 V inputs, 2 OC outputs, 2 24 V inputs and 1 0-5 V output). Can be programmed over USB-C CDC-serial device or ISP.&lt;/li&gt;
  &lt;li&gt;Control of RPi power supply from SAMD. Off by default allows safe start up, only when power input suitable/ready.&lt;/li&gt;
  &lt;li&gt;DIP switch control of device UART connections (SAMD, RPi, RS232).&lt;/li&gt;
  &lt;li&gt;Board replaces laser cut acrylic back piece from original design – it is both electronically and mechanically integrated.&lt;/li&gt;
  &lt;li&gt;Lots of status LEDs 😃.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;usb-c&quot;&gt;USB-C&lt;/h2&gt;

&lt;p&gt;The original WT-220 with DC jack input going to buck-converter for 5 V wasn’t ideal. It was always frustrating attempting to find the right jack, the jack coming loose or if using Micro B USB, finding an adaptor to supply the &amp;gt; 2.5 A required by a RPi 3 B+ &amp;amp; screen – the worse thing was that if the supply was flaker, it might power up then brown out during use.&lt;/p&gt;

&lt;p&gt;I had been wanting to implement a USB-C board in order to understand the interface, so this became the project. The great thing about USB-C is that the upstream device can provide information on the power available to the downstream device. By configuring the CC lines, one can set or detect what current is available and act on this. I opted to use a controller – the TUSB320 – to handle this, with LED indication of current mode detected.&lt;/p&gt;

&lt;figure id=&quot;attachment_1325&quot; aria-describedby=&quot;caption-attachment-1325&quot; class=&quot;wp-caption aligncenter&quot;&gt;&lt;img loading=&quot;lazy&quot; class=&quot;wp-image-1325 size-full&quot; src=&quot;/assets/img/uploads/2019/06/usb-c-wt-220.jpg&quot; alt=&quot;&quot; srcset=&quot;/assets/img/uploads/2019/06/usb-c-wt-220.jpg&quot; /&gt;&lt;figcaption id=&quot;caption-attachment-1325&quot; class=&quot;wp-caption-text&quot;&gt;Using the GPIO mode of the TUSB320 and LEDs, one can visually show the USB-C current mode. Here both LEDs indicate full 5 V/3 A. This could be read over I2C and the boot button restricted if power to low.&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;With the SAMD controlling the power supply to the Pi via a MOSFET swtich and I2C connection to the TUSB320, one can prevent boot up of the Pi until a suitable upstream supply is detected. For something like the WT-220, the LED indication is enough as I’m the only one using it. For a user consumer product however, this is great as it removes the ability to plug in any old phone charger and then the device appearing to not work properly.&lt;/p&gt;

&lt;p&gt;Turns out I wasn’t the only one thinking down this path. Since developing this board and in the process of writing this post, the &lt;a href=&quot;https://www.raspberrypi.org/blog/raspberry-pi-4-on-sale-now-from-35/&quot;&gt;Raspberry Pi 4&lt;/a&gt; has been released with a USB-C port replacing the Micro B. I’m not sure if the new Pi uses current mode detection to prevent start up like suggested above but it would be logical.&lt;/p&gt;

&lt;h1 id=&quot;firmware&quot;&gt;Firmware&lt;/h1&gt;

&lt;p&gt;The SAMD firmware is pretty simple. As said, it controls the power to the Pi and then an I2C communication between the SAMD and Pi allows LED boot status and shutdown/power off control. See below for a basic (messy) state diagram.&lt;/p&gt;

&lt;figure id=&quot;attachment_1320&quot; aria-describedby=&quot;caption-attachment-1320&quot; class=&quot;wp-caption aligncenter&quot;&gt;&lt;img loading=&quot;lazy&quot; class=&quot;size-full wp-image-1320&quot; src=&quot;/assets/img/uploads/2019/06/state-mermaid.png&quot; alt=&quot;state-mermaid&quot; srcset=&quot;/assets/img/uploads/2019/06/state-mermaid.png 871w, /assets/img/uploads/2019/06/state-mermaid-300x175.png 300w, /assets/img/uploads/2019/06/state-mermaid-768x448.png 768w&quot; sizes=&quot;(max-width: 871px) 100vw, 871px&quot; /&gt;&lt;figcaption id=&quot;caption-attachment-1320&quot; class=&quot;wp-caption-text&quot;&gt;Raspberry Pi maintains I2C link with uC once booted and acts on shutdown request from button press. The LED flashing routines were the most complex part of the firmware development!&lt;/figcaption&gt;&lt;/figure&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/3TyF5GWTZb8&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;The other thing the firmware does is provide interface to the buffered IO.&lt;/p&gt;

&lt;h1 id=&quot;raspberry-pi&quot;&gt;Raspberry Pi&lt;/h1&gt;

&lt;p&gt;I opted for Raspbian Lite rather than Arch for this updated build. The support for ARM 64 bit is better and the Lite variant still means I could install only what I wanted.&lt;/p&gt;

&lt;p&gt;For the install, I used I3WM since it’s a keyboard based terminal. I then compiled and installed &lt;a href=&quot;https://github.com/Swordfish90/cool-retro-term&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cool-retro-term&lt;/code&gt;&lt;/a&gt; for the CRT look.&lt;/p&gt;

&lt;p&gt;The rest of the image is fairly standard, bar a few services I created and config scripts (all can be found in &lt;a href=&quot;https://github.com/tuna-f1sh/whitterm-wt220&quot;&gt;repo&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;boot: Runs shell script that displays boot ascii logo.&lt;/li&gt;
  &lt;li&gt;i2c: Runs python I2C script (wt220-i2c.py) that configures case LEDs to act on RX/TX and then maintains link with I2C link with SAMD. Polls shutdown request state and acts on request by issuing system shutdown.&lt;/li&gt;
  &lt;li&gt;poweroff: Runs on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shutdown.target&lt;/code&gt; and issues the final I2C shutdown command so that SAMD disables RPi 5 V.&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Sun, 30 Jun 2019 15:54:08 +0000</pubDate>
      </item>
    
      <item>
        <title>Wooden Bits Binary Clock FPGA Port</title>
        <link>/2018/12/wooden-bits-binary-clock-fpga-port/</link>
        <guid isPermaLink="true">/2018/12/wooden-bits-binary-clock-fpga-port/</guid>
        <description>&lt;p&gt;In attempt to get started with FPGAs and Verilog, I decided to port &lt;a href=&quot;https://github.com/tuna-f1sh/wooden-bits&quot;&gt;Wooden Bits&lt;/a&gt; to a &lt;em&gt;Lattice IceStick&lt;/em&gt; – selected because of the Open-Source &lt;a href=&quot;http://www.clifford.at/icestorm/&quot;&gt;IceStorm toolchain&lt;/a&gt;. Counters and flip-flops are the first thing one learns when starting with FPGA design, so the project lends itself naturally. I learnt things FPGAs are good at and things they are not so good at – best done on a microcontroller. As the project was educational, there were many learnings along the way and invariably still to be learnt; it is not intended as a best use of FPGAs or implementation.&lt;/p&gt;

&lt;p&gt;The most enlightening part of the learning and what finally kicked me to do the project, was the &lt;a href=&quot;https://github.com/cliffordwolf/picorv32/tree/master/picosoc&quot;&gt;PicoSOC&lt;/a&gt; project and in particular, Matt Venn’s addition of a &lt;a href=&quot;https://www.youtube.com/watch?v=us2F8wAncw8&amp;amp;t=841s&quot;&gt;WS2812 peripheral to the PicoSOC&lt;/a&gt;. The idea of rolling one’s own peripheral for driving external hardware into a SoC or only adding the required ones is new ground for me. The concept also really helps to cement what is actually going on when accessing registers during development of embedded software.&lt;/p&gt;

&lt;h2 id=&quot;binary-clock-counter-design&quot;&gt;Binary Clock Counter Design&lt;/h2&gt;

&lt;p&gt;A binary clock is essentially a frequency divider, which can be formed using D-Type Flip-Flops, each data line clocking the next. In order to reset the 4 bit counter at 9 (or the other digits for time), a modulo 9 counter is created by using an AND gate driving reset with bits 1 &amp;amp; 3 (as it clocks 10). This is assuming the D-Type is asynchronous (will reset on reset edge). If it were synchronous, the AND gate must be connected to bits 0 &amp;amp; 3 (9), such that the reset will be clocked as it would be counting 10. The difference becomes quite important in Verilog, particularly when driving the next digit modules with the reset signal.&lt;/p&gt;

&lt;figure class=&quot;wp-block-image&quot;&gt;
&lt;img loading=&quot;lazy&quot; src=&quot;/assets/img/uploads/2018/12/Screenshot-2018-12-17-at-17.30.22-880x1024.png&quot; width=&quot;600&quot; alt=&quot;&quot; class=&quot;wp-image-1249&quot; srcset=&quot;/assets/img/uploads/2018/12/Screenshot-2018-12-17-at-17.30.22-880x1024.png 880w, /assets/img/uploads/2018/12/Screenshot-2018-12-17-at-17.30.22-258x300.png 258w, /assets/img/uploads/2018/12/Screenshot-2018-12-17-at-17.30.22-768x894.png 768w, /assets/img/uploads/2018/12/Screenshot-2018-12-17-at-17.30.22.png 1366w&quot; /&gt; &lt;figcaption&gt;24 hour ninary coded decimal (BDC) clock design. LSB/digit on left. A binary clock is first a frequency divider, which can be created by changing Flip-Flops together. A modulo counter is created by using a logic gate driving reset of synchronous D-Type Flip-Flops. The time is 00:03:38 in this screenshot.&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;It’s good to start with a logic diagram of what one is trying to achieve so I drew one up in &lt;a href=&quot;http://www.falstad.com/circuit/circuitjs.html&quot;&gt;Falstad&lt;/a&gt; (&lt;a href=&quot;https://raw.githubusercontent.com/tuna-f1sh/wooden-bits-fpga/master/falstad.txt&quot;&gt;import this file&lt;/a&gt;). To implement this, I designed a counter module for each digit that is asynchronous (reset on reset edge), so that the reset line can directly feed the next digit module. Initially, my approach was synchronous (read reset on clk edge) but this meant having to have a ‘carry’ output on reset to clock the other digits at the correct time (otherwise they would clock one digit a head of the desired value).&lt;/p&gt;

&lt;figure class=&quot;wp-block-image&quot;&gt;
    &lt;img loading=&quot;lazy&quot; src=&quot;/assets/img/uploads/2018/12/Screenshot-2018-12-21-at-08.34.42-1-1024x298.png&quot; alt=&quot;&quot; class=&quot;wp-image-1271&quot; srcset=&quot;/assets/img/uploads/2018/12/Screenshot-2018-12-21-at-08.34.42-1-1024x298.png 1024w, /assets/img/uploads/2018/12/Screenshot-2018-12-21-at-08.34.42-1-300x87.png 300w, /assets/img/uploads/2018/12/Screenshot-2018-12-21-at-08.34.42-1-768x224.png 768w, /assets/img/uploads/2018/12/Screenshot-2018-12-21-at-08.34.42-1.png 1139w&quot; /&gt;
    &lt;figcaption&gt;Test bench timing diagram for synchronous reset digit module. The reset wire turns the counter into a modulo BCD module. Since the design is synchronous, the reset signal cannot be seen &amp;#8211; unlike the asynchronous plot below, where it lasts for one clock cycle. The wire will instantaneously (in theory but not in physics&amp;#8230;) reset one digit (causing it to clear) whilst driving the next, since it is hardware logic. This is one of the key differences between microcontroller variables and FGPA design.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure class=&quot;wp-block-image&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;/assets/img/uploads/2018/12/Screenshot-2018-12-21-at-08.31.57.png&quot; alt=&quot;&quot; class=&quot;wp-image-1263&quot; srcset=&quot;/assets/img/uploads/2018/12/Screenshot-2018-12-21-at-08.31.57.png 1146w, /assets/img/uploads/2018/12/Screenshot-2018-12-21-at-08.31.57-300x90.png 300w, /assets/img/uploads/2018/12/Screenshot-2018-12-21-at-08.31.57-768x231.png 768w, /assets/img/uploads/2018/12/Screenshot-2018-12-21-at-08.31.57-1024x307.png 1024w&quot; /&gt;
&lt;figcaption&gt;The asynchronous Flip-Flop design results in the proceeding digit being one clock out of phase. I did originally remedy this by including a _modulo_ output bit, that asserted as the reset signal was clocked. It is the equivalent of adding an additional Flip-Flop to latch the reset in the simulation as a clock source for the next module.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Interestingly, one could use a single counter register rather than individual modules. I &lt;a href=&quot;https://github.com/tuna-f1sh/wooden-bits-fpga/blob/master/binary_clock.v&quot;&gt;developed an alternative&lt;/a&gt; based on this idea, using bit logic to clear/increment bit addresses. The advantage is that it only uses 13 bits rather than 16 bits. Other than this, the modular system synthesis should resolve down to the same thing (something that looks like the Falstad simulation), since the reset inputs driving each module are just &lt;em&gt;wire&lt;/em&gt; bit logic as in the massive &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if, else&lt;/code&gt;. I think having modules for each digit helps with readability and helped with learning the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;module&lt;/code&gt; aspect of Verilog.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BITS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;digit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;parameter&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BITS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BITS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;digit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;always&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;posedge&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clk&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;posedge&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;digit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;digit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;digit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;endmodule&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/* seconds (4 and 3 bits but leave all) */&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;wire&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ds0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;wire&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rst_ds0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ds0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ds0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 10&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;s0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clock_clk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rst_ds0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ds0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;wire&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ds1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;wire&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rst_ds1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ds1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ds1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 6(0) minutes&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;s1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rst_ds0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rst_ds1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ds1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/* minutes (4 and 3 bits but leave all) */&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;wire&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dm0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;wire&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rst_dm0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dm0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dm0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 10&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;m0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rst_ds1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rst_dm0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dm0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;wire&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dm1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;wire&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rst_dm1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dm1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dm1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 6(0) minutes&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;m1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rst_dm0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rst_dm1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;dm1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/* hours (4 and 2 bits but leave all) */&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;wire&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dh0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;wire&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rst_dh0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dh0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dh0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rst_dh1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 10 or tens of hour reset&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;h0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rst_dm1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rst_dh0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dh0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;wire&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dh1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;wire&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rst_dh1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dh1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dh0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 2(0) &amp;amp; 4 hours&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rst_dh0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rst_dh1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dh1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p class=&quot;has-text-color has-background has-small-font-size has-very-light-gray-color has-very-dark-gray-background-color&quot;&gt;
  &lt;em&gt;The Falstad simulation realised in Verilog as a per digit synchronous reset module.&lt;/em&gt;
&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;binary_clock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// count enable &lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// two digit bcd counter&lt;/span&gt;

   &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;wire&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;wire&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;wire&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;wire&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

   &lt;span class=&quot;n&quot;&gt;always&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;posedge&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clk&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;posedge&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 9&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 5&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 9&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 2 &amp;amp; last 3&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
           &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
           &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;endmodule&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p class=&quot;has-text-color has-background has-small-font-size has-very-light-gray-color has-very-dark-gray-background-color&quot;&gt;
  &lt;em&gt;Alternatively, one module to do all digits but with 13 bits rather than 16 bits.&lt;/em&gt;
&lt;/p&gt;

&lt;figure class=&quot;wp-block-image&quot;&gt;
&lt;img loading=&quot;lazy&quot; src=&quot;/assets/img/uploads/2018/12/Screenshot-2018-12-21-at-08.36.24.png&quot; alt=&quot;&quot; class=&quot;wp-image-1265&quot; srcset=&quot;/assets/img/uploads/2018/12/Screenshot-2018-12-21-at-08.36.24.png 1144w, /assets/img/uploads/2018/12/Screenshot-2018-12-21-at-08.36.24-300x184.png 300w, /assets/img/uploads/2018/12/Screenshot-2018-12-21-at-08.36.24-768x472.png 768w, /assets/img/uploads/2018/12/Screenshot-2018-12-21-at-08.36.24-1024x629.png 1024w&quot; sizes=&quot;(max-width: 1144px) 100vw, 1144px&quot; /&gt; &lt;figcaption&gt;Binary clock timing diagram over almost 24 hours. The LED matrix wire contains the bits arranged to match how the clock display is wired. They are not in digit order but the half frequency of each bit is quite visible.&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;For development, the clock input to the first Flip-Flop is taken from a divided down master clock (12 MHz) to form a 1 Hz clock. For actual deployment on the bench, I added an additional clock input pin for driving from an external 1 Hz clock generator such as can be found on RTCs.&lt;/p&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;blockquote class=&quot;imgur-embed-pub&quot; lang=&quot;en&quot; data-id=&quot;2Pgq28N&quot;&gt;&lt;a href=&quot;//imgur.com/2Pgq28N&quot;&gt;Wooden Bits FPGA Port Button&lt;/a&gt;&lt;/blockquote&gt;&lt;script async=&quot;&quot; src=&quot;//s.imgur.com/min/embed.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;/div&gt;

&lt;h2 id=&quot;ws2812-led-matrix&quot;&gt;WS2812 LED Matrix&lt;/h2&gt;

&lt;p&gt;My original design uses sixteen one-wire WS2812 LEDs chained through the laser-cut wood to form an addressable LED matrix. WS2812 LEDs simplify wiring and hardware complexity over standard LEDs, at the cost of CPU cycles: The one-wire interface sends 24 bit colour data for each LED by modulating the period of high/low in a serial data stream. Each LED takes the first 24 bits,then sends forwards the rest of the data to the next in line. Since microcontrollers don’t have a peripheral specifically designed to do this, it is normally done using Timers and match/overflow interrupt routines.&lt;/p&gt;

&lt;p&gt;An FPGA can make light work of this however and my real interest peaked with the idea that one can make a WS2812 &lt;em&gt;peripheral&lt;/em&gt; with no processor overhead.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// map bits to matrix in snakes and ladder formation...&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;led_matrix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;dh1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dh0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dm1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dm0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;dm0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dm1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dh0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dh1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;dh1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dh0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dm1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dm0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;dm0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dm1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dh0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dh1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]};&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NUM_LEDS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;led_rgb_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;led_matrix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rainbow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;display_rgb&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h00_00_00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The binary clock face only needs to set LEDs on or off. I created &lt;a href=&quot;https://github.com/tuna-f1sh/ws2812-core&quot;&gt;a fork&lt;/a&gt; of Matt Venn’s WS2812 module that can access the LED colour register directly so that the code then does a mask operation using the digit registers on each update of the digits (1 Hz in standard operation). The main real overhead driving the LEDs is the size of the colour register that is 24 * N bits, where N is the number of LEDs. The FPGA must latch this data, as it can change at different clock edges. I experimented with various different modifications to the code, each with it’s merits but settled on the direct setting of the RGB register for this project.&lt;/p&gt;

&lt;h2 id=&quot;clock-features&quot;&gt;Clock Features&lt;/h2&gt;

&lt;h3 id=&quot;set-button&quot;&gt;Set Button&lt;/h3&gt;

&lt;p&gt;The set button was easy to port: I added an input to the top module connected to an IO pin and a button with hardware pull-up and debounce – hardware is a key point here, I did both on the uC previously. If the button is pressed, the clock source to the first counter flip-flop changes to one that is running at 1000 Hz (using a counter based divider) and the display colour changes red. Releasing the button returns the clock to the normal state. This allows a user to quickly advance the clock to the correct time.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/* binary clock source is either clk_1 (external 1 Hz) or clk_2 (1 kHz) if button is pressed */&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;wire&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock_clk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CLK_1HZ&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clk_2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BTN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Whilst it was an easy port, the user interaction is much less refined compared to the software version. My software design features a delay before advancing at accelerated time so one can button press through minutes when near the correct time, or hold the button to advance quickly. It will also wait in set mode for a few seconds on release before setting the new time. Additionally, the set button can be used to set the main display colour.&lt;/p&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;blockquote class=&quot;imgur-embed-pub&quot; lang=&quot;en&quot; data-id=&quot;bRNOXdM&quot;&gt;&lt;a href=&quot;//imgur.com/bRNOXdM&quot;&gt;Wooden Bits FPGA Port Button&lt;/a&gt;&lt;/blockquote&gt;&lt;script async=&quot;&quot; src=&quot;//s.imgur.com/min/embed.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;/div&gt;

&lt;p&gt;These advanced interaction would all be possible on the FPGA but the design would become somewhat messy and it would need to be carefully implemented as to avoid FPGA bad practices (there are some big pitfalls I have found!). My take away was that these kind of user interaction features are better done in software – there is minimal overhead compared to driving the LEDs and it is very quick to implement.&lt;/p&gt;

&lt;h3 id=&quot;rainbow-colour-cycle&quot;&gt;Rainbow Colour Cycle&lt;/h3&gt;

&lt;p&gt;My original clock also fills the display with a rainbow colour routine at midday and midnight. Implementing this on the &lt;em&gt;IceStick&lt;/em&gt; became quite challenging as I quickly overran the 1280 LUTs (basically combinational logic). I think this was due to setting a RGB colour for each LED in the colour register, where as before it was just an option between two colours based on whether a bit was high or low. Without the rainbow effect, the sythesis was a simple logic mask but with the addition of full 24 bit colour at run time, it would require much more complicated logic. In addition, the routine works using a pseudo colour wheel that also adds complexity to the logic synthesis, due to three &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;&lt;/code&gt; switches.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colour_wheel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wheel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;85&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;red&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wheel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;green&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;blue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wheel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wheel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;170&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;red&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;green&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wheel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;85&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;blue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wheel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;85&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;red&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wheel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;170&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;green&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wheel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;170&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;blue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;endtask&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Encountering these sorts of problems are useful when learning a new topic.Whilst the base project itself is quite simple, adding in these sorts of features brings up challenges that require further reading. I &lt;em&gt;just&lt;/em&gt; managed to squeeze the rainbow effect, after finding areas of optimisation in logic statements and &lt;a href=&quot;https://www.doulos.com/knowhow/verilog_designers_guide/synthesizing_latches/&quot;&gt;transparent latches&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;discussion&quot;&gt;Discussion&lt;/h1&gt;

&lt;p&gt;The project grew well beyond the scope of simply getting a binary clock working on the &lt;em&gt;IceStick&lt;/em&gt; – I achieved that in less than an hour. What took time was refining how the digit module worked and really understanding how to mirror the simulation; digging into the WS2812 module to add masking and direct colour register set; developing a test bench and methods for capturing specific parts of a design and finally, the user interactions and bonus features.&lt;/p&gt;

&lt;p&gt;My take home is that an FPGA is ideal for creating a low-level driver but what one then does with that driver is generally better achieved in software. A binary counter is just as easy and low resource to implement in C and the advantage then is that the button control and advanced features that make the clock unique is much quicker, safer and flexible to incorporate. That code can then directly interface with something like the WS2812 via a FPGA peripheral in this example.&lt;/p&gt;

&lt;p&gt;I’m looking forward to trying other high data rate experiments with FPGAs such as LED matrix and HDMI driving, watch this space…&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/tuna-f1sh/wooden-bits-fpga&quot;&gt;GitHub Project&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/U5OJ7-_I_tY&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
</description>
        <pubDate>Sun, 23 Dec 2018 12:45:27 +0000</pubDate>
      </item>
    
      <item>
        <title>Samsung Frame TV Oak Tripod Stand</title>
        <link>/2018/09/frame-tv-oak-tripod/</link>
        <guid isPermaLink="true">/2018/09/frame-tv-oak-tripod/</guid>
        <description>&lt;p&gt;Being part of a generation that doesn’t watch TV…except documentaries and films…and YouTube…ah well, might as well watch it on a big screen. Got a TV, a &lt;a href=&quot;https://www.samsung.com/uk/tvs/the-frame/highlights/&quot;&gt;Samsung Frame &lt;/a&gt;– designed to look like a picture frame.&lt;/p&gt;

&lt;p&gt;It can mount flush to a wall or be mounted on an &lt;a href=&quot;https://www.samsung.com/uk/tv-accessories/studio-stand-vg-stm11b&quot;&gt;easel inspired stand&lt;/a&gt;, which Samsung sell separately for £500.  I decided to have a go at making one myself.&lt;/p&gt;

&lt;p&gt;The design is simple but required some thought and trigonometry, in order to get the TV mounted on the VESA mount just at the right position to rest on the joining platform. Photos speak for themselves.&lt;/p&gt;

&lt;p&gt;I planned to get the design CNC cut as I didn’t trust my carpentry skills. Finding someone who could cut planned Oak was difficult however (due to the work holding) and I decided plywood wouldn’t cut the mustard. Instead, I laser-cut templates of the DXF exports and traced them with them jigsaw. It turned out OK; only minor fettling and wood filler involved.&lt;/p&gt;

&lt;figure&gt;&lt;a href=&quot;/assets/img/uploads/2018/09/IMG_1627.jpg&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;/assets/img/uploads/2018/09/IMG_1627.jpg&quot; alt=&quot;&quot; data-id=&quot;1219&quot; data-link=&quot;/2018/09/frame-tv-oak-tripod/img_1627/&quot; class=&quot;wp-image-1219&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;Scribbles and sketches to calculate the trigamontry before CAD sketches.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;/assets/img/uploads/2018/09/assembly_2018-Aug-27_08-27-42PM-000_CustomizedView22792228695.png&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;/assets/img/uploads/2018/09/assembly_2018-Aug-27_08-27-42PM-000_CustomizedView22792228695.png&quot; alt=&quot;&quot; data-id=&quot;1220&quot; data-link=&quot;/2018/09/frame-tv-oak-tripod/assembly_2018-aug-27_08-27-42pm-000_customizedview22792228695/&quot; class=&quot;wp-image-1220&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;CAD render&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;/assets/img/uploads/2018/09/DSC_0178-1.jpg&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;/assets/img/uploads/2018/09/DSC_0178-1.jpg&quot; alt=&quot;&quot; data-id=&quot;1217&quot; data-link=&quot;/2018/09/frame-tv-oak-tripod/dsc_0178-2/&quot; class=&quot;wp-image-1217&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;I first created a 1/25 scale model after CAD to get an idea of stability and design proportions&lt;/figcaption&gt;&lt;/figure&gt;

&lt;figure&gt;&lt;a href=&quot;/assets/img/uploads/2018/09/DSC_0181.jpg&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;/assets/img/uploads/2018/09/DSC_0181.jpg&quot; alt=&quot;&quot; data-id=&quot;1216&quot; data-link=&quot;/2018/09/frame-tv-oak-tripod/dsc_0181/&quot; class=&quot;wp-image-1216&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;My model of the TV was critical in getting the stand to fit together first time and to validate my trigonometry &lt;/figcaption&gt;&lt;/figure&gt;

&lt;figure&gt;&lt;a href=&quot;/assets/img/uploads/2018/09/DSC_0139.jpg&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;/assets/img/uploads/2018/09/DSC_0139.jpg&quot; alt=&quot;&quot; data-id=&quot;1213&quot; data-link=&quot;/2018/09/frame-tv-oak-tripod/dsc_0139/&quot; class=&quot;wp-image-1213&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;The front legs butt into a recess, with glue and a hidden screw for added confidence (the screw wouldn&amp;#8217;t be required if my carpentry was better!). The rear is a slotted friction fit.&lt;/figcaption&gt;&lt;/figure&gt;

&lt;figure&gt;&lt;a href=&quot;/assets/img/uploads/2018/09/DSC_0134.jpg&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;/assets/img/uploads/2018/09/DSC_0134.jpg&quot; alt=&quot;&quot; data-id=&quot;1218&quot; data-link=&quot;/2018/09/frame-tv-oak-tripod/dsc_0134/&quot; class=&quot;wp-image-1218&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;The VESA mount is just plywood and is not pretty&amp;#8230;&lt;/figcaption&gt;&lt;/figure&gt;

&lt;figure&gt;&lt;a href=&quot;/assets/img/uploads/2018/09/DSC_0159.jpg&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;/assets/img/uploads/2018/09/DSC_0159.jpg&quot; alt=&quot;&quot; data-id=&quot;1214&quot; data-link=&quot;/2018/09/frame-tv-oak-tripod/dsc_0159/&quot; class=&quot;wp-image-1214&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;The oak appears to blend into the rear of the TV. Getting the VESA mount just at the right height so that the TV rests on the joint required some maths&amp;#8230;&lt;/figcaption&gt;&lt;/figure&gt;

&lt;figure class=&quot;wp-block-image&quot;&gt;
&lt;img loading=&quot;lazy&quot; src=&quot;/assets/img/uploads/2018/09/DSC_0163.jpg&quot; alt=&quot;&quot; class=&quot;wp-image-1212&quot; /&gt;&lt;figcaption&gt;The finished article!&lt;/figcaption&gt;&lt;/figure&gt;
</description>
        <pubDate>Sun, 23 Sep 2018 08:40:29 +0000</pubDate>
      </item>
    
      <item>
        <title>Is Bristol Choking &amp;#8211; Air Pollution Web App</title>
        <link>/2018/02/bristol-choking-air-pollution-web-app/</link>
        <guid isPermaLink="true">/2018/02/bristol-choking-air-pollution-web-app/</guid>
        <description>&lt;p&gt;&lt;strong&gt;UPDATE: I have not renewed the domains for this so it’s now down&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/2018/02/Screen-Shot-2018-02-04-at-10.16.06-825x510.png&quot; alt=&quot;isbristolchoking.uk screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I had some of my &lt;a href=&quot;http://www.nixiepipe.com&quot;&gt;Nixie Pipe&lt;/a&gt; displays showing air pollution data collected by the council, using a Python web scraper at an art trail and people seemed very interested and unaware of the data. I considered how good it would be to have live displays at the air monitoring sites for people to see, but decided a web app was more feasible as a weekend project and less risky!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://isbristolchoking.uk&quot;&gt;Is Bristol Choking?&lt;/a&gt; is the result. You may wonder what I mean by choking: I’ve classed an area as choking if the current 15 minute average NO2 value is greater than the annual mean legal limit set by the EU of 40 µg/m³ and as stated in the WHO guidelines. Check the website during rush hours and weekend daytime and most are choking. Have a read of the &lt;a href=&quot;http://isbristolchoking.uk/#choking?&quot;&gt;choking&lt;/a&gt; and &lt;a href=&quot;http://isbristolchoking.uk/#about&quot;&gt;about&lt;/a&gt; sections for more.&lt;/p&gt;

&lt;p&gt;I used it as a means to learn Python Flask and Python web app tech in general and hope it is clearer and easier to understand than the council site. There is an about section that should add some context to the numbers, which I feel the council site was lacking.&lt;/p&gt;

&lt;p&gt;I enjoyed the process of creating the app and learnt quite a lot. Initially, I was scraping the data in the same function call as the main landing page route, which created a short delay with no feedback for the user; it appeared as if the page was taking a while to load. Instead, I ended up using WebSockets with Flask to asynconously scrape the data from the Bristol Air Quality site so that Flask could render the template index.html with a scraping loading animation, then populate the fields via json passed from Flask to a Javascript socket event.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/tuna-f1sh/bristol-choking&quot;&gt;GitHub repository&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Sun, 04 Feb 2018 10:16:57 +0000</pubDate>
      </item>
    
      <item>
        <title>Honock &amp;#8211; Hexagon Honey Clock</title>
        <link>/2017/11/honock-hexagon-honey-clock/</link>
        <guid isPermaLink="true">/2017/11/honock-hexagon-honey-clock/</guid>
        <description>&lt;!--more--&gt;

&lt;div class=&quot;box&quot;&gt;
    &lt;blockquote class=&quot;imgur-embed-pub&quot; lang=&quot;en&quot; data-id=&quot;a/i6B7j&quot; data-context=&quot;false&quot;&gt;&lt;a href=&quot;//imgur.com/a/i6B7j&quot;&gt;&lt;/a&gt;&lt;/blockquote&gt;&lt;script async=&quot;&quot; src=&quot;//s.imgur.com/min/embed.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;/div&gt;
</description>
        <pubDate>Sat, 25 Nov 2017 11:57:58 +0000</pubDate>
      </item>
    
  </channel>
</rss>
