Anytime x Nixie

    Last year, I set out to build my own Nixie tube clock and integrate it with Anytime, my app that keeps track of local time for contacts. Anytime comprises an app and web service with an HTTP API, and I intend to make use of this to allow me to produce a physical clock which can display the time for a contact.

    In the process of building the clock, my Nixie tube supplier disappeared from the internet, so I turned instead to the Exixe control boards by dekuNukem.

    Prototype

    This post details the process of creating my custom clock, making use of off-the-shelf components where possible:

    1. Introducing the Exixe
    2. Testing the Nixie tubes
    3. Prototyping with the Raspberry Pi
    4. Selecting a microcontroller
    5. Integrating with Anytime
    6. Designing the PCB
    7. Assembling the clock
    8. Next steps

     Introducing the Exixe

    The Exixe are small, inexpensive, microcontrollers boards, each designed to host a single Nixie tube. They talk Serial Peripheral Interface Bus (SPI), and have standard 0.1" headers. Along with a Nixie tube, they constitute a replaceable, socketed component:

    Complete Exixe

    Exixe, complete with IN-12 Nixie tube

    The Exixe boards and Nixie tubes can be powered using a dedicated 5V to 170V Nixie tube power supply making the overall circuitry much simpler (and safer) for someone inexperienced like myself.

    Testing the Nixie Tubes

    It’s good practice to test the Nixie tubes before assembling the boards. This involves connecting up each pin in turn and ensuring the relevant digit lights up correctly:

    Having splayed the pins on the tubes for testing, I couldn’t resist having a bit of photographic fun:

    Invasion of the Nixie tubes

    Invasion of the Nixie Tubes

    Prototyping with the Raspberry Pi

    While I didn’t write many notes, I made pretty good progress with my previous Nixie tube controller, building a fully functional single digit solution. This used a Raspberry Pi as a controller, and cycled the four digits of a 24 hour clock on my one lonely Nixie tube:

    Previous Nixie tube clock

    Previous Nixie tube clock

    In the picture above, the Raspberry Pi is running a small Python Anytime client to drive the Display-O-Tron HAT and Nixie tube. The Anytime HTTP API serves the time zone for a given contact (e.g., ‘Europe/Vienna’) and the client implementation is expected to convert this to local time for that contact, accounting for things like daylight saving. The Raspberry Pi client takes advantage of the pytz library (which includes a comprehensive time zone database) to perform this conversion, vastly reducing the complexity of an Anytime implementation.

    With only a few small changes I was able to update the client to use the Adafruit Python GPIO library and control my newly assembled Exixe:

    Raspberry Pi prototype

    Here, I’m powering both the Nixie tube power supply and the Exixe boards using a USB Micro-B Breakout Board from Adafruit.

    Selecting a Microcontroller

    Having proven the basic electronics and approach, it was time to switch from the Raspberry Pi to a microcontroller; there’s much unneeded complexity in the Raspberry Pi and it tends not to be resilient to power failures (I’ve destroyed the SD cards of a number of Raspberry Pis in the past and a microcontroller board shouldn’t suffer from this).

    The ESP32-based boards come highly recommended for embedded WiFi projects, so I picked up a HUZZAH32 from Adafruit:

    HUZZAH32

    I had originally planned to run MicroPython on the HUZZAH32 to allow me to take advantage of the Python Anytime client, but it quickly became apparent this wasn’t going to work: MicroPython is not so much a fully-featured Python (libraries included), as a basic language port. Only some Python libraries can be used and it’s often necessary to rebuild the MicroPython distribution to add those libraries. Worse still, I was unable to get the crucial pytz library into an image.

    Instead–on the advice of a colleague–I returned to the Arduino port for the the HUZZAH32. This allowed me to take advantage of the Exixe Arduino library which, coupled with various NTP examples, allowed me to get my clock up and running very quickly.

    Integrating with Anytime

    Once it became clear that I wasn’t going to be able to run the full, comprehensive Python stack I had been depending on, it was necessary to find some more pragmatic approaches to integrating with Anytime. Especially around watching for updates and daylight saving changes.

    Hosting the full Olsen database on the HUZZAH32 is troublesome, and updating it, even more so. Instead, I decided to have the clock to establish a persistent connection to the Anytime service and request time zone offset updates for a given contact. The service already manages offsets and contacts, so would simply need to broadcast relevant changes to any listening clocks.

    So far, I’ve created a prototype which runs locally, on my Raspberry Pi. This is good enough for my clock, but I hope to integrate it more completely into the Anytime service in the future.

    Designing the PCB

    As with previous projects, after proving the circuit on the breadboard, I set about designing my own PCB. This circuit board is a little simpler than the Bluetooth keyboard I’ve been building: this time, I just want something robust and simple to bring all the parts together.

    The clock constitutes a number of components:

    • Exixe control boards x 4
    • HUZZAH32 x 1
    • Nixie power supply x 1
    • USB-Micro B breakout board x 1

    I also decided to add a power switch to allow me to power down the controller and–more importantly–the 170V of the Nixie power supply.

    For each of these, I created my own custom components in EagleCAD, allowing me to easily produce the circuit diagram and lay out the board:

    OSHPark Preview

    The layout took a number of attempts, and I discovered the incredibly helpful ripup * EagleCAD command which removes all the routes, allowing you to run the auto-router again from scratch.

    Assembling the Clock

    Upon the arrival of my circuit boards from OSHPark, I fired up the soldering iron, but soon discovered that I shouldn’t be allowed to design a PCB when tired: amongst other things, I forgot to connect up the both the 3V and 5V lines, incorrectly connected the HUZZAH32’s SPI MOSI Exixe boards' MISO, and managed to wire up the switch so the board never turns on.

    This required some creative modifications and bug fixes:

    Bug Fixes

    Somewhere along the way, I discovered what it was like to receive a 170V shock, but eventually managed to produce a working clock:

    Assembled PCB

    Next Steps

    I plan to live with the design for a little while, check that the circuit board (with modifications) works well, and gradually improve the firmware to make initial setup and configuration easier, perhaps with some richer integration with the Anytime web service.

    After that, it’ll be time to order v1.1 of the PCB (something a little smaller, and lacking the troublesome power switch), and design and build a case. I’m currently leaning towards a machined block of walnut.

    I’ve had the pleasure of bouncing ideas off Michael (most recently of Electric Flapjack) throughout this project and there’s one key idea I’ve yet to incorporate: using NFC tokens representing contacts as a way to change the time. I’m considering making it a separate piece of hardware, allowing me to place the controller and display separately.

    Bear Hugs

    Early in our relationship, when Junko and I were still living apart, Skype let us to keep in touch, and emoji–while not nearly as visually rich as what we have today–provided a fantastic way to express our emotions.

    These characters, Bear Hug, Kiss, Flower, and Blush, will always have a special place in my heart for all the love they have allowed us to share.

    Vision of the Future

    Over twenty years ago Philips Design published a collection of concepts they called called ‘Vision of the Future’. It was intended to, ‘explore ideas for products and services which could be part of our future in the year 2005’.

    Vision of the Future Poster

    I personally encountered this collection of designs at a BBC Tomorrow’s World event in 1996. Since then, I’ve been slowly checking off the different products as they become available: we might now be twelve years past the target year, but it remains truly amazing how prescient this work is and how many of the products now exist.

    Perhaps the one thing they didn’t anticipate was the wide reaching impact of today’s smartphones and tablets; these all-purpose devices serve many of the functions of those envisaged by Philips.

    Download Poster

    Keyboard Electronics

    Part two in an on-going series describing the process of turning a Psion Series 5 keyboard into a practical, day-to-day, Bluetooth keyboard.

    Having got the basics of the keyboard working, the next challenge is to start the process of tidying up the circuit, designing a custom printed circuit board (PCB), and moving away from the prototype breadboard electronics.

    Adding a Power Switch

    Since the iPhone on-screen keyboard is only shown when no keyboard is connected, you quickly learn that it’s imperative to be able to easily power off any Bluetooth keyboard. Until now, I’d been relying on manually disconnecting the battery, but that won’t cut it long term.

    The Adafruit Feather nRF52 includes support for this, with the documentation including the following note about the enable pin:

    If you’d like to turn off the 3.3V regulator, you can do that with the EN(able) pin. Simply tie this pin to Ground and it will disable the 3V regulator. The BAT and USB pins will still be powered.

    I tested that I’d understood this correctly by simply shorting this enable pin to ground on my breadboard, and was happy to see it powered down the board but still left the battery charging. Soon after, I added a slide switch to the breadboard:

    Slide switch

    Designing the Circuit

    Autodesk EagleCAD seems to be the go-to software for PCB design and, like Fusion 360, is free for non-commercial use. It’s somewhat inscrutable, but there’s a good introduction on The Ben Heck Show, which helped me get started.

    In EagleCAD, you typically design your circuit first, using the schematic file, and then switch over to a partially generated board file where you perform layout and routing. I started my schematic, and manually drawing connections between each and every one of the pins:

    EagleCAD

    This quickly leads to a very complex schematic and, as I soon learned, is unnecessary: EagleCAD will automatically connect up wires with matching names. This allows for something much, much simpler:

    EagleCAD

    Separate parts and named connections

    As you can see, I’ve also added the slide switch, and made use of the wonderful Adafruit component library1 (adafruit.lbr) which is included in EagleCAD by default. This includes a FeatherWing component, making it extremely easy to design a board to extend the Feather nRF52.

    During the process, I learned the hard way (missing undo history, and out-of-sync board and schematic files) that it’s good to store EagleCAD files in git. I’d certainly recommend this to anyone getting started with EagleCAD.

    Laying Out the Board

    With the schematic nailed down, I went about the process of laying out the board. The board file presents a plan view of the PCB where you simply drag-and-drop components, adjust the shape of the board, place drill holes, and add silkscreen printing.

    The grid is a crucial part of this process. Unfortunately, it’s not enabled by default, so the first thing I do is turn it on, and configure it with a ‘Size’ of 25 mil2, and an ‘Alt’ of 5 mil. I’ve also found that the default board shape isn’t aligned to the grid, so the easiest thing is to simply delete this and re-draw the outline.

    Since this was my first PCB, I left routing to the auto-router and, while this gave me a few more vias than I suspect I need, I’m pretty pleased with the outcome:

    EagleCAD Board

    Ordering the Board

    I turned to OSHPark for manufacture. Ordering is just a matter of uploading the EagleCAD board file, and they generate previews immediately, helping to give me confidence in the design.

    All told, the minimum order of three boards cost me $30 for a rush job. Had I been more patient, I could have saved myself $15. They turned up a week later, ready for soldering:

    Custom PCB

    I already see a few things I’d like to improve for the next version:

    • the silkscreen component names (X2, and S2) have been auto-assigned by EagleCAD and aren’t terribly helpful
    • the orientation of the Feather headers means I need to sit the control board on the top, leading to unnecessary height
    • I forgot to add a name and version to the board

    Assembly

    Much to my surprise, placing the components on the board went surprisingly smoothly. Even my surface mount soldering worked first-time around–I’m starting to learn the benefits of a hot soldering iron, lashings of flux, and quick, deliberate action.

    Finishing Up

    The breadboard is already earmarked for another project, and I very much enjoyed stripping it down now the keyboard has found a new home:


    1. I took a passing look at the ‘con-lsta’, ‘con-lstb’, and ‘pinhead’ libraries which provide default 100 mil header components, but ultimately these were less convenient than using Adafruit’s own components. 

    2. From Wikipedia: “A thousandth of an inch is a derived unit of length in an inch-based system of units. Equal to ​1⁄1000 of an inch, it is normally referred to as a thou /ˈθaʊ/, a thousandth, or (particularly in the United States) a mil.” 

    Psion Bluetooth Keyboard

    Series 5 keyboard and Adafruit Feather

    The Psion Series 5 keyboard is aguably one of the best mobile device keyboards ever made. Heck, there’s even an Indiegogo campaign–the Gemini from Planet Computers–to bring it back in the form of an Android PDA.

    Given the dearth of high quality small bluetooth keyboards, I’ve been wondering for quite some time if it would be possible to instead use the keyboard from a broken Series 5. A few weeks ago, I purchased such a Series 5 from eBay and set about giving it a shot.

    Hardware

    Upon receipt of delivery, I set about disassembling the Series 5, extracting the keyboard, and figuring out how it connects to the mainboard:

    Cable

    As you can see, that’s a 20 way FFC (Flexible Flat Cable). What you can’t see from the photo, is that it’s actually connected to a 22 way ZIF connector. Forutnately, the Psion Series 5 Service Manual helps clear up this discrepancy:

    The Series 5 keyboard contains a total of 53 keys, organised in a conventional QWERTY arrangement. The implementation is a departure from the S3a family of products, and features a separate keyboard switch matrix assembly which slides out as the LCD screen is opened. The electrical connection between the keyboard and the main Series 5 PCB is achieved by means of a 22 way Flat Flexi Cable (only 20 ways are used for keys), fitted to a 22 way ZIF connector. The outside pins on the flexi are the grounded to allow a for a ground ring on the keyboard membrane to improve ESD protection.

    This means that, while I should use a 22 way connector, it’s sufficient to connect up only 20 of those pins. Searching Amazon, I managed to find a suitable connector, and breakout board. Fortunately–given my lack of surface mount soldering experience–these both came in large quantities:

    Ribbon Cable Breakout Boards

    For debugging purposes, I used a breadboard to connect this to the many GPIO pins of a Raspberry Pi:

    Raspberry Pi

    Protocol

    To check that the keyboard was functional (and help figure out how it works), I reassembled the internals, and James and I spent an enjoyable few hours probing the keyboard connector with a multimeter:

    Ad hoc magnification

    We identified ground (as described in the service manual), discovered some pins were consistently high, and that the others were fluttering around low:

    Pin Behaviour
    0 Ground
    1 ~ Low
    2 ~ Low
    3 ~ Low
    4 ~ Low
    5 ~ Low
    6 ~ Low
    7 ~ Low
    8 ~ Low
    9 ~ Low
    10 ~ Low
    11 ~ Low
    12 High
    13 High
    14 High
    15 ~ Low
    16 High
    17 High
    18 High
    19 High
    20 High
    21 Ground

    Having been involved in the OpenPsion project to port Linux to various Psion devices, I had been hopeful that this, coupled with the observations above, would suggest how to read the hardware. Sadly, while Tony Lindgren’s Series 5mx and Revo kernel patches are (wonderfully) still online, and the keyboard driver does indeed confirm the scanning matrix implied above, it’s too far removed from the hardware layout to be clear on the details.

    Instead, the breakthrough came when James discovered Rasmus Backman’s Psioπ project on Hackaday. In it, he details the process of building a USB adapter for the Series 5 keyboard as part of an ambitious project to build a Raspberry Pi powered Psion. It even includes the following diagram showing the layout of the keyboard matrix, and explanation of how to scan:

    Pin-out

    Reverse Engineering the Keyboard, Part I

    Scanning the keyboard:

    1. First of all, all pins are set to Inputs. This makes them high-impedance.
    2. The internal pull-up resistors are enabled on the column pins. This turns them logic HIGH.
    3. Then, one row at a time is turned to an output and driven low.
    4. Check the status on the column pins. A logic LOW signal means that column is connected to the active row because that key is pressed.
    5. When the matrix is scanned, it is compared to the last known state. Then we send ‘pressed’ scancodes for the newly pressed keys, and ‘released’ scancodes for the keys that has been released.
    6. Repeat from step 3.

    Reverse Engineering the Keyboard, Part IV

    Coupled with our earlier pin mapping, this got us off to a great start. What proved a little confusing however was that–for my Series 5 keyboard at least–the key mapping was subtly incorrect: Fn, Menu, Esc and Ctrl did not appear to be working. After some experimentation, I realised that rows 9, 10, and 11 were, in fact, columns, leading to the following revised layout:

    Col 01 (15) Col 02 (11) Col 03 (10) Col 04 (9) Col 05 (8) Col 06 (7) Col 07 (6) Col 08 (5) Col 09 (4) Col 10 (3) Col 11 (2) Col 12 (1)
    Row 01 (20) Space Up . / Left Right Left Shift
    Row 02 (19) Z X C V B N Right Shift
    Row 03 (18) H J K M . ? Down Fn
    Row 04 (17) Tab A S D F G Left Control
    Row 05 (16) 1 2 3 4 5 6
    Row 06 (14) U I O P L Enter Menu
    Row 07 (13) Q W E R T Y Esc
    Row 08 (12) 7 8 9 0 Del ‘ -

    Looking back at the observations made when inspecting the powered-up Series 5 with a multimeter, this allocation of pins corresponds reassuringly with the behviour we were seeing from the Psion itself.

    Bluetooth

    Since it’s clearly is overkill to use a Raspberry Pi, I chose the Adafruit Feather nRF52 Bluefruit LE - nRF52832 for the Bluetooth controller. It supports Bluetooth LE, has 19 GPIO pins, and an Arduino-friendly microcontroller. There’s even an Adafruit HID library and an introductory guide.

    All told, the nRF52 is a great solution with only one minor limitation: the keyboard has 20 connections, but the board only 19 GPIOs pins. Fortunately the solution is a simple one: combine two of the columns into one. I chose to short pins 1 and 4, moving Ctrl onto column 9, alongside Fn.

    The firmware itself is fairly simple, using a tight loop to iterate over the columns and rows as described above. These are then converted to standard Bluetooth HID events, with Psion specific modifiers being handled locally to ensure the behaviour matches the keycaps. To give as much flexibility as possible, the Fn and Menu keys are treated as Alt and Command respectively when not used for these local key combinations.

    for (int c = 0; c < MAX_COLUMNS; c++) {
        int column = COLUMNS[c];
    
        // Pull the column low.
        pinMode(column, OUTPUT);
        digitalWrite(column, LOW);
        delay(5);
    
        // Iterate over the rows, reading their state.
        for (int r = 0; r < MAX_ROWS; r++) {
                
                int keyDown = (digitalRead(ROWS[r]) == LOW) ? 1 : 0;
                int currentKeyDown = keyboardState[c][r];
                
                if (keyDown != currentKeyDown) {
                        char character = CHARACTER_MAP[c][r];
                        if (character != HID_KEY_NONE) {
                                sendKey(character, keyDown);
                                keyboardState[c][r] = keyDown;
                        }
                }
        }
    
        // Restore the column.
        pinMode(column, INPUT_PULLUP);
    }
    

    With this, I now have a fully functional–albeit not terribly portable–keyboard. I’ve even managed to get the Psion specific key presses working, including adjusting the display brightness using the LCD contrast keys: