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 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/serial.h	Thu Oct 12 04:08:48 2017 +0300
     5.3 @@ -0,0 +1,7 @@
     5.4 +#ifndef SERIAL_H_
     5.5 +#define SERIAL_H_
     5.6 +
     5.7 +void init_serial(long baud);
     5.8 +int have_input(void);
     5.9 +
    5.10 +#endif	/* SERIAL_H_ */