# HG changeset patch # User John Tsiombikas # Date 1507770528 -10800 # Node ID 8e8e17a0f88ed4c2dcd46ba38cca2246226dbb49 initial commit: serial comms up, kbd doesn't respond diff -r 000000000000 -r 8e8e17a0f88e .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Thu Oct 12 04:08:48 2017 +0300 @@ -0,0 +1,7 @@ +\.o$ +\.d$ +\.swp$ +\.hex$ +\.map$ +\.eep$ +^a500kbd$ diff -r 000000000000 -r 8e8e17a0f88e Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Thu Oct 12 04:08:48 2017 +0300 @@ -0,0 +1,38 @@ +src = $(wildcard src/*.c) +obj = $(src:.c=.o) +bin = a500kbd +hex = $(bin).hex +eep = $(bin).eep + +mcu_gcc = atmega88 +mcu_dude = m88 + +CC = avr-gcc +OBJCOPY = avr-objcopy + +CFLAGS = -Os -pedantic -Wall -mmcu=$(mcu_gcc) -DXTAL=14745600 +LDFLAGS = -Wl,-Map,$(bin).map -mmcu=$(mcu_gcc) -lprintf_min + +.PHONY: all +all: $(hex) $(eep) + +$(bin): $(obj) + $(CC) -o $@ $(obj) $(LDFLAGS) + +$(hex): $(bin) + $(OBJCOPY) -j .text -j .data -O ihex -R .eeprom $< $@ + +$(eep): $(bin) + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ + +.PHONY: fuses +fuses: + avrdude -c usbtiny -p $(mcu_dude) -U lfuse:w:0xe6:m -U hfuse:w:0xdf:m -U efuse:w:0xf9:m + +.PHONY: program +program: $(hex) + avrdude -c usbtiny -p $(mcu_dude) -e -U flash:w:$(hex) + +.PHONY: clean +clean: + rm -f $(bin) $(obj) $(hex) $(eep) $(bin).map diff -r 000000000000 -r 8e8e17a0f88e src/main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main.c Thu Oct 12 04:08:48 2017 +0300 @@ -0,0 +1,120 @@ +#define F_CPU XTAL +#include +#include +#include +#include +#include +#include "serial.h" + +/* pin assignments: + * B0 PS/2 data + * B1 PS/2 clock + * C0 KBD data + * C1 KBD clock + */ + +#define BIT_DATA 1 +#define BIT_CLK 2 + +#define PS2LOW(bit) do { DDRB |= (bit); PORTB &= ~(bit); } while(0) +#define PS2HIGH(bit) do { DDRB |= (bit); PORTB |= (bit); } while(0) +#define PS2REL(bit) do { DDRB &= ~(bit); PORTB &= ~(bit); } while(0) +#define PS2INTR_UNMASK do { PCICR |= (1 << PCIE0); } while(0) +#define PS2INTR_MASK do { PCICR &= ~(1 << PCIE0); } while(0) + +void ps2write(unsigned char c); +int ps2read(unsigned char *c); + + +int main(void) +{ + int led = 1, dir = 1; + + DDRB = 0; + DDRC = 0; + PORTB = 0; + PORTC = 0; + + /* initialize the UART and enable interrupts */ + init_serial(9600); + sei(); + + printf("PS/2 keyboard controller - John Tsiombikas \r\n"); + fflush(stdout); + + for(;;) { + printf("hello!\r\n"); + fflush(stdout); + unsigned char c; + + ps2write(0xed); + ps2read(&c); + if(c != 0xfa) { + printf("expected ack, got: %xh\r\n", (unsigned int)c); + } else { + ps2write(led); + if(led == 1) dir = 1; + if(led == 7) dir = -1; + + if(dir > 0) { + led <<= 1; + } else { + led >>= 1; + } + + _delay_ms(1000); + } + } + return 0; +} + +void ps2write(unsigned char c) +{ + int i; + unsigned short out = (unsigned short)c | ((unsigned short)(~parity_even_bit(c) & 1) << 8); + + /* pull clock low for >60us */ + PS2LOW(BIT_CLK); + _delay_us(60); + + /* then pull data low and release clock */ + PS2LOW(BIT_DATA); + PS2REL(BIT_CLK); + + for(i=0; i<9; i++) { + printf("bit %d: wait for clk-low\r\n", i); + while(PINB & BIT_CLK); /* wait for kbd to drive the clock low */ + PORTB |= out & 1; + out >>= 1; + printf("bit %d: wait for clk-high\r\n", i); + while(!(PINB & BIT_CLK)); /* wait for kbd to drive the clock high */ + } + + PS2REL(BIT_DATA); + /* wait for ack */ + printf("wait for ack (low)\r\n"); + while(PINB & BIT_DATA); + printf("wait for ack (high)\r\n"); + while(!(PINB & BIT_DATA)); +} + +int ps2read(unsigned char *c) +{ + int i, p; + unsigned short in = 0; + + /* wait for kbd to drive the clock low for the start bit (blocks here) */ + while(PINB & BIT_CLK); + while(!(PINB & BIT_CLK)); + + for(i=0; i<9; i++) { + while(PINB & BIT_CLK); /* wait for clock to go low */ + in |= (PINB & 1) << i; + while(!(PINB & BIT_CLK)); + } + + p = ~parity_even_bit((unsigned char)in); + *c = in; + + return (p == ((in >> 8) & 1)) ? 0 : -1; +} diff -r 000000000000 -r 8e8e17a0f88e src/serial.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/serial.c Thu Oct 12 04:08:48 2017 +0300 @@ -0,0 +1,102 @@ +#ifdef XTAL +#define F_CLK XTAL +#define F_CPU XTAL +#else +#warning "compiled for 1mhz internal rc osc. serial comms won't work" +#define F_CLK 1000000 +#define F_CPU 1000000 +#endif + +#include +#include +#include +#include +#include + +static int uart_send_char(char c, FILE *fp); +static int uart_get_char(FILE *fp); + +#define BUF_SZ 16 +#define BUF_IDX_MASK (BUF_SZ - 1) +#define NEXT_IDX(x) (((x) + 1) & BUF_IDX_MASK) +static char outbuf[BUF_SZ]; +static volatile unsigned char out_rd, out_wr; +static char inbuf[BUF_SZ]; +static volatile unsigned char in_rd, in_wr; + +static FILE std_stream = FDEV_SETUP_STREAM(uart_send_char, uart_get_char, _FDEV_SETUP_RW); + + + +void init_serial(long baud) +{ + unsigned int ubrr_val = F_CLK / 16 / baud - 1; + + power_usart0_enable(); + + /* set baud generator timer reset value */ + UBRR0H = (unsigned char)(ubrr_val >> 8); + UBRR0L = (unsigned char)ubrr_val; + + /* enable rx/tx and recv interrupt */ + UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0); + /* set frame format: 8n1 */ + UCSR0C = 3 << UCSZ00; + + stdin = stdout = stderr = &std_stream; +} + +int have_input(void) +{ + return in_wr != in_rd; +} + +static int uart_send_char(char c, FILE *fp) +{ + /*int next;*/ + + while((UCSR0A & (1 << UDRE0)) == 0); + UDR0 = (unsigned char)c; +#if 0 + next = NEXT_IDX(out_wr); + while(next == out_rd); + + outbuf[out_wr] = c; + out_wr = next; + + /* enable the Tx data register empty interrupt */ + UCSR0B |= 1 << UDRIE0; +#endif + return 0; +} + +static int uart_get_char(FILE *fp) +{ + char c; + + while(in_rd == in_wr); + + c = inbuf[in_rd]; + in_rd = NEXT_IDX(in_rd); + return c; +} + +ISR(USART_RX_vect) +{ + char c = UDR0; + + inbuf[in_wr] = c; + in_wr = NEXT_IDX(in_wr); +} + +/* USART Tx data register empty (can send more data) */ +ISR(USART_UDRE_vect) +{ + if(out_rd != out_wr) { + UDR0 = outbuf[out_rd]; + out_rd = NEXT_IDX(out_rd); + } else { + /* no more data to send for now, disable the interrupt */ + UCSR0B &= ~(1 << UDRIE0); + } +} diff -r 000000000000 -r 8e8e17a0f88e src/serial.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/serial.h Thu Oct 12 04:08:48 2017 +0300 @@ -0,0 +1,7 @@ +#ifndef SERIAL_H_ +#define SERIAL_H_ + +void init_serial(long baud); +int have_input(void); + +#endif /* SERIAL_H_ */