Jump to content
IGNORED

Auto-Detecting Controller at Startup


Recommended Posts

As I am continuing to develop my first game, I ran into an issue that I couldn't find any information on. I would like to have the system detect the controllers on startup. This way, I can support multiple controllers in the game without using the difficulty switches or some other U/I system to select controller types, simply plug-and-play.

I first had the idea of using the fire button to get past the splash screen of the game. However, moving the joystick instead could put the game into paddle mode, which wouldn't be good. So instead, I discovered that you can simply dump the capacitors for the paddles, wait long enough (512 scanlines works), and then read INPT0 (and INPT2).

And that's it.

 

Here's the code I wrote, which works perfectly. If a paddle is connected to the left I/O port at startup, the screen will be red. Otherwise, the screen is black.

	CLEAN_START

	sta WSYNC	; ensure a whole scanline is spent dumping capacitors
	lda #$80
	sta VBLANK	; dump paddle capacitors to ground
WaitLoop
	sta WSYNC
	stx VBLANK	; (X=0) stop dumping capacitors
	sta WSYNC	; waste 2 scanlines per iteration
	dey		; Y starts and ends as 0
	bne WaitLoop	; wait 512 scanlines in loop (511 after grounding caps)

	lda INPT0	; D7 set if left paddle is connected, clear otherwise
	bpl Joystick
	lda #$46	; set bg color to red to signify a paddle, else black
	sta COLUBK	; in a game, you would set a bit in RAM, instead
Joystick

I attached a .bin and the source code. Obviously, try it on a real system if you can, but it works in Stella, as well.

paddletest.bin

paddletest.asm

Edited by JeremiahK
  • Like 2
Link to comment
Share on other sites

Very interesting. Here is the Astroblast method:

DetermineControllerType
   lda #DUMP_PORTS | DISABLE_TIA
   sta VBLANK
   ldx #0
.waitForCapacitorCharge
   bit INPT0                        ; check paddle 0 value
   bpl .continueDetermineControllerType; branch if capacitor not charged
   dex
   bne .waitForCapacitorCharge
   beq .setControllerTypeToPaddles  ; unconditional branch
   
.continueDetermineControllerType
   lda #DISABLE_TIA
   sta VBLANK                       ; disable TIA (i.e. D1 = 1)
   ldx #32                          ; wait ~538 scanlines (i.e. ~2 frames)
.outerLoopWait
   ldy #0
.innerLoopWait
   iny
   bne .innerLoopWait
   dex
   bne .outerLoopWait
   bit INPT0                        ; check paddle 0 value
   bpl .doneDetermineControllerType ; branch if capacitor not charged
.setControllerTypeToPaddles
   lda gameState                    ; get current game state value
   ora #USING_PADDLES
   sta gameState                    ; set game state to USING_PADDLES
.doneDetermineControllerType
   rts

It seems to be doing more or less exactly the same thing, except I am using WSYNC to waste time much more efficiently.

Link to comment
Share on other sites

Keep in mind that a Sega Genesis/Megadrive pad will fail the test and will be detected as a paddle instead. There are pullup resistors connected to pins 5 and 9 inside the controller that cause the paddle caps to be recharged. Pin 9 (INPT1 or INPT3 depending on which port the controller is plugged in) can be grounded if button C is pressed (That's how that extra button can be read by some homebrews and hacks), while the pullup in pin 5 (INPT0/INPT2) is always connected so the related capacitor will always be recharged.

Those controllers are a common choice for people who prefer D-pads over a classic joystick, so you might want to consider a way to make them work with your game.

For example, you can add a way to force joystick mode by holding a button while powering the console (the RESET or SELECT switch, for example or a button/direction on the controller ). The Harmony menu forces joystick mode by holding the fire button on the controller itself ("B" on the genesis pad).

Or you could add code to revert to joystick mode if any of the UP/DOWN directions or the firebutton is pressed.


  • Like 2
Link to comment
Share on other sites

Does that mean that the auto-detection would correctly detect a Sega Genesis controller as a "joystick" if you read from INPT1/INPT3, as long as button C was not pressed at startup? Or would it only detect a joystick type controller if button C was pressed?

Link to comment
Share on other sites

I am pretty sure it's the latter, now that I carefully re-read your previous post.

In that case, I think the best solution is to check the fire button on startup, since you can't accidentally do that with a paddle.

 

Here's an update to my auto-detect program. There are bars on either side of the screen, representing the left and right I/O ports. They are each one of three colors (red = paddle auto-detected, blue = joystick auto-detected, green = joystick forced). You can force joystick mode by pressing the fire button. I would love to know if this works with Sega Genesis and other non-Atari controllers, although I would bet it works fine.

paddletest.bin

paddletest.asm

Edited by JeremiahK
Link to comment
Share on other sites

One workaround would be to make the user press fire to exit the splash screen. That way, if a paddle was detected, but a joystick's fire button was pressed, it would switch to joystick mode.

 

Edit: That would only work with one controller, though.

Edited by JeremiahK
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...