• entries
58
218
• views
114355

# I HAS SKILLS

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_00000000VAR long cogon, cog long nes_bits_parm ' local storage for NES state/bitsPUB 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)) > 0PUB 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)DATorg$000NES_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, #8NES_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!

## 1 Comment

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?

## Create an account

Register a new account