You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
264 lines
5.3 KiB
264 lines
5.3 KiB
#include <avr/io.h> |
|
|
|
; When compiling, you must define the following. |
|
; |
|
; SUFFIX : The suffix for exported function (eg: Set to 0 to generate gcn64_sendBytes0) |
|
; GCN64_DATA_BIT : The bit number in the port. |
|
; |
|
; Port and Pin IOs are defined below. |
|
; |
|
|
|
#define CONCAT(a,b) a##b |
|
#define EXPORT_SYMBOL(a, b) .global CONCAT(a,b) |
|
#define FUNCTION(a, b) CONCAT(a,b) |
|
|
|
.text |
|
EXPORT_SYMBOL(gcn64_sendBytes, SUFFIX) |
|
EXPORT_SYMBOL(gcn64_receiveBytes, SUFFIX) |
|
|
|
#define xl r26 |
|
#define xh r27 |
|
#define yl r28 |
|
#define yh r29 |
|
#define zl r30 |
|
#define zh r31 |
|
#define __zero_reg__ r1 |
|
|
|
/* the value of the gpio is pre-configured to low. We simulate |
|
an open drain output by toggling the direction */ |
|
|
|
#ifdef STK525 |
|
#define GCN64_DATA_PORT _SFR_IO_ADDR(PORTA) |
|
#define GCN64_DATA_DDR _SFR_IO_ADDR(DDRA) |
|
#define GCN64_DATA_PIN _SFR_IO_ADDR(PINA) |
|
#else |
|
#define GCN64_DATA_PORT _SFR_IO_ADDR(PORTD) |
|
#define GCN64_DATA_DDR _SFR_IO_ADDR(DDRD) |
|
#define GCN64_DATA_PIN _SFR_IO_ADDR(PIND) |
|
#endif |
|
;#define GCN64_DATA_BIT 0 |
|
|
|
#if F_CPU != 16000000L |
|
#error Only 16MHz clock supported |
|
#endif |
|
|
|
/************************************************ |
|
* Function gcn64_receiveBits |
|
* |
|
* Works by timing the low and high periods of each bit and |
|
* then comparing them to know if a 1 or a 0 was on the wire. |
|
* |
|
* Example timed values: |
|
* 54 4e 53 4d 53 4d 53 4e 53 4d 4d 53 53 4e 4c 54 53 4d 54 4d 53 4d 53 4d ... |
|
* 0 0 0 0 0 1 0 1 0 0 0 0 .... |
|
*/ |
|
|
|
; The bit timeout is a counter to 127. This is the |
|
; start value. Counting from 0 takes hundreads of |
|
; microseconds. Because of this, the reception function |
|
; "hangs in there" much longer than necessary.. |
|
#define TIMING_OFFSET 75 |
|
; unsigned int gcn64_receiveBytes(unsigned char *dstbuf, unsigned char max_bytes); |
|
; r24,r25 : dstbuf |
|
; r22 : max bytes (for fututre use) |
|
; return: count in r24,r25 (0xff: Error, 0xfe: Overflow [max_bytes too low]) |
|
FUNCTION(gcn64_receiveBytes, SUFFIX): |
|
clr xl |
|
clr xh |
|
mov zl, r24 |
|
mov zh, r25 |
|
clr r18 |
|
ldi r20, 1 |
|
clr r24 |
|
initial_wait_low: |
|
inc r18 |
|
breq timeout ; overflow to 0 |
|
sbic GCN64_DATA_PIN, GCN64_DATA_BIT |
|
rjmp initial_wait_low |
|
|
|
; the next transition is to a high bit |
|
rjmp waithigh |
|
|
|
waitlow: |
|
mov r21, r18 ; Save the last value |
|
ldi r18, TIMING_OFFSET |
|
waitlow_lp: |
|
inc r18 |
|
brmi rxdone ; > 127 (approx 50uS timeout) |
|
sbic GCN64_DATA_PIN, GCN64_DATA_BIT |
|
rjmp waitlow_lp |
|
|
|
; Compare the low period and the high period. |
|
sub r19, r18 ; Carry is set when 1 |
|
rol r20 |
|
brcs store_byte |
|
rjmp waithigh |
|
|
|
store_byte: |
|
cp r22, r24 ; Check max_bytes |
|
breq overflow |
|
inc r24 ; Count byte |
|
st z+,r20 |
|
ldi r20, 1 |
|
|
|
waithigh: |
|
ldi r19, TIMING_OFFSET |
|
waithigh_lp: |
|
inc r19 |
|
brmi frame_error ; This means the line is stuck in a low state... |
|
sbis GCN64_DATA_PIN, GCN64_DATA_BIT |
|
rjmp waithigh_lp |
|
rjmp waitlow |
|
|
|
overflow: |
|
ser r24 ; 0xff |
|
dec r24 ; 0xfe |
|
ret |
|
|
|
timeout: |
|
tst r24 |
|
breq rxdone ; If r24 is still zero, we did not receive anything. Return 0. |
|
; Otherwise, it is a frame error (i.e. A partial byte was received) |
|
frame_error: |
|
ser r24 |
|
rxdone: |
|
; Return the number if received bits in r24 |
|
ret |
|
|
|
|
|
; These are for a slower 4us/1.5us timing. |
|
; The MadCatz Microcon does not work with 3us/1us timing... |
|
#define LOOPS_SEND0_LOW 20 |
|
#define DELAY_SEND0_HIGH 2 |
|
#define LOOPS_SEND1_LOW 4 |
|
#define LOOPS_SEND1_HIGH 13 |
|
|
|
/* |
|
; These are for the perfect 3us/1us timing described below |
|
#define LOOPS_SEND0_LOW 15 |
|
#define LOOPS_SEND1_LOW 4 |
|
#define LOOPS_SEND1_HIGH 10 |
|
*/ |
|
/************************************************ |
|
* Send data using the N64/GC serial protocol which |
|
* is as follows: |
|
* 0 1 |
|
* __ _____ |
|
* ____| __| |
|
* ^ ^ ^ ^ ^ ^ |
|
* 3us 1us 1us 3us |
|
* |
|
* To send a 1, the pin direction is set to input. |
|
* To send a 0, the pin direction is set to output. |
|
* (of course, it's value is preset to zero) |
|
* |
|
* At 16 mhz, a 1us period is 16 cycles. Thus a 3us period |
|
* is 48 cycles. |
|
* |
|
* Pointer to data is passed in r24, r25 |
|
* Number of bytes to send is passed in r22 |
|
* |
|
* A stop bit is added at thy end of the packet. |
|
* |
|
************************************************/ |
|
FUNCTION(gcn64_sendBytes, SUFFIX): |
|
; Move r23,r24 pointer to z |
|
mov zl, r24 |
|
mov zh, r25 |
|
|
|
tst r22 |
|
breq done_send |
|
|
|
send_next_byte: |
|
; Check if this is the last byte. |
|
tst r22 |
|
breq send_stop |
|
dec r22 |
|
ld r21, z+ |
|
ldi r27, 0x80 ; mask |
|
|
|
send_next_bit: |
|
mov r19, r21 |
|
and r19, r27 |
|
brne send1 |
|
nop |
|
|
|
send0: |
|
sbi GCN64_DATA_DDR, GCN64_DATA_BIT ; Pull bus to 0 |
|
|
|
ldi r20, LOOPS_SEND0_LOW |
|
lp_send0_3us: |
|
dec r20 |
|
brne lp_send0_3us |
|
nop |
|
|
|
cbi GCN64_DATA_DDR, GCN64_DATA_BIT ; Release bus to 1 |
|
|
|
#ifdef DELAY_SEND0_HIGH |
|
ldi r20, DELAY_SEND0_HIGH |
|
lp_send0_1us: |
|
dec r20 |
|
brne lp_send0_1us |
|
#endif |
|
|
|
lsr r27 |
|
breq send_next_byte |
|
nop |
|
nop |
|
nop |
|
nop |
|
nop |
|
nop |
|
rjmp send_next_bit |
|
|
|
send1: |
|
sbi GCN64_DATA_DDR, GCN64_DATA_BIT ; Pull bus to 0 |
|
|
|
ldi r20, LOOPS_SEND1_LOW |
|
lp_send1_1us: |
|
dec r20 |
|
brne lp_send1_1us |
|
nop |
|
nop |
|
|
|
cbi GCN64_DATA_DDR, GCN64_DATA_BIT ; Release bus to 1 |
|
|
|
ldi r20, LOOPS_SEND1_HIGH |
|
lp_send1_3us: |
|
dec r20 |
|
brne lp_send1_3us |
|
nop |
|
nop |
|
|
|
lsr r27 |
|
breq send_next_byte |
|
nop |
|
nop |
|
nop |
|
nop |
|
nop |
|
nop |
|
rjmp send_next_bit |
|
|
|
send_stop: |
|
nop |
|
nop |
|
nop |
|
nop |
|
nop |
|
nop |
|
nop |
|
nop |
|
; STOP BIT |
|
sbi GCN64_DATA_DDR, GCN64_DATA_BIT ; Pull low for stop bit |
|
ldi r20, LOOPS_SEND1_LOW |
|
stbdly0: |
|
dec r20 |
|
brne stbdly0 |
|
nop |
|
cbi GCN64_DATA_DDR, GCN64_DATA_BIT ; Release |
|
|
|
done_send: |
|
ret |
|
|
|
|
|
|