PDA

View Full Version : Help implementing SNES Controller + PIC1F887



Daguava
- 7th September 2010, 22:00
Hello, I am fairly new to programming with PICBASIC Pro and have run into a problem. I am currently using a Snes Controller, a Pic16F887, and a HD44780 compatible display (4 lines, 20 char)

I'm reading the output of the Snes Controller, and am trying to display what character is pressed on the LCD screen. I have a word variable which stores the button values from a shiftin command. This word is then displayed on the LCD. (I have fixed this portion of the problem, read past the italics)My problem is that the only button that changes anything displayed is the "B" button, and when B is pressed, it reads as all buttons being pressed (The LCD shows 0000000000000000 where 0 means pressed, 1 means unpressed.) When B is not pressed it reads 1111111111111111. When B is pressed it should read 0111111111111111 since the B button's status is the first bit transferred. I fixed the italicized portion to an extent, I cannot read any buttons after "Y" (the second bit sent) because my timing is not exact enough. Sometimes Y registers like it should, sometimes it does not, so I will have to work on the timing.

I found this information about how the controller passes information:


The SNES controller has three data pins plus +5V power and ground.*A high on

the Data Latch pin for 12 us signals the controller to start sending data

which is clocked by a sequence of 16 pulses (6 us high, 6 us low) on the

clock pin. Serial data (8 buttons + 4 directions + 4 unused signals) is

returned on the serial data pin.*The serial data is negative-edge triggered.

Clock Cycle Button Reported
=========== ===============
1 B
2 Y
3 Select
4 Start
5 Up on joypad
6 Down on joypad
7 Left on joypad
8 Right on joypad
9 A
10 X
11 L
12 R
13 none (always high)
14 none (always high)
15 none (always high)
16 none (always high)




My current code programmed onto the PIC is as follows:


Include "modedefs.bas"

OSCCON = %01110000 ' INTRC = 8MHz

DEFINE OSC 8


DEFINE LCD_DREG PORTB ' Set LCD Data port
DEFINE LCD_DBIT 0 ' Set starting Data bit (0 or 4) if 4-bit bus i.e, PortD.4-PORTD.7
DEFINE LCD_RSREG PORTD ' Set LCD Register Select port
DEFINE LCD_RSBIT 2 ' Set LCD Register Select bit i.e, PORTC.5
DEFINE LCD_EREG PORTD ' Set LCD Enable port
DEFINE LCD_EBIT 4 ' Set LCD Enable bit i.e, PORTE.4
DEFINE LCD_BITS 8 ' Set LCD bus size ot 4 bit Upper Nibble (4 or 8 bits)
DEFINE LCD_LINES 4 ' Set number of lines on LCD to 4 Lines
DEFINE LCD_COMMANDUS 2000 ' Set command delay time in us
DEFINE LCD_DATAUS 50 ' dSet data delay time in us
DEFINE LCD_RWREG PORTD
DEFINE LCD_RWBIT 3




theoutput var Word


ANSEL = 0

PAUSE 1000 ' Wait a second

OUTPUT PORTC.1 ' configure input/output pins
OUTPUT PORTC.0
INPUT PORTC.2


LOW PORTC.1 ' Initialize LATCH
LOW PORTC.0 ' Initialize CLK

Loop: ' Main loop

PULSOUT PORTC.1, 10 ' Latch the data

SHIFTIN PORTC.2, PORTC.0, LSBPRE,[theoutput \16] ' Shift in socket 1 data

LCDOUT $FE, 1, BIN16 dasresult ' Display values

pause 50

GOTO Loop
END ' Repeat main loop

My guess on what is going on is that the internal oscillator might not be precise enough and is causing timing problems with the shiftin operation, but it could also be due to a complete lack of understanding of the shiftin operation, as this is the first time I've used it.

Does anyone have any ideas as to what might be going on? I'm not looking for someone to completely spell things out for me as I like t solve these kinds of problems, but a few nudges if anyone has some insight to this problem would be great. If anyone would like me to provide any more information please let me know.

Edit: Looking at some example code for a PS2 controller, I believe my shiftin code may be wrong, I'm going to mess around with it and see if that helps.
Edit2: spotted an error with the shiftin statement, 0 should be PORTC.0, will report back in a bit.

Edit3: It is now working to an extent. There is a timing issue as button Y, the next bit reported, will sometimes register as pressed to the mcrocontroller, and sometimes not, while all bits after it register no presses.

mackrackit
- 7th September 2010, 22:49
Welcome to the forum.

Is that the whole code posted? I do not see how this will work

SHIFTIN PORTC.2, PORTC.0, LSBPRE,[theoutput \16] ' Shift in socket 1 data
LCDOUT $FE, 1, BIN16 dasresult ' Display values
I do not see "dasresult " as a VAR or how you are going from "theoutput" to "dasresult".

Daguava
- 7th September 2010, 23:19
Oops, thats a mistake from when I was cleaning it up to post, the revised code is below XD


Include "modedefs.bas"

OSCCON = %01110000 ' INTRC = 8MHz

DEFINE OSC 8


DEFINE LCD_DREG PORTB ' Set LCD Data port
DEFINE LCD_DBIT 0 ' Set starting Data bit (0 or 4) if 4-bit bus i.e, PortD.4-PORTD.7
DEFINE LCD_RSREG PORTD ' Set LCD Register Select port
DEFINE LCD_RSBIT 2 ' Set LCD Register Select bit i.e, PORTC.5
DEFINE LCD_EREG PORTD ' Set LCD Enable port
DEFINE LCD_EBIT 4 ' Set LCD Enable bit i.e, PORTE.4
DEFINE LCD_BITS 8 ' Set LCD bus size ot 4 bit Upper Nibble (4 or 8 bits)
DEFINE LCD_LINES 4 ' Set number of lines on LCD to 4 Lines
DEFINE LCD_COMMANDUS 2000 ' Set command delay time in us
DEFINE LCD_DATAUS 50 ' dSet data delay time in us
DEFINE LCD_RWREG PORTD
DEFINE LCD_RWBIT 3




theoutput var Word

ANSEL = 0

PAUSE 1000 ' Wait a second

OUTPUT PORTC.1 ' configure input/output pins
OUTPUT PORTC.0
INPUT PORTC.2


LOW PORTC.1 ' Initialize LATCH
LOW PORTC.0 ' Initialize CLK

Loop: ' Main loop

PULSOUT PORTC.1, 10 ' Latch the data

SHIFTIN PORTC.2, PORTC.0, MSBPRE,[theoutput \16] ' Shift in socket 1 data

LCDOUT $FE, 1, BIN16 theoutput ' Display values



pause 50

GOTO Loop
END ' Repeat main loop

The only issue that remains is that my timing is not precise enough and I'm losing a lot of the button press bits. I think the only solution is purchasing a crystal as the internal oscillator is not accurate enough.

mackrackit
- 7th September 2010, 23:53
I have not used one of those controllers..
The internal OSC should be accurate enough, the speed might be the issue.
You are pushing buttons while data is being sent to the display or looping for the next call???

Would be nice to push the data from the controller instead of calling for it. Is there some way to have a signal going to a PORTB interrupt?

Daguava
- 8th September 2010, 00:23
Oh wow, I feel so stupid, but I've just solved my own problem. Undervolting the shift-register inside of the controller by a half volt was enough to cause it to freak out giving me incomplete output, my code now works as expected and everything is working great.

Thanks for the help, and, if you wouldn't mind, could you elaborate a bit on what you meant by the PortB interrupt, I've done very little with interrupts and don't quite get what you mean.

mackrackit
- 8th September 2010, 01:00
Glad it is working.

PORTB has an interrupt on change. When the state of PORTB.0 changes an interrupt can be triggered.

An example would be counting parts on a conveyor. The MCU can be off doing something else like sending data to a display while a sensor/switch is activated as a part passes by. Then when the MCU is finished with the display the part count can be increases.
That is using PBP interrupts. If you go with ASM or Darrel Taylor's instant interrupts then the trigger is instantly. But you still need a certain amount of time for everything to happen.

Either way, you do not need to loop back and check the state of the pin, it happens for you in the background.