a500kbd
changeset 0:8e8e17a0f88e
initial commit: serial comms up, kbd doesn't respond
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 12 Oct 2017 04:08:48 +0300 |
parents | |
children | 3228a731d4db |
files | .hgignore Makefile src/main.c src/serial.c src/serial.h |
diffstat | 5 files changed, 274 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/.hgignore Thu Oct 12 04:08:48 2017 +0300 1.3 @@ -0,0 +1,7 @@ 1.4 +\.o$ 1.5 +\.d$ 1.6 +\.swp$ 1.7 +\.hex$ 1.8 +\.map$ 1.9 +\.eep$ 1.10 +^a500kbd$
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/Makefile Thu Oct 12 04:08:48 2017 +0300 2.3 @@ -0,0 +1,38 @@ 2.4 +src = $(wildcard src/*.c) 2.5 +obj = $(src:.c=.o) 2.6 +bin = a500kbd 2.7 +hex = $(bin).hex 2.8 +eep = $(bin).eep 2.9 + 2.10 +mcu_gcc = atmega88 2.11 +mcu_dude = m88 2.12 + 2.13 +CC = avr-gcc 2.14 +OBJCOPY = avr-objcopy 2.15 + 2.16 +CFLAGS = -Os -pedantic -Wall -mmcu=$(mcu_gcc) -DXTAL=14745600 2.17 +LDFLAGS = -Wl,-Map,$(bin).map -mmcu=$(mcu_gcc) -lprintf_min 2.18 + 2.19 +.PHONY: all 2.20 +all: $(hex) $(eep) 2.21 + 2.22 +$(bin): $(obj) 2.23 + $(CC) -o $@ $(obj) $(LDFLAGS) 2.24 + 2.25 +$(hex): $(bin) 2.26 + $(OBJCOPY) -j .text -j .data -O ihex -R .eeprom $< $@ 2.27 + 2.28 +$(eep): $(bin) 2.29 + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ 2.30 + 2.31 +.PHONY: fuses 2.32 +fuses: 2.33 + avrdude -c usbtiny -p $(mcu_dude) -U lfuse:w:0xe6:m -U hfuse:w:0xdf:m -U efuse:w:0xf9:m 2.34 + 2.35 +.PHONY: program 2.36 +program: $(hex) 2.37 + avrdude -c usbtiny -p $(mcu_dude) -e -U flash:w:$(hex) 2.38 + 2.39 +.PHONY: clean 2.40 +clean: 2.41 + rm -f $(bin) $(obj) $(hex) $(eep) $(bin).map
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/src/main.c Thu Oct 12 04:08:48 2017 +0300 3.3 @@ -0,0 +1,120 @@ 3.4 +#define F_CPU XTAL 3.5 +#include <stdio.h> 3.6 +#include <avr/io.h> 3.7 +#include <avr/interrupt.h> 3.8 +#include <util/delay.h> 3.9 +#include <util/parity.h> 3.10 +#include "serial.h" 3.11 + 3.12 +/* pin assignments: 3.13 + * B0 PS/2 data 3.14 + * B1 PS/2 clock 3.15 + * C0 KBD data 3.16 + * C1 KBD clock 3.17 + */ 3.18 + 3.19 +#define BIT_DATA 1 3.20 +#define BIT_CLK 2 3.21 + 3.22 +#define PS2LOW(bit) do { DDRB |= (bit); PORTB &= ~(bit); } while(0) 3.23 +#define PS2HIGH(bit) do { DDRB |= (bit); PORTB |= (bit); } while(0) 3.24 +#define PS2REL(bit) do { DDRB &= ~(bit); PORTB &= ~(bit); } while(0) 3.25 +#define PS2INTR_UNMASK do { PCICR |= (1 << PCIE0); } while(0) 3.26 +#define PS2INTR_MASK do { PCICR &= ~(1 << PCIE0); } while(0) 3.27 + 3.28 +void ps2write(unsigned char c); 3.29 +int ps2read(unsigned char *c); 3.30 + 3.31 + 3.32 +int main(void) 3.33 +{ 3.34 + int led = 1, dir = 1; 3.35 + 3.36 + DDRB = 0; 3.37 + DDRC = 0; 3.38 + PORTB = 0; 3.39 + PORTC = 0; 3.40 + 3.41 + /* initialize the UART and enable interrupts */ 3.42 + init_serial(9600); 3.43 + sei(); 3.44 + 3.45 + printf("PS/2 keyboard controller - John Tsiombikas <nuclear@member.fsf.org>\r\n"); 3.46 + fflush(stdout); 3.47 + 3.48 + for(;;) { 3.49 + printf("hello!\r\n"); 3.50 + fflush(stdout); 3.51 + unsigned char c; 3.52 + 3.53 + ps2write(0xed); 3.54 + ps2read(&c); 3.55 + if(c != 0xfa) { 3.56 + printf("expected ack, got: %xh\r\n", (unsigned int)c); 3.57 + } else { 3.58 + ps2write(led); 3.59 + if(led == 1) dir = 1; 3.60 + if(led == 7) dir = -1; 3.61 + 3.62 + if(dir > 0) { 3.63 + led <<= 1; 3.64 + } else { 3.65 + led >>= 1; 3.66 + } 3.67 + 3.68 + _delay_ms(1000); 3.69 + } 3.70 + } 3.71 + return 0; 3.72 +} 3.73 + 3.74 +void ps2write(unsigned char c) 3.75 +{ 3.76 + int i; 3.77 + unsigned short out = (unsigned short)c | ((unsigned short)(~parity_even_bit(c) & 1) << 8); 3.78 + 3.79 + /* pull clock low for >60us */ 3.80 + PS2LOW(BIT_CLK); 3.81 + _delay_us(60); 3.82 + 3.83 + /* then pull data low and release clock */ 3.84 + PS2LOW(BIT_DATA); 3.85 + PS2REL(BIT_CLK); 3.86 + 3.87 + for(i=0; i<9; i++) { 3.88 + printf("bit %d: wait for clk-low\r\n", i); 3.89 + while(PINB & BIT_CLK); /* wait for kbd to drive the clock low */ 3.90 + PORTB |= out & 1; 3.91 + out >>= 1; 3.92 + printf("bit %d: wait for clk-high\r\n", i); 3.93 + while(!(PINB & BIT_CLK)); /* wait for kbd to drive the clock high */ 3.94 + } 3.95 + 3.96 + PS2REL(BIT_DATA); 3.97 + /* wait for ack */ 3.98 + printf("wait for ack (low)\r\n"); 3.99 + while(PINB & BIT_DATA); 3.100 + printf("wait for ack (high)\r\n"); 3.101 + while(!(PINB & BIT_DATA)); 3.102 +} 3.103 + 3.104 +int ps2read(unsigned char *c) 3.105 +{ 3.106 + int i, p; 3.107 + unsigned short in = 0; 3.108 + 3.109 + /* wait for kbd to drive the clock low for the start bit (blocks here) */ 3.110 + while(PINB & BIT_CLK); 3.111 + while(!(PINB & BIT_CLK)); 3.112 + 3.113 + for(i=0; i<9; i++) { 3.114 + while(PINB & BIT_CLK); /* wait for clock to go low */ 3.115 + in |= (PINB & 1) << i; 3.116 + while(!(PINB & BIT_CLK)); 3.117 + } 3.118 + 3.119 + p = ~parity_even_bit((unsigned char)in); 3.120 + *c = in; 3.121 + 3.122 + return (p == ((in >> 8) & 1)) ? 0 : -1; 3.123 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/serial.c Thu Oct 12 04:08:48 2017 +0300 4.3 @@ -0,0 +1,102 @@ 4.4 +#ifdef XTAL 4.5 +#define F_CLK XTAL 4.6 +#define F_CPU XTAL 4.7 +#else 4.8 +#warning "compiled for 1mhz internal rc osc. serial comms won't work" 4.9 +#define F_CLK 1000000 4.10 +#define F_CPU 1000000 4.11 +#endif 4.12 + 4.13 +#include <stdio.h> 4.14 +#include <avr/io.h> 4.15 +#include <avr/interrupt.h> 4.16 +#include <util/delay.h> 4.17 +#include <avr/power.h> 4.18 + 4.19 +static int uart_send_char(char c, FILE *fp); 4.20 +static int uart_get_char(FILE *fp); 4.21 + 4.22 +#define BUF_SZ 16 4.23 +#define BUF_IDX_MASK (BUF_SZ - 1) 4.24 +#define NEXT_IDX(x) (((x) + 1) & BUF_IDX_MASK) 4.25 +static char outbuf[BUF_SZ]; 4.26 +static volatile unsigned char out_rd, out_wr; 4.27 +static char inbuf[BUF_SZ]; 4.28 +static volatile unsigned char in_rd, in_wr; 4.29 + 4.30 +static FILE std_stream = FDEV_SETUP_STREAM(uart_send_char, uart_get_char, _FDEV_SETUP_RW); 4.31 + 4.32 + 4.33 + 4.34 +void init_serial(long baud) 4.35 +{ 4.36 + unsigned int ubrr_val = F_CLK / 16 / baud - 1; 4.37 + 4.38 + power_usart0_enable(); 4.39 + 4.40 + /* set baud generator timer reset value */ 4.41 + UBRR0H = (unsigned char)(ubrr_val >> 8); 4.42 + UBRR0L = (unsigned char)ubrr_val; 4.43 + 4.44 + /* enable rx/tx and recv interrupt */ 4.45 + UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0); 4.46 + /* set frame format: 8n1 */ 4.47 + UCSR0C = 3 << UCSZ00; 4.48 + 4.49 + stdin = stdout = stderr = &std_stream; 4.50 +} 4.51 + 4.52 +int have_input(void) 4.53 +{ 4.54 + return in_wr != in_rd; 4.55 +} 4.56 + 4.57 +static int uart_send_char(char c, FILE *fp) 4.58 +{ 4.59 + /*int next;*/ 4.60 + 4.61 + while((UCSR0A & (1 << UDRE0)) == 0); 4.62 + UDR0 = (unsigned char)c; 4.63 +#if 0 4.64 + next = NEXT_IDX(out_wr); 4.65 + while(next == out_rd); 4.66 + 4.67 + outbuf[out_wr] = c; 4.68 + out_wr = next; 4.69 + 4.70 + /* enable the Tx data register empty interrupt */ 4.71 + UCSR0B |= 1 << UDRIE0; 4.72 +#endif 4.73 + return 0; 4.74 +} 4.75 + 4.76 +static int uart_get_char(FILE *fp) 4.77 +{ 4.78 + char c; 4.79 + 4.80 + while(in_rd == in_wr); 4.81 + 4.82 + c = inbuf[in_rd]; 4.83 + in_rd = NEXT_IDX(in_rd); 4.84 + return c; 4.85 +} 4.86 + 4.87 +ISR(USART_RX_vect) 4.88 +{ 4.89 + char c = UDR0; 4.90 + 4.91 + inbuf[in_wr] = c; 4.92 + in_wr = NEXT_IDX(in_wr); 4.93 +} 4.94 + 4.95 +/* USART Tx data register empty (can send more data) */ 4.96 +ISR(USART_UDRE_vect) 4.97 +{ 4.98 + if(out_rd != out_wr) { 4.99 + UDR0 = outbuf[out_rd]; 4.100 + out_rd = NEXT_IDX(out_rd); 4.101 + } else { 4.102 + /* no more data to send for now, disable the interrupt */ 4.103 + UCSR0B &= ~(1 << UDRIE0); 4.104 + } 4.105 +}