a500kbd

diff src/serial.c @ 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 a4fd9c5a6655
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/serial.c	Thu Oct 12 04:08:48 2017 +0300
     1.3 @@ -0,0 +1,102 @@
     1.4 +#ifdef XTAL
     1.5 +#define F_CLK	XTAL
     1.6 +#define F_CPU	XTAL
     1.7 +#else
     1.8 +#warning "compiled for 1mhz internal rc osc. serial comms won't work"
     1.9 +#define F_CLK	1000000
    1.10 +#define F_CPU	1000000
    1.11 +#endif
    1.12 +
    1.13 +#include <stdio.h>
    1.14 +#include <avr/io.h>
    1.15 +#include <avr/interrupt.h>
    1.16 +#include <util/delay.h>
    1.17 +#include <avr/power.h>
    1.18 +
    1.19 +static int uart_send_char(char c, FILE *fp);
    1.20 +static int uart_get_char(FILE *fp);
    1.21 +
    1.22 +#define BUF_SZ	16
    1.23 +#define BUF_IDX_MASK	(BUF_SZ - 1)
    1.24 +#define NEXT_IDX(x)	(((x) + 1) & BUF_IDX_MASK)
    1.25 +static char outbuf[BUF_SZ];
    1.26 +static volatile unsigned char out_rd, out_wr;
    1.27 +static char inbuf[BUF_SZ];
    1.28 +static volatile unsigned char in_rd, in_wr;
    1.29 +
    1.30 +static FILE std_stream = FDEV_SETUP_STREAM(uart_send_char, uart_get_char, _FDEV_SETUP_RW);
    1.31 +
    1.32 +
    1.33 +
    1.34 +void init_serial(long baud)
    1.35 +{
    1.36 +	unsigned int ubrr_val = F_CLK / 16 / baud - 1;
    1.37 +
    1.38 +	power_usart0_enable();
    1.39 +
    1.40 +	/* set baud generator timer reset value */
    1.41 +	UBRR0H = (unsigned char)(ubrr_val >> 8);
    1.42 +	UBRR0L = (unsigned char)ubrr_val;
    1.43 +
    1.44 +	/* enable rx/tx and recv interrupt */
    1.45 +	UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0);
    1.46 +	/* set frame format: 8n1 */
    1.47 +	UCSR0C = 3 << UCSZ00;
    1.48 +
    1.49 +	stdin = stdout = stderr = &std_stream;
    1.50 +}
    1.51 +
    1.52 +int have_input(void)
    1.53 +{
    1.54 +	return in_wr != in_rd;
    1.55 +}
    1.56 +
    1.57 +static int uart_send_char(char c, FILE *fp)
    1.58 +{
    1.59 +	/*int next;*/
    1.60 +
    1.61 +	while((UCSR0A & (1 << UDRE0)) == 0);
    1.62 +	UDR0 = (unsigned char)c;
    1.63 +#if 0
    1.64 +	next = NEXT_IDX(out_wr);
    1.65 +	while(next == out_rd);
    1.66 +
    1.67 +	outbuf[out_wr] = c;
    1.68 +	out_wr = next;
    1.69 +
    1.70 +	/* enable the Tx data register empty interrupt */
    1.71 +	UCSR0B |= 1 << UDRIE0;
    1.72 +#endif
    1.73 +	return 0;
    1.74 +}
    1.75 +
    1.76 +static int uart_get_char(FILE *fp)
    1.77 +{
    1.78 +	char c;
    1.79 +
    1.80 +	while(in_rd == in_wr);
    1.81 +
    1.82 +	c = inbuf[in_rd];
    1.83 +	in_rd = NEXT_IDX(in_rd);
    1.84 +	return c;
    1.85 +}
    1.86 +
    1.87 +ISR(USART_RX_vect)
    1.88 +{
    1.89 +	char c = UDR0;
    1.90 +
    1.91 +	inbuf[in_wr] = c;
    1.92 +	in_wr = NEXT_IDX(in_wr);
    1.93 +}
    1.94 +
    1.95 +/* USART Tx data register empty (can send more data) */
    1.96 +ISR(USART_UDRE_vect)
    1.97 +{
    1.98 +	if(out_rd != out_wr) {
    1.99 +		UDR0 = outbuf[out_rd];
   1.100 +		out_rd = NEXT_IDX(out_rd);
   1.101 +	} else {
   1.102 +		/* no more data to send for now, disable the interrupt */
   1.103 +		UCSR0B &= ~(1 << UDRIE0);
   1.104 +	}
   1.105 +}