Jump to content
IGNORED

Help with 5200 Joystick Emulation Algorithm


flickertail

Recommended Posts

I was wondering if I could get some feedback on the code that I am using to emulate the 5200 joystick for the USB adapter that I am developing.

 

I posted a demo of a somewhat working USB adapter for the 5200 on my blog last night.

It sorta works with Joust... not so much with Pac-man. I don't have too many 5200 games on-hand, beyond Pac-man, so not sure how well it will work with other games. Off-topic question, is there something like a Harmony Cart for the 5200?

 

Joystick Pot Chip

For the potentiometers, I am using the AD5242 I2C chip.

The datasheet for which can be found here:

https://www.analog.com/media/en/technical-documentation/data-sheets/AD5241_5242.pdf

 

Essentially, it offers 2 x 1-MegaOhm Digital-to-Analog Converters (DAC) digital pots and two logic pins (which I use to control the 5200 fire buttons). For those who have the knowledge to understand the datasheet, I'm running 5200 Pin 9 to the chip's A1 and A2 pins, 5200 Pin 15 to B1 and B2, 5200 Pin 10 to W1, and 5200 Pin 11 to W2. 

 

The DACs are set via an unsigned 8-bit integer with a value of 0-255. Since the 5200 pots are only 500K Ohms, I'm only setting the DAC values using a range of 0-127. The DACs get set according to the following values:

  • // 0 is Right (East  - 500K Ohms), 127 is Left (West  - 0 Ohms)
  • // 0 is Down (South - 500K Ohms), 127 is Up   (North - 0 Ohms)
     

I've based this off the info found on the Pinouts.ru website that "playsoft" mentioned in response to one of my previous posts:

https://old.pinouts.ru/InputCables/JoystickAtari5200_pinout.shtml

 

Controller Being Used

My code evaluates the Left analog joystick of the Atari VCS Modern Controller (MC). I'll try to figure out a way for the user to choose between left/right joysticks in the future.

Some info about the MC's joystick output:

  • Horizontal (X)
    • Full Left Value: -32,XXX
    • Full Right Value: 32,XXX
    • Centered: 0
  • Vertical (Y):
    • Full Up Value: -32,XXX
    • Full Dn Value: 32,XXX
    • Centered: 0

 

Joystick C Code

// 'atm_report' is a USB reporting Struct
// leftJSY leftJSX are uint16_t data types that report joystick X,Y axis values
int32_t tempY = (int32_t) atm_report.leftJSY;
int32_t tempX = (int32_t) atm_report.leftJSX;

tempY = (tempY + 32767) / 512;
tempX = (tempX + 32767) / 512;

tempY = 127 - tempY;
tempX = 127 - tempX;

uint8_t theY = (uint8_t) tempY;
uint8_t theX = (uint8_t) tempX;

This code works 'ok' with Joust, but seems to be completely not usable with Pac-man.

 

So I'm not sure what I'm asking here. Maybe, does this seem like a reasonable algorithm for emulating the 5200's physical joystick pots? This is a linear algorithm, but it's my understanding that the pot rotations doen't actual translate to a linear ohm change. If so, then the above code leaves something to be desired, I guess.

 

Any thoughts on this are appreciated.

 

Link to comment
Share on other sites

I think that the issue might be related to trackball detection scheme.

You should watch the Pot Voltage source at pin 9. This is a switchable voltage that can be either ON or OFF.

When this voltage is off (zero Volts):

  • The joysticks will never charge the internal capacitors, thus the timing will exceed the maximum count (228).
  • The trackball, on the other side will present theoretically half the maximum count ( 114 ).

 

That difference allows some games to differentiate between Joysticks and trackballs.

 

Also notice that:

When the voltage is ON it can reach up to 6.5Volts depending upon the adjustments of internal potentiometer.

The trackball converts the turning speed of the ball into the position of the potentiomenter (so to speak). Indeed the trackball uses PWM to "pump charge" the capacitors and then the charging time will correspond to the integral of the value along every charging cycle of the pokey chip.

 

 

Link to comment
Share on other sites

12 minutes ago, flickertail said:

Sorry, I'm not entirely following the timing issue. I apologize, as I am unfamiliar with 5200 programming.

The joystick position is obtained by the 5200 by measuring the time it takes for a capacitor to charge. Such task is perfomed automatically by the Pokey chip.

The capacitors are kept dircharged by forcing a "0" level on the (every) POT pin.

When the 5200 wants to "read" the controller it commands the Pokey Chip to release the pins, then the capacitors start to charge.

The counting increments every video line (64us each) until the capacitor voltage exceeds a given threshold (1.9V to 2.6V according to Pokey datasheet) or when the counter reaches 228.

 

In practice, for you to simulate a joystick you should turn your digipots to the maximum whenever the voltage at pin 9 drops to zero, otherwise the trackball games will take your adapter for a trackball.

 

Link to comment
Share on other sites

50 minutes ago, Danjovic said:

In practice, for you to simulate a joystick you should turn your digipots to the maximum whenever the voltage at pin 9 drops to zero, otherwise the trackball games will take your adapter for a trackball.

I appreciate the explanation. I can probably use the GPIO/ADC pins to track the Pin 9 voltage.

Link to comment
Share on other sites

  • 2 weeks later...
On 1/11/2022 at 8:59 AM, Danjovic said:

BTW, extension cord with db15. It might be useful for new designed contrlollers or adapters 

I actually have a coupe of those... I ordered a female db15 connector this week to see if it'll fit.

 

I'm frustrated though. I still can't get the AD5242s to work as expected. It's especially irritating as I know other people have gotten them to work. And back when I was working on this with a RPi Zero instead of a pico, I got it to work. But for the life of me, I can't figure out what I'm doing wrong.

 

I tried wiring them as rheostats (as that's how the original controller pots seem to be wired), I've tried wiring them as actual digital pots. When wired as rheostats, they seem to work as expected... except... they only work in one direction. They seem to work in both directions when wires as digital pots, but they are flakey... sometimes they do, sometimes they don't.

 

I would assume that he rheostat wiring is the way to go, but then why I can't get the "up" and "right" working. I'm inclined to believe that it's my crappy C code is some how clipping 0-255 value of the AD5242, but I've tried it 1000 different ways, and it either it doesn't work any better than they way it's currently working or doesn't work at all.

 

Maybe my understanding of analog joysticks of the Atari Modern Controller isn't correct. Maybe the USB report for the joysticks isn't a int16. IDK.

 

I suppose to could start working on Xbox 360 controller support, as it the sticks on the xbox controller are definitely a 16bit signed int.

Link to comment
Share on other sites

14 hours ago, flickertail said:

I tried wiring them as rheostats (as that's how the original controller pots seem to be wired), I've tried wiring them as actual digital pots. When wired as rheostats, they seem to work as expected... except... they only work in one direction.

I think this is probably down to the joystick code.

On 1/1/2022 at 10:04 PM, flickertail said:

Some info about the MC's joystick output:

  • Horizontal (X)
    • Full Left Value: -32,XXX
    • Full Right Value: 32,XXX
    • Centered: 0
  • Vertical (Y):
    • Full Up Value: -32,XXX
    • Full Dn Value: 32,XXX
    • Centered: 0

 

On 1/1/2022 at 10:04 PM, flickertail said:

Joystick C Code


// 'atm_report' is a USB reporting Struct
// leftJSY leftJSX are uint16_t data types that report joystick X,Y axis values
int32_t tempY = (int32_t) atm_report.leftJSY;
int32_t tempX = (int32_t) atm_report.leftJSX;

 

So the MC value is signed 16-bit but held in an unsigned 16-bit variable. However casting an unsigned 16-bit to a signed 32-bit will always result in a positive value. I would expect the joystick to work for right and down because positive values are OK, but not left and up.

 

If you change the casts to int16_t it will tell the compiler to treat the value as signed first, then it should automatically convert it from signed 16-bit to signed 32-bit (or you can do 2 casts or add interim int16_t variables).

 

Also, while I doubt it will make any noticeable difference, I'd change 32767 below to 32768 because the range of a signed 16-bit value is -32768 to 32767:

On 1/1/2022 at 10:04 PM, flickertail said:

tempY = (tempY + 32767) / 512;
tempX = (tempX + 32767) / 512;

 

 

Link to comment
Share on other sites

10 hours ago, playsoft said:

If you change the casts to int16_t it will tell the compiler to treat the value as signed first, then it should automatically convert it from signed 16-bit to signed 32-bit (or you can do 2 casts or add interim int16_t variables).

I thought about that, but the atm_report.leftJSX and .leftJSY are already defined as int16_t data types inside the atari_modern_report_t struct. See below.

typedef struct TU_ATTR_PACKED
{
    uint8_t  cInfo, cFire, cDirFunc;
    int16_t  leftJSX, leftJSY, rightJSX, rightJSY;
    uint16_t leftTrigger, rightTrigger;
} atari_modern_report_t;

Though in my desperation, I thought that it might be a casting issue anyway. So I tried the following instead:

int16_t tempX = (atm_report.leftJSX / 512) + 64
        tempX = 255 - tempX

uint8_t valueX = (uint8_t) tempX;

...but this didn't work either.

 

I really think I'm just not wiring the DAC correctly. Scott Baker uses a 100 Ohm DAC (MCP42100) to emulate the 5200 JS pots. I tried doing something similar to his wiring, but that didn't work either. I'm guessing its because I'm using 1M ohm DAC and he's using a 100K ohm DAC with additional capacitors connected to ground. Essentially he's trying to bump up to 500K ohm pots, and I'm trying to drop down to 500K ohm pots.

 

I guess I have a question. The pinouts for the 5200 controller that I've found state that the 5200 uses 500K ohm pots, but they also say that left/up are 0 ohms, and right/down are 500 ohms.

https://old.pinouts.ru/InputCables/JoystickAtari5200_pinout.shtml

 

Is the "500 ohms" a typo? I'm assuming it is and is instead supposed to be 500K ohms, but I've found this listed as 500 ohms in at least one other spot.

 

I can post the schematic of what I think my design should be... warning... the schematic is not a proper technical drawing, but should be somewhat self explanatory. If someone can provide feedback on how the AD5242 wiring is wrong, I would be grateful. I've had my friend David look at it already, but he seems to be at as much of a loss as I am.

 

I'll post the schematic a bit later.

Link to comment
Share on other sites

If anyone is interested in looking this over, I'd be happy for any advice about the proper wiring for the AD5242 chip. I suppose I should post my code too, but I don't have a github site, I'll upload the files here for those who are interested in seeing all the code... though it's a bit messy at the moment and not commented.

5200-schematic.jpg

Link to comment
Share on other sites

It may be a long shot, but check if the digital pots can operate correctly with a voltages above vcc, because the voltage at pin 9 can reach up to 6.2Volts depending on the adjustment of the internal calibratio  pot.

Another suggestion is to wire your digipots to an arduino and execute simon baker's code (with required modification on control, of course). 

Link to comment
Share on other sites

1 hour ago, Danjovic said:

It may be a long shot, but check if the digital pots can operate correctly with a voltages above vcc, because the voltage at pin 9 can reach up to 6.2Volts depending on the adjustment of the internal calibration pot.

Another suggestion is to wire your digipots to an arduino and execute simon baker's code (with required modification on control, of course). 

As for the voltage, according to David, the 5242 can handle up to 7 Volts on the DACs.

 

I already tried copying his wiring. Problem is that he uses the 42100 100K ohm digi pot chip connecting the wiper to ground through additional capacitors in order to "up level" to the necessary 500K ohm pots needed. I sorta have the opposite problem, I'm trying to cut a 1M ohm digi pot chip down to the necessary 500K ohm pots.

 

I know you pointed out that I'll need to modify the control (SPI vs I2C) his code somewhat.

 

His code generates a 0-255 int based on the voltage coming off the modern analog joystick, where as I'm trying to use the int16_t value received via the USB atari controller report. As such, the calculation used to find the 0-255 is significantly different.

 

For is code "v" is voltage from the 10K ohm analog joystick.

The 0-255 Y value is calculated by using: 255-((v-128)*18/20)+128

The 0-255 X value is calculated by using: 255-((v-128)*17/20)+128-4

 

I don't know why he's subtracting 4 or using different fractions for X and Y. IDK, maybe that's a code typo.

 

I'm almost ready to use SPI and buy some 42100's ad just do it the way he's doing it. However, I'd need to do my fire button code differently if I ditched the 5242.

 

I posted the files on my blog just a few minutes ago, but I'll repost it here in case anyone is interested.

main.c  hid_app.c

Link to comment
Share on other sites

The capacitors on Baker's circuit are there to compensate the smaller potentiometer value (100k instead of 500k), and he used some offset values to have both axes at 

 

In your case, with the 1M digipots you may loose half of the scale (using 0-127 only)

 

But my point is: try to validate that the 5242 can operate correctly using a simpler code.

Just send some constant values and check the values you obtain on the screen (using a test cartridge). 

 

Link to comment
Share on other sites

11 hours ago, flickertail said:

I thought about that, but the atm_report.leftJSX and .leftJSY are already defined as int16_t data types inside the atari_modern_report_t struct.

I didn't mean that you should change the types in the structure, but that you should change the casts in the section of code I quoted.

 

Change:

// 'atm_report' is a USB reporting Struct
// leftJSY leftJSX are uint16_t data types that report joystick X,Y axis values
int32_t tempY = (int32_t) atm_report.leftJSY;
int32_t tempX = (int32_t) atm_report.leftJSX;

To:

// 'atm_report' is a USB reporting Struct
// leftJSY leftJSX are uint16_t data types that report joystick X,Y axis values
int32_t tempY = (int16_t) atm_report.leftJSY;
int32_t tempX = (int16_t) atm_report.leftJSX;

Or this which is a bit clearer:

// 'atm_report' is a USB reporting Struct
// leftJSY leftJSX are uint16_t data types that report joystick X,Y axis values
int16_t signedJSY = (int16_t) atm_report.leftJSY;
int16_t signedJSX = (int16_t) atm_report.leftJSX;
int32_t tempY = (int32_t) signedJSY;
int32_t tempX = (int32_t) signedJSX;

When the MC reports a negative value your code currently generates a byte value in the range 192..255. With the change it will be 64..127.

Link to comment
Share on other sites

11 hours ago, flickertail said:

Though in my desperation, I thought that it might be a casting issue anyway. So I tried the following instead:


int16_t tempX = (atm_report.leftJSX / 512) + 64
        tempX = 255 - tempX

uint8_t valueX = (uint8_t) tempX;

...but this didn't work either.

This is OK for negative values, but positive values generate a byte value in the range 127..192.

Link to comment
Share on other sites

3 hours ago, playsoft said:

This is OK for negative values, but positive values generate a byte value in the range 127..192.

Indeed!

The output of the function return a value between 0 to 127 thus to invert this axis the operation should be :

 

tempX = 127 - tempX

 

instead of:

 

tempX = 255 - tempX 

 

 

 

 

Edited by Danjovic
Link to comment
Share on other sites

Before I do anything further, I decided to buy new 5242 chips, just in case I've damaged the ones I have. I have previously damaged the RIOT chip in my 7800 working on this stuff. It's possible that the chips I have been using have suffered a similar fate. At least, if I start with a batch of fresh chips and I still have a problem, then I'll know for certain that it's me and not the chips.

 

The new chips arrived yesterday, but I am unskilled when it comes to soldering, so David will have to put the chips on boards for me. So it'll probably be another week before I can take another stab at getting this to work.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...