• entries
    58
  • comments
    218
  • views
    114355

I HAS SKILLS

Sign in to follow this  

613 views

Well, it's been a while since my last entry, so I figured I should spend the day getting back into my project. I was still trying to figure out to connect the damn NES controllers to the rest of the project. After scratching my head for a bit, I decided to solder them back into the Four Score and then doing some general mangling of the circuit board to make it do what I wanted. I soldered in a few jumpers, ripped out the turbo buttons, ripped out a few resistors, capacitors, the main Four Score processor, and the output wire, and ended up with this:



As you can see from the well placed and stylish ON/OFF labels, I have converted the selector switch into an On/Off switch for my system. The extended leads are easily pluggable into the breadboard system, so my task has been completed.

Next, I have to actually read the damn thing. Fortunately, there is tons of information on how the NES controllers work, and even some sample code on the Parallax forums that I could investigate and play with.

After a little experimenting to see what did what, I ended up with the following gamepad driver code:


CON
IO_JOY_CLK = %00001000
IO_JOY_SHLDn = %00010000
IO_JOY_DATAOUT0 = %00100000
IO_JOY_DATAOUT1 = %01000000
NES_LATCH_DELAY = $40

NES_RIGHT = %00000001
NES_LEFT = %00000010
NES_DOWN = %00000100
NES_UP = %00001000
NES_START = %00010000
NES_SELECT = %00100000
NES_B = %01000000
NES_A = %10000000

NES0_RIGHT = %00000000_00000001
NES0_LEFT = %00000000_00000010
NES0_DOWN = %00000000_00000100
NES0_UP = %00000000_00001000
NES0_START = %00000000_00010000
NES0_SELECT = %00000000_00100000
NES0_B = %00000000_01000000
NES0_A = %00000000_10000000

NES1_RIGHT = %00000001_00000000
NES1_LEFT = %00000010_00000000
NES1_DOWN = %00000100_00000000
NES1_UP = %00001000_00000000
NES1_START = %00010000_00000000
NES1_SELECT = %00100000_00000000
NES1_B = %01000000_00000000
NES1_A = %10000000_00000000

VAR
long cogon, cog
long nes_bits_parm ' local storage for NES state/bits

PUB start : okay

'' Start the NES gamepad reading process
'' returns false if no cog available
''
stop
okay := cogon := (cog := cognew(@NES_Read_Gamepad_ASM_Entry, @nes_bits_parm)) > 0


PUB stop

'' Stops driver - frees a cog

if cogon~
cogstop(cog)

PUB read
'' Reads the NES state and sends it back to caller
return(nes_bits_parm)


PUB button(nes_button)
'' Return TRUE/FALSE if sent button is down
return(nes_button & nes_bits_parm)

DAT

org $000

NES_Read_Gamepad_ASM_Entry

' step 1: set I/Os,
or DIRA, #(IO_JOY_CLK | IO_JOY_SHLDn) ' JOY_CLK and JOY_SH/LDn to outputs
and DIRA, #(!(IO_JOY_DATAOUT0 | IO_JOY_DATAOUT1)) & $1ff ' JOY_DATAOUT0 and JOY_DATAOUT1 to inputs

NES_Latchbits

' step 2: set latch and clock to 0
and OUTA, #(!(IO_JOY_CLK | IO_JOY_SHLDn)) & $1ff ' JOY_CLK = 0, JOY_SH/LDn = 0

' initialize counter and delay to let NES settle
mov _counter, CNT
add _counter, #NES_LATCH_DELAY
waitcnt _counter, #NES_LATCH_DELAY

' step 3: set latch to 1
or OUTA, #(IO_JOY_SHLDn) ' JOY_SH/LDn = 1

' initialize counter and delay to let NES settle
mov _counter, CNT
add _counter, #NES_LATCH_DELAY
waitcnt _counter, #NES_LATCH_DELAY

' step 4: set latch to 0
and OUTA,#(!(IO_JOY_SHLDn) & $1ff) ' JOY_SH/LDn = 0

' clear gamepad storage word
xor _nes_bits, _nes_bits

' step 5: read 8 bits, 1st bits are already latched and ready, simply save and clock remaining bits
mov _index, #8

NES_Getbits_Loop

shl _nes_bits, #$1 ' ' shift results 1 bit to the left each time

mov _nes_gamepad0, INA ' read all 32-bits of input including gamepads
mov _nes_gamepad1, _nes_gamepad0 ' copy all 32-bits of input including gamepads

' now extract bits from inputs
and _nes_gamepad0, #(IO_JOY_DATAOUT0)
and _nes_gamepad1, #(IO_JOY_DATAOUT1)

' shift bits into place, so that gamepad0 bits fall into bit 0 of 16-bit result and gamepad1 bits fall into bit 8 of 16-bit result
' then continuously shift the entire result until every buttons has been shifted into position from both gamepads
shr _nes_gamepad0, #5
shl _nes_gamepad1, #2

' finally OR results into accumulating result/sum
or _nes_bits, _nes_gamepad0
or _nes_bits, _nes_gamepad1

' pulse clock...
or OUTA, #%00001000 ' JOY_CLK = 1

' initialize counter and delay to let NES settle
mov _counter, CNT
add _counter, #NES_LATCH_DELAY
waitcnt _counter, #NES_LATCH_DELAY

and OUTA,#%11110111 ' JOY_CLK = 0

' initialize counter and delay to let NES settle
mov _counter, CNT
add _counter, #NES_LATCH_DELAY
waitcnt _counter, #NES_LATCH_DELAY

djnz _index, #NES_Getbits_Loop
' END NES_getbits_loop

' invert bits to make positive logic
xor _nes_bits, _MAXINT

' mask lower 16-bits only
and _nes_bits, _NES_GAMEPAD_MASK

' finally write results back out to caller
wrlong _nes_bits, par ' now access main memory and write the value

' continue looping...
jmp #NES_Latchbits


_MAXINT long $ffff_ffff ' 32-bit maximum value constant
_NES_GAMEPAD_MASK long $0000_ffff ' mask for NES lower 16-bits

_nes_bits long $0 ' storage for 16 NES gamepad bits (lower 16-bits)
_nes_gamepad0 long $0 ' left gamepad temp storage
_nes_gamepad1 long $0 ' right gamepad temp storage
_index long $0 ' general counter/index
_counter long $0 ' general counter



Using this, I set up a simple tester program that would let me see the state of all the buttons visually. I downloaded the nice PropTerminal program, which talks to a Propeller hooked up through a USB port and reports any textual video information to the screen. That way I didn't need a real TV to hook up with.

Here is the result of the gamepad test (Note: I'm holding down the B and Up buttons on the first controller).



Not bad for a day's work. So I finally have some reliable input. Next step is graphical output to a TV, and from there, any game I want to make is up for grabs.

I have a few ideas of the first few games I want to make. I'm thinking of Pong as my first, since it's such a classic. After that, it's not as clear. I could go with Pac Man or Defender or Robotron, or maybe even asteroids. There are simply tons of cool old games that would be a blast to recreate. If anyone has any ideas for a great game, let me hear 'em!

On a final note, I started thinking seriously about the next step the project will take. The breadboard is nice for quick prototyping, but I need something more stable and more permanent. I found EAGLE, a freeware schematic diagramming application that seems to be highly recommended. Couple a board design from there and the cheap pricing of Batch PCB and I may be able to go with a custom PCB for a tidier solution.

Thoughts or comments? Let me hear 'em!
Sign in to follow this  


1 Comment


Recommended Comments

Hey, I've been building robots on and off for a year, and have a fair handle on electronics, and a kind of "Meh" one on microcontrollers. I have a few atemga8's laying around and have been interested in building my own console for a long time. I'm thinking of having 3 or 4 Atmega's, one controlling input. Then, I would somehow arrange the screen into 64 pixels (large blocks) and the programmer for the game just decides how to use these pixels to make something. As in, if you had pong, you would have 3 or 4 turned on on each side, and if the up was pressed, the paddle's top would be moved up 1 pixel, and the same for the bottom. I need to figure out a way to interface to a TV though, or use an LED matrix, which would seem to be expensive and time-consuming. I also need to think of how I'm going to link up the atmega's. Do you have any ideas?

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now