+/* serial-demo.c - Copyright (c) 2015 Pat Thoyts
+ *
+ * Simple synchronous serial echo firmware for AVR without using stdio.
+ */
+
+#include <avr/io.h>
+#include <avr/power.h>
+
+void usart_init(int baud);
+inline uint8_t usart_is_rx_ready(void);
+inline uint8_t usart_is_tx_ready(void);
+int usart_getchar(void);
+int usart_putchar(char c);
+
+void usart_init(int baud)
+{
+ uint16_t ubrr = F_CPU / 16 / baud - 1;
+ UBRR0H = (uint8_t)(ubrr >> 8); /* write before UBRR0L */
+ UBRR0L = (uint8_t)ubrr;
+ UCSR0B = _BV(RXEN0) | _BV(TXEN0); /* enable RX and TX */
+ UCSR0C = _BV(USBS0) | _BV(UCSZ01) | _BV(UCSZ00); /* async, 8,1,n */
+}
+
+/* nonzero if serial data is available to read. */
+inline uint8_t usart_is_rx_ready(void)
+{
+ return bit_is_set(UCSR0A, RXC0);
+}
+
+/* nonzero if transmit register is ready to receive new data. */
+inline uint8_t usart_is_tx_ready(void)
+{
+ return bit_is_set(UCSR0A, UDRE0);
+}
+
+int usart_getchar(void)
+{
+ loop_until_bit_is_set(UCSR0A, RXC0); /* wait for rx ready */
+ return UDR0;
+}
+
+int usart_putchar(char c)
+{
+ loop_until_bit_is_set(UCSR0A, UDRE0); /* wait until data register empty */
+ UDR0 = c;
+ return 0;
+}
+
+int
+main (void)
+{
+ int n;
+ static char version[] = {'S','e','r','i','a','l',' ','D','e','m','o','\r','\n'};
+
+ /* turn off all unused peripherals */
+ power_adc_disable();
+ power_spi_disable();
+ power_twi_disable();
+
+ /* set all unused pins to high-Z state */
+ DDRB = 0; PORTB = 0xff;
+ DDRC = 0; PORTC = 0xff;
+ DDRD = 0; PORTD = 0xff;
+
+ /* use PB5 (pin 13) as serial receive indicator and trigger */
+ DDRB |= _BV(DDB5); PORTB &= ~_BV(PB5);
+
+ usart_init(9600);
+
+ for (n = 0; n < sizeof(version); ++n)
+ usart_putchar(version[n]);
+
+ for (;;)
+ {
+ if (usart_is_rx_ready())
+ {
+ char c = 0;
+ PORTB ^= _BV(PB5);
+ c = usart_getchar();
+ usart_putchar(c);
+ PORTB ^= _BV(PB5);
+ }
+ }
+ return 0;
+}