#ifndef __COMMUNICATION_PROGRAMMER__ #define __COMMUNICATION_PROGRAMMER__ #include #include #include #include #define SCK PB5 /* AVR writes at L->H; programmer reads at H->L */ #define MISO PB4 /* AVR reads on L->H; doc page 299 */ #define MOSI PB3 unsigned char out_buf[64], out_buf_cur=0, // current byte, >= 0 out_buf_end=0, // number of bytes to send, >= 1 cur_bit, // 7 .. 0 overflow, inp_buf[64], inp_buf_cur, // current byte to recv inp_buf_read; // last used byte SIGNAL(SIG_PIN_CHANGE0) { static unsigned char cur_out, pins, tmp, cur_in; pins=PINB; /* if SCK now high, read and/or write */ if (pins & _BV(SCK)) { /* read. MSB is first. */ cur_in= ( cur_in << 1) | ((pins & _BV(MOSI)) ? 1 : 0); /* sending */ tmp=0; if (overflow) { tmp=1; overflow--; } else { /* next byte ? */ if (cur_bit == 0) { if (out_buf_cur < out_buf_end) { cur_out=out_buf[out_buf_cur]; out_buf_cur++; if (out_buf_cur == out_buf_end) out_buf_end=out_buf_cur=0; } PORTB = PORTB ^ _BV(PB6); } /* MSB first */ tmp = cur_out & 0x80; cur_out = cur_out << 1; } /* put on port */ if (tmp) PORTB |= _BV(MISO); else PORTB &= ~_BV(MISO); /* next bits */ cur_bit++; /* if we have a 0x7f in cur_in, we're in a resync phase. * so assume that we're now synchronized. */ if (cur_in == 0x7f) { cur_bit=0; } if (cur_bit>=8) { cur_bit=0; /* full byte received. * 0x00 ... ignored * 0x7f ... sync byte. should be given multiple times. * 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe * used for re-synchronisation. */ switch (cur_in) { case 0: break; /* just ignored */ default: inp_buf[inp_buf_cur]=cur_in; inp_buf_cur++; break; } PORTB = PORTB ^ _BV(PB7); } if (inp_buf_cur>sizeof(inp_buf)) { /* if input buffer is overrun, input is discarded and * a number of 0xff bytes is written out. * only zeroes should be given until this is finished. */ overflow= 8*10; // multiple of 8 !!! inp_buf_cur=0; } } return; } void io_init(void) { /* enable MISO as output; SCK, MOSI as input. No pull-ups. */ DDRB = ( DDRB & ~(_BV(MOSI) | _BV(SCK)) ) | _BV(MISO); PORTB &= ~(_BV(MISO) | _BV(MOSI) | _BV(SCK)); PCMSK0|=_BV(SCK) | _BV(PB1); PCICR|=_BV(PCIE0); PCIFR=0xff; } inline char output_buffer_empty(void) { return out_buf_end == 0; } inline void set_output_buffer(char len) { out_buf_end=len; } char read_byte(void) { char ret; if (inp_buf_read == inp_buf_cur) return 0; cli(); ret=inp_buf[inp_buf_read++]; if (inp_buf_read == inp_buf_cur) inp_buf_cur=inp_buf_read=0; sei(); return ret; } inline char look_last_byte(void) { if (inp_buf_read == inp_buf_cur) return 0; return inp_buf[inp_buf_cur-1]; } void write_byte(char x) { if (out_buf_end >= sizeof(out_buf)-1) return; cli(); out_buf[out_buf_end]=x; out_buf_end++; sei(); } #endif // vi: sw=3 ts=3