Frost on a roof

#DIY

New ZX Spectrum 48K

The original Issue 3 board, with some labels explaining the functions of the components. I got this board of a Sinclair ZX Spectrum. It must have been a ZX Spectrum Plus model before, because there was this reset wire attached to it. There were also a few labels that were explaining the functionality of the components in German language, maybe for educational purposes.

I tried to run the diagnostics, but the module didn't even start, and the D0 LED was permanently dark. There must have been a short circuit somewhere on the data bus. But instead of repairing it, my plan was to make a completely new ZX Spectrum from as many new components as possible, with reusing only the ULA, CPU, LM1889N, the coil, and the RAM chips.

So I first removed the valuable components. The stripped original board was a sad sight, but the prospect of making a new Speccy from it made it less painful.

The board, with all valuable components stripped.

I checked the ULA in another Speccy, and it turned out to be fine. From the 16 RAM chips however, only 9 were still functional. This was much less than I expected. I'm having some of those old RAM chips in my stock, but they are precious and hard to find.

A New Board

The new board and some of the components. The new replica board is made by PABB and can be ordered from PCBWay.

For the required components, I assembled a bill of materials. It contains as many new components as I could find, but some rare parts are long out of production. They can still be found as NOS parts at online marketplaces, or they can be replaced with replacement types or replicas (like the Retroleum Nebula or vRetro vLA82).

There are four wire bridges that configure the type of the upper RAM chips, and the brand of the ROM chip manufacturer. The correct configuration can be found in my bill of materials as well.

Instead of the modulator, I decided to use an S-Video mod and a 3D printed base plate. A simple alternative is to just solder an RCA connector to COMP and GND, and use it as a composite output.

After a lot of soldering, the assembly was almost completed. But before seating the valuable chips, I first checked that all three voltages (+5V, +12V, -5V) were present and within their acceptable tolerance.

The replica board, with all components soldered in, but the chips are not seated into their sockets yet.

The S-Video mod takes the place of the original modulator, but is not soldered in, but held by two screws. The screws also provide ground, so they must not be isolating. Three wires then connect the board with +5V, and the composite signal as luma. The chroma signal is connected to the positive end of C65, which must be removed first so the luma and chroma signals won't mix.

The S-Video mod mounted in place.

After that, the new board was finally completed and ready for a first test.

The completed ZX Spectrum replica board with S-Video mod.

Bugfixing

But alas, this is what I was seeing when I powered it up for the first time.

This is what we don't want to see: black and white columns.

The diagnostics showed no action on the CPU bus controls. My suspicion was confirmed when I checked the clock input of the CPU with a scope. It was just a flat line:

The CPU clock is generated by the ULA, but the clock signal was present there.

A look into the schematics shows that between the ULA clock output and the CPU clock input there is the transistor TR3, probably for amplifying the signal. Strange enough, the signal was still present at the right of R24, which is directly connected to the clock output, but at the left of R24 (which is connected to the base of the transistor) the signal was missing already. When I removed TR3, the clock signal appeared there too, so TR3 must have been the cause.

After a longer search, I found out that the Spectrum is very picky about the type used for TR3. The original ZTX313 is not in production anymore, so I used a BC548 first, which is said to be a replacement type, however not at this position. For TR3, the only recommended replacement type is the MPS2369, which is also a bit hard to find now. With that type, the clock signal was finally good (cyan: ULA clock output, yellow: CPU clock input).

And to my joy, the new Spectrum finally started up and showed the famous start screen.

Hello there, Speccy!

The next step was to run a full diagnostics check. Now I got an error that the M1 signal was missing.

Diagnostics complains that the hardware was not found.

The M1 signal is generated by the CPU, and indicates the first of four machine cycles, which is the cycle where the next instruction is read from memory. The Spectrum itself does not use the M1 signal, but a few expansions like the ZX Interface 1 need it.

After replacing the CPU, all diagnostics checks finally passed.

We are green!

So at the bottom line, all I could reuse from the old ZX Spectrum was the ULA, the ROM, the LM1888N and the coil. I was hoping for the RAM chips and the CPU, but I haven't been really lucky with them.

Test Run

Anyway, it was finally time for a test run. I connected the new Speccy to my computer, and used tzxplay to play the tape file of my favorite game, Starquake. It was loading and running fine. Also, the image quality of the S-Video output is excellent, and probably the best one can get from this old design. Only the ZX Spectrum Next has a better quality with its native, pixel perfect HDMI output.

I bought the original board without any case. But luckily, there are replica cases, keymats, membranes, and faceplates on the market, so I could assemble a brand new outerior. Of course, I chose a transparent case, so the nice black mainboard could be seen from the outside. Well, at least a bit.

And there it is, an (almost) new ZX Spectrum in mint condition.

A new Harlequin

The Superfo Harlequin is a ZX Spectrum 128K clone. It is special because even though it's a 128K Spectrum, it still fits into an 48K Spectrum case. It's also special because the ULA custom chip is replicated by discrete 74HC-type standard chips that can be replaced easily if one of them should get broken. It's just a small advantage though, because the RAM chips, sound chip, and Z80 CPU are rare by now.

I have ordered the Harlequin 128K Black Large DIY Kit at ByteDelight. It comes with all components that are required to build the main board, even those that are difficult to find elsewhere. There is also a Flash ROM chip enclosed in the kit, but it does not contain a Sinclair ROM image for license reasons. What's still required to build a complete Speccy is a ZX Spectrum case with keyboard, and a Flash ROM programmer for the Sinclair ROM.

Assembling

The Harlequin has only a single SMD component, and that one was even presoldered. All the other components are through-hole, so this DIY kit is even suitable for soldering novices.

The ByteDelight Harlequin kit. Also on the photo: The Diag Cart kit, en heerlijke Stroopwafels. 😋 How it started. The board, with the only SMD part already presoldered.

I spent the rest of the day with getting the components out of their bags, locating their correct location and then soldering them in. The ByteDelight kit was carefully assembled. Every component comes in separate bags per value, and are enumerated in their optimal order for assembling. It's literally just soldering by numbers. 😄

The most boring part was to solder in all the 51 sockets. The DIY kit came with standard sockets, but I generally prefer turned pin sockets, so I used that ones instead.

Completely assembled.

The kit also contains the crystal that is needed for an NTSC setup, so you can choose between a PAL and NTSC machine. The board itself is pre-configured for PAL though. For an NTSC machine, a few traces at the bottom side of the PCB need to be cut.

Flashing the ROM

The DIY kit comes with an AMD AM29F040B Flash ROM. It is large enough to contain up to 8 ROM images. A DIP switch selects the image to be used. The pre-flashed image contains a Diag ROM, some other software, but no ZX Spectrum ROM for license reasons. The board itself also supports original Spectrum 48K and 128K ROMs, as well as 27C256 and 27C512 EPROMs.

ROM files can be found on the internet. I decided to keep the first six Flash ROM banks, and use bank 7 for a Spectrum 48K ROM, and bank 8 for a Spectrum 128K+2 ROM.

For flashing, I use the XGecu TL866II+ programmer and the minipro open source software. First I read the original content of the Flash ROM:

minipro --device 'am29f040b@DIP32' --read harlequin.bin

Then I made a copy of the first six banks. It's easy with the dd command. With a block size of 65536 bytes, the banks can be selected with the skip and count options. To keep the first six banks:

dd if=harlequin.bin of=harlequin-6banks.bin bs=65536 count=6

After that, I use cat to compile a new binary. Note that each bank must be 65536 bytes large, so if a ROM image is smaller, it must be duplicated (or quadruplicated):

cat harlequin-6banks.bin \
  48k.rom 48k.rom 48k.rom 48k.rom \
  128k+2.rom 128k+2.rom \
  > harlequin-new.bin

The new image can then be burned to the Flash ROM:

minipro --device 'am29f040b@DIP32' --write harlequin-new.bin

With the Flash ROM inserted into the Harlequin board, it was finally completed and ready for a first start. Unfortunately the maker of the Harlequin board saved a rectifier bridge, so it's still important to take care for the correct polarity of the power plug. Like the ZX Spectrum, the Harlequin needs a power supply with a 5.5/2.1 mm barrel plug with center negative. Most power supplys on the market are center positive.

The Harlequin is alive!

Even though the Harlequin has a lot more chips than an original ZX Spectrum, it is very frugal. It only consumes 1.7W at 9V, while the original Speccy consumes 4.8W. On the other hand, the Harlequin does not need 12V and -5V to run, so these voltages are not generated. This might be a problem for a few very exotic expansions.

The Case

The DIY kit only comprises everything that is needed to assemble the main board. What's missing is a case with keyboard, and a power supply. The board has the same dimension as an original ZX Spectrum 48K board, so you can use original cases (e.g. the standard "rubber key" case or the ZX Spectrum Plus case), or buy a new replica case with new membranes, keymat and faceplate. The latter case is more expensive, but you get a brand new case in return, and you can pick from a large variety of colors.

I decided for a white keyboard, and a transparent case so one can still admire the beautiful Harlequin board even inside a closed case.

A brand new ZX Spectrum 128K "Harlequin"!

The Harlequin has a separate RGB mini DIN connector. It is made in a manner so it won't interfere with a classic case. However you might want to use the RGB connector as it offers a much better image quality. Shops like ZX Renew offer special Harlequin cases with a cutout for the RGB connector. If you want to use a classic case, you might need to cut out a bit of the beautiful old case to access the connector.

From left to right: stereo audio, tape (mic/ear), RGB, composite

Since we are talking about making holes into old cases: The Harlequin has a built-in joystick interface. If you want to, you can cut out a space for a 9 pin Sub-D male connector, and wire it to the board. I refrained from making a cut into my beautiful Harlequin case, and use a classic Kempston joystick interface instead.

Let's Play

The simplest way to load software into the Harlequin is by the Mic/Ear port. There are smartphone apps and also a lot of tools that can generate the sounds to load TAP or TZX files, so there is no need to dig out the old tape recorder and audio cassettes.

I am using my tzxtools. The tzxplay command plays back TZX and TAP files to the standard audio output. I connect the sound card output to the mic/ear connector using a classic phone jack cable.

Since the Harlequin is a full-featured 128K clone, it also comes with an AY-3-8912 sound chip and even a stereo output. So the first thing I did was loading a game that makes use of that soundchip for in-game music.

The 128K version of Cybernoid uses the AY-3-8912 sound chip.

Thunderbolt and Lightning

 The Kaminari Lightning Detector Pyramid I recently found an article about the AS3935 Franklin Lightning Sensor. As I am already recording some weather data, it immediately raised my interest.

The sensor module can be found at many online shops selling products from China. It is not really cheap, but still affordable. I decided to use an ESP8266 as microcontroller, so I can read the sensor data by WLAN. The sensor is connected to the ESP via SPI. There was also some space left for a SK6812 RGBW LED indicating the sensor status.

The result of this project can be found at GitHub. It's called Kaminari (which is Japanese for lightning), and also comes with OpenSCAD files for a 3D printed, pyramid shaped case with illuminated tip. In this article I will explain a bit about how I developed the Kaminari firmware.

The first problem was the calibration. The sensor is roughly pre-calibrated, but must be fine-tuned to 500 kHz ±3.5% via the TUN_CAP register. For this purpose, the antenna frequency can be routed to the IRQ pin and then be measured by the ESP. I chose to prescale the frequency by a ratio of 128, giving an IRQ frequency of 3,906.25 Hz. For measurement, I've set an IRQ handler that is just counting up a variable on each interrupt. I then reset the counter, wait for 1000 ms, then read the counter, and get the IRQ frequency in Hz units. It's not 100% accurate, but good enough for this purpose.

The TUN_CAP register offers 16 calibration steps. Just incrementing it until the frequency matches, would take up to 16 seconds. Instead I used an algorithm called successive approximation to find the correct calibration value in only 4 iterations, taking a quarter of the time.

 The AS3935 connected to an ESP8266 To my disappointment, it turned out that the manufacturer of my module (CJMCU) has used nonstandard components, so my module could only reach a maximum frequency of about 491 kHz. I first suspected that the ESP might be too slow for this kind of measurement, but a scope connected to the IRQ pin confirmed the frequency. Well, it is still within the required tolerance, but it gives a suboptimal tuning result and renders the TUN_CAP register useless.

The next problem is finding a good noise floor level. This is some kind of background radio noise filter. If the level is too low, the sensor cannot operate properly because of interfering background noise. If it is set too high, the lightning detection quality declines.

The noise floor level cannot be calibrated just once at the start. Radio noise sources come and go, may it by turning on an electronic device or just by a change in the weather. I did some experiments, and the most promising solution is a kind of tug-of-war. When the AS3935 detects too much noise, it triggers an interrupt, and the noise floor level is raised to the next higher step. If the last level change was 10 minutes ago, the ESP attempts to reduce the level by one step.

In order to reduce the number of level changes, I have added a counter. Each noise interrupt increments the counter, and every 10 minutes the counter is decremented. The level is raised when the counter reaches 2, and lowered when the counter reaches -2.

Sometimes I noticed a "noise level runaway", where the AS3935 triggers a lot of noise interrupts in a very short time, raising the noise floor level to its maximum value immediately. To stop that behavior, further noise interrupts are being ignored for one minute after a noise interrupt has been processed.

Now the noise floor level has settled to an average of 95 µVrms here. In the graph, one can see that the level is raised at some time, but then reduced again after a while. One can also see the frequent attempts to lower the level a bit further, immediately followed by a raise back to the average level. It seems that the AS3935 and the ESP have negotiated a good compromise. 😉

The AS3935 seems to be set up in an optimal way now, but I still get some false lightning events from time to time. There are a few registers left to experiment with, namely WDTH (watchdog threshold), SREJ (spike rejection) and MIN_NUM_LIGH (minimum number of lightning). I have raised the watchdog threshold to 2, and did not have a false lightning event since then.

Now I have to wait for some real lightnings… 😄

Premium Wall Bias Lighting, Part 3

I haven't forgotten about you. Some private stuff kept me from completing this project for a while. To make it up, I have added OpenSCAD files for a 3D printed case.

The controller was a little tricky to complete, mostly because of the very different component heights. I decided to use two circuit boards that are stacked onto each other by headers.

On the upper board, there are only the two buttons and the LCD, as well as the transistor and resistor for the LCD backlight. As I only used one-layer TriPad strip boards, I had to use this one upside down for the male headers to point downward. This rather unconventional use made it a little tricky to solder the buttons and LCD headers on the actual bottom side of the board.

The soldered controller boards. The lower board contains all the other components, as well as the wiring. The rotary encoder also made it to the lower board, because it is much taller than the other buttons. This way, the top of the button caps are almost level and nice to look at.

The result is surprisingly compact for a DIY solution. The button caps and the LCD are just perfectly positioned for a case.

With plastic feet attached, you can use the controller as it is. You can also get a plastic case with transparent top, drill three holes in it for the button caps, and mount the sandwich with spacers. But if you have the chance, you should definitely go for a 3D printed case.

I have set up a project at GitHub. It contains the circuit diagram, the bill of materials, the firmware source code, and OpenSCAD files for a printed case. There is no firmware binary yet, as you need to adapt the source code to the length of your LED strip anyway.

You will find the OpenSCAD files for the case in the GitHub project. There are bonus OpenSCAD files in the project, for printing a customized case. Due to the absence of properly layouted PCBs, I am aware that each controller is going to look differently when finished. In the parameter.scad file, you can change all kind of parameters, so you should be able to make your individual case in, well, almost any case (silly pun intended). 😄

The SPI flash memory of the Feather M0 Express is not used yet. In a future release, I may add a settings menu for the LED strip size. The controller is also forgetting all its settings when disconnected from the power. This needs to be addressed in a future release as well.

But after all, this is a start for your own DIY wall bias lighting. Feel free to send pull requests for enhancements!

Again, remember that you must remove the jumper before connecting the Feather to an USB port, otherwise your computer will be damaged.

Premium Wall Bias Lighting, Part 2

The completed prototype on a breadboard In the first part, I have assembled a working proof-of-concept for my premium wall bias lighting. Thanks to CircuitPython, it just took a couple of minutes to program a light effect once the hardware was working.

Now it's time to extend the hardware to its final stage. I'd like to have a LC display that shows the current settings. A button and a rotary encoder allows to browse through different menus and change the parameters. And finally, the strip shall be switched on and off by an illuminated power button.

Thanks to the bread board, the components were quickly added and connected to the Feather with some wires. Polling the buttons is a basic functionality of CircuitPython. It was also incredibly easy to poll the rotary encoder, because CircuitPython already comes with a library for that.

It took a lot more time to set up the LC display. CircuitPython supports SPI out of the box, but the SSD1803A controller of the display uses a weird protocol. Each command byte must be split up into two nibbles (4 bits), which are packed into bytes again, with the bit order reversed. The SPI library does not offer support for it, so I had to do all this bit mangling in Python, which turned out to become a rather ugly piece of code.

But then, finally, a minimal version of the firmware was working. I could turn the light on and off, select between two light effects, and I could also control the brightness.

However the Feather often took long breaks, where it did not react on key presses for multiple seconds. I guess the reason for that is Python's garbage collector, which stops the world while it is collecting unused objects and freeing some memory. This was actually a pretty annoying behavior that rendered the controller unusable.

After I added a third light effect, I also started to run into frequent out of memory errors. It seems that I have reached the limits of what is technically possible with CircuitPython on a Feather.

Was my approach too ambitious?

Luckily it wasn't. The Feather can also be programmed in C++, using the well known Arduino IDE. It comes with a lot of libraries that are ready to use. It's all very lightweight and is looking very promising. So why did I use Python in first place? Well, it is because I wrote my last lines of C++ code about 20 years ago. 😅

Porting the existing Python code to C++ was easier than I had expected. The SPI library now even supports reversed bit order, so it was much easier to address the LC display. On the down side, I had to test several libraries until I found a reliable one for the rotary encoder.

The C++ code consumes a fraction of the Python code's memory, so there is a lot left for extensions. The garbage collection breaks are also gone now, so the controller instantly responds to key presses. And I haven't even used the Feather's SPI flash memory yet. 😀

I have added some more light effects, and menus for adjusting brightness, saturation, and color temperature. Everything is working as expected now. It's time to finish the prototype phase and draw a circuit diagram.

R2 is the series resistor for the power button LED. A green LED would need an 68 Ω resistor at 3.3 V. However the LED is directly connected to the Feather, so the current should not exceed 7 mA (maximum rating is 10 mA). A 500 Ω resistor limits the current to a safe value. If you need more current for a fancy power LED, you can use one of the three 74HCT125 drivers left, or add a transistor.

R3 is the series resistor for the LCD backlight. The manufacturer specifies a 27 Ω resistor when the backlight LEDs are connected in series and powered with 5 V. If you use a different backlight, change the resistor accordingly. The BC 548 transistor permits up to 100 mA in this configuration.

Remember: You must remove the jumper JP1 before connecting the Feather to an USB port, or your computer will be damaged.

In the next part, I'm going to grab my soldering iron and build a final version. It's high time. The many wires on the breadboard prototype are annoying when operating the rotary encoder. Also its pins are too short and are often disconnecting from the breadboard when I use it.