Wire wrap

The lost ancient art of wire wrapping.

{funny story]
In 2019 i wanted to make a simple probe, which could detect 0 or 1 or a pulse. I wanted to make this on a little print using wirewrap wires and IC sockets. (I still have the tool which i used in the 90s.)
When going to a well-known electronics shop in Den Hague. A great shop to get all kinds of oldskool electronics. But i’m getting ahead of the story.
This shop has a lot of components for all kinds of electronics. New and what it looked like de-soldered component from boards or bought from old going-out-of-business shops or factories. Stuff you needed for 60s equipment.
Well i was at the counter, asking a old guy.
“Do you have wire-wrap wire”
He said: ” No that’s old skool” ….
{/funny story]

The wirewrap tool has a cable stripper. After stripping you would put a short part in the tool, place the tool over a IC pin and turning would wrap the wire on the pins.
You could stack multiple connections on one pin.
Removing could be done by turning the tool counterclockwise.
Sometimes you had to remove the one closest to the print, replacing all wires. (Or cut the wrong/not needed wire and leave it in place … )

I’m thinking of moving my breadboard 6502 to a wirewrapped version.
All my old boards are gone .. before i got a digital camera .. 🙁

Example from a 8031 setup of a friend of mine

6502 progress

Altered clock module

  • Changed button press
  • Dipswitches for more speed control (red .. upper left)

Changed Rom/Ram

  • Changed addressing
  • Added RAM
  • ZIF Socket for ROM

VIC 6522

  • Fixed clock


  • Display works now
  • To test: Create Address logic to access display without VIA
  • To buy: st7920 lcd 128×64

Generic improvements

  • Rewired most parts, using color codes
    (Blue data, Yellow Address and so on)
  • Added leds on data and address bus using ULN2803 darlington arrays
  • 100nF Decoupling capacitors on the power rails

To do’s or ‘have to look into’s’

  • For sound i planned to use a General Instrument AY-3-8910, it is somewhere in my Lab, i know it is.
    Where are my plans for the simple v1 setup?
  • I have to start writing rom functions for display usage. Like
    JSR $ff00 – Clear screen subroutine .. etc
  • I’m scraping information from websites, to get started on my clock controller.
    ATmega328 with ssd1306 display and rotary encoder

Notes about the movie:
Left side is Arduino IDE monitor reading Addressbus and Databus.
(I’m going to try to rewrite this to realtime disassemble)
Resetting system.
Stepping CPU with manual clock pulses.
Start vector being read at $FFFC/$FFFD.
Program being run from $8000.
Set clock on automatic ( ~ about 150 Hz )
Last opcodes you see a JMP loop 4C 2F 80, that is JMP $802F
Display enlarged on video, was not visible on movie i took on mobile.
(Wrong angle?)

Breadboard overview

Clock moduleReset module
Address decode + Bus divideAddres/Data bus leds
6522 VIA + Display(sound board)
(Hex keyboard)More I/O?

TIL: 6502 can run without ram only rom,expect when using JSR … which uses a program stack in RAM

C64 PRG to cartridge.

I’ve got the tools and Bigred made me enthusiastic again.
My goal is to make a C64 Cartridge from a PRG. And Not any program, it is the 8085 Emulator from Sepp.

Serveral problems i have to ‘fix’

  • The program is 17K, Cartridges can only be 16K.
    So i have to use 2x 8K and compress the data.
    This means it have to be uncompressed at start time.
    ( I was thinking of using exomiser for this )
  • Program starts normally at $0820 and probably is not optimised to run anywhere else.
    So a starting routine has to copy the program from cartridge memory to the correct location

Luckily i have the source! How cool is that

For version 4.73 it states : Starting at $0820 .. but my hexdump is off by one??!?

root@battlestation:/home/fash/Projects/minipro# hexdump -C /tmp/8085.prg  | head
00000000  01 08 1e 08 c5 07 9e 32  30 38 30 20 42 59 20 4d  |.......2080 BY M|
00000010  41 52 54 49 4e 20 4d 45  59 45 52 49 4e 4b 00 00  |ARTIN MEYERINK..|
00000020  00 20 ec 08 20 7f 19 20  2b 2c 20 11 19 20 b8 08  |. .. .. +, .. ..|
00000030  20 20 2c 20 a0 2c 20 f2  2c 20 11 e1 4c 00 15 aa  |  , ., ., ..L...|
00000040  aa a2 06 ad b7 08 9d 48  d8 bd 48 04 20 88 39 9d  |.......H..H. .9.|
00000050  48 04 ca 10 ee a9 60 8d  4c 04 4c 50 47 00 a9 d0  |H.....`.L.LPG...|
00000060  2c a9 f0 8d 45 1f 4c 11  e1 1e 93 0d 20 20 4d 41  |,...E.L.....  MA|
00000070  52 54 49 4e 20 4d 45 59  45 52 49 4e 4b 27 53 0d  |RTIN MEYERINK'S.|
00000080  0d 20 38 30 38 35 20 45  4d 55 4c 41 54 4f 52 20  |. 8085 EMULATOR |
00000090  20 56 34 2e 38 30 0d 0d  20 20 28 43 29 20 31 20  | V4.80..  (C) 1 |

00000020 00 20 ec starts with 00 at $0020 .. and not 20 ?!?!

Tools used until now:

  • Vice – C64 Emulator
    x64 -cartcrt 8085.crt
  • c1541 – Linux disk tool for C64 images.
    Used this to extract the 8085emulator PRG
  • prg2crt.py – a convertor from PRG to a cartrid file which can be used by Vice
    python2 prg2crt.py 8085.prg 8085.crt
  • minipro – eeprom programming tool for Linux
    minipro -p AT28C64 -w /tmp/test.bin
  • cartconv (tool from vice to convert crt <-> bin)
    cartconv -t normal -i test.bin -n ‘my cart’ -o test.crt
  • xa – Cross assembler 65xx/R65C02/65816
  • ACME – the ACME Crossassembler for Multiple Environments
Memory Map C64 – source c64-wiki.com

Card Low starts at $8000, so that’s the place where those roms are going to be.
To place on this address:

Copy routine : from ($8000 + this copy routine) to $0820
When to decompress??
jmp routine to $0820

A cartridge file >16K and with his emulation headers seems to work??!

Also nice: Magic Desk Cartridge Generator V3.0

UPDATE: 20220811

exomizer sfx 0x0820 8085.prg -o data.exo # Compress and start at 0x0820 
xa frame.asm -o frame.bin # Add code and write binary
x64 --cart16 frame.bin # Test cartridge with Vice


; example usage
; xa frame.asm -o frame.bin
; cartconv -t normal -i frame.bin -n 'my cart' -o frame.crt
; x64 -cartcrt frame.crt

;no load-adress for bin-file, so no header here

.word launcher ;cold start
.word launcher ;warm start
.byte $c3	;c
.byte $c2	;b
.byte $cd	;m
.byte $38	;8
.byte $30	;0

  stx $d016
  jsr $fda3	;prepare irq
  jsr $fd50	;init memory
  jsr $fd15	;init i/o
  jsr $ff5b	;init video
                ;make sure this sets up everything you need,
                ;the calls above are probably sufficient
  ldx #$fb

;set up starting code outside of cartridge-area
  ldx #(starter_end-starter_start)
  lda starter_start,x
  sta $100,x
  bpl loop1
  jmp $100
  ldx #$40 ;64 pages = 256 * 64 = 16384 Bytes
  ldy #0
  lda exomized_data,y
  sta $801,y
  bne loop
  inc src+2-starter_start+$100 
  inc dst+2-starter_start+$100
  bpl loop

;make sure settings for $01 and IRQ etc are correct for your code
;remember THIS table from AAY64:

;       Bit+-------------+-----------+------------+
;       210| $8000-$BFFF |$D000-$DFFF|$E000-$FFFF |
;  +---+---+-------------+-----------+------------+
;  | 7 |111| Cart.+Basic |    I/O    | Kernal ROM |
;  +---+---+-------------+-----------+------------+
;  | 6 |110|     RAM     |    I/O    | Kernal ROM |
;  +---+---+-------------+-----------+------------+
;  | 5 |101|     RAM     |    I/O    |    RAM     |
;  +---+---+-------------+-----------+------------+
;  | 4 |100|     RAM     |    RAM    |    RAM     |
;  +---+---+-------------+-----------+------------+
;  | 3 |011| Cart.+Basic | Char. ROM | Kernal ROM |
;  +---+---+-------------+-----------+------------+
;  | 2 |010|     RAM     | Char. ROM | Kernal ROM |
;  +---+---+-------------+-----------+------------+
;  | 1 |001|     RAM     | Char. ROM |    RAM     |
;  +---+---+-------------+-----------+------------+
;  | 0 |000|     RAM     |    RAM    |    RAM     |
;  +---+---+-------------+-----------+------------+

  lda #$35 ;cart is always on instead of BASIC unless it can be switched off via software
  sta $01
  jmp $80d ;for exomizer, i.e.

.bin 2,0,"data.exo"
;syntax for exomizer 2.0.1:
;exomizer sfx sys game.prg -o data.exo
;fill up full $4000 bytes for bin file ($c000-$8000=$4000)
.dsb ($c000-main_file_end),0

Exomiser info

 Reading "8085.prg", loading from $0801 to $4CE9.
 Crunching from $0801 to $4CE9.
Phase 1: Instrumenting file
 Length of indata: 17640 bytes.
 Instrumenting file, done.

Phase 2: Calculating encoding
 pass 1: optimizing ..
  size 80273.0 bits ~10035 bytes
 pass 2: optimizing ..
  size 80039.0 bits ~10005 bytes
 pass 3: optimizing ..
 Calculating encoding, done.

Phase 3: Generating output file
 Encoding: 1101112133423160,1122,2010223445667788,032144406789BBCD
 Length of crunched data: 10034 bytes.
 Crunched data reduced 7606 bytes (43.12%)
 Target is self-decrunching C64 executable,
 jmp address $0820.
 Writing "data.exo" as prg, saving from $0801 to $304C.
Memory layout:   |Start |End   |
 Crunched data   | $07E7| $2F18|
 Decrunched data | $0801| $4CE9|
 Decrunch table  | $0334| $03D0|
 Decruncher      | $00FD| $01C0| and $9F,$A7,$AE,$AF
 Decrunch effect writes to $DBE7.
Decruncher:  |Enter |During|Exit  |
 RAM config  |   $37|   $37|   $37|
 IRQ enabled |     1|     1|     1|

Altair 8800

After a whole day soldering yesterday, ending up with a wire mess.
Which didn’t work at the end…

Starting measuring some things, and create some test sketches (led blinky tests)
I found out that the main problem was not having the red switches connected to GND.
Blue switches where upside down, this was a easy fix. Because these are ON-ON switches, and where already connected to a common line.
Then a mixup between D0 and D6 (wires crossed)
And it is working! Made some lines and lettering on the frontplate after some playing around.

Weird to input stuff in octal (group of 3 bits)

Finding files on my fileserver

I use several tools to find files on my server.

Loads of stuff on my main fileserver.
(Graph is a great tool called DUC) https://duc.zevv.nl/

Besides a search engine, i have a file finder.
Due to the massive amount of data, i like to find things by other means than knowing the directory structure.

I can find files by filename, but also by contents.

I’ll talk about find by contents first.

I’ve got loads of documents in Pdf, HTML, txt, doc, sheets , wordperfect etcetera.
Those documents i can find using a tool named Namazu.
This is quite a old tool, but i’m using it for a long time and it still works great.
I didn’t find a better replacement yet.
(But i’ve been looking into : elasticsearch, Solr, Lucene)

http://www.namazu.org/ is easy to install, but if you want the tool to scrape different kinds of documents you have to add some additional software.

My multipurpose printer can scan pages in pdf.
Those are only embedded jpg’s in a pdf container.
I will talk about how i handle these later.

My current start page :
This index contains 267,763 documents and 14,036,762 keywords.
Search example of namazu

Some things to consider when implementing namazu:

  • tweak the file types to scrape, it makes no sense to scrape binaries
  • tweak the directories to scrape (example below)
    • 0 1 * * 1 fash /usr/bin/mknmz -f /etc/namazu/mknmzrc –output-dir=/namazu/ /mnt/private/paperwork/ /mnt/private/information/ /mnt/private/Art\ en\ hobby\ Projects/ /mnt/private/Music\ Projects/ /mnt/private/bagpipe-music-writer/ –exclude=XXX –exclude=/mnt/binaries > /tmp/namazu.log 2>&1
  • you can set a parameter in the config for search only, this disables downloading the found link in the results!

Before Namazu i used HtDig.

Screenshot htdig

HtDIg also can scrape remote websites, Namazu can’t.

Preparing PDF for indexing:

I’ve written some scripts to make PDFs containing scanned text scrape-able.
( https://gitlab.com/fash/inotify-scanner-parser )
What it does:

  • My scanner puts a scanned pdf on my fileserver in a certain directory
  • Inotify detects a written file
  • it will copy the file, run OCR on it (tesseract) and writes a txt file (scapeable)
  • After that the text will be embedded (overlay) on the PDF, so now it becomes searchable/scrapeable
  • When certain keywords are found, it will sort documents in subdirs
Example from a scanned jpg, i can find OCR words!
(note .. the overlay is exact on the found words)

Finding files by name:

For finding files a made a little webpage like this:

It is a simple webpage grabbing through a list of files.
It takes the first keyword and does a grep, it takes a second keyword to match also.
I can select different file databases to search. (This case is private)
Between search and private i can give the number of entries to print.
So i can do
Search “ansible” NOT “tower” 50 entries from the public fileset


20 5 * * * /usr/bin/find /mnt/shark*  > /var/www/html/findfiles/sharkoon
10 4 * * * /usr/bin/find /tank/populair > /var/www/html/findfiles/populair
20 4 * * * /usr/bin/find /tank/celtic > /var/www/html/findfiles/celtic

And a php script (dirty fast hack, never came around it to make it a final version)

<font face="Tahoma"><small>|keyword|(keyword)|search|(nr results)|NOT SECOND KEYWORD|share|</small><BR>
Search: <form method="post" action="/findfiles/?"><input type="Text" name="words" size=10 value=""><input type="Text" name="words2" size=10 value=""><input type="Submit" name="submit" value="search"><input type="Text" name="nrlines" size=3 value=""><input type="checkbox" name="not" unchecked>
<SELECT NAME=findfile>
<OPTION VALUE=private>private
<OPTION VALUE=celtic>celtic
<OPTION VALUE=populair>populair
<OPTION VALUE=dump>public
<OPTION VALUE=sharkoon>sharkoon

if ($words2=="xsearch") { $findfile="other"; $words2=""; }
if ($nrlines) {  } else { $nrlines=100; }
if ($words && $words2=="") {
$words = preg_replace("(\r\n|\n|\r)", "", $words);
$words = preg_replace("/[^0-9a-z]/i",'', $words);
$command = "/bin/cat $findfile |/bin/grep -i $words |head -$nrlines";
$blah=str_replace($words, "<b><font color=red>$words</font></b>",$blah);
print $blah;
if (($words) and ($words2)) {
$words = preg_replace("(\r\n|\n|\r)", "", $words);
$words = preg_replace("/[^0-9a-z.]/i",'', $words);
$words2 = preg_replace("(\r\n|\n|\r)", "", $words2);
$words2 = preg_replace("/[^0-9a-z.]/i",'', $words2);
if ($not=="on") {
$command = "/bin/cat $findfile |/bin/grep -i $words | /bin/grep -iv $words2 |head -$nrlines";
} else {
$command = "/bin/cat $findfile |/bin/grep -i $words | /bin/grep -i $words2 |head -$nrlines";
$blah=str_replace($words, "<b><font color=red>$words</font></b>",$blah);
$blah=str_replace($words2, "<b><font color=red>$words2</font></b>",$blah);
print $blah;

Altair 8800

The Altair 8800 is a microcomputer designed in 1974 by MITS and based on the Intel 8080CPU. Interest grew quickly after it was featured on the cover of the January 1975 issue of Popular Electronics and was sold by mail order through advertisements there, in Radio-Electronics, and in other hobbyist magazines.

(picture from wikipedia)

UPDATE: 20220804 – Added Octal sheet

I alway loved the simple setup of this computer.
There was no screen and no keyboard.
Only later additions to the machine provided these.

One explanation of the Altair name, is that the name was inspired by Star Trek episode “Amok Time“, where the Enterprise crew went to Altair (Six).

There are only a few differences between the used 8080 CPU and the 8085 CPU of a machine i learned machinecode on.

See : https://www.henriaanstoot.nl/1989/01/01/8085-machinecode-at-school/

So for a really long time i wanted to have a Altair alike machine. There are do it yourself kits for sale. Which look like perfect relica’s and there are virtual machines and emulators. But i wanted to have the feeling of throwing the switches.
You can find a emulator here (https://s2js.com/altair/)

So i bought the components, a poker case which can hold the machine. And started building today.

The backend is a arduino based emulator, but with real leds and switches!

Next to do:

  • Fix plate into case
  • Solder a LOT of wires and components!
    • Shall i get rid off the transitors and use darlington arrays?
  • Put lettering on the aluminium plate : Functions and Bus information.
  • Build a power connector in the case

And then … programming 🙂

UPDATE: 20220804 – Added Octal sheet

The Altair is a octal based machine, but i couldn’t find a opcode list in Octal. So i generated one.
When entering a MOV D,M instruction for example, you have to enter
x 0 1 0 1 0 1 1 0 using the switches
Thats 126 in octal but most tables are in hex ( MOV D,M is 56, which is 0101 0110 but not that clear on the switches)

Opcode (oct)InstructionfunctionsizeflagsOpcode
001LXI B,D16B <- byte 3, C <- byte 230x01
002STAX B(BC) <- A10x02
003INX BBC <- BC+110x03
004INR BB <- B+11Z, S, P, AC0x04
005DCR BB <- B-11Z, S, P, AC0x05
006MVI B, D8B <- byte 220x06
007RLCA = A << 1; bit 0 = prev bit 7; CY = prev bit 71CY0x07
011DAD BHL = HL + BC1CY0x09
012LDAX BA <- (BC)10x0a
013DCX BBC = BC-110x0b
014INR CC <- C+11Z, S, P, AC0x0c
015DCR CC <-C-11Z, S, P, AC0x0d
016MVI C,D8C <- byte 220x0e
017RRCA = A >> 1; bit 7 = prev bit 0; CY = prev bit 01CY0x0f
021LXI D,D16D <- byte 3, E <- byte 230x11
022STAX D(DE) <- A10x12
023INX DDE <- DE + 110x13
024INR DD <- D+11Z, S, P, AC0x14
025DCR DD <- D-11Z, S, P, AC0x15
026MVI D, D8D <- byte 220x16
027RALA = A << 1; bit 0 = prev CY; CY = prev bit 71CY0x17
031DAD DHL = HL + DE1CY0x19
032LDAX DA <- (DE)10x1a
033DCX DDE = DE-110x1b
034INR EE <-E+11Z, S, P, AC0x1c
035DCR EE <- E-11Z, S, P, AC0x1d
036MVI E,D8E <- byte 220x1e
037RARA = A >> 1; bit 7 = prev bit 7; CY = prev bit 01CY0x1f
041LXI H,D16H <- byte 3, L <- byte 230x21
042SHLD adr(adr) <-L; (adr+1)<-H30x22
043INX HHL <- HL + 110x23
044INR HH <- H+11Z, S, P, AC0x24
045DCR HH <- H-11Z, S, P, AC0x25
046MVI H,D8H <- byte 220x26
051DAD HHL = HL + HI1CY0x29
052LHLD adrL <- (adr); H<-(adr+1)30x2a
053DCX HHL = HL-110x2b
054INR LL <- L+11Z, S, P, AC0x2c
055DCR LL <- L-11Z, S, P, AC0x2d
056MVI L, D8L <- byte 220x2e
057CMAA <- !A10x2f
061LXI SP, D16SP.hi <- byte 3, SP.lo <- byte 230x31
062STA adr(adr) <- A30x32
063INX SPSP = SP + 110x33
064INR M(HL) <- (HL)+11Z, S, P, AC0x34
065DCR M(HL) <- (HL)-11Z, S, P, AC0x35
066MVI M,D8(HL) <- byte 220x36
067STCCY = 11CY0x37
071DAD SPHL = HL + SP1CY0x39
072LDA adrA <- (adr)30x3a
073DCX SPSP = SP-110x3b
074INR AA <- A+11Z, S, P, AC0x3c
075DCR AA <- A-11Z, S, P, AC0x3d
076MVI A,D8A <- byte 220x3e
100MOV B,BB <- B10x40
101MOV B,CB <- C10x41
102MOV B,DB <- D10x42
103MOV B,EB <- E10x43
104MOV B,HB <- H10x44
105MOV B,LB <- L10x45
106MOV B,MB <- (HL)10x46
107MOV B,AB <- A10x47
110MOV C,BC <- B10x48
111MOV C,CC <- C10x49
112MOV C,DC <- D10x4a
113MOV C,EC <- E10x4b
114MOV C,HC <- H10x4c
115MOV C,LC <- L10x4d
116MOV C,MC <- (HL)10x4e
117MOV C,AC <- A10x4f
120MOV D,BD <- B10x50
121MOV D,CD <- C10x51
122MOV D,DD <- D10x52
123MOV D,ED <- E10x53
124MOV D,HD <- H10x54
125MOV D,LD <- L10x55
126MOV D,MD <- (HL)10x56
127MOV D,AD <- A10x57
130MOV E,BE <- B10x58
131MOV E,CE <- C10x59
132MOV E,DE <- D10x5a
133MOV E,EE <- E10x5b
134MOV E,HE <- H10x5c
135MOV E,LE <- L10x5d
136MOV E,ME <- (HL)10x5e
137MOV E,AE <- A10x5f
140MOV H,BH <- B10x60
141MOV H,CH <- C10x61
142MOV H,DH <- D10x62
143MOV H,EH <- E10x63
144MOV H,HH <- H10x64
145MOV H,LH <- L10x65
146MOV H,MH <- (HL)10x66
147MOV H,AH <- A10x67
150MOV L,BL <- B10x68
151MOV L,CL <- C10x69
152MOV L,DL <- D10x6a
153MOV L,EL <- E10x6b
154MOV L,HL <- H10x6c
155MOV L,LL <- L10x6d
156MOV L,ML <- (HL)10x6e
157MOV L,AL <- A10x6f
160MOV M,B(HL) <- B10x70
161MOV M,C(HL) <- C10x71
162MOV M,D(HL) <- D10x72
163MOV M,E(HL) <- E10x73
164MOV M,H(HL) <- H10x74
165MOV M,L(HL) <- L10x75
167MOV M,A(HL) <- A10x77
170MOV A,BA <- B10x78
171MOV A,CA <- C10x79
172MOV A,DA <- D10x7a
173MOV A,EA <- E10x7b
174MOV A,HA <- H10x7c
175MOV A,LA <- L10x7d
176MOV A,MA <- (HL)10x7e
177MOV A,AA <- A10x7f
200ADD BA <- A + B1Z, S, P, CY, AC0x80
201ADD CA <- A + C1Z, S, P, CY, AC0x81
202ADD DA <- A + D1Z, S, P, CY, AC0x82
203ADD EA <- A + E1Z, S, P, CY, AC0x83
204ADD HA <- A + H1Z, S, P, CY, AC0x84
205ADD LA <- A + L1Z, S, P, CY, AC0x85
206ADD MA <- A + (HL)1Z, S, P, CY, AC0x86
207ADD AA <- A + A1Z, S, P, CY, AC0x87
210ADC BA <- A + B + CY1Z, S, P, CY, AC0x88
211ADC CA <- A + C + CY1Z, S, P, CY, AC0x89
212ADC DA <- A + D + CY1Z, S, P, CY, AC0x8a
213ADC EA <- A + E + CY1Z, S, P, CY, AC0x8b
214ADC HA <- A + H + CY1Z, S, P, CY, AC0x8c
215ADC LA <- A + L + CY1Z, S, P, CY, AC0x8d
216ADC MA <- A + (HL) + CY1Z, S, P, CY, AC0x8e
217ADC AA <- A + A + CY1Z, S, P, CY, AC0x8f
220SUB BA <- A – B1Z, S, P, CY, AC0x90
221SUB CA <- A – C1Z, S, P, CY, AC0x91
222SUB DA <- A + D1Z, S, P, CY, AC0x92
223SUB EA <- A – E1Z, S, P, CY, AC0x93
224SUB HA <- A + H1Z, S, P, CY, AC0x94
225SUB LA <- A – L1Z, S, P, CY, AC0x95
226SUB MA <- A + (HL)1Z, S, P, CY, AC0x96
227SUB AA <- A – A1Z, S, P, CY, AC0x97
230SBB BA <- A – B – CY1Z, S, P, CY, AC0x98
231SBB CA <- A – C – CY1Z, S, P, CY, AC0x99
232SBB DA <- A – D – CY1Z, S, P, CY, AC0x9a
233SBB EA <- A – E – CY1Z, S, P, CY, AC0x9b
234SBB HA <- A – H – CY1Z, S, P, CY, AC0x9c
235SBB LA <- A – L – CY1Z, S, P, CY, AC0x9d
236SBB MA <- A – (HL) – CY1Z, S, P, CY, AC0x9e
237SBB AA <- A – A – CY1Z, S, P, CY, AC0x9f
240ANA BA <- A & B1Z, S, P, CY, AC0xa0
241ANA CA <- A & C1Z, S, P, CY, AC0xa1
242ANA DA <- A & D1Z, S, P, CY, AC0xa2
243ANA EA <- A & E1Z, S, P, CY, AC0xa3
244ANA HA <- A & H1Z, S, P, CY, AC0xa4
245ANA LA <- A & L1Z, S, P, CY, AC0xa5
246ANA MA <- A & (HL)1Z, S, P, CY, AC0xa6
247ANA AA <- A & A1Z, S, P, CY, AC0xa7
250XRA BA <- A ^ B1Z, S, P, CY, AC0xa8
251XRA CA <- A ^ C1Z, S, P, CY, AC0xa9
252XRA DA <- A ^ D1Z, S, P, CY, AC0xaa
253XRA EA <- A ^ E1Z, S, P, CY, AC0xab
254XRA HA <- A ^ H1Z, S, P, CY, AC0xac
255XRA LA <- A ^ L1Z, S, P, CY, AC0xad
256XRA MA <- A ^ (HL)1Z, S, P, CY, AC0xae
257XRA AA <- A ^ A1Z, S, P, CY, AC0xaf
260ORA BA <- A | B1Z, S, P, CY, AC0xb0
261ORA CA <- A | C1Z, S, P, CY, AC0xb1
262ORA DA <- A | D1Z, S, P, CY, AC0xb2
263ORA EA <- A | E1Z, S, P, CY, AC0xb3
264ORA HA <- A | H1Z, S, P, CY, AC0xb4
265ORA LA <- A | L1Z, S, P, CY, AC0xb5
266ORA MA <- A | (HL)1Z, S, P, CY, AC0xb6
267ORA AA <- A | A1Z, S, P, CY, AC0xb7
270CMP BA – B1Z, S, P, CY, AC0xb8
271CMP CA – C1Z, S, P, CY, AC0xb9
272CMP DA – D1Z, S, P, CY, AC0xba
273CMP EA – E1Z, S, P, CY, AC0xbb
274CMP HA – H1Z, S, P, CY, AC0xbc
275CMP LA – L1Z, S, P, CY, AC0xbd
276CMP MA – (HL)1Z, S, P, CY, AC0xbe
277CMP AA – A1Z, S, P, CY, AC0xbf
300RNZif NZ, RET10xc0
301POP BC <- (sp); B <- (sp+1); sp <- sp+210xc1
302JNZ adrif NZ, PC <- adr30xc2
303JMP adrPC <= adr30xc3
304CNZ adrif NZ, CALL adr30xc4
305PUSH B(sp-2)<-C; (sp-1)<-B; sp <- sp – 210xc5
306ADI D8A <- A + byte2Z, S, P, CY, AC0xc6
307RST 0CALL $010xc7
310RZif Z, RET10xc8
311RETPC.lo <- (sp); PC.hi<-(sp+1); SP <- SP+210xc9
312JZ adrif Z, PC <- adr30xca
314CZ adrif Z, CALL adr30xcc
315CALL adr(SP-1)<-PC.hi;(SP-2)<-PC.lo;SP<-SP-2;PC=adr30xcd
316ACI D8A <- A + data + CY2Z, S, P, CY, AC0xce
317RST 1CALL $810xcf
320RNCif NCY, RET10xd0
321POP DE <- (sp); D <- (sp+1); sp <- sp+210xd1
322JNC adrif NCY, PC<-adr30xd2
323OUT D8special20xd3
324CNC adrif NCY, CALL adr30xd4
325PUSH D(sp-2)<-E; (sp-1)<-D; sp <- sp – 210xd5
326SUI D8A <- A – data2Z, S, P, CY, AC0xd6
327RST 2CALL $1010xd7
330RCif CY, RET10xd8
332JC adrif CY, PC<-adr30xda
333IN D8special20xdb
334CC adrif CY, CALL adr30xdc
336SBI D8A <- A – data – CY2Z, S, P, CY, AC0xde
337RST 3CALL $1810xdf
340RPOif PO, RET10xe0
341POP HL <- (sp); H <- (sp+1); sp <- sp+210xe1
342JPO adrif PO, PC <- adr30xe2
343XTHLL <-> (SP); H <-> (SP+1)10xe3
344CPO adrif PO, CALL adr30xe4
345PUSH H(sp-2)<-L; (sp-1)<-H; sp <- sp – 210xe5
346ANI D8A <- A & data2Z, S, P, CY, AC0xe6
347RST 4CALL $2010xe7
350RPEif PE, RET10xe8
351PCHLPC.hi <- H; PC.lo <- L10xe9
352JPE adrif PE, PC <- adr30xea
353XCHGH <-> D; L <-> E10xeb
354CPE adrif PE, CALL adr30xec
356XRI D8A <- A ^ data2Z, S, P, CY, AC0xee
357RST 5CALL $2810xef
360RPif P, RET10xf0
361POP PSWflags <- (sp); A <- (sp+1); sp <- sp+210xf1
362JP adrif P=1 PC <- adr30xf2
364CP adrif P, PC <- adr30xf4
365PUSH PSW(sp-2)<-flags; (sp-1)<-A; sp <- sp – 210xf5
366ORI D8A <- A | data2Z, S, P, CY, AC0xf6
367RST 6CALL $3010xf7
370RMif M, RET10xf8
372JM adrif M, PC <- adr30xfa
374CM adrif M, CALL adr30xfc
376CPI D8A – data2Z, S, P, CY, AC0xfe
377RST 7CALL $3810xff

i2c and cap1188 Musical instrument (from vga to esp32?)

Way back in 2018 i was playing around with i2c and touch.

CAP1188 Multi touch sensor

I remembered that VGA was using i2c to get information from monitors like brand/type and connection information.

I managed to access the cap1188 up to my Laptop via VGA.

2018 Schematic i used to abuse vga …

The final python code i used to play with the variables and playing sound i can’t find.
But below is the test code


# NOTE: i did a address scan, now i have 3v3 connected to AD, so probably the address is 0x28 !!

import smbus

bus = smbus.SMBus(1)    # 0 = /dev/i2c-0 (port I2C0), 1 = /dev/i2c-1 (port I2C1)

DEVICE_ADDRESS = 0x29      
DEVICEx = 0x10      

#Write a single register
bus.write_byte_data(DEVICE_ADDRESS, 0x1f, 0x3F)

#Write an array of registers
#ledout_values = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
#bus.write_i2c_block_data(DEVICE_ADDRESS, DEVICE_REG_LEDOUT0, ledout_values)
while True:

        print bus.read_byte_data(DEVICE_ADDRESS,0x10), bus.read_byte_data(DEVICE_ADDRESS,0x11) , bus.read_byte_data(DEVICE_ADDRESS,0x12), bus.read_byte_data(DEVICE_ADDRESS,0x13), bus.read_byte_data(DEVICE_ADDRESS,0x14), bus.read_byte_dat
a(DEVICE_ADDRESS,0x15), bus.read_byte_data(DEVICE_ADDRESS,0x16), bus.read_byte_data(DEVICE_ADDRESS,0x17)

Today i connected the cap1188 to a ESP32 and a piezo buzzer.

/*** Based on below library ***/
/*** Changed pins and added sound ***/

  This is a library for the CAP1188 I2C/SPI 8-chan Capacitive Sensor

  Designed specifically to work with the CAP1188 sensor from Adafruit
  ----> https://www.adafruit.com/products/1602

  These sensors use I2C/SPI to communicate, 2+ pins are required to  
  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_CAP1188.h>

const int TONE_OUTPUT_PIN = 26;
const int TONE_PWM_CHANNEL = 0; 
int freq = 0;

// Reset Pin is used for I2C or SPI
#define CAP1188_RESET  9

// CS pin is used for software or hardware SPI
#define CAP1188_CS  10

// These are defined for software SPI, for hardware SPI, check your 
// board's SPI pins in the Arduino documentation
#define CAP1188_MOSI  11
#define CAP1188_MISO  12
#define CAP1188_CLK  13

// For I2C, connect SDA to your Arduino's SDA pin, SCL to SCL pin
// On UNO/Duemilanove/etc, SDA == Analog 4, SCL == Analog 5
// On Leonardo/Micro, SDA == Digital 2, SCL == Digital 3
// On Mega/ADK/Due, SDA == Digital 20, SCL == Digital 21

// Use I2C, no reset pin!
Adafruit_CAP1188 cap = Adafruit_CAP1188();

// Or...Use I2C, with reset pin
//Adafruit_CAP1188 cap = Adafruit_CAP1188(CAP1188_RESET);

// Or... Hardware SPI, CS pin & reset pin 
// Adafruit_CAP1188 cap = Adafruit_CAP1188(CAP1188_CS, CAP1188_RESET);

// Or.. Software SPI: clock, miso, mosi, cs, reset
//Adafruit_CAP1188 cap = Adafruit_CAP1188(CAP1188_CLK, CAP1188_MISO, CAP1188_MOSI, CAP1188_CS, CAP1188_RESET);

void setup() {
  Serial.println("CAP1188 test!");

  // Initialize the sensor, if using i2c you can pass in the i2c address
  if (!cap.begin(0x28)){
  //if (!cap.begin()) {
    Serial.println("CAP1188 not found");
    while (1);
  Serial.println("CAP1188 found!");

void loop() {
  uint8_t touched = cap.touched();

  if (touched == 0) {
    // No touch detected
  for (uint8_t i=0; i<8; i++) {
    if (touched & (1 << i)) {
      Serial.print(touched); Serial.print("\t");
      freq = (i * 100);
      ledcWriteTone(TONE_PWM_CHANNEL, freq);


Finding the right pins or above pinout was the hardest part.
The sketch reads the pins binary so value 129 is first and last bit.

Now i have to get the sound sounding a little better and add frequencies and fingersettings to the sketch to get a minimal electronic bagpipe. (V3 it is .. )

To be continued ..

Micropython and TFT display test environment

This exercise is to get a micropython dev environment with a graphical display.

pip3 install esptool adafruit-ampy

Erase board (use correct tty device!)

esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash

Flash using

esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800 write_flash -z 0x1000 esp32-20190125-v1.10.bin

Download from https://micropython.org/resources/firmware/esp32-20220618-v1.19.1.bin

Test with

screen /dev/ttyUSB0 115200

import machine

Great up and running

Now we have to install a boot loader
Use ampy to list files

#list boot
ampy -p /dev/ttyUSB0 ls 

#get boot.py
ampy -p /dev/ttyUSB0 get boot.py

vi boot.py (create new)

#import esp
#import webrepl

def connect():
    import network
    sta_if = network.WLAN(network.STA_IF)
    if not sta_if.isconnected():
        print('connecting to network...')
        sta_if.connect('WIFISSID', 'WIFIPASS')
        while not sta_if.isconnected():
    print('network config:', sta_if.ifconfig())

Push the file

ampy -p /dev/ttyUSB0 put boot.py
Usage: ampy [OPTIONS] COMMAND [ARGS]...

  ampy - Adafruit MicroPython Tool

  Ampy is a tool to control MicroPython boards over a serial connection.
  Using ampy you can manipulate files on the board's internal filesystem and
  even run scripts.

  -p, --port PORT    Name of serial port for connected board.  Can optionally
                     specify with AMPY_PORT environment variable.  [required]
  -b, --baud BAUD    Baud rate for the serial connection (default 115200).
                     Can optionally specify with AMPY_BAUD environment
  -d, --delay DELAY  Delay in seconds before entering RAW MODE (default 0).
                     Can optionally specify with AMPY_DELAY environment
  --version          Show the version and exit.
  --help             Show this message and exit.

  get    Retrieve a file from the board.
  ls     List contents of a directory on the board.
  mkdir  Create a directory on the board.
  put    Put a file or folder and its contents on the board.
  reset  Perform soft reset/reboot of the board.
  rm     Remove a file from the board.
  rmdir  Forcefully remove a folder and all its children from the board.
  run    Run a script and print its output.

Connect to serial console using screen

sudo screen /dev/ttyUSB0 115200
(use CTRL-A \ to exit)

Connect to wifi

import boot

Led blinky test, with below file named ledtest.py

import time
from machine import Pin
led=Pin(2,Pin.OUT)        #Internal led pin

while True:
  led.value(1)            #Set led turn on
  led.value(0)            #Set led turn off

Upload and run script

ampy -p /dev/ttyUSB0 put ledtest.py
import ledtest (without .py!)

Next todo: boot.py @boot ?!?
Run custom python after booting.
Connect display and play with drawing.

Tip: Install rshell !

sudo pip3 install rshell
fash@zspot:~$ rshell 
Welcome to rshell. Use Control-D (or the exit command) to exit rshell.

No MicroPython boards connected - use the connect command to add one

/home/fash> autoconnect: /dev/ttyUSB0 action: add

/home/fash> ?

Documented commands (type help <topic>):
args    cat  connect  date  edit  filesize  help  mkdir  rm     shell
boards  cd   cp       echo  exit  filetype  ls    repl   rsync

Use Control-D (or the exit command) to exit rshell.

Connecting the display

I’ve connected the display as above. Note the different connections on the display. Above fritzing part has connections for touch screen!
The 4 or 5 pins on the other side are for sdcard functionallity.

display       esp
SDO/MISO      D19
LED           VIN (5v)
SCK           D18
SDI/MOSI      D23
DC/RS         D15
RESET         D14
CS            D5
GND           GND
VCC           3.3V

Not my different ESP, gpio has high numbers and only 30 pins.
Most ESP have 2 SPI controllers. Check yours!

Software part

git clone https://github.com/rdagger/micropython-ili9341

Next create a setupmydisplay.py file, and edit your pin connections

from ili9341 import Display
from machine import Pin, SPI

TFT_CLK_PIN = const(18)
TFT_MOSI_PIN = const(23)
TFT_MISO_PIN = const(19)

TFT_CS_PIN = const(5)
TFT_RST_PIN = const(14)
TFT_DC_PIN = const(15)

def createMyDisplay():
    #spi = SPI(0, baudrate=40000000, sck=Pin(TFT_CLK_PIN), mosi=Pin(TFT_MOSI_PIN))
    spiTFT = SPI(2, baudrate=51200000,
                 sck=Pin(TFT_CLK_PIN), mosi=Pin(TFT_MOSI_PIN))
    display = Display(spiTFT,
                      dc=Pin(TFT_DC_PIN), cs=Pin(TFT_CS_PIN), rst=Pin(TFT_RST_PIN))
    return display

Now you can use the library by editing a example like demo_bouncing_boxes.py

Add and change

# At the beginning of the file
import setupmydisplay.py

Futher down comment two lines and add your own setup

        # Baud rate of 40000000 seems about the max
        #spi = SPI(1, baudrate=40000000, sck=Pin(14), mosi=Pin(13))
        #display = Display(spi, dc=Pin(4), cs=Pin(16), rst=Pin(17))
        display = setup.createMyDisplay()

Upload to ESP32 and testing!

ampy -p /dev/ttyUSB0 put demo_bouncing_boxes.py
ampy -p /dev/ttyUSB0 put setupmydisplay.py
# connect and start
sudo screen /dev/ttyUSB0 115200
import demo_bouncing_boxes.py

Race track Controller

I got a vintage racetrack from a colleage a while back.

In the past i had some ideas controlling train or race tracks.
For train tracks i wanted to write intelligent maneuver software.
For a racetrack a web controllable race. Maybe with a webcam mounted on the car??

L298N – DC motor controller

So i bought a little DC motor controller (2 channels) and took a esp32.

GPIO04 Player1 IN1 
GPIO05 Player1 IN2
GPIO19 Player2 IN1 
GPIO18 Player2 IN2
GPIO13 PWM Player1
GPIO14 PWM Player2

The webinterface is behind a reverse proxy (apache)

TO BE POSTED .. arduino code

<VirtualHost *:443>
   SSLEngine on
   SSLProxyEngine On

   SSLProtocol all -SSLv2 -SSLv3 +TLSv1

   SSLCertificateFile /etc/ssl/.......cer
   SSLCertificateKeyFile /etc/ssl/private/........key
   SSLCertificateChainFile /etc/ssl/private/GlobalSignRootCA.cer
   SSLCertificateChainFile /etc/ssl/private/AlphaSSLCA-SHA256-G2.cer

   CustomLog /var/log/httpd/media_ssl_request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

    ServerAdmin webmaster@henriaanstoot.nl
    ServerName race.henriaanstoot.nl

ProxyRequests Off
ProxyPreserveHost On
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off

<Location />

    ErrorLog /var/log/httpd/race.henriaanstoot.nl-error.log
    CustomLog /var/log/httpd/race.henriaanstoot.nl-access.log combined

Arduino IDE

Adding boards:

File > Preferences > Additional Boards
Add url (comma separated)
Press OK

ESP32 :




After that go to the Board manager.
Tools > Board: ..... > Board Manager
Search board, click and install.
NOTE: Some sketches require a specific version!

Select your board, and write/open you sketch.

First thing to do is test compiling your sketch

Press the little button on the left


When you get a compile error like below, you are missing those libraries

Goto tools > Manage libraries

Search for your needed library, sometimes there are multiple which look alike. This is a trial and error approach.
Sometimes it doesn’t exists and you need to upload a zip containing the library. (Sketch > Include Library > Add .zip library

Downloading a zip containing the library
Adding the library zip file

When looking at the first lines of you sketch, there are include statements like:

#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>

But sometimes there are statements without the < > characters.
Then it will be a included file just for your sketch.

Note the second tab MPU6050x.h which contains specific code only for this sketch.

Redo a test recompile using the tic icon again.

Everything okay? .. Select the correct port in Tools > Port
And press the Arrowright icon to upload/flash.
Note: sometimes you have to hold a button or press a little flash button on your device to flash.

esptool.py v3.3
Serial port COM8
Chip is ESP32-D0WDQ6-V3 (revision 3)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: c8:c9:a3:f9:02:d0
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 921600
Configuring flash size...
Flash will be erased from 0x00001000 to 0x00005fff...
Flash will be erased from 0x00008000 to 0x00008fff...
Flash will be erased from 0x0000e000 to 0x0000ffff...
Flash will be erased from 0x00010000 to 0x000c7fff...
Flash params set to 0x022f
Compressed 18880 bytes to 12992...
Writing at 0x00001000... (100 %)
Wrote 18880 bytes (12992 compressed) at 0x00001000 in 0.3 seconds (effective 482.8 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 128...
Writing at 0x00008000... (100 %)
Wrote 3072 bytes (128 compressed) at 0x00008000 in 0.0 seconds (effective 627.7 kbit/s)...
Hash of data verified.
Compressed 8192 bytes to 47...
Writing at 0x0000e000... (100 %)
Wrote 8192 bytes (47 compressed) at 0x0000e000 in 0.1 seconds (effective 1087.9 kbit/s)...
Hash of data verified.
Compressed 750976 bytes to 477779...
Writing at 0x00010000... (3 %)
Writing at 0x000bb633... (93 %)
Writing at 0x000c0acd... (96 %)
Writing at 0x000c6649... (100 %)
Wrote 750976 bytes (477779 compressed) at 0x00010000 in 6.3 seconds (effective 947.4 kbit/s)...
Hash of data verified.

Hard resetting via RTS pin...

Most of the boards you can connect via micro-usb.
Sometimes you need adaptors like:

TIPS ‘n tricks:

Open same file in another editor, so you can compare for example the top (declarations) and futher down the code.
Else you could be ending up scolling up/down all day long. And probably forgetting how a variablename was exacly spelled.

Use serial monitor!
When debugging this is a valuable tool.
Enter statements into you code, which prints debugging info to a serial monitoring window when your device is still hookedup to your PC.

Example printing connected IP and values registered
You even can use serial plotting!!

How to print?

void setup(){
  ... code 
  ... code



Other obvious tips:
Add comment lines (documentation)
Use variable names which make sense!
( Hard to find what aaaa() does, or what tmp-a is, but
LastTempValue says a lot more)

"If something is worth doing, it's worth overdoing."