Many months later I have picked up a nice Stern Dracula pinball machine, which allowed me to actually go and start testing this code in a game and get working on the I/O support.
Bally has an interesting system for driving their lamps. Unlike Gottlieb (who just had one transistor for each lamp and banks of latches to remember their state) or Williams (who used an 8x8 switch matrix), Bally opted to use 60 individual SCRs. SCRs have an interesting property to them: unlike transistors, which allow current through when there's voltage at their input and then cut it off when the input turns off, SCRs will keep letting current through until the input turns off, and the current drops to zero. This has a cool effect in that, you can hook a lamp up to an SCR, give it a quick pulse on its input, and then just leave it and the lamp will stay on. Of course, you don't want your lamps to stay on forever, so Bally powered all its lamps via raw rectified DC, which follows the same 120Hz sine wave the 110VAC coming from the wall has.
You can see the DC in purple here compared to the AC in blue. Effectively a rectifier just inverts the negative half of the AC signal, which means the DC still looks like an AC wave. Because of this, the power source for the lamps is dropping down to 0VDC 120 times a second, stopping current from flowing through the SCR, allowing the light to turn off. So what Bally does is, 120 times a second, the MPU pulses any lights it wants to be on, and then they stay on until the next 'zero crossing'. As long as the MPU pulses the lamp again right as the SCR turns off, the lamp appears to stay on. If it wants to turn a lamp off, it just doesn't pulse it any more. Pretty nifty, but it also means timing is going to matter a lot here, since there's factors beyond the MPU's control at work.
Of course, this complicated system wouldn't be very useful unless you could also pulse all your lamps simply, so Bally hooks up each bank of 15 lamps to a 4 to 16 decoder. This chip has 16 outputs, and turns only one on at a time depending on which 4 bit binary number is sent into it. Unlike Gottlieb, who needed a dedicated output on each chip for every light (limiting them to 4 lights per chip), Bally could use one chip for 16 lights. But I said 15 earlier, right? That's because one of those 16 outputs isn't connected to anything. Since the same data lines that the MPU uses to control the lamp board also go to the displays, they use one output as a 'safe' output to leave the lamp board on while the MPU does other stuff. (The same is done with their solenoid board, which can control 15 solenoids from its decoder).
15 lamps per decoder means we need four decoders to control 60 lamps, and four also is a nice round computery number. All four decoders are hooked up in parallel, so another set of 4 bits, one per decoder, is used to enable/disable each one while all 15 outputs are run through. 4 bits happens to be the size of the 5101 RAM chip on the MPU, so 15 bytes of that RAM will go to storing the state of all the lamps.
With that in mind, I feel like I have a pretty good idea of how to interface with the lamp board:
Each time the lamp voltages crosses zero, the MPU gets an interrupt signal and starts the lamp update sequence Load up each 'row' of four lamps Combine this with the 4 bit 'column' address for the decoder Send them out as one 8 bit byte to the lamp board 'strobe' the decoders to tell them to latch in the data Repeat for the rest of the rows
Nice, simple code, aided by the four 'data' bits of the lamp board inputs being mapped to the top 4 bits of the MPU PIA's 8 bit output port, which coincidentally matches which four bits of RAM the data is stored in. Almost like they planned all this! Too bad it didn't work. The lamp I wanted to turn on did turn on, but so did another in the same column.
After some thought, I realized that the decoder chips only 'latch' the address. The enable/disable data signal takes effect immediately. So when I sent out the next combined byte containing both the 4 data signals and 4 address signals, the new data for the next row must be affecting the previous row.
So now I had another step. Instead of sending them both out at once, first I'd have to disable all four encoders. Then, I'd send out the new address and latch it in. Finally, I'd enable to encoders again. A bit slower, but much safer than relying on the timing of the two signals to work out. Of course, this also didn't work.
After tearing my hair out for a few days reading and rereading data sheets for the decoder chips, staring at schematics, and scrutinizing my code, I finally discovered that my data sheets were wrong! The part number on the schematic was 14514CP, but my data sheet was for 14514B. Very similar chips, but with one important difference: for the 14514B the way to latch a new address was to drop the latch signal from high to low. That transition was what triggered the latching of new data. With the 14514CP, when the latch pin was high, it was instantly passing the address data through. Dropping the latch pin low just made it stop passing the data and remember whatever it had last. So I rearranged my code to quickly pulse the latch pin high for a few microseconds, instead of leaving it in one state or another, and finally my issues were solved
The code for all this is available on my github, if you want to check it out
With I/O figured out, I theoretically know everything necessary to start writing code, so I want to start with the simplest possible thing: getting an infinite loop to run in pinMAME. The CPU (Motorola 6800) is fairly basic, it only needs to know one thing to run code: where to start. You do this by putting the address of your starting code at the highest location available in memory, so I wrote a quick assembly file:
.orq $1800 ; start of U6 main: jmp main .orq $1FFF-1 ; two bytes before end of U6 .dw main ; address of main
It doesn't get much simpler! And besides from a classic off-by-one error (I did $1FFF-2 instead of -1), it worked on the first (heh) try. Loading this up in PinMAME I was able to open the debugger and see it dutifully running around its tiny loop, forever.
U10 Bank A: control: |self test irq|n/u|1|1|!blanking 0|D|0|1| direction: out (1) data: 11110000 - bits 0-3 go to display latches, start low - bits 4-7 go to display data, start high (1111 = blank) Bank B: control: |zero crossing irq|n/u|1|1|lamp strobe 1|D|1|1| direction: in (0) U11 Bank A: control: |display irq|n/u|1|1|led 0|D|0|1| direction: out (1) data: 00000000 - bit 0: credit display latch, start low - but 1: not used - bits 2-7: digits 1 thru 100k, start low Bank B: control: |n/u|n/u|1|1|solenoid0|D|0|0| direction: out (1) data: 10011111 - bits 0-3: number of solenoid to fire, use 1111 to fire none - bits 4-8: continuous solenoid data (turn flippers off, coin lockout on)
Configuring the PIAs is a bit of a pain as they have three bytes of memory internally (the control byte, the direction byte, and the data byte) per bank, but you can only access two at a time. Therefore, one bit (2) of the control byte chooses which (direction or data) the other byte goes to. Fully configuring a PIA involves first initializing the control byte so that you can access the direction byte, then initializing the direction byte (read or write), then changing the control byte to let you access the data byte so you can actually do some I/O:
ldaA 00110001b ; irq state | n/u | CA2 output | ...mode | CA2 value 0 = blank displays | enable direction register | irq on | ...self test ->low staA u10AControl ldaA 11111111b ; all outputs staA u10A ldaA 00000100b ; toggle DDRA (3rd) bit to write to ports oraA >u10AControl staA u10AControl ldaA 11110000b ; blanking means any outputs here will affect displays staA u10A ; 0-3 set all display latches low, 4-7 blank disp data
Finally, I can use the PIA to start controlling the LED, toggling it on and off repeatedly:
inc counter ifeq ; counter = 0, it wrapped around from 255 ldaA 00001000b ; led bit bitA >u11AControl ifne ; led on? ; turn led off ldaA 11110111b andA >u11AControl staA u11AControl else ; turn led on oraA >u11AControl staA u11AControl endif endif
and it works! At least in PinMAME. I don't have any Bally/Stern machines on hand and configured correctly to easily test it in game right now, but that's alright. PinMAME isn't perfect but you can at least get most of the logic ironed out when it's easily debuggable before throwing it on the black box of a real machine.
The code for all this is available on my github, if you want to check it out
With my previous success programming a new rom/os for early williams pinball machines, I thought: why not do the same for their competitor, Bally? I've already got most of the code worked out, so it can't be that bad to adapt the I/O part to the other board, can it? They both use the same CPU, RAM, and IO chips as well. So today I dug into the schematics and started documenting what I'd need.
The first step for coding some basic I/O is to get the memory map:
|U7||$00||128B of RAM|
|U8||$200||256 nibbles of RAM|
|U2||$1000||2KB Game ROM|
|U6||$1800||2KB OS ROM|
What's notable here is how small it is. The Williams boards used 3 RAM chips instead of 2, 4 PIAs instead of 2, and 3 ROMs instead of 2 but, besides from an extra 128B of RAM (which I'll miss), the Bally boards have comparable capabilities to the Williams.
Williams took a very straightforward approach to their design: 16 solenoids? Well that will need 16 I/Os, so that's one PIA (each PIA has two banks of 8 I/O pins). An 8x8 switch matrix? Another 16 I/Os (and thus another PIA) obviously. This resulted in a system that was easy to program, but uses a ton of chips that can all go bad. Williams boards are notoriously unreliable, and reproductions aren't readily available.
Bally took the opposite approach here. 16 solenoids? That sounds like 4 bits of data. Why an 8x8 switch matrix when we probably won't need more than 5x8 switches? Lets use those other three bits for other unrelated things. We won't need to write to the lamp board and switch matrix at the same time, so lets connect both up to the same pins, and use another pin to select which one. And hey, the same logic works for the displays as well, right? Stuff like this allows Bally to make due with half the I/O lines, but I can imagine it'll be a pain to work with. Still, it worked out well, right? Bally boards are considered the most reliable and well designed of that era, they're easily repairable, and replacements are available with better, modern designs.
It took me a good few hours to decode the meanings of all the pins on the 2 PIA chips. Each has two banks (A and B) with eight lines each, and four extra lines (CA/B 1/2) with more limited functionality:
U10: A0-4: switch strobe ST0-4 (NH) A5-7: dip switch 1-3 strobe (NH) A0-3: lamp address selects lamps 0-14 for each of the four lamp chips all high (15) for no lamp A4-7: lamp data low to enable any of the four lamp chips A0-3: display 1-4 latch, nored with CA2 J1-(20-24) bcd enabled when high A4-7: display data CA1: self test switch input (low = pressed) CA2: nored with display latch: display blanking/enable (low -> high blanking) bcd blank when blanking high (signal low) CB1: zero crossing input (NL) CB2: dip switch 4 strobe (NH), lamp strobe 1 latches data for first lamp board on down signal B0-7: switch return I0-I7 U11: A0: display 5 (credit?) latch, nored with U10-CA2 A1: 'sound module address enable'? J1-7 A2-7: display digit enable #6-#1 (100k-1 or v.v?) J1-(6-1) B0-3: solenoid/sound data A-D 0-14 turns on that solenoid 15 all solenoids off (only one solenoid can be on at a time!) B4-7: 'continuous solenoid data' A4J4-(5-8) -> A3J4-[11,9,8,10] low=enable B4: A3J4-11: Cont 2 B5: A3J4- 9: Cont 4 coin door lock out B6: A3J4- 8: Cont 1 flipper disable (high=enable flippers?) B7: A3J4-10: Cont 3 CA1: display interrupt input (NH) CA2: LED (high turns on), lamp strobe 2 CB1: n/u? CB2: solenoid (low) or sound (high) select
With this, I have a general idea of what my OS will need to do to run the peripherals, and most importantly, I know how to turn the diagnostic LED on the board on and off, which will be the simplest way of knowing whether my code is actually running. My next step will be to set up an entry point and toggle the LED via one of the PIAs
Many older games from the dawn of computer based ('solid state') pinball have some pretty basic rules, and I've often pondered hacking the roms to improve them, but reverse engineering assembly from scratch isn't really my idea of fun so I never really got into it. Driving home one night though, I got to thinking: the hardware for these machines is pretty simple, the schematics are available (and even have memory addresses!), would it really be that hard to just write a brand new rom from scratch? Sure, I didn't know assembly or anything, but it couldn't be that hard!
So I sat down with a copy of the Motorola 6800 reference manual, some data sheets, the schematics, and a copy of PinMAME to debug my code in, found where the entry point/address was, and started coding.
Long story short, it actually was pretty easy! The williams hardware was designed for simplicity from a programming standpoint (though that ended up making the boards overly complicated and unreliable), all the I/O was easy to work with and within a few days I had simple drivers written for all the different peripherals and a basic 'OS' for a game that could control lights, display scores, and jump into a callback table when a switch was hit by the ball.
Programming a game itself using this would prove a bit more complicated of course, due mostly to timing/threading issues (of course, I just had to write a custom threading system for this 1MHz processor), but nothing extreme. A few months later, and I had a brand new rom for my Hot Tip, with many fancy new features which I showed off in a video here
I didn't document the whole process very much, but if you'd like to know more, or would like to try to write your own new game rom using this as a basis, drop me a line!
The full source code and roms are available at http://github.com/zacaj/williams-sys-3-6
I found a pinball machine sitting disassembled on the floor of a leaky shed and brought it home to tinker with. The mechanisms and electronics inside were all rusted solid, as was most of the metal on the outside. The backglass had lost half its paint, and one entire side of the machine was covered in mold.
I'd originally planned to disassemble the machine for parts, but after I got the glass off I found that the playfield itself was in amazing condition. With the glass to protect it and no light, it had survived unscathed, and I couldn't bring myself to tear it up. Instead, I decided to teach myself some electrical engineering and wire it all up to an Arduino.
I managed to clean off the mold and dirt using a combination of extremely toxic solutions. The door and plunger needed to be sand-blasted and repainted. Luckily, the rails along the edges were stainless steel, so they only needed a quick cleaning.
If you've got any questions, feel free to email or tweet me; I'll be happy to elaborate
Posted Sunday, April 01, 2018
at 06:06 PM
I got a hold of an old EM Stock Car pinball machine a few weeks ago with the hopes of repairing it, but my first attempt ended in failure. The machine had been sitting in a damp, moldy garage against a wall, under a leaky window for at least twenty years, and it was beyond repair. About a third of the inside was covered in mold, all the moving parts were stuck, all the metal was rusted, and the back glass was damaged beyond repair.
So instead I realized that this would be a good way to use an Arduino. I could just plug one into all the inputs and outputs of the machine and then program it to react in the same way all those complicated and broken electronics would have. I ordered an Arduino Mega, which has 54 I/O ports, and then got to work investigating how complicated it would be to interface it with the pinball machine.
Some quick testing revealed that all the moving parts of the pinball machine ran off 25V AC, which posed my first problem, as the Arduino runs off 5V DC. Asking about how to fix this online wasn't much help; the experts couldn't even agree on whether an AC coil would work with DC. Being the pragmatic and cautious individual that I am, I of course took the rational route, and hooked two old car batteries up (12V DC each x2=24V DC) to a solenoid to see if it would work. (It did). Of course, this still left the big problem, which is that even if the coils would work off DC, they still needed 25V.
The answer, of course, was to use a transistor, or a MOSFET to be precise (I still haven't figured out the difference), to switch the high power current with a low power current from the Arduino. Three burned out husks of transistors later, I'd figured out how they worked, and rigged up this insane hodgepodge of circuitry to control the eight solenoids in the machine.
After an arduous day soldering wires to all the components and hooking them up, I now have control of all the moving parts of the machine from my Arduino.
Tomorrow, I get to start working on wiring all the rollovers to the Arduino so it can begin actually scoring points
Posted Sunday, April 01, 2018
at 06:06 PM
Some ugly Spring Break artwork wouldn't do, so I spray-painted the cabinet black:
The same went for the head:
I've never understood pinball machines that couldn't think of a use for more buttons, so I put a second set in:
I picked up a sheet of 0.5" MDF at Home Depot, and lightly drew out my layout
I also used leftover scraps from cutting it to the right size to experiment with mounting components
Using a small router and an 1/8" bit, I found that, as long as you go slowly, it can produce workable light insert holes
Since I couldn't find any launchers, I made one myself by welding a scoop to a piece of 0.5" iron stock and attaching some plastic to the front to guide it
When you power the coil, it pulls the iron stock in, and the plastic guides it through
After two trips to the Allentown PinFest, I've managed to get together pretty much all the components I'll need for the build.
I got two boxes of assorted used parts for $20, and a ruined, half populated Spiderman playfield for $30, yielding an assortment of playfield parts:
I also bought a head from a mysterious 4 player EM for $20:
I really wasn't looking forward to the thought of trying to assemble a cabinet from scratch that would work with regular parts, but luckily I found this slightly beaten Spring Break cabinet for $15
(the legs were separate, another $20)
It even came with a working power supply, so I didn't need to worry about finding a 25-50V power supply. I was able to find a combination of taps that put out 28VDC after recification. Most non-EM pinball aficionados seem to think that 50V+ is the way to go, but honestly the flippers seem just as strong on my 25V games as my 50V.
I put in an order to Digikey for $70 (!) of electronics, including some high power MOSFETs for the solenoid drivers:
, some parts for making molex connectors,
, three CPU boards (basically cheaper, more powerful, lower level Arduinos),
...and a ton of stuff for audio output, including this surface mount op-amp, which turned out to be *really tiny*
I made some nice compact solenoid driver boards
Looking at schematics for actual machines they've got all kinds of weird stuff, however just a MOSFET, two resistors, and a line to the CPU were enough to fire the solenoids just fine. I wish I had some way to turn them off in case the CPU locks up while one is turned on, but I don't know what that would be, and as far as I can tell 'professional' machines don't do it either.