Half the memory footprint for reception code

This commit is contained in:
Raphael Assenat 2015-10-27 23:50:18 -04:00
parent cb9be3f604
commit 6aaccb0eb3
2 changed files with 65 additions and 72 deletions

View File

@ -71,54 +71,6 @@ void gcn64_protocol_getBytes(int offset, int n_bytes, unsigned char *dstbuf)
}
}
/* \brief Decode the received length of low/high states to byte-per-bit format
*
* The result is in workbuf.
*
**/
static void gcn64_decodeWorkbuf(unsigned int count)
{
unsigned int i;
volatile unsigned char *output = gcn64_workbuf;
volatile unsigned char *input = gcn64_workbuf;
unsigned char t;
//
// ________
// ________/
//
// [i*2] [i*2+1]
//
// ________________
// 0 : ____/
// ____
// 1 : ________________/
//
// The timings on a real N64 are
//
// 0 : 1 us low, 3 us high
// 1 : 3 us low, 1 us high
//
// However, HORI pads use something similar to
//
// 0 : 1.5 us low, 4.5 us high
// 1 : 4.5 us low, 1.5 us high
//
//
// No64 us = microseconds
// This operation takes approximately 100uS on 64bit gamecube messages
for (i=0; i<count; i++) {
t = *input;
input++;
*output = t < *input;
input++;
output++;
}
}
void gcn64protocol_hwinit(void)
{
// data as input
@ -133,8 +85,6 @@ void gcn64protocol_hwinit(void)
PORTB &= ~0x10;
}
/**
* \brief Send n data bytes + stop bit, wait for answer.
* \return The number of bits received, 0 on timeout/error.
@ -146,21 +96,27 @@ int gcn64_transaction(unsigned char *data_out, int data_out_len)
{
int count;
unsigned char sreg = SREG;
int i;
#ifdef DISABLE_INTS_DURING_COMM
cli();
#endif
gcn64_sendBytes(data_out, data_out_len);
//count = gcn64_receive();
count = gcn64_receiveBits(gcn64_workbuf, 0);
SREG = sreg;
#if 0
printf("Count: %d { ", count);
for (i=0; i<count; i++) {
printf("%02x ", gcn64_workbuf[i]);
}
printf("}\r\n");
#endif
if (!count)
return 0;
if (!(count & 0x01)) {
// If we don't get an odd number of level lengths from gcn64_receive
// something is wrong.
// something is wrong.
//
// The stop bit is a short (~1us) low state followed by an "infinite"
// high state, which timeouts and lets the function return. This
@ -168,15 +124,13 @@ int gcn64_transaction(unsigned char *data_out, int data_out_len)
return 0;
}
gcn64_decodeWorkbuf(count);
/* this delay is required on N64 controllers. Otherwise, after sending
* a rumble-on or rumble-off command (probably init too), the following
* get status fails. This starts to work at 2us. 5 should be safe. */
_delay_us(5);
/* return the number of full bits received. */
return (count-1) / 2;
* get status fails. This starts to work at 30us. 60us should be safe. */
_delay_us(60); // Note that this results in a 100us delay between packets.
/* return the number of full bits received, minus the stop bit */
return count-1;
}

View File

@ -10,6 +10,7 @@
#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 */
@ -29,12 +30,22 @@
#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)
@ -44,8 +55,9 @@ gcn64_receiveBits:
clr xh
mov zl, r24
mov zh, r25
clr r18
clr r20
inc r20
initial_wait_low:
inc r18
breq timeout ; overflow to 0
@ -56,33 +68,60 @@ initial_wait_low:
rjmp waithigh
waitlow:
mov r21, r18 ; Save the last value
ldi r18, TIMING_OFFSET
waitlow_lp:
inc r18
brmi timeout ; > 127 (approx 50uS timeout)
brmi timeout_waitlow ; > 127 (approx 50uS timeout)
sbic GCN64_DATA_PIN, GCN64_DATA_BIT
rjmp waitlow_lp
adiw xl, 1 ; count this timed low level
adiw xl, 1 ; count this bit
breq overflow ; > 255
st z+,r18
#if 0
st z+, r19
st z+, r18
rjmp waithigh
#else
; Compare the low period and the high period.
sub r19, r18
brcs got1
got0:
st z+, __zero_reg__
rjmp waithigh
got1:
st z+,r20
#endif
waithigh:
ldi r18, TIMING_OFFSET
ldi r19, TIMING_OFFSET
waithigh_lp:
inc r18
inc r19
brmi timeout ; > 127
sbis GCN64_DATA_PIN, GCN64_DATA_BIT
rjmp waithigh_lp
adiw xl, 1 ; count this timed high level
breq overflow ; > 255
st z+,r18
rjmp waitlow
timeout_waitlow:
adiw xl, 1 ;
breq overflow ; > 255
; Compare the low period and the high period.
sub r19, r21
brcs lastwas1
lastwas0:
st z+, __zero_reg__
rjmp rxdone
lastwas1:
st z+,r20
rjmp rxdone
overflow:
clr xl
clr xh
timeout:
rxdone:
; Return the number if received bits in r24,r25
mov r24, xl ; yl
mov r25, xh ; yh