;************************************************ ;* BACKPACK WATCHDOG / TRANSMITTER ;* ;* Chip Number : U1 ;* File Name : E22_8515.asm ;* Date : 03.25.2005 ;* Last Update : 05.05.2005 ;* Version : 1.0.0 ;* Support Telephone: withheld ;* Support Fax : withheld ;* Support E-mail : brm016000@utdallas.edu ;* Target MCU : AT90S8515 ;* Frequency : 8.00MHz ;* ;* DESCRIPTION ;* ;* The control program has been copied almost verbatum from the E-22 ;* program created in May 2004. ;* ;* PORT SUMMARY ;* ;* PortC.0 --- ;* PortC.1 PSX Controller ;* PortC.2 PSX Controller ;* PortC.3 PSX Controller ;* PortC.4 PSX Controller ;* PortC.5 PSX Controller ;* PortC.6 Debugging LED ;* PortC.7 --- ;* ;* DISCLAIMER ;* ;* ALL INFORMATION WITHIN THIS DOCUMENT IS PROVIDED ;* "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, ;* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES ;* OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ;* I DO NOT GUARANTEE ANY INFORMATION IN THIS DOCUMENT IS ;* ACCURATE, AND IT SHOULD BE USED FOR ABSTRACT EDUCATIONAL ;* PURPOSES ONLY. ;************************************************* .device AT90S8515 .nolist ; Halt listfile generation .include "8515def.inc" ; Chip Definitions and Appnote file .list ; Resume listfiles ;- Register Aliases ----- ;.def = R16 ; General-purpose register by tradition .def loop = R17 ; Loop/increment counter by tradition .def addr = R18 ; Address-holder by tradition .def addr2 = R19 ; Secondary address-holder .def icount = R20 ; Interrupt counter (use only within interrupt) .def accum2 = R21 ; Interrupt-only general purpose register .def istatus = R22 ; Status register saver .def accum3 = R23 ; Interrupt-only general purpose register ;- Define Constants ----- .equ psx_capture = $60 ; RAM location for key info .equ psx_status = psx_capture+1 ; Latest transfer status .equ psx_line1 = psx_capture+2 ; 1st key group (menu/direction buttons) .equ psx_line2 = psx_capture+3 ; 2nd key group (action buttons) .equ psx_line3 = psx_capture+4 ; Analog button/joystick data .equ psx_line4 = psx_capture+5 ; Analog button/joystick data .equ psx_line5 = psx_capture+6 ; Analog button/joystick data .equ psx_line6 = psx_capture+7 ; Analog button/joystick data .equ psx_delay = 50 ; Approx delay between bits .equ ACK_timeout = 60 ; Time for controller to ACK .equ digital_con = 0x5A ; Controller Designator .equ neg_con = 0x23 ; Controller Designator .equ analog_g_con = 0x53 ; Controller Designator .equ analog_r_con = 0x73 ; Controller Designator .equ PORT_PSX = PORTC ; Port to use for PSX ios .equ DDR_PSX = DDRC ; Directions (must apply to PORT_PSX's port) .equ PIN_PSX = PINC ; Inputs (must apply to same port as PORT_PSX) .equ CLK = 1 ; AVR output .equ CLK_msk = 0b00000010; Bit mask for output .equ DATA = 2 ; AVR input .equ DATA_msk = 0b00000100; Bit mask for input .equ COMM = 3 ; AVR output .equ COMM_msk = 0b00001000; Bit mask for output .equ ATT = 4 ; AVR output .equ ATT_msk = 0b00010000; Bit mask for output .equ ACK = 5 ;AVR input .equ ACK_msk = 0b00100000; Bit mask for input ;- Macros --------------- .macro CLK_SHIFT cbi PORT_PSX,CLK ; Lower clock. "Shift bit" .endmacro .macro CLK_SAMPLE sbi PORT_PSX,CLK ; Raise clock. "Sample bit" .endmacro ;------------------------ ;######################## ;# Flash Memory # ;######################## .cseg ; Code Segment Begins .org 0x00 ; Starting Address rjmp main ; Reset vector ;######################## ;# Interrupt Vectors # ;# 8515 # ;######################## RETI ; IRQ0 Handler RETI ; IRQ1 Handler RETI ; Timer1 Capture Event RETI ; Timer1 CompareA Match RETI ; Timer1 CompareB Match RETI ; Timer1 Overflow Handler RETI ; Timer0 Overflow Handler RETI ; SPI Transfer Complete RETI ; UART RX Complete Handler RETI ; UDR Empty Handler RETI ; UART TX Complete Handler RETI ; Analog Comparitor Handler ;######################## ;# End Interrupt Vectors# ;######################## main: ;---Initialize D port---- ldi R16,0b11111011 ; ::: PORT (D) DIRECTION SETUP out DDRD,R16 ldi R16,0b00010100 ; Pull-up inputs ; Q-mode alarm on out PORTD,R16 ; Send configuration ;---Initialize C port---- ldi R16,0b01011011 ; ::: PORT (C) DIRECTION SETUP out DDRC,R16 ldi R16,0b11110101 ; Pull-up inputs ; Ready all PSX pins out PORTC,R16 ;---Initialize B port---- ldi R16,0b00000001 ; ;:: PORT (B) DIRECTION SETUP out DDRB,R16 ldi R16,0b11111110 ; Pull-up inputs ; Transmitter on stndby out PORTB,R16 ;---Initialize A port---- ser R16 ; ::: PORT (A) DIRECTION SETUP out DDRA,R16 clr R16 ; No port A pins in use out PORTA,R16 ;---Stack Setup---------- ldi R16,0x02 ; Stack start address: $025F out SPH,R16 ; Setup pointer high byte ldi R16,0x5F out SPL,R16 ; Setup pointer low byte ;---Timer/Counter 0 Setup ;---Timer/Counter 1 Setup ;---External IRQ Setup--- ;---X-Pointer Setup ldi R26,PIN_PSX + $20 ldi R27,0x00 ; Add "$20" to point to the register mirror in SRAM polling_loop: rcall PSX_GETKEY lds R16,psx_capture ; Load controller type/mode cpi R16,analog_r_con ; Controller in red mode? breq ana cbi PORTC,6 rjmp polling_loop ana: sbi PORTC,6 rjmp polling_loop PSX_GETKEY: ; ::: X- 22 :::::Controller Read cbi PORT_PSX,ATT ; Lower the "ATTENTION" line ;---FRAME 1------------------ ldi accum2,0x01 ; 0x01 is the STARTUP command mov R8,accum2 ; Copy register rcall psx_get_send ; :::SEND: Wakeup 0x01 GET: nothing ; No need to store, keypad is idle ;---FRAME 2------------------ ldi accum2,0x42 ; 0x42 is the "Request for Data" command mov R8,accum2 ; Copy register rcall psx_get_send ; SEND: Request 0x42 GET: controller type sts psx_capture,accum3 ; STORE: keypad's type number ;---FRAME 3------------------ ; No need to send commands rcall command_idle ; Stay idle rcall psx_get_send ; SEND: nothing GET: 0x5A ; Keypad will send "0x5A" ;---FRAME 4------------------ ; No need to send commands rcall command_idle ; Stay idle rcall psx_get_send ; SEND: nothing GET: keys sts psx_capture+2,accum3; Store 1st line of key info ;---FRAME 5------------------ ; No need to send commands rcall command_idle ; Stay idle rcall psx_get_send ; SEND: nothing GET: keys sts psx_capture+3,accum3; Store 2nd line of key info ;---------------------------- lds accum2,psx_capture ; Load captured data (controller type) cpi accum2,digital_con ; "Is this the digital controller?" brne analogs_only ; Contine if this is an "Advanced" controller sbi PORT_PSX,ATT ; Raise ATTention line to end transfer ret analogs_only: ;---FRAME 6------------------ ; No need to send commands rcall command_idle ; Stay idle rcall psx_get_send ; SEND: nothing GET: keys sts psx_capture+4,accum3; Store 3rd line of key/analog info ;---FRAME 7------------------ ; No need to send commands rcall command_idle ; Stay idle rcall psx_get_send ; SEND: nothing GET: keys sts psx_capture+5,accum3; Store 4th line of key/analog info ;---FRAME 8------------------ ; No need to send commands rcall command_idle ; Stay idle rcall psx_get_send ; SEND: nothing GET: keys sts psx_capture+6,accum3; Store 5th line of key/analog info ;---FRAME 9------------------ ; No need to send commands rcall command_idle ; Stay idle rcall psx_get_send ; SEND: nothing GET: keys sts psx_capture+7,accum3; Store 6th line of key/analog info ;---------------------------- sbi PORT_PSX,ATT ; Raise ATTention line again ret command_idle: ; Send the "idle" state ser accum2 mov R8,accum2 ret ;---------------------------\ ; PSX GET-SEND ; psx_get_send: ; ; ; ; Transfer 1 byte to PSX and; ; 1 byte from PSX ; ; simultaneously. ; ; ; ; Wait for ACKNOWLEDGE at ; ; end of transfer ; ; ; ; LSB must arrive first ; ; ; ; Lines are active-high ; ; Normally high ; ; ; ; IN: R8 = outgoing byte ; ; OUT: accum3 =received byte; ; DESTROYED: ; ; icount = R20 ; ; accum2 = R21 ; ;---------------------------/ clr accum3 ; Clear the "received byte" register ldi icount,8 ; Number of bits to exchange? transfer_bit: ; :: BEGIN! next_bit: push icount ; Save bit tracker rcall delay ; Pause for bit settling CLK_SHIFT ; "Shift in next bit" ror R8 ; Rotate right through carry brcs send_1 ; Need to send a ONE? send_0: cbi PORT_PSX,COMM ; Lower command line rjmp send_escape send_1: sbi PORT_PSX,COMM ; Raise command line nop ; Pause for consistancy send_escape: rcall delay ; Pause. Let lines settle. CLK_SAMPLE ; "Sample bits now!" ld accum2,X ; Get pins status sbrc accum2,DATA ; Check incoming DATA bit rjmp got_1 got_0: lsr accum3 ; Shift register. Insert ZERO in MSB. nop ; Pause for consistancy rjmp got_escape got_1: sec ; Set carry flag. Prepare to rotate ror accum3 ; Rotate a ONE into the current MSB got_escape: pop icount ; Restore bit tracker dec icount ; Decrement bit counter brne next_bit bits_done: ; :: PAUSE! WAIT for ACK signal ldi icount,ACK_timeout ; Length of timeout period wait_for_ack: dec icount ; Decrement timeout counter breq transfer_fail ; Fail the Xfer if no ACK arrived ld accum2,X ; Read PINB status andi accum2,ACK_msk ; Mask off unneeded bits brne wait_for_ack ; Loop until ACK goes low ret transfer_fail: ret ; SHORT DELAY for bit propagation and settling delay: ; Total Delay time is ; 1.00us + 1us(psx_delay) ; @ 4.00MHz push icount ; Save bit counter ldi icount,psx_delay - 1 delay_loop: nop ; IN: icount = length of delay dec icount ; Decrement loop count brne delay_loop ; Loop until ready pop icount ; Restore bit counter ret exx: ; ::: EXCHANGE STATUS in istatus,SREG ; Read CPU Status flags ret exxe: ; ::: EXCHANGE AND EXIT out SREG,istatus ; Restore CPU Status flags reti ; Return from interrupts ;######################## ;# EEPROM Memory # ;######################## .eseg .org 0x02 ;######################## ;# SRAM Memory # ;######################## .dseg .org 0x60