Close
0%
0%

SMSX paddle

One paddle to turn them all

Similar projects worth following
This project implements a paddle control that can be used to play games on MSX computers and in Sega Master System video game console.
On MSX it replicates the behavior of a Taito Arkanoid controller while on Master System it acts like a Japanese HPD200 paddle controller.
The circuit is composed by an Arduino Nano board and some discrete components. A couple of diodes are used to route the negative rail supply from either pin 8 (SMS) or pin 9 (MSX) to power the Arduino Board.
The host system is auto detected on power-up depending upon the signals present at the inputs.

Working around joystick port differences

The most notorious difference is the negative rail pin, being the GND at pin 8 of the Sega Master System controller port but in MSX the GND is at pin 9.

A couple of diodes is used to route either GND pin to the negative rail (GND) of the arduino board.

HOST Auto Detection

The state of pin 9 at power up is used to detect which host the circuit is connected. Pin 9 is a input on SMS and therefore shall high (pulled up, indeed). On MSX this pin will always LOW as this is a GND pin.

MSX paddle program flow

The MSX paddle follows the Taito Arkanoid model.
Each data bit is sampled then a brief low going clock pulse is generated by the MSX on pin 6 to shif out the next bit (data changes on risign edge). After the 9th bit is read another short going pulse is generated this time on pin 8. The rising edge of such pulse starts an ADC conversion. After the conversion is complete the most significant bit gets ready at pin 1 and the remaining bits are stored in a variable to be shifted later by pulses coming from pin 6. Button is sampled right after the conversion and pin 2 is updated accordingly.

Code is implemented using a couple of interrupts, one on pin 6 (clock shift) and another at pin 8 (start new sample). Main loop  does nothing else than put CPU to sleep.

SMS paddle
SMS paddle sends one nibble at a time at a rate of 8kHz (62.5us per nibble). Each nibble is signaled by the level of pin 9 ("0" for lower nibble,"1" for higher nibble). The potentiometer is read right after the higher nibble is put on the outputs, then the button is read and pin 6 is updated accordingly.
Timing synchronization is done by use of a timer that wakes up the AVR.

  • 1 × Arduino Nano
  • 2 × 560 Ohms resistor
  • 2 × 1N4148 Discrete Semiconductors / Diodes and Rectifiers
  • 1 × 10K linear potentiometer
  • 1 × Push Button

View all 7 components

  • Testing

    danjovic09/07/2019 at 08:36 0 comments

    I' ve spent some time debugging the code for SMS and MSX.

    Latency was too high to respond properly for Clock pulses coming from MSX. Analyzing the code that reads the paddle in Arkanoid game:

    430f  out     (0a1h),a    ; 12  clock low
    4311  ld      a,1fh       ; 8
    4313  out     (0a1h),a    ; 12  clock high
    4315  ld      a,0eh       ; 8  
    4317  out     (0a0h),a    ; 12
    4319  in      a,(0a2h)    ; 

    We have only 52 Z80 cpu cycles for the data to be ready from the fall of the clock (0x430f) till the moment of reading (0x4319) which translated to numbers turn into (52 * 0.28us = 14,5us.

    Initially the total latency was higher than 30us from the RISE of the clock pin to the moment that the data was effectively changing resulting in a extremely unstable position of the paddle on the screen.

    The latency was reduced down to 3.6us by:

    • Pre-shifting the shiftRegister variable at the end of the interrupt
    • Changing the pins by writing to registers DDR/PORT instead of use digitalWrite()
    • Triggering the interrupt at the FALL of the clock signal.
      // External Interrupt driven by Clock pin (6)
      ISR(INT1_vect) {
      
         if (shiftRegister & (1<<15) ){
            OUT_DDR  &= ~(1<<0); // data on bit 0
            OUT_PORT |= (1<<0);       
          } else {
            OUT_PORT  &= ~(1<<0); 
            OUT_DDR |= (1<<0);      
            }
          // shift regiter was pre-shifted 
         digitalWrite(debugPin,HIGH);  
         digitalWrite(debugPin,LOW); 
        
          // pre-shift next bit   
          shiftRegister<<=1;    
      }

    Now the next data is ready even before the Z80 rise back the clock signal!

    Last but not least, the capture below shows the moment that the button is sampled and the output (pin 2) is changed. The capure also shows the method of reading. As the ADC on the original Arkanoid controller takes too much time (3-10ms) to convert the potentiometer position, the shifts are shifted FIRST then a NEW SAMPLE is requested by a pulse on pin 8.

View project log

Enjoy this project?

Share

Discussions

Sean Green wrote 11/16/2022 at 23:02 point

curiosity if you have a scan saved. I want to know if the sms paddle runs the clock 24 7. Does it ever sleep. But more importantly I was hoping to know if the console reads it full time ( guessing not).  Would need to look at the game code for that.  Also at what point does it read data. I gathered it was around 10 after rise/fall of trigger.

  Are you sure? yes | no

danjovic wrote 11/17/2022 at 20:27 point

Sorry I don't have any capture from the logic analyzer.

I haven't captured the logic analyzer data for SMS. The source code is available as a link to github on this same page.

  Are you sure? yes | no

sdsnatcher wrote 02/20/2020 at 05:26 point

I forgot to mention this suggestion:

- For the Arkanoid paddle, limit the absolute maximum value to 510. 511 is an impossibly high value on the original Vaus paddle, so I use it on HIDlib as a reserved value to detect that the paddle was disconnected.

  Are you sure? yes | no

danjovic wrote 02/23/2020 at 13:45 point

Sure! I will range the reading to match the Vaus paddle output values, something about 112 to 399 (128-12 to 384+11) center at 256.

  Are you sure? yes | no

sdsnatcher wrote 02/19/2020 at 18:01 point

This is a really nice project, danjovic! Here goes some suggestions to improve its interoperability:

It seems possible to support 4 modes of operation:

1) MSX/Arkanoid

2) MSX-Paddle (standard)

3) SMS/Japanese paddle

4) SMS/Export paddle

Two select between the four modes:

1) MSX or SMS: keep the pin-9 detection as you did

2) MSX/Arkanoid: If the pin-6 is toggled by the computer, switch to Arkanoid mode. But you might also want to add a way to force the Arkanoid mode, since on auto mode HIDlib will always detect first it as a standard MSX-paddle and never toggle the pin-6.

3) SMS/Export paddle: if the pin-7 (TH) is toggled by the console, switch to Export mode.

More info about the SMS/Export paddle can be read here:

https://www.smspower.org/Development/Paddle

On the MSX-paddle,  HIDlib detects more buttons, allowing you to use a SNES joypad case. In case you're interested, I described it here:

http://frs.badcoffee.info/hardware/PWM_devices.html

  Are you sure? yes | no

danjovic wrote 02/23/2020 at 13:57 point

First version of firmware used the trigger button held on startup to toggle between paddle modes, then came the autodetection (yet unreleased). I may think in a combination of button plus potentiometer side or even second button to program the operating modes.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates