Jump to content
Dropcheck

Arduino Emulated Atari Joystick CX40

Recommended Posts

I'm playing with a fairly small project at this time.  Learning about Arduino and the Atmega328PB. 

 

Right now I have learned how to read the original Atari joystick CX40 via an Arduino Uno.  That didn't seem to hard.  :)

 

The next logical step is to emulate that joystick via an Uno connected to the joystick port of an Atari 800XL.  This is where I am running into a bit of a road block.  🤔

 

As I understand it the Atari provides a voltage on the UP/DOWN/LEFT/RIGHT/FIRE pins and when the joystick is moved to close one of the pin circuit, it presents a high to the PIA port.  I'm not quite certain how to emulate that in code for the Uno.  

 

Does someone have an example of that they've verified works?

  • Like 1

Share this post


Link to post
Share on other sites

The input pins on PIA have weak pullups - ie, 5 volts but at very low amps.  The directions on the stick ground the input forcing it to zero.

 

So I guess to emulate it, either do nothing or supply 5V at very low current to the relevant pin for "not active" and ground the pin for "active".

  • Like 1

Share this post


Link to post
Share on other sites
25 minutes ago, Rybags said:

The input pins on PIA have weak pullups - ie, 5 volts but at very low amps.  The directions on the stick ground the input forcing it to zero.

 

So I guess to emulate it, either do nothing or supply 5V at very low current to the relevant pin for "not active" and ground the pin for "active".

So my understanding is actually reversed?  Hmmm.....

 

So I have the joystick port pins connected to the specific UNO pins 2-5(UP/DOWN/LEFT/RIGHT) and 6(FIRE).  I would need to set those to pinMode(Input) and DigitalWrite(x, High) in setup to simulate a joystick at rest.

 

Then as the Fire button is pressed or the joystick is moved to the various cardinal points, I would use DigitalWrite(x, Low)? 

Edited by Dropcheck

Share this post


Link to post
Share on other sites

I guess so.

Or if there's a mode that just leaves the line alone use that as the resting state.

Share this post


Link to post
Share on other sites

Sort of related, I had a USB joypad I use on my PC with Altirra64 and wanted to use it on my 130XE.

 

I bought a USB HAT for the Arduino and used the outputs from the Arduino and needed no pullups

works a treat (see highligthed text below)

 

#include <usbhid.h>
#include <hiduniversal.h>
#include <usbhub.h>
// Gamepad pressed values


// Satisfy IDE, which only needs to see the include statment in the ino.
#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif
#include <SPI.h>

#include "hidjoystickrptparser.h"

USB Usb;
USBHub Hub(&Usb);
HIDUniversal Hid(&Usb);
JoystickEvents JoyEvents;
JoystickReportParser Joy(&JoyEvents);

void setup() {
  Serial.begin(115200);
  #if !defined(__MIPSEL__)
    while (!Serial); 
  #endif
  Serial.println("Start");
  if (Usb.Init() == -1)
    Serial.println("OSC did not start.");
  delay(200);
  if (!Hid.SetReportParser(0, &Joy))
    ErrorMessage<uint8_t > (PSTR("SetReportParser"), 1);
  for(int i=4;i<9;i++) // set output pins
  {
    pinMode(i, OUTPUT); 
    digitalWrite(i,HIGH);
  }           

}

void loop() {
  uint8_t but;
        Usb.Task();

 

}

Share this post


Link to post
Share on other sites

I realize there are probably as many ways of doing this as there are people.   And that nearly infinite way of writing code is where the confusion reigns when someone like me tries to understand it.

 

But let me try. 

 

void setup() {

       // Set Uno pins 2-6 (UP/DOWN/LEFT/RIGHT/FIRE Joystick) off 

       turnJPinsOFF();

 

}

 

loop() {

      //Test Fire button operation

      pinMode(6, OUPUT);

      digitalWrite(6, HIGH);

      delay(1000);

      turnJPinsOFF();

}

 

void turnJPinsOFF() {

      // Set Uno pins 2-6 (UP/DOWN/LEFT/RIGHT/FIRE Joystick) off 

       for (int pinNumber = 2; pinNumber  < 7; pinNumber++) {

             pinMode(pinNumber, INPUT_PULLUP);

             digitalWrite(pinNumber, LOW);

       }

}

    

 

      

Share this post


Link to post
Share on other sites
43 minutes ago, ivop said:

Here's how I did it on an Arduino Nano for snes2joy:

 

https://github.com/ivop/snes2joy/blob/master/firmware/main.c

 

It's basically line 219 and joy_init().

 

Clear as mud.   Here's what I think I see.  You are using pure C or C++ not the tamer Arduino Sketch code and what looks like bitwise comparison or something like that.  Way beyond my comprehension level at this point with the Arduino.  I still need training wheels.  😧

 

But I'll try to translate it back to something that I am familiar enough with to understand what is happening.  😕  Okay let's start with the function that seems equivalent to the setup() function in Arduino Sketch code.

 

Quote
static void joy_init(void) {
DDRB |= 0x1f;
PORTB |= 0x1f;

}

 

I get that this seems to be setting PortB's pin direction, but what is it setting it too?   

 

 

 

Share this post


Link to post
Share on other sites
37 minutes ago, Dropcheck said:

Clear as mud.   Here's what I think I see.  You are using pure C or C++ not the tamer Arduino Sketch code and what looks like bitwise comparison or something like that.  Way beyond my comprehension level at this point with the Arduino.  I still need training wheels.  😧

 

Yes, I never use the Arduino Sketch IDE, as it generates inferior code IMO. This is plain C.

 

Quote

I get that this seems to be setting PortB's pin direction, but what is it setting it too?  

 

Output. See e.g. for more details on the DDRx/PORTx/PINx registers:

 

https://www.arduino.cc/en/Reference/PortManipulation

 

...
#define BUTTON_UP       0x0010
#define BUTTON_DOWN     0x0020
#define BUTTON_LEFT     0x0040
#define BUTTON_RIGHT 0x0080
...
	PORTB = ((w0>>4) & 0x0f) | (!(w1 & mask) ? 0x10 : 0);
...

w0 contains the directions in the upper four bits of the lower byte, hence >>4 shift right 4 times and then bitwise & to mask out any upper bits .

 

w0 now contains the direction bits in the lowest four bits, bit 0-3

 

bit 4 is the trigger bit.

 

w1 is w0 inverted, and mask is $0F0F, i.e. all the SNES buttons. Totally irrelevant to your use case. Basically you have to | (or) in the trigger bit (either $10 or $00).

 

Look at the schematics how PORTB is connected to the joystick port.

 

Edit: at the end of the linked document they state exactly the reasons why I use plain C in the first place:

 

* You may need to be able to turn pins on and off very quickly. (not relevant here though)

* Sometimes you might need to set multiple output pins at exactly the same time. (relevant here, possible wrong directions if the atari reads the port inbetween separate bit changes)

* If you are running low on program memory, you can use these tricks to make your code smaller.  (always relevant :) )

 

Edited by ivop
  • Like 1

Share this post


Link to post
Share on other sites

I've heard that about Arduino Sketch, but for this small a project in the beginning learning phase of the whole environment,  I wanted to use the training wheels that Arduino provided.  Once I got some experience under my belt I felt I could then 'grow up' into the full blown C or C++ language usage. 

 

Baby steps I know.  I'll take this info and try not to get to bloodied trying to translate it/understand it.  🤕

 

Thank you. 🙂

Share this post


Link to post
Share on other sites
7 minutes ago, Dropcheck said:

I've heard that about Arduino Sketch, but for this small a project in the beginning learning phase of the whole environment,  I wanted to use the training wheels that Arduino provided.  Once I got some experience under my belt I felt I could then 'grow up' into the full blown C or C++ language usage. 

 

Yeah, I understand that. Feel free to ask any questions. I'm not familiar with the Sketch API, but I can explain what my code does :)

 

BTW how nice of the new forum software that you can easily split quotes by pressing enter. You used to go "underwater" to do that!

Share this post


Link to post
Share on other sites

Don't know if you're on Windows or Linux or somethingElseOS, but with the debian WSL (Windows Subsystem for Linux) you should be able to get a similar bash prompt and avr-gcc environment I use on vanilla debian Linux.

 

Then

 

# apt-get install avr-libc avrdude binutils-avr gcc-avr git

 

Clone my github repo (git clone https://github.com/ivop/snes2joy.git) and run make in the firmware directory. If that works, you have a working toolchain. Don't know how good the USB  support is with WSL, but running real Linux, you can use avrdude to flash your device. Check the flash: rule in the Makefile for a sample command line. Or try make flash if you're brave ;)

 

 

 

Edited by ivop
typo

Share this post


Link to post
Share on other sites
4 minutes ago, ivop said:

Don't know how good the USB  support is with WSL, but running real Linux, you can use avrdude to flash your device. Check the flash: rule in the Makefile for a sample command line. Or try make flash if you're brave ;)

 

I think I did this last summer and it worked fine but I found WSL limiting for what I wanted to do. More recently, I've got to an Ubuntu installation running inside VirtualBox. That's how I flash the UNO inside my SDrive-MAX. So if I can do it in VirtualBox, I have to believe WSL would work just as well.

Share this post


Link to post
Share on other sites
56 minutes ago, DrVenkman said:

I think I did this last summer and it worked fine but I found WSL limiting for what I wanted to do. More recently, I've got to an Ubuntu installation running inside VirtualBox. That's how I flash the UNO inside my SDrive-MAX. So if I can do it in VirtualBox, I have to believe WSL would work just as well.

That's not necessarily so, because of drivers. Linux+VirtualBox runs all the true Linux kernel drivers on the raw devices that are passed through to VirtualBox. WSL does not have those priviliges. But there's WSL2 now that seems to run way more of the Linux kernel, including drivers, so it might workt out-of-the-box now.

 

 

Edit: Oh, this is my 1024th post :)

Edited by ivop
  • Like 1

Share this post


Link to post
Share on other sites
On 7/2/2019 at 8:18 AM, Dropcheck said:

So my understanding is actually reversed?  Hmmm.....

 

So I have the joystick port pins connected to the specific UNO pins 2-5(UP/DOWN/LEFT/RIGHT) and 6(FIRE).  I would need to set those to pinMode(Input) and DigitalWrite(x, High) in setup to simulate a joystick at rest.

 

Then as the Fire button is pressed or the joystick is moved to the various cardinal points, I would use DigitalWrite(x, Low)? 

I don’t think you want to use pins 0 and 1. Those are typically used for xmit and rcv and can cause issues if you try to use them like you are trying to use them. 

Share this post


Link to post
Share on other sites

Following - this is a timely thread for me!

 

I built a Raspberry Pi Zero-based mod for my ST and Falcon030 so I could use USB and Bluetooth keyboards, mice and joysticks with them.

 

I'm about to receive an XEGS and am wanting to do something similar.  Seems like getting an Arduino Nano to send joystick signals to the A8 is easy enough.  I'm looking at a few Nano clones which have built-in Bluetooth support, but I can't quite get a definitive answer on whether I can successfully pair a BT gamepad with such a board.

 

Hmmm!

  • Like 1

Share this post


Link to post
Share on other sites
41 minutes ago, toddtmw said:

I don’t think you want to use pins 0 and 1. Those are typically used for xmit and rcv and can cause issues if you try to use them like you are trying to use them. 

I'm not.   Digital pins 0 and 1 are the TX/RX pins.  Digital pins 2 and up reference the rest of Port D (PD2 - PD7)

Share this post


Link to post
Share on other sites

I always use a template in a spreadsheet to see which bits/ports I'm going to use for a certain signal.

 

https://github.com/ivop/snes2joy/tree/master/doc

 

Quick gimped screenshot of xpdf snes2joy.pdf ;)

 

nano-snes2joy-ods.thumb.png.4fdba8ed8b6444923fffc31e6fbf9013.png

 

The .ods is an Open Document Sheet and is editable, so you can edit your own first and last column. During development I especially like it that you immediately see which things you might give up, like SPI, 2-wire, USART, certain PWM channels, interrupts or ADC channels.

 

I create such sheets for every MCU I encounter :)

 

Edited by ivop
  • Like 3

Share this post


Link to post
Share on other sites

There might be some information you will find interesting in this blog entry.  I have had the Arduino hooked up to the Atari for several projects in several different ways.  I generally like to use optocouplers between the Atari and Arduino for the safety factor they provide. This particular optocoupler works well enough for setting the inputs.  Its a little hit and miss when used when the Atari joystick pins are set for output. 

 

 

 

  • Like 2

Share this post


Link to post
Share on other sites
23 hours ago, k-Pack said:

There might be some information you will find interesting in this blog entry.  I have had the Arduino hooked up to the Atari for several projects in several different ways.  I generally like to use optocouplers between the Atari and Arduino for the safety factor they provide. This particular optocoupler works well enough for setting the inputs.  Its a little hit and miss when used when the Atari joystick pins are set for output. 

 

 

 

Looking over your blog post there, I had a bit of trouble making out the handwritten diagram for the optocouplers.  On the transistor side you tied all the emitters together, but to what.  I can't quite make out the word.  🙂

Share this post


Link to post
Share on other sites
2 hours ago, Dropcheck said:

Looking over your blog post there, I had a bit of trouble making out the handwritten diagram for the optocouplers.  On the transistor side you tied all the emitters together, but to what.  I can't quite make out the word.  🙂

The ground would be pin 8 of the atari joystick ports.  The transisters are replacing the switches in the joystick. They are being turned on and off by the LEDs.

Share this post


Link to post
Share on other sites
12 hours ago, k-Pack said:

The ground would be pin 8 of the atari joystick ports.  The transisters are replacing the switches in the joystick. They are being turned on and off by the LEDs.

Okay I think I see how the arduino is buffered from the joystick ports.  Would the following schematic accurately describe the proper connection between the Atari joystick ports and the arduino?  It's part of a stand alone ATMega 328P circuit getting power from the ports, not a development board.

 

JoystickBuffer.thumb.jpg.eaf451c4b5b8e68c044e824d4afc11e4.jpg

Edited by Dropcheck

Share this post


Link to post
Share on other sites
11 hours ago, Dropcheck said:

Okay I think I see how the arduino is buffered from the joystick ports.  Would the following schematic accurately describe the proper connection between the Atari joystick ports and the arduino?  It's part of a stand alone ATMega 328P circuit getting power from the ports, not a development board.

 

 

It should work if the Atari can handle the power requirements of the ATMega.  I have no idea what the power requirement is or how much the Atari can provide.  Since there is only one power source the optocouplers haven't isolated the two circuits;  replacing the optocouplers with transistors would probably be a better choice.

Share this post


Link to post
Share on other sites

Why not just connect them straight to the joystick port? The Atari has resistors in series. A few weeks ago we sank 9V into the PIA for a whole afternoon, and it still works fine.

 

Share this post


Link to post
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.

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...