Category: computers suck

  • Raspberry Pi Pico: DS18x20 in MicroPython

    Updated: Thanks to Ben, who noticed the Fritzing diagrams had the sensors the wrong way round. Fixed now…

    Hidden away in the Pico MicroPython guide is a hint that there may be more modules installed in the system than they let on. In the section about picotool, the guide has a seemingly innocuous couple of lines:

    frozen modules: _boot, rp2, ds18x20, onewire, uasyncio, uasyncio/core, uasyncio/event, uasyncio/funcs, uasyncio/lock, uasyncio/stream

    The third and fourth ‘frozen modules’ are a giveaway: it shows that support for the popular Dallas/Maxim DS18x20 1-Wire temperature sensors is built in. Nowhere else in the guide are they mentioned. I guess someone needs to write them up.

    DS18x20 digital temperature sensors – usually sold as DS18B20 by Maxim and the many clone/knock-off suppliers – are handy. They can report temperatures from -55 to 125 °C, although not every sensor will withstand that range. They come in a variety of packages, including immersible sealed units. They give a reliable result, free from ADC noise. They’re fairly cheap, the wiring’s absurdly simple, and you can chain long strings of them together from the same input pin and they’ll all work. What they aren’t, though, is fast: 1-Wire is a slow serial protocol that takes a while to query all of its attached devices and ferry the results back to the controller. But when we’re talking about environmental temperature, querying more often than a few times a minute is unnecessary.

    So this is the most complex way you can wire up a DS18x20 sensor:

    breadboard with raspberry Pi Pico, DS18x20 sensor with 47 k? pull-up resistor between 3V3 power and sensor data line
    Raspberry Pi Pico connected to a single DS18x20 sensor

    and this is how it’s wired:

       DS18X20    Pico
       =========  =========
       VDD      ? 3V3
                  /
         --47 k?--
        /
       DQ       ? GP22
       GND      ? GND
    
     (47 k? resistor between DQ and 3V3 as pull-up)

    Adding another sensor is no more complicated: connect it exactly as the first, chaining the sensors together –

    breadboard with raspberry Pi Pico, two DS18x20 sensors with 47 k? pull-up resistor between 3V3 power and sensor data line
    Two DS18x20 sensors, though quite why you’d want two temperature sensors less than 8 mm apart, I’ll never know. Imagine one is a fancy immersible one on a long cable

    The code is not complex, either:

    # Raspberry Pi Pico - MicroPython DS18X20 Sensor demo
    # scruss - 2021-02
    # -*- coding: utf-8 -*-
    
    from machine import Pin
    from onewire import OneWire
    from ds18x20 import DS18X20
    from time import sleep_ms
    from ubinascii import hexlify    # for sensor ID nice display
    
    ds = DS18X20(OneWire(Pin(22)))
    sensors = ds.scan()
    
    while True:
        ds.convert_temp()
        sleep_ms(750)     # mandatory pause to collect results
        for s in sensors:
            print(hexlify(s).decode(), ":", "%6.1f" % (ds.read_temp(s)))
            print()
        sleep_ms(2000)
    

    This generic code will read any number of attached sensors and return their readings along with the sensor ID. The sensor ID is a big ugly hex string (the one I’m using right now has an ID of 284c907997070344, but its friends call it ThreeFourFour) that’s unique across all of the sensors that are out there.

    If you’re reading a single sensor, the code can be much simpler:

    # Raspberry Pi Pico - MicroPython 1x DS18X20 Sensor demo
    # scruss - 2021-02
    # -*- coding: utf-8 -*-
    
    from machine import Pin
    from onewire import OneWire
    from ds18x20 import DS18X20
    from time import sleep_ms
    
    ds = DS18X20(OneWire(Pin(22)))
    sensor_id = ds.scan()[0]  # the one and only sensor
    
    while True:
        ds.convert_temp()
        sleep_ms(750)         # wait for results
        print(ds.read_temp(sensor_id), " °C")
        sleep_ms(2000)
    

    The important bits of the program:

    1. Tell your Pico you have a DS18x20 on pin GP22:
      ds = DS18X20(OneWire(Pin(22)))
    2. Get the first (and only) sensor ID:
      sensor_id = ds.scan()[0]
    3. Every time you need a reading:
      1. Request a temperature reading:
        ds.convert_temp()
      2. Wait for results to come back:
        sleep_ms(750)
      3. Get the reading back as a floating-point value in °C:
        ds.read_temp(sensor_id)

    That’s it. No faffing about with analogue conversion factors and mystery multipliers. No “will it feel like returning a result this time?” like the DHT sensors. While the 1-Wire protocol is immensely complicated (Trevor Woerner has a really clear summary: Device Enumeration on a 1-Wire Bus) it’s not something you need to understand to make them work.

  • Quick labelled Fritzing Raspberry Pi Pico layout

    half-size breadboard with Raspberry Pi Pico mounted on top. Labels for each of the pin functions are on the left and right
    and now, with labels!

    Nothing particularly new or innovative here, but if you’re making simple Raspberry Pi Pico circuits and need to explain them to folks, this little Fritzing template might help. It’s mashed up from:

    1. the pinout diagram (chopped and scaled);
    2. the Raspberry Pi Pico Fritzing part.

    Since both of these components are from the Raspberry Pi Foundation’s Getting Started documentation, it’s supplied under the same licence.

  • Presentation: Getting Started with MicroPython on the Raspberry Pi Pico

    I just gave this talk to the Toronto Raspberry Pi Meetup group: Getting Started with MicroPython on the Raspberry Pi Pico. Slides are here:

    or, if you must, pptx:

    PDF, for the impatient:

    If I were to do this again, I’d drop the messy thermistor code as an example and use a DS18x20, like here: Raspberry Pi Pico: DS18x20 in MicroPython

    also, simple potentiometer demo I wrote during the talk: potentiometer.py

  • Book: Fortran techniques with special reference to non-numerical applications (1972)

    Programming flow diagram, with the flow of a program using subroutines on the left ("closed coding") and the same structure on the right written as a series of GOTO-controlled sections ("open coding") to save computer memory and execution time
    “Subroutines do, however, bring with them considerable
    overheads in both space and execution time
    .”

    Imagine you have a programming task that involves parsing and analyzing text. Nothing complicated: maybe just breaking it into tokens. Now imagine the only programming language you had available:

    • has no text handling functions at all: you can pack characters into numeric types, but how they are packed and how many you get per type are system dependent;
    • allows integers in variables starting with the letters I→N, with A→H and O→Z floating point;
    • has IF … THEN but no ELSE, with the preferred form being
      IF (expr) neg, zero, pos
      where expr is the expression to evaluate, and neg, zero and pos are statement labels to jump to if the evaluation is negative, zero or positive, respectively;
    • has only enough memory for (linear, non-associative) arrays of a couple of thousand entries;
    • disallows recursion completely;
    • charges for computing time such that a solo researcher’s work might cost many times their salary in a few weeks.

    Sounds impossible, right? But that’s the world described in Colin Day’s book from 1972, Fortran techniques with special reference to non-numerical applications.

    The programming language used is USA Standard FORTRAN X3.9 1966, commonly known as Fortran IV after IBM’s naming convention. For all it looks crude today, Fortran was an efficient, sod-the-theory-just-get-the-job-done language that allowed numerical problems to be described as a text program and solved with previously impossible speed. Every computer shipped with some form of Fortran compiler at the time. Day wasn’t alone working within Fortran IV’s text limitations in the early 1970s: the first Unix tools at Bell Labs were written in Fortran IV — that was before they built themselves their own toolchain and invented the segmentation fault.

    The book is a small (~ 90 page) delight, and is a window into system limitations we might almost find unimaginable. Wanna create a lookup table of a thousand entries? Today it’s a fraction of a thought and microseconds of program time. But nearly fifty years ago, Colin Day described methods of manually creating two small index and target arrays and rolling your own hash functions to store and retrieve stuff. Text? Hollerith constants, mate; that’s yer lot — 6HOH HAI might fit in one computer word if you were running on big iron. Sorting and searching (especially without recursion) are revealed to be the immensely complex subjects they are, all hidden behind today’s one-liner methods. Day shows methods to simulate recursion with arrays standing in for pointer stacks of GO TO targets (:coding_horror_face:). And if it’s graphics you want, that’s what the line printer’s for:

    Damped cosine 2d function density plot rendered as mono-spaced characters, approximately 60 colums across, made up of only X, 0, *, +, - and space characters
    “… the most serious drawback to a density plot of the type shown above is the limited number of characters used to represent the height above the page.”
    (This image was deemed impressive enough by Cambridge University Press that they used it as the cover of the book. The same function became a bit of a visual cliché, with home computers being able to render it in colour and isometric 3D less than a decade later.)

    Why do I like this book enough to track down a used copy, import it, scan it, correct it and upload it to the Internet Archive? To me, it shows the layers we now take for granted, and the privilege we have with these hard problems of half a century ago being trivially soluble on a $10 computer the size of a stick of gum. When we run today’s massive AI models with little interest in the underlying assumptions but a sharp focus on getting the results we want, we do a disservice to the years of R&D that got us here.

    The ‘charges for computing time’ comment above is from Colin’s website. Early central computing facilities had the SaaS billing down solid, partly because many mainframes were rented from the vendor and system usage was accounted for in minute detail. Apparently the system Colin used (when a new lecturer) was at another college, and it was the custom to send periodic invoices for CPU time and storage used back to the user’s department. Nowhere on these invoices did it say that these accounts were for information only and were not payable. Not the best way to greet your users.

    (Incidentally, if you hate yourself and everyone else around you, you can get a feel of system billing on any Linux system by enabling user quotas. You’ll very likely stop doing this almost immediately as the restrictions and reporting burden seem utterly alien to us today.)

    While the book is still very much in copyright, the copy I have sat unread at Lakehead University Library since June 1995; the due date slip’s still pasted in the back. It’s been out of print at Cambridge University Press since May 1987, even if they do have a plaintive/passive aggressive “hey we could totally make an ebook of this if you really want it” link on their site. I — and the lovely folks hosting it at the Internet Archive — have saved them from what’s evidently too much trouble. I won’t even raise an eyebrow if they pull a Nintendo and start selling this scan.


    Colossal thanks to Internet Archive for making the book uploading process much easier than I thought it was. They’ve completely revamped the processing behind it, and the fully open-source engine gives great results. As ever, if you assumed you knew how to do it, think again and read the How to upload scanned images to make a book guide. Uploading a zip file of images is much easier than mucking about with weird command-line TIFF and PDF tools. The resulting PDF is about half the size of the optimized scans I uploaded, and it’s nicely tagged with metadata and contains (mostly) searchable text. It took more than an hour to process on the archive’s spectacularly powerful servers, though, so I hate to think what Colin Day’s bill would have been in 1972 for that many CPU cycles … or if even a computer of that time, given enough storage, could complete the project by now.

  • TIMTOWTDI ’70

    One of the earlier acknowledgements of the inevitability of TIMTOWTDI in programming:

    In computing there is always more than one correct way of approaching a given problem. Generally a standard mathematical method for solution can be found, or a method developed. Programs using the same method can still be written in more than one correct way.
    from Digital Equipment Corporation, PDP-8 Handbook Series: Programming Languages (May 1970), p.12-6

    Admittedly, it’s talking about BASIC — and by BASIC, PDP-8 BASIC was very basic¹ indeed — but there’s always more than one correct way to implement a solution.


    ¹: no text string handling, variable names limited to two characters in [A-Z][0-9] format, IF…THEN can only take a line number as argument (as with Dartmouth BASIC), one statement per line, max 350 lines or so. I’d heard that DEC thought that BASIC was going to be a passing fad and that their own FOCAL language was going to “win”, so their BASIC offerings were deliberately given less attention than FOCAL. Hmm …

  • bench64: a new BASIC benchmark index for 8-bit computers

    Nobody asked for this. Nobody needs this. But here we are …

    commodore 64 screen shot showing benchmark results:
basic bench index
>i good. ntsc c64=100

1/8 - for:
 60 s; 674.5 /s; i= 100
2/8 - goto:
 60 s; 442.3 /s; i= 100
3/8 - gosub:
 60 s; 350.8 /s; i= 100
4/8 - if:
 60 s; 242.9 /s; i= 100
5/8 - fn:
 60 s; 60.7 /s; i= 100
6/8 - maths:
 60 s; 6.4 /s; i= 100
7/8 - string:
 60 s; 82.2 /s; i= 100
8/8 - array:
 60 s; 27.9 /s; i= 100

overall index= 100


ready.
    bench64 running on the reference system, an NTSC Commodore 64c

    Inspired by J. G. Harston’s clever but domain-specific ClockSp benchmark, I set out to write a BASIC benchmark suite that was:

    1. more portable;
    2. based on a benchmark system that more people might own;
    3. and a bunch of other less important ideas.

    Since I already had a Commodore 64, and seemingly several million other people did too, it seemed like a fair choice to use as the reference system. But the details, so many details …

    basic bench index
>i good. ntsc c64=100

1/8 - for:
 309.5 s; 130.8 /s; i= 19 
2/8 - goto:
 367.8 s; 72.1 /s; i= 16 
3/8 - gosub:
 340.9 s; 61.7 /s; i= 18 
4/8 - if:
 181.8 s; 80.1 /s; i= 33 
5/8 - fn:
 135.3 s; 26.9 /s; i= 44 
6/8 - maths:
 110.1 s; 3.5 /s; i= 54 
7/8 - string:
 125.8 s; 39.2 /s; i= 48 
8/8 - array:
 103 s; 16.3 /s; i= 58 

overall index= 29
    It was entirely painful running the same code on a real ZX Spectrum at under ⅓ the speed of a C64

    (I mean: who knew that Commodore PET BASIC could run faster or slower depending on how your numbered your lines? Not me — until today, that is.)

    While the benchmark doesn’t scale well for BASIC running on modern computers — the comparisons between a simple 8-bit processor at a few MHz and a multi-core wildly complex modern CPU at many GHz just aren’t applicable — it turns out I may have one of the fastest 8-bit BASIC computers around in the matchbox-sized shape of the MinZ v1.1 (36.864 Z180, CP/M 2.2, BBC BASIC [Z80] v3):

    BASIC BENCH INDEX
    >I GOOD. NTSC C64=100
    
    1/8 - FOR:
     3.2 S; 12778 /S; I= 1895 
    2/8 - GOTO:
     6.1 S; 4324.5 /S; I= 978 
    3/8 - GOSUB:
     3.1 S; 6789 /S; I= 1935 
    4/8 - IF:
     2.9 S; 4966.9 /S; I= 2046 
    5/8 - FN:
     3.5 S; 1030.6 /S; I= 1698 
    6/8 - MATHS:
     1.5 S; 255.3 /S; I= 4000 
    7/8 - STRING:
     2.6 S; 1871.6 /S; I= 2279 
    8/8 - ARRAY:
     3.1 S; 540.3 /S; I= 1935 
    
    OVERALL INDEX= 1839 
    

    That’s more than 9× the speed of a BBC Micro Model B.

    Github link: bench64 – a new BASIC benchmark index for 8-bit computers.

    Archive download:

  • Raspberry Pi Meetup tonight: the SeedStudio Wio Terminal

    Anthopomorphized line drawing of the Wio terminal, with a simple smiling face on the screen, waving arms and legs with feet underneath
    Wio Terminal-chan, the mascot for SeedStudio’s Wio Terminal

    Hey – the Toronto Raspberry Pi Meetup Group is meeting online tonight! All welcome: you don’t have to be in/near Toronto to attend.

    I’ll be introducing the SeeedStudio Wio Terminal: a flexible, small input and display device. The Wio Terminal has many interesting uses — including as an adjunct to or even alternative to the Raspberry Pi

    Thursday, December 10, 2020
    7:00 PM to 8:30 PM EST

    Signup link: https://www.meetup.com/Raspberry-Pi/events/dhwnzrybcqbnb/
    or directly on Google Meet: https://meet.google.com/snu-befk-ivf


    Slides!

  • Stand for PROTODOME’s 4000AD chiptune album

    Stand for PROTODOME’s 4000AD chiptune album

    4000AD album PCB in stand, with Print+ 3D printed headphones in foreground

    So Dr. Blake “PROTODOME” Troise (previously) made a chiptune album that’s entirely synthesized by an Atmel/Microchip ATmega328P microcontroller in realtime. And every chip needs a PCB, right? So Blake released the album as a physical device you can solder up for yourself.

    Of course, having the PCB lying flat doesn’t allow you to see Marianne Thompson’s great pixel cover art, or read the liner notes on the back — and risks having the circuit short out on random tinny things on your desk. (Maybe that’s just my desk, though.)

    This stand allows you to display the board at a convenient 75° angle, but also allows the PCB to be flipped forward so you can read the liner notes comfortably. Yeah, I may have been a crate-digger at one time.

    Links:

    (or Thingiverse link: https://www.thingiverse.com/thing:4579706)

    4000AD album PCB in stand, front view
    4000AD album PCB in stand, rear view (messy Kapton taping optional)
    4000AD album PCB stand in black low-sheen PLA
  • calculator for engineering nerds

    For something to do with my head, I’m taking the RAC Advanced Ham Radio course. The exam uses a non-programmable scientific calculator. I thought that all my calculators were programmable, but we found this one lurking in the basement and it’s just perfect:

    Casio fx-115MS scientific calculator
    SI prefixes above 1…9 on the fx-115MS: f, p, n µ, m, k, M, G, T

    This is one of the few calculators I’ve seen that both displays and takes inputs in SI units. How to put it into SI engineering display mode is explained in this delightful (archived) site Casio fx-115MS.

    Entering numbers with SI prefixes is simple: type the number, then Shift and hit the prefix. So to enter 300000, you’d type 300 Shift 4 to get 300 k.

    You do have to be a little careful reading the display in this mode, though. The display above reads 221 × 10-3 (from the m at right), or 0.221.

    I don’t see any calculator in Casio’s current range that offers this handy feature. Guess I’m lucky I found it before the exam!

  • speech on Raspberry Pi: espeak-ng

    Audio can be a bit dismal on a Raspberry Pi. Once you get a configuration that works, sometimes you’re not sure how you got there and you’ll do anything to keep that arcane setup going. It’s better than it was.

    Speech synthesis or TTS adds an extra layer for potential failure. One of the popular Linux TTS systems, eSpeak, hasn’t seen much development in almost a decade and seems to only work through workarounds and hand-waving.

    Thankfully, there’s a fork of eSpeak that is maintained: espeak-ng. Better yet, it’s packaged with Raspberry Pi OS and can be installed quite easily:

    sudo apt install espeak-ng espeak-ng-data libespeak-ng-dev
    

    In my simple tests, it output everything I expected of it.

    eSpeak had a Python module that kinda worked, but espeak-ng’s is much more ambitious, and (mostly) does what it sets out to do. You can install it like this:

    sudo pip3 install py-espeak-ng
    

    py-espeak-ng has some documentation, but it’s still got some trial and error in getting it to work. The biggest issue that held me up was that the module needs to be initialized with a voice that espeak-ng already knows about. If you don’t specify a voice, or specify one that the system doesn’t know about, you won’t get any errors — but you won’t get any output, either.

    Here’s a small Python example that you’ll probably want to try with no-one else within earshot. It repeats the same English phrase (a favourite of elocution teachers) in every English regional language that espeak-ng knows about. In addition, since I’m a dictionary nerd, it outputs phonetics too.

    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
    # an espeakng elocution lesson from scruss, 2020-07
    #     I suffered this at school, now you get to as well!
    # You will need to:
    #     sudo apt install espeak-ng espeak-ng-data libespeak-ng-dev
    #     sudo pip3 install py-espeak-ng
    
    from espeakng import ESpeakNG
    from time import sleep
    
    # you have to initialize with a voice that exists
    #   `espeak-ng --voices=en` will list English ones
    esng = ESpeakNG(voice='en-gb')
    esng.pitch = 32
    esng.speed = 150
    
    phrase = "Father's car is a Jaguar and pa drives rather fast. "\
        "Castles, farms and draughty barns, all go charging past."
    print(phrase)
    print()
    
    for voice in esng.voices:
        if voice['language'].startswith('en-'):
            print('Using voice:', voice['language'],
                  'for', voice['voice_name'], '-')
            esng.voice = voice['language']
            ipa = esng.g2p(phrase, ipa=2)
            print(voice['language'], 'phonetics:', ipa)
            esng.say(phrase, sync=True)
            print()
            sleep(0.1)
    
    

    Be thankful you can’t hear the output. The IPA output, however, is a thing of beauty:

    ./espeakNG_test.py
    Father's car is a Jaguar and pa drives rather fast. Castles, farms and draughty barns, all go charging past.
    
    Using voice: en-029 for English_(Caribbean) -
    en-029 phonetics: fˈɑːdaz kˈɑ͡əɹ ɪz a d͡ʒˈaɡwɑ͡ə and pˈɑː dɹˈa͡ɪvz ɹˈɑːda fˈa͡astkˈa͡asɛlzfˈɑ͡əmz and dɹˈa͡afti bˈɑ͡ənzˈɔːl ɡˌo͡ʊ t͡ʃˈɑ͡əd͡ʒɪn pˈa͡ast
    
    Using voice: en-gb for English_(Great_Britain) -
    en-gb phonetics: fˈɑːðəz kˈɑːɹ ɪz ɐ d͡ʒˈaɡwɑː and pˈɑː dɹˈa͡ɪvz ɹˈɑːðə fˈastkˈasə͡lzfˈɑːmz and dɹˈafti bˈɑːnzˈɔːl ɡˌə͡ʊ t͡ʃˈɑːd͡ʒɪŋ pˈast
    
    Using voice: en-gb-scotland for English_(Scotland) -
    en-gb-scotland phonetics: fˈa:ðɜz kˈaːr ɪz ɐ d͡ʒˈaɡwaːr and pˈa: drˈa͡ɪvz rˈa:ðɜ fˈa:stkˈa:sə͡lzfˈaːrmz and drˈa:fte bˈaːrnzˈɔːl ɡˌoː t͡ʃˈaːrd͡ʒɪŋ pˈa:st
     …
    
    
  • yet another homage …

    So it turns out that Mines Incas is yet another variant on 2D Star Dodge / Asterisk Tracker theme. And it’s really well done!

    Play it in your browser: Mines Incas

    Info page at CPC-POWER: Mines Incas

  • WeAct F411 + MicroPython + NeoPixels

    Further to the Canaduino STM32 boards with MicroPython writeup, I thought I’d start showing how you’d interface common electronics to the WeAct F411 boards. First off, NeoPixels!

    Rather than use the Adafruit trade name, these are more properly called WS2812 LEDs. Each one contains a tiny microcontroller and it only takes three connections to drive a long chain of addressable colour LEDs. The downside is that the protocol to drive these is a bit of a bear, and really needs an accurate, fast clock signal to be reliable.

    The STM32F411 chip does have just such a clock, and the generic micropython-ws2812 library slightly misuses the SPI bus to handle the signalling. The wiring’s simple:

    • F411 GND to WS2812 GND;
    • F411 3V3 to WS2812 5V;
    • F411 PA7 (SPI1_MOSI) PB15 (SPI2_MOSI) to WS2812 DIn

    Next, copy ws2812.py into the WeAct F411’s flash. Now create a script to drive the LEDs. Here’s one to drive 8 LEDs, modified from the library’s advanced example:

    # -*- coding: utf-8 -*-
    
    import time
    import math
    
    from ws2812 import WS2812
    
    ring = WS2812(spi_bus=2, led_count=8, intensity=0.1)
    
    def data_generator(led_count):
        data = [(0, 0, 0) for i in range(led_count)]
        step = 0
        while True:
            red = int((1 + math.sin(step * 0.1324)) * 127)
            green = int((1 + math.sin(step * 0.1654)) * 127)
            blue = int((1 + math.sin(step * 0.1)) * 127)
            data[step % led_count] = (red, green, blue)
            yield data
            step += 1
    
    for data in data_generator(ring.led_count):
        ring.show(data)
        time.sleep_ms(100)
    

    Previously I said you’d see your WS2812s flicker and shimmer from the SPI bus noise. I thought it was cool, but I suspect it was also why the external flash on my F411 board just died. By pumping data into PA7, I was also hammering the flash chip’s DI line …

  • Canaduino STM32 boards with MicroPython

    Volker Forster at Universal Solder was kind enough to send me a couple of these boards for free when I asked about availability. By way of thanks, I’m writing this article about what’s neat about these micro-controller boards.

    always neat packaging from Universal Solder

    Can I just say how nicely packaged Universal Solder’s own or customized products are? They want it to get to you, and they want it to work.

    I’d previously played around with Blue Pill and Black Pill boards with limited success. Yes, they’re cheap and powerful, but getting the toolchain to work reliably was so much work. So when I read about the WeAct STM32F411CEU6 board on the MicroPython forum, I knew they’d be a much better bet.

    Canaduino Black Pill Carrier Board with STM32F411 (and battery) installed

    Volker sent me two different things:

    Let’s start with the STM32 Screw Terminal Adapter:

    Canaduino Black Pill Carrier Board (front)

    It’s a neat, solid board built on a black 1.6 mm thick PCB. Apart from the obvious screw terminals — essential for long-term industrial installations — it adds three handy features:

    • a real-time clock battery. If you’re using a micro-controller for data logging, an RTC battery helps you keep timestamps accurate even if the device loses power.
    • mounting holes! This may seem a small thing, but if you can mount your micro-controller solidly, your project will look much more professional and last longer too.
    • A 6–30 V DC regulator. Connect this voltage between Vin and GND and the regulator will keep the board happy. From the helpful graph on the back of the board, it doesn’t look as if things start getting efficient until around 12 V, but it’s really nice to have a choice.
    Canaduino Black Pill Carrier Board (back)

    I made a little slip-case for this board so it wouldn’t short out on the workbench. The project is here: Canaduino STM32 Screw Terminal board tray and you can download a snapshot here:

    The boards themselves are pretty neat:

    two STM32F411 Black Pill boards from Canaduino

    Gone are the lumpy pin headers of the earlier Blue and Black Pill boards, replaced by tactile switches. The iffy micro USB connectors are replaced by much more solid USB C connectors. According to STM32-base, the STM32F411 has:

    • 100 MHz ARM Cortex-M4 core. This brings fast (single-precision) floating point so you don’t have to fret over integer maths
    • 512 K Flash, 128 K RAM. MicroPython runs in this, but more flash is always helpful
    • Lots of digital and analogue I/O, including a 12-bit ADC
    • A user LED and user input switch.

    About the only advanced features it’s missing are a true RNG, a DAC for analogue outputs, and WiFi. But on top of all this, Volker added:

    the all-important 128 Mbit flash chip (and capacitor) fitted by Universal Solder

    128 Mbit of Flash! This gives the board roughly 16 MB of storage that, when used with MicroPython, appears as a small USB drive for your programs and data. I found I was able to read the ADC more than 22,000 times/second under MicroPython, so who needs slow-to-deploy compiled code?

    STM32F411 board pinout
    board pinout from STM32F4x1 MiniF4 / WeAct Studio 微行工作室 出品.
    Avoid A4-A7 if you’re using a flash chip.

    Building and Installing MicroPython

    This is surprisingly easy. You’ll need to install the gcc-arm-none-eabi compiler set before you start, but following the instructions at mcauser/WEACT_F411CEU6: MicroPython board definition for the WeAct STM32F411CEU6 board will get you there.

    I had to run make a couple of times before it would build, but it built and installed quickly. This board doesn’t take UF2 image files that other boards use, so the installation is a little more complicated than other. But it works!

    Once flashed, you should have a USB device with two important MicroPython files on it: boot.py and main.py. boot.py is best left alone, but main.py can be used for your program. I’m going into more details in a later article, but how about replacing the main.py program with the fanciest version if Blink you ever saw:

    # main.py -- fancy Blink (scruss, 2020-05)
    
    from pyb import LED
    from machine import Timer
    tim = Timer(-1)
    tim.init(period=1000, mode=Timer.PERIODIC,
             callback=lambda t: LED(1).toggle())
    

    None of that blocking delay() nonsense: we’re using a periodic timer to toggle the user LED every second!

    debugging the mystery huge potentiometer using two ADC channels

    I’m really impressed with the Universal Solder-modified board as an experimentation/discovery platform. MicroPython makes development and testing really quick and easy.

    [and about the mystery huge potentiometer: it’s a Computer Instruments Corporation Model 206-IG multi-turn, multi-track potentiometer I picked up from the free table at a nerd event. I think it’s a 1950s (so Servo-control/Cybernetics age) analogue equivalent of a shaft encoder, looking at the patent. Best I can tell is that each pot (there are two, stacked, with precision bearings) appears to have two 120° 10k ohm sweep tracks offset 90° to one another. The four wipers are labelled -COS, -SIN, +COS and +SIN. If anyone knows more about the thing, let me know!]

  • MicroPython on the terrible old ESP8266-12 Development Board

    … + 1 + 1 + 1 …

    I just found my first ESP8266 dev board. This was from way back before Arduino support, and long before MicroPython

    esp8266-dev-boards from ESP8266 Support WIKI

    It’s not really in a useful form factor, but it’s got some sensors and outputs:

    • an LDR on the ADC channel
    • RGB LED for PWM on pins 15, 12 & 13
    • red LEDs pins 16, 14, 5, 4, 0, 2 with inverted logic: set them low to light them.

    My board can’t quite be the earliest of the early, as it has 1 MB of flash. This is enough to install MicroPython, so I wrote a tiny test program for the outputs:

    • run a binary counter every second on the six red LEDs;
    • cycle through a colour wheel on the RGB LED while this is happening.

    Here’s the code:

    # esp8266 old explorer board
    # see https://www.esp8266.com/wiki/lib/exe/detail.php?id=esp8266-dev-boards&media=esp8266-12_mod.png
    
    from time import sleep
    from machine import Pin, PWM
    # LEDs are 16, 14, 5, 4, 0, 2 - L to R
    # inverted logic: 1 = off
    leds = [Pin(2, Pin.OUT, value=1), Pin(0, Pin.OUT, value=1), Pin(4, Pin.OUT, value=1), Pin(
        5, Pin.OUT, value=1), Pin(14, Pin.OUT, value=1), Pin(16, Pin.OUT, value=1)]
    
    # RGB for PWM on [15, 12, 13]
    rgb = (PWM(Pin(15)), PWM(Pin(12)), PWM(Pin(13)))
    # LDR on ADC
    
    
    def cos_wheel(pos):
        # Input a value 0 to 255 to get a colour value.
        # scruss (Stewart Russell) - 2019-03 - CC-BY-SA
        from math import cos, pi
        if pos < 0:
            return (0, 0, 0)
        pos %= 256
        pos /= 255.0
        return (int(255 * (1 + cos(pos * 2 * pi)) / 2),
                int(255 * (1 + cos((pos - 1 / 3.0) * 2 * pi)) / 2),
                int(255 * (1 + cos((pos - 2 / 3.0) * 2 * pi)) / 2))
    
    
    i = 1
    while True:
        i = i + 1
        i = i % 64
        w = cos_wheel(4 * i)
        for j in range(3):
            rgb[j].duty(4 * w[j])
    
        for k in range(6):
            if i & (1 << k):
                leds[k].value(0)
            else:
                leds[k].value(1)
        sleep(1)
    
    
  • super-special serial port standards

    The PC I put together a few years ago (well, Scott Sullivan told me which bits to get, I bought them and assembled it) is still working really well. It was quite spiffy in its day — i7-4790K, 32 GB DDR3, Asus H97M-E — and is quite fast enough for me.

    One thing, though, has never worked. The hardware serial port (the old kind, not the USB kind) refused to do anything. Only in the last day or so did I work out why and managed to fix it.

    PC serial ports for roughly the last 25 years connected to the motherboard like this:

    motherboard pin 1 → RS232 pin 1; motherboard pin 2 → RS232 pin 6; motherboard pin 3 → RS232 pin 2; motherboard pin 4 → RS232 pin 7; motherboard pin 5 → RS232 pin 3; 
motherboard pin 6 → RS232 pin 8; 
motherboard pin 7 → RS232 pin 4; motherboard pin 8 → RS232 pin 9; motherboard pin 9 → RS232 pin 5; motherboard pin 10 not connected
    ZF SystemCard – Data Book (1998)

    This rather strange mapping makes sense as soon as you see an IDC ribbon-cable DB-9 connector:

    serial cable for the SBC6120-RBC, unhelpfully the wrong way up

    Going along the cable from left to right (reversed in the photo above), we have:

        1 2 3 4 5 6 7 8 9
    
        1   2   3   4   5
          6   7   8   9

    This was good enough for everyone except ASUS, who decided that they needed their own way of arranging cables. Because of course they would:

    ASUS wiring: motherboard pin 1 → RS232 pin 1; motherboard pin 2 → RS232 pin 2; motherboard pin 3 → RS232 pin 3; etc.
    Oh ASUS, how could you?

    With a bit of resoldering, I’ve got a working serial port. You can never have too many.

  • lots of whirly LED domes

    birdsong not included …

    For it-seemed-like-a-good-idea-at-the-time reasons, I’ve ended up with a couple of tubes of the big dome LEDs. A tube is a lot; something over 20 pieces. Oh well, I’ll find uses for them eventually.

    It seems these are LEDTronics 806 Series ‘Super Intensity 20mm Big Dome 6-Chip LEDs’. The datasheet shows they are configured as a DIP-12, with LED cathodes and anodes alternating around the pins:

    Dome LED pinout: 12 pins, spaced 15.24 mm across, 2.54 mm between pins
    that’s a pretty big dome

    The six LEDs are enough to use all of the available PWM pins on a regular Arduino. The green LEDs I have look like they’re supposed to take a current-limiting resistor of ≥ 75 Ω or so at 5 V. The 100 Ω resistors I used did pretty much max out the weedy regulator on the cheap Arduino Nano I was using, so you may want to use bigger resistors if you want to avoid having your USB disappear.

    No Fritzing model of the part yet, but here’s a sketch that works, but quite fails to use any interesting PWM functions at all:

    // do a whirly thing with the 6 LEDs inside a LEDTronics L806T_UG-LIME 20 mm Big Dome unit
    // scruss - 2020-04
    // https://www.ledtronics.com/Products/ProductsDetails.aspx?WP=281
    // each thru 100R resistor - which might be rather small
    
    #define MAXPINS 5
    int pwmpins[] = { 3, 5, 6, 9, 10, 11 };
    int i = 0;
    
    void setup() {
      // pwm pins as output, all initially off
      for (i = 0; i <= MAXPINS; i++) {
        pinMode(pwmpins[i], OUTPUT);
        analogWrite(pwmpins[i], 0);
      }
    }
    
    void loop() {
      if (i > MAXPINS) {
        i = 0;
      }
      analogWrite(pwmpins[i], 255);
      analogWrite((i > 0) ? pwmpins[i - 1] : pwmpins[MAXPINS], 0);
      delay(30);
      i++;
    }
    
    
  • Today’s achievement: make my 3d printer sound like a washing machine

    It has a certain rough-hewn quality …

    or if you must: Ender-3 plays LG on YouTube.

    musical score for the LG theme

    I’ll admit that this version is strongly influenced by Washing Machine Sheet music for Percussion, which seems to have a couple of off notes.

    That tune again

    Midi, MuseScore, gcode and PDF file:

    But this is mostly about the discovery of I wrote a program that converts MIDI files to G-Code, enabling my printer to play music with its LCD buzzer on reddit, with the converter at: MIDI to M300

    So here’s the gcode to play this:

    M300 P632 S554
    M300 P35 S0
    M300 P222 S740
    M300 P222 S698
    M300 P222 S622
    M300 P632 S554
    M300 P35 S0
    M300 P632 S466
    M300 P35 S0
    M300 P222 S494
    M300 P222 S466
    M300 P222 S494
    M300 P222 S415
    M300 P222 S466
    M300 P222 S494
    M300 P632 S466
    M300 P35 S0
    M300 P632 S554
    M300 P35 S0
    M300 P632 S554
    M300 P35 S0
    M300 P222 S740
    M300 P222 S698
    M300 P222 S622
    M300 P632 S554
    M300 P35 S0
    M300 P632 S740
    M300 P35 S0
    M300 P222 S740
    M300 P222 S831
    M300 P222 S740
    M300 P222 S698
    M300 P222 S622
    M300 P222 S698
    M300 P2532 S740
  • Compiling Kermit on modern Linux

    One of the quirks of the SBC6120-RBC boards I just built is that its serial port talks a protocol that’s very rarely seen these days: 7 bits, mark parity, 1 stop bit. minicom supports it, but seemingly can’t set it from the command line.

    Kermit, of course, can. Kermit (not the frog, but named after him) is the connect-to-anything, with-anything comms package. It’s been in constant development since 1981, and there’s hardly a computer system that exists that it won’t run on. The Unix/Linux variant, C-Kermit, has an incredibly intricate hand-crafted makefile that predates autoconf or cmake or any of those newfangled toys. Unfortunately, though, this means it may need a lot of reading and a little hand to compile.

    There may be some additional dependencies, but to build a simple version of C-Kermit 9.0.304 Dev.23 on Ubuntu 19.10 and Raspbian Buster you need this patch, and do something like:

    mkdir ckermit
    cd ckermit
    wget http://www.kermitproject.org/ftp/kermit/test/tar/cku304-dev23.tar.gz
    tar xvzf cku304-dev23.tar.gz
    wget https://src.fedoraproject.org/rpms/ckermit/raw/master/f/ckermit-9.0.302-fix_build_with_glibc_2_28_and_earlier.patch
    patch < ckermit-9.0.302-fix_build_with_glibc_2_28_and_earlier.patch
    make linux

    and it should build correctly. There are many, many options: make linux+ssl gives some extra network security features; make install puts it in the system path.

    The command line I use to connect to the SBC6120-RBC is:

    kermit -l /dev/ttyUSB0 -p m -b 38400 -m none -c

    That drops you straight into a connection. To get you back to Kermit’s command mode, type Ctrl + \ + C.

  • Single board PDP-8: take 2 …

    A couple of years back, I said I was building a single board computer and then things went quiet. Yes, I screwed up. A mix of dry joints and possibly burning through traces caused by following old instructions, impatience and a very unforgiving solder type made the original board almost unusable. I finally got a replacement board (thanks, Andrew!) and put in a humongous Digikey order for all the projects that I want to finish, and got going.

    circuit board with many chips
    I swapped out the 5 MHz crystal for a blazingly fast 8 MHz one

    I took quite a bit more care building this, but it was still only a couple of evenings to put it together. While I still used lead-free solder, I hardly needed extra flux at all. The nice ($$$) turned-pin sockets hold the chips much more securely than the cheaper plain sockets I used before.

    After a minor hiccup (homebrew null modem cable needs both RX and TX to be useful), it lives!

    SBC6120 ROM Monitor V320 Checksum 3752 6072 3515 09-APR-10 21:15:39
    Copyright (C) 1983-2010 by Spare Time Gizmos. All rights reserved.
    NVR: Not detected
    IDE: 489MB - LEXAR ATA FLASH
    IOB: Not detected
    B
    -IDA0
    .BASIC
    NEW OR OLD--OLD
    FILE NAME--ASCART
    READY
    LIST
    ASCART BA 5B
    100 FOR Y=-12 TO 12
    110 FOR X=-39 TO 39
    120 C1=X*.0458
    130 C2=Y*.08333
    140 A=C1
    150 B=C2
    160 FOR I=0 TO 15
    170 T=A*A-B*B+C1
    180 B=2*A*B+C2
    190 A=T
    200 IF (A*A+B*B)>4 GOTO 240
    210 NEXT I
    220 PRINT " ";
    230 GOTO 270
    240 IF I<=9 GOTO 260
    250 I=I-57
    260 PRINT CHR$(48+I);
    270 NEXT X
    280 PRINT
    290 NEXT Y
    300 END
    READY
    RUN
    ASCART BA 5B
    000000011111111111111111122222233347E7AB322222111100000000000000000000000000000
    000001111111111111111122222222333557BF75433222211111000000000000000000000000000
    000111111111111111112222222233445C 643332222111110000000000000000000000000
    011111111111111111222222233444556C 654433332211111100000000000000000000000
    11111111111111112222233346 D978 BCF DF9 6556F4221111110000000000000000000000
    111111111111122223333334469 D 6322111111000000000000000000000
    1111111111222333333334457DB 85332111111100000000000000000000
    11111122234B744444455556A 96532211111110000000000000000000
    122222233347BAA7AB776679 A32211111110000000000000000000
    2222233334567 9A A532221111111000000000000000000
    222333346679 9432221111111000000000000000000
    234445568 F B5432221111111000000000000000000
    864332221111111000000000000000000
    234445568 F B5432221111111000000000000000000
    222333346679 9432221111111000000000000000000
    2222233334567 9A A532221111111000000000000000000
    122222233347BAA7AB776679 A32211111110000000000000000000
    11111122234B744444455556A 96532211111110000000000000000000
    1111111111222333333334457DB 85332111111100000000000000000000
    111111111111122223333334469 D 6322111111000000000000000000000
    11111111111111112222233346 D978 BCF DF9 6556F4221111110000000000000000000000
    011111111111111111222222233444556C 654433332211111100000000000000000000000
    000111111111111111112222222233445C 643332222111110000000000000000000000000
    000001111111111111111122222222333557BF75433222211111000000000000000000000000000
    000000011111111111111111122222233347E7AB322222111100000000000000000000000000000
    READY
    ASCII art Mandelbrot set
    If WordPress’s line wrapping has mangled the above, it should look like this

    It compiles and runs a slightly modified ASCIIART.BAS Mandelbrot set benchmark in 144 seconds. This is comparable to many 8-bit computers. The modifications were:

    • PDP-8 BASIC doesn’t quite use ASCII. Its six-bit character set has digits 0-9 at decimal 48-57 like ASCII, but characters A-F are at decimal 1-6 (instead of 65-70). The manual claims that CHR$() works modulo 64, so maybe I didn’t need to make this change.
    • Variable names can be called Letter+Number at most, so the original’s CA and CB had to become C1 and C2.
    • PDP-8 BASIC doesn’t support a familiar IF … THEN … structure, but only effectively an IF … GOTO …. I mean, sure, you can use THEN if you want, but only a line number or a GOTO … following it will avoid the dreaded terse NM error. ELSE? Who needs it?!