Thursday, October 13, 2011

Diy Portable video projector

My newest project is to build a pocket sized, battery powered portable video projector that accepts a standard composite input. It all started when I received an old jvc (circa 1998) vhs camcorder with a tiny color lcd viewfinder. I took it apart and started hacking it. I quickly found the composite input to the display driver but was unable to get the screen to accept input without tethering it to the camera's main board (which told me that the camera was somehow initializing the driver board for the display). I powered the screen with 12V and 5V but nothing happened without connecting three specific wires to the mainboard. Time went by and I decided to pick up the project again recently. I once again noticed the group of three wires that seemed fishy so the first thing I though was SPI. I looked up all the data sheets and traced these three to the Mitsubishi M62353FP which is a 8 channel DAC and confirmed that they were three wire SPI thanks to the datasheet. The outputs led to some inputs for the display driver (Sony CXA1854AR) which controlled color, contrast, etc. I tried sniffing the data that was coming from the camera's mainboard with my PICKIT2's logic tool, but it didn't make much sense. Instead I measured the analog voltages on each of the DAC's outputs, calculated the binary values using a formula from the datasheet and wrote up a driver for my PIC which sends a four bit address (for each of the 8 outputs) followed by the 8 bit output value. I wired everything up, plugged it in and everything worked like a charm (well colors are a bit washed out but that can be fixed by adjusting the software a little). So now onto making the optics for the projector.

 Here's a shot of the tiny LCD (Sony LCX005BK). Pretty low resolution but it was free so I wont complain.

Here is the backlight. High voltage and not so bright so it needs to go.

This is the other side of the backlight. Note the step up transformer and switching mosfet.

Finally here is where I am at right now. I am running it all off of a 12V wallwart, using a LM7805 linear regulator for the 5V line (when I go to make this battery powered I will use a lithium rechargeable battery and a TI step up converter module to get the 12V). My PIC is on the right (with a little development board I made to make things easier) with code to set display values. I plan on adding buttons to allow the user to change brightness, contrast, saturation, etc on the fly. On the left is the display driver. and I attached a 1W white led as a replacement for the original backlight.

Sorry about the blurry display shots, photographing a .5" lcd is a lot more difficult than it would seem.


Full set up with my ipod outputting video. More to come soon.
datasheets available below:
CXA1854AR
M62353FP

Update! Working on optical assembly and took some test photos of video projection.

Here's my test setup with the optical assembly and projection lens in the center.
Picture of projection (about 10" or so) onto a glossy white screen in my room with blinds shut but lots of light seeping in.
Had to drag the setup into my bathroom to get a completely dark background. Once again image is around 10". I noticed that I nicked the lcd's polarizing filter a bit and that there are some dead/stuck pixels in the screen which show up in the image. Oh well, I got all the parts for free and this is merely a proof of concept so I don't really care.

Update: Made tons of progress on this project. Demo video below and pictures and explanation to come.

Sandisk Sansa Clip+

Tuesday, May 24, 2011

Controlling a nokia5110 lcd with software SPI on a pic16f84a




My newest project has been implementing a software SPI routine so that my pic (which lacks hardware SPI) can communicate with a cheap nokia 84x48 graphical lcd (later I will show how I wired it up). I've written subroutines in assembly for setting x,y address of the lcd's ram as well as sending data or commands for initialization (8bit, but could be easily modified to work with 9bit color lcd protocols I've seen). I plan on using a look up table to store standard character hex data so that I can make things easier for myself in upcoming projects. I know that my code is pretty inefficient so I plan on fixing it a little later (but not bad for just reading the datasheet and a few hours of coding). I just have the mcu writing "Hello World!" and drawing a video game character sprite at the bottom (I converted the image by hand, but I could easily write a program to do that for me). This is just the beginning, I plan on using this, as well as everything else I've been working on in my projects to come. I plan on adding the ability to animate/scroll text and images and will update the site with the code once I get the chance. I also plan on describing the SPI protocol and lcd commands in detail. For now I will post the code to just write "Hello World" and draw a sprite.

Start    BSF  03h,5         ;switch from bank 0 to 1

    MOVLW  b'00000000' ;Out RB to output
    MOVWF 06h
    MOVLW  b'00000'       ;Out RA to output
    MOVWF 05h

    BCF 03h,5          ;switch from bank 1 to 0     
;RB0=sclk
;RB1=sda
;RB2=D_C
;RB3=Sce
;RB4=reset
;RB5=disp pwr
Begin
    bsf 06h,3 ;disable serial
    bsf 06h,5 ;power on display
    nop
    bcf 06h,4 ;reset
    nop
    bsf 06h,4 ;release from reset

; sel extended instruction set (h=1)
    movlw b'00100001'
    movwf 0Ch
    call spi_command

; set Vop (Contrast)
    movlw b'10111001'
    movwf 0Ch
    call spi_command

; sel normal instruction set (h=0)
    movlw b'00100000'
    movwf 0Ch
    call spi_command

; display normal mode
    movlw b'00001100'
    movwf 0Ch
    call spi_command

;---------------------------

; draw H
    movlw b'01111111'
    movwf 0Ch
    call spi_data
    movlw b'00001000'
    movwf 0Ch
    call spi_data
    movlw b'00001000'
    movwf 0Ch
    call spi_data
    movlw b'00001000'
    movwf 0Ch
    call spi_data
    movlw b'01111111'
    movwf 0Ch
    call spi_data

call _space

; draw e
    movlw b'00001110'
    movwf 0Ch
    call spi_data
    movlw b'00010101'
    movwf 0Ch
    call spi_data
    movlw b'00010101'
    movwf 0Ch
    call spi_data
    movlw b'00010101'
    movwf 0Ch
    call spi_data
    movlw b'00001100'
    movwf 0Ch
    call spi_data

call _space

; draw l
    movlw b'00000000'
    movwf 0Ch
    call spi_data
    movlw b'01000001'
    movwf 0Ch
    call spi_data
    movlw b'01111111'
    movwf 0Ch
    call spi_data
    movlw b'00000001'
    movwf 0Ch
    call spi_data
    movlw b'00000000'
    movwf 0Ch
    call spi_data

call _space

; draw l
    movlw b'00000000'
    movwf 0Ch
    call spi_data
    movlw b'01000001'
    movwf 0Ch
    call spi_data
    movlw b'01111111'
    movwf 0Ch
    call spi_data
    movlw b'00000001'
    movwf 0Ch
    call spi_data
    movlw b'00000000'
    movwf 0Ch
    call spi_data

call _space

; draw o
    movlw b'00001110'
    movwf 0Ch
    call spi_data
    movlw b'00010001'
    movwf 0Ch
    call spi_data
    movlw b'00010001'
    movwf 0Ch
    call spi_data
    movlw b'00010001'
    movwf 0Ch
    call spi_data
    movlw b'00001110'
    movwf 0Ch
    call spi_data

call _space

; goto y=1,x=0
    movlw b'00000001'
    movwf 0Ch
    movlw b'00000000'
    movwf 0Dh
    call setxy

; draw W
    movlw b'01111110'
    movwf 0Ch
    call spi_data
    movlw b'00000001'
    movwf 0Ch
    call spi_data
    movlw b'00001110'
    movwf 0Ch
    call spi_data
    movlw b'00000001'
    movwf 0Ch
    call spi_data
    movlw b'01111110'
    movwf 0Ch
    call spi_data

call _space

; draw o
    movlw b'00001110'
    movwf 0Ch
    call spi_data
    movlw b'00010001'
    movwf 0Ch
    call spi_data
    movlw b'00010001'
    movwf 0Ch
    call spi_data
    movlw b'00010001'
    movwf 0Ch
    call spi_data
    movlw b'00001110'
    movwf 0Ch
    call spi_data

call _space

; draw r
    movlw b'00011111'
    movwf 0Ch
    call spi_data
    movlw b'00001000'
    movwf 0Ch
    call spi_data
    movlw b'00010000'
    movwf 0Ch
    call spi_data
    movlw b'00010000'
    movwf 0Ch
    call spi_data
    movlw b'00001000'
    movwf 0Ch
    call spi_data

call _space

; draw l
    movlw b'00000000'
    movwf 0Ch
    call spi_data
    movlw b'01000001'
    movwf 0Ch
    call spi_data
    movlw b'01111111'
    movwf 0Ch
    call spi_data
    movlw b'00000001'
    movwf 0Ch
    call spi_data
    movlw b'00000000'
    movwf 0Ch
    call spi_data

call _space

; draw d
    movlw b'00001110'
    movwf 0Ch
    call spi_data
    movlw b'00010001'
    movwf 0Ch
    call spi_data
    movlw b'00010001'
    movwf 0Ch
    call spi_data
    movlw b'00001001'
    movwf 0Ch
    call spi_data
    movlw b'01111111'
    movwf 0Ch
    call spi_data

call _space

; draw !
    movlw b'01111101'
    movwf 0Ch
    call spi_data

;---------------------------
; goto y=5,x=0
    movlw b'00000101'
    movwf 0Ch
    movlw b'00000000'
    movwf 0Dh
    call setxy
;draw image block 4
    movlw b'10000111';1
    movwf 0Ch
    call spi_data
    movlw b'11111101';2
    movwf 0Ch
    call spi_data
    movlw b'10000001';3
    movwf 0Ch
    call spi_data
    movlw b'01100001';4
    movwf 0Ch
    call spi_data
    movlw b'00010001';5
    movwf 0Ch
    call spi_data
    movlw b'11001001';6
    movwf 0Ch
    call spi_data
    movlw b'00100101';7
    movwf 0Ch
    call spi_data
    movlw b'00100101';8
    movwf 0Ch
    call spi_data
    movlw b'11100001';9
    movwf 0Ch
    call spi_data
    movlw b'00011001';10
    movwf 0Ch
    call spi_data
    movlw b'00000101';11
    movwf 0Ch
    call spi_data
    movlw b'00000011';12
    movwf 0Ch
    call spi_data
    movlw b'00000011';13
    movwf 0Ch
    call spi_data
    movlw b'00000001';14
    movwf 0Ch
    call spi_data
    movlw b'00111001';15
    movwf 0Ch
    call spi_data
    movlw b'11101101';16
    movwf 0Ch
    call spi_data
    movlw b'00000111';17
    movwf 0Ch
    call spi_data

; goto y=4,x=0
    movlw b'00000100'
    movwf 0Ch
    movlw b'00000000'
    movwf 0Dh
    call setxy
;draw image block 3
    movlw b'00000111';1
    movwf 0Ch
    call spi_data
    movlw b'00111100';2
    movwf 0Ch
    call spi_data
    movlw b'01100100';3
    movwf 0Ch
    call spi_data
    movlw b'01010011';4
    movwf 0Ch
    call spi_data
    movlw b'11110000';5
    movwf 0Ch
    call spi_data
    movlw b'00111000';6
    movwf 0Ch
    call spi_data
    movlw b'11111001';7
    movwf 0Ch
    call spi_data
    movlw b'11111011';8
    movwf 0Ch
    call spi_data
    movlw b'10010011';9
    movwf 0Ch
    call spi_data
    movlw b'11110100';10
    movwf 0Ch
    call spi_data
    movlw b'11110100';11
    movwf 0Ch
    call spi_data
    movlw b'01110100';12
    movwf 0Ch
    call spi_data
    movlw b'01110000';13
    movwf 0Ch
    call spi_data
    movlw b'00010000';14
    movwf 0Ch
    call spi_data
    movlw b'00100100';15
    movwf 0Ch
    call spi_data
    movlw b'10011111';16
    movwf 0Ch
    call spi_data
    movlw b'11010000';17
    movwf 0Ch
    call spi_data
    movlw b'01110000';18
    movwf 0Ch
    call spi_data

; goto y=3,x=0
    movlw b'00000011'
    movwf 0Ch
    movlw b'00000000'
    movwf 0Dh
    call setxy
;draw image block 2
    movlw b'00011100';1
    movwf 0Ch
    call spi_data
    movlw b'00010110';2
    movwf 0Ch
    call spi_data
    movlw b'00010010';3
    movwf 0Ch
    call spi_data
    movlw b'00010010';4
    movwf 0Ch
    call spi_data
    movlw b'00010011';5
    movwf 0Ch
    call spi_data
    movlw b'00010001';6
    movwf 0Ch
    call spi_data
    movlw b'00110001';7
    movwf 0Ch
    call spi_data
    movlw b'00100000';8
    movwf 0Ch
    call spi_data
    movlw b'01100000';9
    movwf 0Ch
    call spi_data
    movlw b'01000000';10
    movwf 0Ch
    call spi_data
    movlw b'11000000';11
    movwf 0Ch
    call spi_data
    movlw b'10000000';12
    movwf 0Ch
    call spi_data
    movlw b'00000000';13
    movwf 0Ch
    call spi_data
    movlw b'00000010';14
    movwf 0Ch
    call spi_data
    movlw b'00011111';15
    movwf 0Ch
    call spi_data
    movlw b'01110001';16
    movwf 0Ch
    call spi_data
    movlw b'11000000';17
    movwf 0Ch
    call spi_data

; goto y=2,x=12
    movlw b'00000010'
    movwf 0Ch
    movlw b'00001100'
    movwf 0Dh
    call setxy
;draw image block 1
    movlw b'00000001';12
    movwf 0Ch
    call spi_data
    movlw b'00000001';13
    movwf 0Ch
    call spi_data
    movlw b'00000011';14
    movwf 0Ch
    call spi_data
    movlw b'00000010';15
    movwf 0Ch
    call spi_data
    movlw b'00000010';16
    movwf 0Ch
    call spi_data
    movlw b'00000011';17
    movwf 0Ch
    call spi_data

a goto a

;----------------------------

spi_command
    bcf 06h,3 ;start serial transmission
    bcf 06h,2 ;D_C=0
        btfss 0Ch,7
        goto c1
        call one
        goto c1n
    c1    call zero
    c1n    btfss 0Ch,6
        goto c2
        call one
        goto c2n
    c2    call zero
    c2n    btfss 0Ch,5
        goto c3
        call one
        goto c3n
    c3    call zero
    c3n    btfss 0Ch,4
        goto c4
        call one
        goto c4n
    c4    call zero
    c4n    btfss 0Ch,3
        goto c5
        call one
        goto c5n
    c5    call zero
    c5n    btfss 0Ch,2
        goto c6
        call one
        goto c6n
    c6    call zero
    c6n    btfss 0Ch,1
        goto c7
        call one
        goto c7n
    c7    call zero
    c7n    btfss 0Ch,0
        goto cd
        call one
        goto cdn
    cd    call zero
cdn    bcf 06h,0
    bsf 06h,3 ;end serial transmission
return

spi_data
    bcf 06h,3 ;start serial transmission
    bsf 06h,2 ;D_C=1
        btfss 0Ch,0
        goto b1
        call one
        goto b1n
    b1    call zero
    b1n    btfss 0Ch,1
        goto b2
        call one
        goto b2n
    b2    call zero
    b2n    btfss 0Ch,2
        goto b3
        call one
        goto b3n
    b3    call zero
    b3n    btfss 0Ch,3
        goto b4
        call one
        goto b4n
    b4    call zero
    b4n    btfss 0Ch,4
        goto b5
        call one
        goto b5n
    b5    call zero
    b5n    btfss 0Ch,5
        goto b6
        call one
        goto b6n
    b6    call zero
    b6n    btfss 0Ch,6
        goto b7
        call one
        goto b7n
    b7    call zero
    b7n    btfss 0Ch,7
        goto d
        call one
        goto dn
    d    call zero
dn    bcf 06h,0
    bsf 06h,3 ;end serial transmission
return

zero
    bcf 06h,0
    bcf 06h,1 ;0
    bsf 06h,0 ;sclk pulse
return

one
    bcf 06h,0
    bsf 06h,1 ;1
    bsf 06h,0 ;sclk pulse
return

_space ;send byte='00000000', draw space
    movlw b'00000000'
    movwf 0Ch
    call spi_data
return

setxy
    bsf 0Ch,6
    call spi_command
    bsf 0Dh,7
    movf 0Dh,0
    movwf 0Ch
    call spi_command
return

end

Tuesday, May 10, 2011

Capacitive Touch Sensor for pic16F84A (no special hardware required)

Here is my newest project I've been working on. I'll get more details up when I have the time. In the mean while enjoy the video.

 
Update: Sorry its been awhile since my last update. I've been busy with work and my other projects. The capacitive sensing input is really simple because everything is done in software. Here's my hand drawn schematic for the input stage generalized so that any mcu can be used (For some reason I haven't yet installed a schematic program on my netbook and I don't feel like booting up my other laptop).
It's amazing that all you really need is a single gpio and a resistor (the capacitance is provided by the traces on the breadboard). The ten megaohm resistor allows the discharge rate for the stray capacitance to be slowed down enough for the uC to measure. The uC just continually charges up this capacitance, puts the pin into high impedance by making it an input, and then counts until it measures the "capacitor" is discharged. This count can then be analyzed to determine if the pin has been pressed or not (the count increases if the button is pressed because your finger adds to the stray capacitance in parallel which increases the discharge time). That's pretty much all that's necessary other than some fancy algorithms for error proofing detection.

Update 2: I've finally gotten around to porting my capacitive touch sensing code to C. The code should work for most PICs and can be easily modified to change pin assignments and whatnot to work on any other chip you might need. Below you will find the function freqcapsense. All you need to do is call it and it will sense whether RA0 is being touch or not. I've included averaging multiple samples and an adjustable threshold in order to tweak the sensitivity and accuracy for any given setup. You can have it return a 1 or 0 for touch status or by commenting out the if else statement at the end and uncommenting the return current statement it will return the raw period value it is reading from the pin. Enjoy.

int freqcapsense(){
    unsigned int avg;
    unsigned int current=0;
    unsigned int thresh=29;
    unsigned int trials=10;

    while(trials>0){
        TRISA=0b0;
        RA0=1;
        delay();
        TRISA=0b1;
        while(RA0==1){current++;}
        trials--;
        avg=(avg+current)/2;
    }

    if((current-avg)>thresh){return 1;}
    else{return 0;}

    //return current;
}

Saturday, January 22, 2011

Interfacing a SNES controller and 16x2 LCD to the PIC16f84A



I threw together this demo this morning after finding two snes controllers last night for $1.90 each at a thrift store.

                                          Controller after I meticulously cleaned it.
Next I researched online a bit to find out how to read the button presses (this pdf helped: http://www.parallax.com/dl/docs/prod/prop/hydra-ch6all-v1.0.pdf). The controller uses a active low 16bit wide shift register (last 4bits are always high). Read the pdf for the specifics of pulsing the latch and clock. All that needs to be hooked up is +5v, gnd, Clock, Latch, and Data (the pinout can be found here: http://pinouts.ru/Game/snescontroller_pinout.shtml). I used solid core copper wire that was folded over once to thicken it enough to hold when inserted in the connector socket since I didn't have a proper connector.
                                          Perfect for prototyping.
Next I wired up the breadboard. The first part was the power supply which consists of a AA battery and a max756 to step it up to the 5v needed by the controller, lcd, and pic.
                                          Indicator led and switch to turn on the power.
Next I wired up the PIC16f84A with an external RC clock and icsp header.
Finally I wired the controller (to port A) and lcd (to port B) up and started coding.
                                          The lcd printing button presses.
The code basically initializes the lcd and then continually polls the controller and when a certain button is pressed sends the character to the display. This way the display types the button presses and when you want to clear the screen you just press start or select.

For now I will post the code below (in assembly, and sorry about the formatting, it looked much nicer in mplab) and will upload a schematic and video of it in action when I get some time.
Note: The code provided below is not optimized and is rather messy. Remember that I am not responsible if you try and make this and it doesn't work or ends up blowing up. This was just meant as a proof of concept and a neat morning wake up exercise for me.

UPDATE:
Sorry its been awhile, I've been busy at school, but here is the schematic. Note that I left out the step up converter circuitry.



Code:
;Shawn Maxwell  ;
;1/22/11        ;
;LCD SNES       ;
;;;;;;;;;;;;;;;;;

;Writes SNES key presses to HD44780 compatable LCD in 4bit mode

COUNT1  equ  08h           ;delay constants
COUNT2  equ  09h

Start    BSF  03h,5         ;switch from bank 0 to 1

    MOVLW  b'00000000' ;Out RB to output
    MOVWF 06h
    MOVLW  b'11100'       ;Out RA0,1 to output, RA2-4 to input
    MOVWF 05h

    BCF 03h,5          ;switch from bank 1 to 0 
   
    ;RS = RB0, EN = RB1, D4-D7 = RB2-RB5
    ;CLK = RA0, Latch = RA1, Data = RA2

Begin
    call LongDelay
    call LongDelay
   
;initialize LCD
    movlw b'00001010'    ;Out EN high
    call Out  ;;;;
    movlw b'00001000'    ;Out to 4 bit operation (note: 1 nibble

operation)
    call Out  ;;;;      ;Out EN low

    movlw b'00001010'    ;Out EN high
    call Out  ;;;;
    movlw b'00001000'    ;Function Out, 8 bit
    call Out  ;;;;        ;Out EN low
    movlw b'00100010'    ;Out EN high
    call Out  ;;;;
    movlw b'00100000'    ;2nd nibble
    call Out  ;;;;      ;Out EN low

    movlw b'00000010'    ;Out EN high
    call Out  ;;;;
    movlw b'00000000'    ;Display ON, Cursor On, Cursor Blinking
    call Out  ;;;;      ;Out EN low
    movlw b'00111110'    ;Out EN high
    call Out  ;;;;
    movlw b'00111100'    ;2nd nibble
    call Out  ;;;;      ;Out EN low

    movlw b'00000010'    ;Out EN high
    call Out  ;;;;
    movlw b'00000000'    ;Entry Mode, Increment cursor position, No

display shift
    call Out  ;;;;      ;Out EN low
    movlw b'00011010'    ;Out EN high
    call Out  ;;;;
    movlw b'00011000'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
;initialize SNES controller and read data
SNES
    movlw b'00011'        ;set Latch, CLK high
    movwf 05h
    call Delay
    movlw b'00001'        ;set Latch low
    movwf 05h
    call Delay
    movlw b'00000'        ;set CLK low
    movwf 05h
    call Delay
    movlw b'00010'        ;pulse Latch high
    movwf 05h
    call Delay
    movwf b'00000'
    movwf 05h
    btfss 05h,2            ;read B
    call buttonB
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read Y
    call buttonY
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read Select
    call Clear
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read Start
    call Clear
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read Up
    call buttonUp
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read Down
    call buttonDown
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read Left
    call buttonLeft
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read Right
    call buttonRight
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read A
    call buttonA
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read X
    call buttonX
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read L
    call buttonL
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read R
    call buttonR
    call Delay
    call Delay
    goto SNES

;--------------------------------------------
buttonB
    movlw b'00010011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010001'    ;B
    call Out  ;;;;      ;Out EN low
    movlw b'00001011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00001001'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

buttonY
    movlw b'00010111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010101'    ;Y
    call Out  ;;;;      ;Out EN low
    movlw b'00100111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00100101'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

Clear
    movlw b'00000010'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00000000'    ;Clear
    call Out  ;;;;      ;Out EN low
    movlw b'00000110'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00000100'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

buttonUp
    movlw b'00010111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010101'    ;Up
    call Out  ;;;;      ;Out EN low
    movlw b'00010111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010101'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

buttonDown
    movlw b'00010011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010001'    ;Down
    call Out  ;;;;      ;Out EN low
    movlw b'00010011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010001'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

buttonLeft
    movlw b'00011111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00011101'    ;Left
    call Out  ;;;;      ;Out EN low
    movlw b'00111111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00111101'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

buttonRight
    movlw b'00011111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00011101'    ;Right
    call Out  ;;;;      ;Out EN low
    movlw b'00111011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00111001'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

buttonA
    movlw b'00010011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010001'    ;A
    call Out  ;;;;      ;Out EN low
    movlw b'00000111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00000101'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

buttonX
    movlw b'00010111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010101'    ;X
    call Out  ;;;;      ;Out EN low
    movlw b'00100011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00100001'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

buttonL
    movlw b'00010011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010001'    ;L
    call Out  ;;;;      ;Out EN low
    movlw b'00110011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00110001'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

buttonR
    movlw b'00010111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010101'    ;R
    call Out  ;;;;      ;Out EN low
    movlw b'00001011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00001001'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return
   
Out
    movwf 06h
Loop01  decfsz COUNT1,1
        goto   Loop01
Loop02    decfsz COUNT1,1
    goto   Loop02
return

Delay
Loop1   decfsz COUNT1,1
        goto   Loop1
Loop2    decfsz COUNT1,1
    goto   Loop2
return

LongDelay
loop1   decfsz COUNT1,1
        goto   loop1
loop2    decfsz COUNT1,1
    goto   loop2
loop3    decfsz COUNT1,1
    goto   loop3
loop4    decfsz COUNT1,1
    goto   loop4
loop5    decfsz COUNT1,1
    goto   loop5
loop6    decfsz COUNT1,1
    goto   loop6
loop7    decfsz COUNT1,1
    goto   loop7
loop8    decfsz COUNT1,1
    goto   loop8
loop9    decfsz COUNT1,1
    goto   loop9
loop10    decfsz COUNT1,1
    goto   loop10
loop11    decfsz COUNT1,1
    goto   loop11
loop12    decfsz COUNT1,1
    goto   loop12
loop13    decfsz COUNT1,1
    goto   loop13
loop14    decfsz COUNT1,1
    goto   loop14
loop15    decfsz COUNT1,1
    goto   loop15
loop16    decfsz COUNT1,1
    goto   loop16
loop17    decfsz COUNT1,1
    goto   loop17
loop18    decfsz COUNT1,1
    goto   loop18
loop19    decfsz COUNT1,1
    goto   loop19
loop20    decfsz COUNT1,1
    goto   loop20
return

end