// TODO: send using interrupt if available uint8_t ps2_host_send(uint8_t data) { uint8_t res = 0; bool parity = true; ps2_error = PS2_ERR_NONE; #ifdef PS2_USE_INT PS2_INT_OFF(); #endif /* terminate a transmission if we have */ inhibit(); _delay_us(200); // at least 100us /* start bit [1] */ data_lo(); clock_hi(); WAIT(clock_lo, 20000, 10); // may take 15ms at most until device starts clocking /* data [2-9] */ for (uint8_t i = 0; i < 8; i++) { _delay_us(15); if (data&(1<<i)) { parity = !parity; data_hi(); } else { data_lo(); } WAIT(clock_hi, 50, 2); WAIT(clock_lo, 50, 3); } /* parity [10] */ _delay_us(15); if (parity) { data_hi(); } else { data_lo(); } WAIT(clock_hi, 50, 4); WAIT(clock_lo, 50, 5); /* stop bit [11] */ _delay_us(15); data_hi(); /* ack [12] */ WAIT(data_lo, 50, 6); WAIT(clock_lo, 50, 7); /* wait for idle state */ WAIT(clock_hi, 50, 8); WAIT(data_hi, 50, 9); #ifdef PS2_USE_INT PS2_INT_ON(); #endif res = ps2_host_recv_response(); ERROR: #ifdef PS2_USE_INT PS2_INT_ON(); idle(); #else inhibit(); #endif return res; }
uint8_t ps2_host_send(uint8_t data) { bool parity = true; ps2_error = PS2_ERR_NONE; PS2_INT_OFF(); /* terminate a transmission if we have */ inhibit(); _delay_us(100); // 100us [4]p.13, [5]p.50 /* 'Request to Send' and Start bit */ data_lo(); clock_hi(); WAIT(clock_lo, 10000, 10); // 10ms [5]p.50 /* Data bit[2-9] */ for (uint8_t i = 0; i < 8; i++) { _delay_us(15); if (data&(1<<i)) { parity = !parity; data_hi(); } else { data_lo(); } WAIT(clock_hi, 50, 2); WAIT(clock_lo, 50, 3); } /* Parity bit */ _delay_us(15); if (parity) { data_hi(); } else { data_lo(); } WAIT(clock_hi, 50, 4); WAIT(clock_lo, 50, 5); /* Stop bit */ _delay_us(15); data_hi(); /* Ack */ WAIT(data_lo, 50, 6); WAIT(clock_lo, 50, 7); /* wait for idle state */ WAIT(clock_hi, 50, 8); WAIT(data_hi, 50, 9); idle(); PS2_INT_ON(); return ps2_host_recv_response(); ERROR: idle(); PS2_INT_ON(); return 0; }
/* receive data when host want else inhibit communication */ uint8_t ps2_host_recv_response(void) { uint8_t data = 0; #ifdef PS2_USE_INT PS2_INT_OFF(); #endif /* terminate a transmission if we have */ inhibit(); _delay_us(100); /* release lines(idle state) */ idle(); /* wait start bit */ wait_clock_lo(25000); // command response may take 20 ms at most data = recv_data(); inhibit(); return data; }