2022-12-26

Sea Glass: a "breathing" night light

This is mostly just a repost of something that was on my GitHub. A small project that makes a "breathing" night light from glass washed up on a beach and a microcontroller + LEDs.

This code drives a string of four Adafruit Neopixel LEDs connected to an AdaFruit 5V Trinket causing the four LEDs to glow white with varying brightness that emulates the rhythm of human breathing.

The four LEDs are hidden inside the sea glass and kept inside an old glass jar. 

Parts

This little project was made from things I had lying around or found:

1. An AdaFruit 5V Trinket

2. Four LEDs cut from a strip of AdaFruit Neopixel

3. An old wall wart adapter giving 5V @ 2000mA

4. A glass that had previously held a candle

5. Sea glass picked up on a beach

6. Some Kintsuglue (Sugru is similar).

Steps

I first drilled a hole in the glass using a ceramic drill. The hole is there do that the cable from the wall wart can pass through. To protect the cable once in place I use the Kintsuglue to make a little strain relief grommet. It also covers the sharp edges of the drilled glass.


The code is pretty simple. It uses the AdaFruit Neopixel library to drive the four LEDs. The LEDs are literally cut with scissors from a strip and then bent into a circle and super-glued together.


There are just three wires to solder:

1. +5V from wall wart goes to the Neopixel strip and BAT+ on the Trinket. The LEDs draw power directly from the wall wart.

2. GND goes to the Neopixel strip and GND on the Trinket.

3. A single wire goes from PIN #0 on the Trinket to the Neopixel data line.

The electronics are simply buried in the sea glass.


Breathing

The breathing is based on the old "sleep LED" on Macs (the explanation I originally used was to be found here and can now be found on the Internet archive). (Note that Lady Ada did some reverse engineering work on the Mac's breathing light way back and the origin of the formula is from a comment on her post).

The formula for the LED brightness is

where x is the number of milliseconds since start. It looks like this when plotted (there's a sharper intake of breath than exhalation):



2022-12-01

The Rogers Watch: a retro display and all the insides on the outside

This blog is about a watch I built using a microcontroller, a lovely bubble LED display (like the ones in my Commodore P50 and Rockwell 8R calculators) and a NATO watch strap. Along the way, I built a self-contained AVR programmer and learnt how to use OpenSCAD.

There's something comforting about those bubble LED displays. I managed to track down a small number on eBay but they seem to be very rare.

Here's the finished watch alongside my 44mm Apple Watch.


The watch design is entirely based on an idea implemented by Jürgen Müller and Inge P. They both built watches on a tiny breadboard. The type that seem to be ubiquitous giveaways with electronic components. I used one in my self-contained AVR programmer.

To start the project I duplicated Jürgen Müller's watch on a little breadboard:


There it's running with a totally unsuitable battery which is replaced with a LiPo battery for the real thing, but this at least proved that it worked. I deviated from the two previous projects by opting to solder the components to a breadboard and 3D print a case for it to go in. Sparkfun make a breadboard with the same size.

I programmed the AVR in the programmer I'd built and inserted it into the breadboard. Happily, it worked first time. Note that because the AVR is going to use an external clock (a tiny 32kHz crystal) it's necessary to supply a clock signal to the AVR while programming it. That's the yellow 8MHz connection in this picture.


Although the watch is kind of ugly I decided two things: first to name it after the architect Richard Rogers who famously designed the "inside out" Centre Pompidou in Paris; second to modify the firmware so that I could lay out the diodes at the top in a more pleasing manner. My fork of the code is here.

Then it was just a matter of duplicating the circuit on the breadboard. I took a long time over bending the leads to make everything look good and there are some really carefully placed connections that took some time to get right. Some of the connections are literally under the diode leads and I opted for bare wires for aesthetic reasons.


To minimize the amount of space taken up inside the watch I cut the legs off the components flush with the breadboard and soldered things in place. In the final assembly I also cut a small piece of clear plastic which goes between the battery and board to prevent anything sharp from puncturing the battery.


The battery is a 250mAh LiPo from Cellevia. I shortened its leads so that it fits in the watch case. To charge the battery I made a charger from a Sparkfun LiPo Charger Basic. I soldered the correct connector for this battery in place, added a USB cable and encased the whole thing in clear heatshrink.


Because of the work done by Inge P to put the microcontroller into its lowest power mode it draws about 10uA when the display is off (you press the button to see the time, cf. Sinclair Black Watch). With the battery I am using that should give the watch a time between charges of about 2 years 9 months.

The case is in two parts. There's a main case that holds the breadboard and there's a back that fits into it. Both have slots in them for the watch strap. I am using a 22mm NATO watch strap. 



The NATO strap is convenient because its design means that the hard plastic of the watch is not against your skin. And by having slots in the case and back the strap holds the whole thing together. To keep the breadboard in place I used.. glue.


And there you have it. And just like le Centre Pompidou it's either the most beautiful or the ugliest thing you've ever seen. If you want to build your own my fork of the code is here and the 3D case files are here.


There are two resistors, nine Schottky diodes, an ATtiny84A, the bubble display, a switch and a 32kHz crystal. Plus a bunch of small wires to make connections. It's not obvious from this that I put a tiny piece of clear heatshrink over the crystal and glued it in place. 

And finally, a few close ups should you wish to build your own version.




Need more crazy watch things? Read about my Casio F-91W's new mainboard.

2022-11-18

Restoring my Commodore P50 calculator with a little solder and a 3D printer

Hot on the heels of me restoring my Rockwell 8R calculator with a small amount of cleaning and a little 3D print, it was time to restore my other 1970s calculator: the Commodore P50. But this restoration required a little more work. 

Once again, I'd lost the battery cover but its shape was much more complex than the Rockwell's. Also, the actual battery connector was broken and the keyboard a bit flaky.


Fixing the battery connector is pretty simple. It's soldered onto two huge pads on the left and it's just a matter of unsoldering, cleaning up and soldering a new one in place.



Next up is dismantling the keyboard and cleaning it. The main circuit board is held down by eight screws. Once removed the keyboard comes apart into individual buttons and the rubberized sheet that makes the contacts and makes them spring.

First step was to clean the contacts with alcohol on a cotton bud.


Then I washed and dried the very dirty rubber components which had been gathering crud since the 1970s.


Lastly, the missing battery cover. For this I recreated it (or something like it) in OpenSCAD and 3D printed it. Here are the OpenSCAD instructions for it:

// w is the width of the entire cover

w = 54.5;

// cover is the main part of the cover without the hook or clip.
module cover() {
    linear_extrude(w) hull() {
        translate([0, 28, 0]) square(1.5);
        square(1.5);
        translate([8.5, -5, 0]) square(1.5);
    }
}

hook_width = 20;

// hook is the part the catches at the bottom of the angled piece 
// of the cover
module hook() {
    translate([9.5, -4.5, (w-hook_width)/2])
        linear_extrude(hook_width)
            square([0.5, 4]);
}

clip_width = 13;

// clip is the part that clips in place inside the
// calculator housing
module clip() {
    translate([1.5, 24, (w-clip_width)/2]) union() {
        linear_extrude(clip_width) union() {
            square([2, 12]);
            translate([-1, 8, 0]) square([2, 0.5]);
        }
    }
}

finger_width = 10;

// finger is a small indentation to help you remove the cover
module finger() {
    translate([1, 10, (w-finger_width)/2])
        rotate(180)
            linear_extrude(finger_width)
                polygon([[1, 5], [1, 0], [0, 5]]);
}

difference() {
    cover();
    translate([1.5, 1.5, 0]) cover();
    finger();
}
 
hook();
clip();

And here's what that looks like:



And once printed (I only had black and not brown) looks like this:


And fits beautifully onto the calculator with a satisfying click as the clip locks into place.


And with it all back together I can go off and do important things like program it to identify prime numbers in its incredibly limited space (24 program steps max!).

2022-11-17

Restoring my Rockwell 8R calculator with a 3D printer

I've owned a Rockwell 8R calculator for a very long time. It was released in 1975 and it seems to have survived the intervening 47 years pretty well. Except that when I was a child I liked to take it apart to examine its innards. Along the way I lost all four screws and the battery cover.



The inside of the calculator consists of a main board with attached screen (with those lovely bubble LEDs) and a keyboard that attaches with spikes around the edge.



The only restoration I did was clean those spikes with some sandpaper and alcohol. But the calculator needed a battery cover. It's a fairly simple design so I whipped one up in OpenSCAD with the following code:

difference() {
    union() {
        linear_extrude(1) square([50.5, 32], true);
        translate([-22.75,0,-1])  linear_extrude(1) 
            square([5, 29], true);
        translate([23.75,0,-2.5]) linear_extrude(3) 
            square([3, 29], true);
    }

    translate([-24.75,0,0]) linear_extrude(1) 
        square([1, 12], true);
}

translate([23.5,10.5,-2.5])  linear_extrude(1) square([4, 4]);
translate([23.5,-2,-2.5])    linear_extrude(1) square([4, 4]);
translate([23.5,-14.5,-2.5]) linear_extrude(1) square([4, 4]);

and then 3D printed it. 



The 3D print (on my Toybox printer) needs support material and has to be separated into two parts (the top part here is the support material that is discarded):


With four screws added the Rockwell 8R is finally whole again:


And can be placed in its protective, padded case for another 47 years of use:


If you like calculators you can read about my Commodore P50 (which I'm currently in the process of restoring also... I lost the battery cover for that too!)

2022-11-06

Primality testing on the Commodore P50 programmable calculator with one register and 23 steps

Partly because of when I started writing code (the 1970s), and partly because of money, a lot of my early coding was in very constrained environments. I've written before about programming some industrial machinery using a KIM-1. However, the most constrained environment I've coded on is the Commodore P50 programmable calculator in the late 1970s.

Its programming capabilities are very, very limited. There's a single 'register' (the standard memory function of the calculator) and only 24 steps (which are for the most part single presses of a key) are programmable. For example, if your program needs the constant 1234 that's four steps out of 24 taken up!


It was great for writing a program that is just a function that you need to evaluate for multiple values of x. For example, you can store the function sin(1/x) like this:

   lrn
   1/x
   SIN
   R/S
   GOTO 00
   
lrn

And then enter a number and press R/S to evaluate sin(1/x). lrn puts the calculator in programming mode and then can accept up to 24 keystrokes. R/S causes the program to terminate. 

Adding in line numbers shows that the GOTO takes the program back to the start. This is done because if you run a program and hit R/S again it continues where it left off which could result in an error if the program previously terminated in the middle somewhere.

      lrn
   00 1/x
   01 SIN
   02 R/S
   03 GOTO
   04 00
      
lrn

Notice how GOTO 00 takes two of 24 steps!

Loops

You can easily write simple loops. For example, if you wanted to plot sin(1/x) for x starting at 0.001 in increments of 0.001 you'd write (STO stores a number in the memory, RCL gets it from memory)

      lrn
   00 0
   01 STO
   02 RCL
   03 +
   04 .
   05 0
   06 0
   07 1
   08 =
   09 STO
   10 1/x
   11 SIN
   12 R/S
   13 GOTO
   14 02
      lrn

This program uses the memory to store 0.001, 0.002, 0.003, ... and stops outputting sin(1/0.001), sin(1/0.002), sin(1/0.003), ... Hitting R/S obtains the next result.

Conditional branching

The calculator also has three conditional branch operations SKZ, SKN, SKP (skip zero, skip negative, skip positive) which simply skip the next instruction if the displayed number is zero, negative or positive. Here's a program that calculates x modulo y. x is the number on screen when the program is run and y should be stored in the memory beforehand.

Since  SKZSKNSKP only skip the next instruction they are most commonly followed by a GOTO somewhere else.

      lrn
   00 -
   01 RCL
   02 =
   03 SKN
   04 GOTO 
   05 00
   06 +
   07 RCL
   08 =
   09 R/S
   10 GOTO
   11 00
      lrn

This program runs extremely slowly even though it just does integer addition and subtraction. 89 modulo 5 takes almost 12 seconds to calculate. 

Is this number a prime?

But I'm not letting that deter me. Here's a complete program that returns 1 if the number being tested is prime, or returns a number that divides it if not.

The program divides the x by numbers from sqrt(x) to 2 looking for a divisor. 

      lrn
   00 RCL
   01 -
   02 INT
   03 *
   04 4
   05 10^x
   06 

   07 RCL
   08 INT
   09 -
   10 INT
   11 =
   12 SKZ
   13 GOTO 
   14 18
   15 RCL
   16 INT
   17 R/S
   18 1
   19 +/-
   20 M+
   21 GOTO
   22 00
      lrn

Unfortunately, it requires a little bit of set up by the user. Because the calculator has only one register (the memory) I am forced to store both the original number, x, being divided, and the current divisor, d, being tested in the memory. This is done by storing d + x/10000 in the memory. Thus the program only works to test numbers up to 9,999 (it can easily be extended by changing the number in step 4 above).

Lines 00 to 08 retrieve the number and trial divisor from memory and divides the former by the latter. Lines 09 to 12 determine whether the result is an integer or not (by subtracting the integer part of the result from itself). Lines 15 to 17 are where the program halts when a divisor is found. Lines 18 to 22 subtract one from the trial divisor and loop back to the start.

So, suppose the program is testing if 11 divides 198. The memory would contain 11.0198. Here's what's on screen at each program step (note that the display does not show anything when really running a program but will if you use the single step, SSTP, key) 

Since 11 does divide 198 the program will terminate at step 17.

   00 RCL               11.0198
   01 -                 11.0198
   02 INT               11
   03 *                  0.0198 
   04 4                  4
   05 10^x           10000
   06 
               198
   07 RCL               11.0198
   08 INT               11
   09 -                 18
   10 INT               18
   11 =                  0
   12 SKZ
   13 GOTO 
   14 18
   15 RCL               11.0198
   16 INT               11
   17 R/S               11
   18 1
   19 +/-
   20 M+
   21 GOTO
   22 00

Now, here's what happens when testing if 12 divides 198 (which it doesn't). The memory would contain 12.0198. Once again, here's the step by step.

   00 RCL               12.0198
   01 -                 12.0198
   02 INT               12
   03 *                  0.0198 
   04 4                  4
   05 10^x           10000
   06 ➗                198
   07 RCL               12.0198
   08 INT               12
   09 -                 16.5
   10 INT               16
   11 =                  0.5
   12 SKZ
   13 GOTO 
   14 18
   15 RCL               
   16 INT               
   17 R/S               
   18 1                  1
   19 +/-               -1
   20 M+                -1
   21 GOTO
   22 00

This time the SKZ doesn't happen so the GOTO 18 occurs. The memory is decremented by 1 and the program loops back to the start with 11.0198 in memory.

To use the program the operator needs to store the number being tested and its square root in the memory. Thus they need to perform the following to set up the memory correctly after entering the number they want tested.

   STO
   √x
   INT 
   *
   4
   10^x
   =
   M+
   4
   +/-
   10^x
   Mx

They can then hit R/S and wait... a long time. For example, determining if 199 is prime (it is) takes... 1m44s.


But, at least I know it is possible to fit a primality testing program in 23 steps with a single register.

2022-10-31

The hidden "code" inside 2-XL's space age noises

The other day I posted about getting my old 2-XL toy working again. In that post I had a short video clip of 2-XL operating. Listening to the clip after I blogged I suddenly thought "that sounds like RTTY or FSK" and instantly wondered if it was decodable.

If you're unfamiliar with RTTY or FSK then (a) it's time you went off and got your amateur radio license and (b) here's a quick primer.

FSK means "frequency shift keying". It's a way of sending data that uses two levels (0 or 1, or mark or space in the jargon). Data is encoded in some format (e.g. Baudot code or ASCII) and then sent using those two levels as audio or radio. One such radio format is RTTY which I messed around with in the past when sending up a high-altitude balloon.

I grabbed an audio file version of the clip of 2-XL and fed it into Fldigi to see if I could get an instant decode. No such luck. But I shoved the file into Audacity and took a look at the spectrum and there are two distinct peaks:


Which made me think it looked even more like FSK with a gap between frequencies of about 500Hz. 

Switching the audio file itself into Spectrum mode was a real "a ha" moment because that looks a lot like two frequencies being used to send data with a regular period. Measuring that period it looks like the time for a single symbol is about 60ms (which would correspond to a data rate of 16.67 baud).

Aside: typically RTTY uses a 170Hz gap rather than 500Hz, a data rate of 45.45 baud rather than 16.67 baud, and the typical upper frequency would be 1447Hz rather than what looks like around 3300Hz. Nevertheless this does look like data transmission with FSK and could be some RTTY or ASCII variant.


Zooming in a bit you can see this more clearly.


Here's what a clean RTTY signal might look like:


So, I went ahead and turned this into a stream of 1s and 0s, assume that the upper frequency is 1 and the lower 0.


which gave me:

011010110110011101101111011000001110100011100100111010011010001011101010111001101110111010101110101010011110010111101001101000

Since I don't know what format this is I went hunting for start and stop bits by breaking this string at various widths. e.g. standard RTTY would be 1 start + 5 data + 1 stop bit, ASCII might be transmitted as 1 start + 7 data + 1 stop. And there are many other variants.

Breaking at 8 bits I get

01101011
01100111
01101111
01100000
11101000
11100100
11101001
10100010
11101010
11100110
11101110
10101110
10101001
11100101
11101001
101000

You can quickly see that there's an entire column of zeroes and an entire column of ones (which I have highlighted). A very common format is 1 start bit (0) + data + 1 stop bit (1). So adjusting to start with 0 and end with 1 I get:

     011
01011011
00111011
01111011
00000111
01000111
00100111
01001101
00010111
01010111
00110111
01110101
01110101
01001111
00101111
01001101
000

It's very common for data to be sent LSB first so removing the start, stop bits and reversing the data I get:

10
101101
101110
101111
110000
110001
110010
011001
110100
110101
110110
010111
010111
111001
111010
011001
    00

And a pattern emerges. The data seems to be counting up with some interruptions. But the counting doesn't seem to break down even with the interruptions.

10
101101 45
101110 46
101111 47
110000 48
110001 49
110010 50 
011001 25
110100 52
110101 53
110110 54
010111 23
010111 23
111001 57
111010 58
011001 25
    00

Why this pattern? I don't know. Anyone have an idea? Why six bits? Teletypesetter code? 6-bit BCD? If this had just counted up then I would have dismissed it as test data. But why those breaks?


2022-10-30

Childhood toys: 40 years on 2-XL works just fine

Sitting and literally gathering dust on a shelf has been my childhood 2-XL toy. A few years ago I turned it on and it seemed to work but then it went back on the shelf. Today I sorted out a power supply for it (it needs 9V through a 3.5mm jack with +ve through the tip). 


2-XL uses an 8 track audio cassette with carefully arranged tracks to make it seem like it's intelligent and responding to input via the four buttons. Those four buttons are simply changing tracks but it's enough to allow 2-XL to ask questions and respond to your response. Where necessary there are interludes of space age sounds and even 2-XL telling jokes or whistling a tune. 

My 2-XL appears to date from 1978 and is a curious toy because many of the questions are about US culture in 1978. Must have been very hard to answer some of the questions at the time in the UK (e.g. at one point 2-XL hums the tune of The Andy Griffith Show which apparently ended in 1968!). Even 8 track players were an oddity in 1978 UK.

The only "repair" 2-XL needed was some isopropyl alcohol dripped into the volume control potentiometer (bottom left in the picture above). I used an insulin syringe to get the alcohol in there and this fixed annoying static/crunchy sounds when adjusting the volume.

On opening 2-XL by removing 13 screws I was ready for an internal mess and had the air duster ready. But the insides were pretty clean for something 44 years old.

I don't put this down to care taken with the toy. It's more down to the 13 screws and lip around the two edges that mean they connect tightly, the spring loaded flap on the 8 track door, and the material that covers the speaker grille on the back.

Here's close up of the 8 track mechanism showing just how well it's lasted.

Here's a little taste of 2-XL in action