Tuesday, April 7, 2020

CPS2 2-Player / 4-Player wiring switch

So I have this CPS2 (Capcom System II) Dungeons & Dragons: Shadow over Mystara cabinet with an absolutely awful button layout. I'm pretty sure whoever did the button placement on this thing was drunk, stoned, or both. Aside from the button layout being awful, the 4 player cabinets only have 4 buttons per player. This is no good, because I have a huge collection of 2 player CPS2 boards that require 6 buttons per player (that I've never been able to enjoy). Time for me to make a thing.

Now this should be easy, I just need to hook up the wires for the extra buttons, right? Wrong! That would be way too easy. A quick read of a few manuals, and its pretty clear to see that there are two different button configuration standards. One configuration for 2 player, and one for 4 player. The 2 player mode reuses some of the same wiring that's used for the 4 player mode. And to top it all off, each layout puts the buttons in different places. This looks like a job for relays, I just need to figure out how many, and how to hook it all up

After a few cups of coffee, and a headache, I came up with this:

It looks daunting, but its actually quite simple:
-14 Inputs
-14 Relays (i used 16 because its always nice to have spares)
-26 Outputs

I decided if I was going to rewire a bunch of stuff and drill new holes for the extra buttons, I might as well replace everything, and try to fix the horrible button layout (as best I can)

As you can see, the button layout is still... bad. But I didn't want to deal with moving the joysticks, and all i had to work with was a paddle bit and a Dremel. I plan on making a new top at some point anyway, so this will do.

I went with light up buttons, so I could see which buttons were active (those extra relays came in handy), and threw a switch in one of the holes left from the previous layout. Here it is in action:

Everything works! Does this mean were done? Of coarse not. This isn't good enough, I still have another problem to fix.

First, you need to hear a little back story. I have A LOT of CPS2 boards, a ridiculous amount for a single person to own for their personal arcade. Swapping out these boards every time I want to play a different game can be quite annoying, so I invested in Darksoft's CPS2 Multi Kit. This kit lets me convert one of my boards into a multi-cart system that contains all the games I own, on one board, on the original hardware, not emulated, as it should be. All I need to do to swap a game is select it from a 16x2 LCD screen, and click the load button. So lets figure out how to automatically switch the button configuration depending on which game is loaded.

I started by looking into the 16x2 LCD, as it displays which game is currently loaded. After reading every datasheet I could find, I discovered that, while there are lots of different 16x2 LCD's available, once you remove the backpack/controller, the LCD boards that look like this are mostly the same (with maybe difference in pinout).

There are 8 data pins (but only 4 are usually used). And among all the other pins, one stood out to me: the RW (read/write) pin. Setting this pin to LOW lets you write to the display. But setting this pin to HIGH lets you read whats currently being displayed on the LCD. I found an Arduino library and got to work writing something.

I used a LCD off of an Adafruit LCD Backpack, as I didn't want to hurt the one from my Multi-Kit. I quickly realized that the RW pin wasn't being held LOW by logic, but was just soldered straight to ground. So I did what anyone would do, and de-soldered that pin, and wired it directly to my Arduino.  This worked! I managed to write to the LCD, and successfully read back what I wrote. So I  moved onto the LCD from the Multi-Kit.

This LCD had the RW pin soldered directly to ground as well. No problem, we've been here before, just de-solder that pin, and take control of it with my Arduino. Here's were the fun kicked in; I could read and write to the LCD just fine, but most the time it put garbage on the LCD, and the data i got back was not consistent. I realized that the Multi-Kit was sending data pretty regularly, and we were stepping over each other. Another problem easily fixed.

I wired up the Arduino to sit in the middle of the Multi-Kit and the LCD. It would listen to data being sent from the Multi-Kit, and send that data back out. This gave me control of when the LCD would receive data from the Multi-Kit, so the Arduino could send data uninterrupted. This worked, but it was only a partial success. The Arduino would sometimes miss some of the data being sent, which would leave the LCD displaying garbage again. I tried overclocking the Arduino, playing with timing, checking connections, and changing my code. I had it running pretty well at this point, but it would still, on occasion, display garbage, which was unacceptable. I needed a different approach.

Then it hit me; I'm over engineering this; I don't need to read data from the LCD itself, I don't actually need to send any commands to the LCD at all. I can just read whats being sent from the Multi-Kit. This would take a lot less wires, as I'd just be tapping into whats being sent. And, bonus, I wouldn't have to de-solder that RW pin.

This worked on the first attempt. No errors, consistent data, and best of all, no garbage on the LCD. I poked around for a bit, logging all the data for each game, and creating large arrays identifying each game. After a while, this seemed to be a very inefficient way of doing things. This was taking up tons of my program space, and I didn't want to have to do this every time i got a new game. There had to be a simple fix, and there was.

The Multi-Kit looks on an SD card for the games to load, and along with each game is a file that contains what will be sent to the LCD. I modified all these files to include the numbers 2, 3, or 4, at the end, depending on how many players are supported on that game. Now I just needed to look at the last piece of data being sent; that's super easy. I just consistently read data, and looked for a slight pause in data being sent. Then I look at the last bits recorded, and that's all I needed. This worked great, but I didn't like that slight delay in detection. When I turn on the machine, I want those relays to trigger immediately.

Last and final step was speeding this up. I remembered from the datasheets that the EN pin on the LCD would switch states while data is being actively sent, then immediately switch back when its not (it might have helped me if i remembered this sooner). I hooked the EN pin to an interrupt on the Arduino, so when EN switched states, it would immediately read the last bits sent. And it worked. I made a thing.

And i shall name her CPS2 Lightning Kick, because, reasons.

Here's the final schematic:

Download the code here

Check it out on my Github for more: CPS2_Lightning_Kick

Programming a 48pin chip with a TOP Programmer

I have a TOP programmer. I got it because of its support for up to 48 pin chips, the wide variety of chips supported, and the cheap price po...