summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorroot <root@no.no.james.local>2014-12-08 18:39:07 +0000
committerroot <root@no.no.james.local>2014-12-08 18:39:07 +0000
commit804820fe687affa38a52e302179e4a2293cb1ffb (patch)
treeacb784fd60af24d8c389e366d74409c75802dfa0
downloadrgb_ring-804820fe687affa38a52e302179e4a2293cb1ffb.tar.gz
rgb_ring-804820fe687affa38a52e302179e4a2293cb1ffb.tar.bz2
rgb_ring-804820fe687affa38a52e302179e4a2293cb1ffb.zip
fish
-rw-r--r--Makefile41
-rw-r--r--blinky.c99
-rw-r--r--lib_ws2812.c168
-rw-r--r--lib_ws2812.h64
-rw-r--r--project.h28
-rw-r--r--prototypes.h35
-rw-r--r--stdio.c24
-rw-r--r--uart.c686
-rw-r--r--uart.h183
-rw-r--r--util.c13
10 files changed, 1341 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..767a9a8
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,41 @@
+CSRCS= lib_ws2812.c blinky.c util.c uart.c stdio.c
+SSRCS=
+CC=avr-gcc -mmcu=atmega328p
+PROJECT=blinky
+HEX=${PROJECT}.hex
+
+AVRDUDE=avrdude
+
+CPPFLAGS=
+CPP=${CC} -E
+
+CFLAGS=-O2 -MP -MD -Wall -Werror -Wno-unused
+
+OBJS=${CSRCS:%.c=%.o} ${SSRCS:%.S=%.o}
+
+default: ${HEX}
+
+clean:
+
+${PROJECT}:${OBJS}
+ ${CC} -o $@ ${OBJS}
+
+${HEX}: ${PROJECT}
+ avr-objcopy -O ihex -R .eeprom $< $@
+
+program: ${HEX}
+ ${AVRDUDE} -F -V -c usbasp -p ATMEGA328P -P usb -U flash:w:$<
+ #${AVRDUDE} -F -V -c avrispmkII -p ATMEGA328P -P usb -U flash:w:$<
+
+
+protos:
+ echo -n > prototypes.h
+ cproto -E "${CPP}" ${CPPFLAGS} -DPROTOTYPING ${CSRCS} > prototypes.h.tmp
+ mv prototypes.h.tmp prototypes.h
+
+clean:
+ /bin/rm -f ${PROJECT} ${HEX} ${OBJS} *~ *.d
+
+
+-include ${CSRCS:%.c=%.d}
+
diff --git a/blinky.c b/blinky.c
new file mode 100644
index 0000000..4b92d4c
--- /dev/null
+++ b/blinky.c
@@ -0,0 +1,99 @@
+/*
+* Light_WS2812 library example - RGB_blinky
+*
+* cycles one LED through red, green, blue
+*
+* This example is configured for a ATtiny85 with PLL clock fuse set and
+* the WS2812 string connected to PB4.
+*/
+
+#include "project.h"
+
+
+#define N_COLORS 288
+#define N_LEDS 24
+
+
+struct RGB color[N_COLORS];
+struct RGB led[N_LEDS];
+
+
+static int
+map (int j, int n)
+{
+ j = (255UL * j) / n;
+ if (j > 255)
+ j = 255;
+
+ return j;
+}
+
+int
+ramp (int j, int n)
+{
+
+ if ((j >= -n) && (j < 0))
+ return map (j + n, n);
+ if ((j >= 0) && (j <= n))
+ return map (n - j, n);
+
+ return 0;
+}
+
+
+static void
+setup_colors (struct RGB *colors, int n)
+{
+ int i;
+
+ int n3 = n / 3;
+
+ for (i = 0; i < n; ++i)
+ {
+ colors[i].r = ramp (((i) % n) - n3, n3);
+ colors[i].g = ramp (((i + n3) % n) - n3, n3);
+ colors[i].b = ramp (((i + n3 + n3) % n) - n3, n3);
+
+ printf ("%3d: %3d %3d %3d\n", i, colors[i].r, colors[i].g, colors[i].b);
+
+ }
+}
+
+
+
+
+int
+main (void)
+{
+ int i, j, k;
+
+ setup_clocks ();
+ stdio_init ();
+
+
+ setup_colors (color, N_COLORS);
+
+
+ i = 0;
+
+ while (1)
+ {
+
+ for (j = 0; j < N_LEDS; ++j)
+ {
+ k = (j * (N_COLORS - 1)) / (N_LEDS - 1);
+ k += i;
+ while (k >= N_COLORS)
+ k -= N_COLORS;
+
+ led[j] = color[k];
+ }
+
+ ws2812_setleds (led, N_LEDS);
+ _delay_ms (5); // wait for 500ms.
+
+
+ i++;
+ i %= N_COLORS;
+ }
+}
diff --git a/lib_ws2812.c b/lib_ws2812.c
new file mode 100644
index 0000000..7f29425
--- /dev/null
+++ b/lib_ws2812.c
@@ -0,0 +1,168 @@
+/*
+* light weight WS2812 lib V2.0b
+*
+* Controls WS2811/WS2812/WS2812B RGB-LEDs
+* Author: Tim (cpldcpu@gmail.com)
+*
+* Jan 18th, 2014 v2.0b Initial Version
+*
+* License: GNU GPL v2 (see License.txt)
+*/
+
+#include "project.h"
+
+void inline
+ws2812_setleds (struct RGB *ledarray, uint16_t leds)
+{
+ ws2812_setleds_pin (ledarray, leds, _BV (WS2812_PIN));
+}
+
+void inline
+ws2812_setleds_pin (struct RGB *ledarray, uint16_t leds, uint8_t pinmask)
+{
+ WS2812_DDRREG |= pinmask; // Enable DDR
+ ws2812_sendarray_mask ((uint8_t *) ledarray, leds + leds + leds, pinmask);
+ _delay_us (50);
+}
+
+void
+ws2812_sendarray (uint8_t * data, uint16_t datlen)
+{
+ ws2812_sendarray_mask (data, datlen, _BV (WS2812_PIN));
+}
+
+/*
+ This routine writes an array of bytes with RGB values to the Dataout pin
+ using the fast 800kHz clockless WS2811/2812 protocol.
+*/
+
+// Timing in ns
+#define w_zeropulse 350
+#define w_onepulse 900
+#define w_totalperiod 1250
+
+// Fixed cycles used by the inner loop
+#define w_fixedlow 2
+#define w_fixedhigh 4
+#define w_fixedtotal 8
+
+// Insert NOPs to match the timing, if possible
+#define w_zerocycles (((F_CPU/1000)*w_zeropulse )/1000000)
+#define w_onecycles (((F_CPU/1000)*w_onepulse +500000)/1000000)
+#define w_totalcycles (((F_CPU/1000)*w_totalperiod +500000)/1000000)
+
+// w1 - nops between rising edge and falling edge - low
+#define w1 (w_zerocycles-w_fixedlow)
+// w2 nops between fe low and fe high
+#define w2 (w_onecycles-w_fixedhigh-w1)
+// w3 nops to complete loop
+#define w3 (w_totalcycles-w_fixedtotal-w1-w2)
+
+#if w1>0
+#define w1_nops w1
+#else
+#define w1_nops 0
+#endif
+
+// The only critical timing parameter is the minimum pulse length of the "0"
+// Warn or throw error if this timing can not be met with current F_CPU settings.
+#define w_lowtime ((w1_nops+w_fixedlow)*1000000)/(F_CPU/1000)
+#if w_lowtime>550
+#error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?"
+#elif w_lowtime>450
+#warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)."
+#warning "Please consider a higher clockspeed, if possible"
+#endif
+
+#if w2>0
+#define w2_nops w2
+#else
+#define w2_nops 0
+#endif
+
+#if w3>0
+#define w3_nops w3
+#else
+#define w3_nops 0
+#endif
+
+#define w_nop1 "nop \n\t"
+#define w_nop2 "rjmp .+0 \n\t"
+#define w_nop4 w_nop2 w_nop2
+#define w_nop8 w_nop4 w_nop4
+#define w_nop16 w_nop8 w_nop8
+
+void inline
+ws2812_sendarray_mask (uint8_t * data, uint16_t datlen, uint8_t maskhi)
+{
+ uint8_t curbyte, ctr, masklo;
+ uint8_t sreg_prev;
+
+ masklo = ~maskhi & WS2812_PORTREG;
+ maskhi |= WS2812_PORTREG;
+ sreg_prev = SREG;
+ cli ();
+
+ while (datlen--)
+ {
+ curbyte = *data++;
+
+ asm volatile (" ldi %0,8 \n\t" "loop%=: \n\t" " out %2,%3 \n\t" // '1' [01] '0' [01] - re
+#if (w1_nops&1)
+ w_nop1
+#endif
+#if (w1_nops&2)
+ w_nop2
+#endif
+#if (w1_nops&4)
+ w_nop4
+#endif
+#if (w1_nops&8)
+ w_nop8
+#endif
+#if (w1_nops&16)
+ w_nop16
+#endif
+ " sbrs %1,7 \n\t" // '1' [03] '0' [02]
+ " out %2,%4 \n\t" // '1' [--] '0' [03] - fe-low
+ " lsl %1 \n\t" // '1' [04] '0' [04]
+#if (w2_nops&1)
+ w_nop1
+#endif
+#if (w2_nops&2)
+ w_nop2
+#endif
+#if (w2_nops&4)
+ w_nop4
+#endif
+#if (w2_nops&8)
+ w_nop8
+#endif
+#if (w2_nops&16)
+ w_nop16
+#endif
+ " out %2,%4 \n\t" // '1' [+1] '0' [+1] - fe-high
+#if (w3_nops&1)
+ w_nop1
+#endif
+#if (w3_nops&2)
+ w_nop2
+#endif
+#if (w3_nops&4)
+ w_nop4
+#endif
+#if (w3_nops&8)
+ w_nop8
+#endif
+#if (w3_nops&16)
+ w_nop16
+#endif
+ " dec %0 \n\t" // '1' [+2] '0' [+2]
+ " brne loop%=\n\t" // '1' [+3] '0' [+4]
+ :"=&d" (ctr):"r" (curbyte),
+ "I" (_SFR_IO_ADDR (WS2812_PORTREG)), "r" (maskhi),
+ "r" (masklo));
+ }
+
+ SREG = sreg_prev;
+}
diff --git a/lib_ws2812.h b/lib_ws2812.h
new file mode 100644
index 0000000..2142fa1
--- /dev/null
+++ b/lib_ws2812.h
@@ -0,0 +1,64 @@
+/*
+ * light weight WS2812 lib include
+ *
+ * Version 2.0a3 - Jan 18th 2014
+ * Author: Tim (cpldcpu@gmail.com)
+ *
+ * Please do not change this file! All configuration is handled in "ws2812_config.h"
+ *
+ * License: GNU GPL v2 (see License.txt)
+ +
+ */
+
+#ifndef LIGHT_WS2812_H_
+#define LIGHT_WS2812_H_
+
+/*
+ * Structure of the LED array
+ */
+
+struct RGB
+{
+ uint8_t g;
+ uint8_t r;
+ uint8_t b;
+};
+
+/* User Interface
+ *
+ * Input:
+ * ledarray: An array of GRB data describing the LED colors
+ * number_of_leds: The number of LEDs to write
+ * pinmask (optional): Bitmask describing the output bin. e.g. _BV(PB0)
+ *
+ * The functions will perform the following actions:
+ * - Set the data-out pin as output
+ * - Send out the LED data
+ * - Wait 50µs to reset the LEDs
+ */
+
+void ws2812_setleds (struct RGB *ledarray, uint16_t number_of_leds);
+void ws2812_setleds_pin (struct RGB *ledarray, uint16_t number_of_leds,
+ uint8_t pinmask);
+
+/*
+ * Old interface / Internal functions
+ *
+ * The functions take a byte-array and send to the data output as WS2812 bitstream.
+ * The length is the number of bytes to send - three per LED.
+ */
+
+void ws2812_sendarray (uint8_t * array, uint16_t length);
+void ws2812_sendarray_mask (uint8_t * array, uint16_t length,
+ uint8_t pinmask);
+
+
+/*
+ * Internal defines
+ */
+
+#define CONCAT(a, b) a ## b
+#define CONCAT_EXP(a, b) CONCAT(a, b)
+
+
+#endif /* LIGHT_WS2812_H_ */
diff --git a/project.h b/project.h
new file mode 100644
index 0000000..d75338b
--- /dev/null
+++ b/project.h
@@ -0,0 +1,28 @@
+#define F_CPU 16000000
+
+#include <stdio.h>
+#include <stdint.h>
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/pgmspace.h>
+#include <util/delay.h>
+
+#include "uart.h"
+
+#define UART_BAUD_RATE 115200
+
+#define WS2812_PORTREG PORTB
+#define WS2812_DDRREG DDRB
+#define WS2812_PIN 1
+
+#include "lib_ws2812.h"
+
+#ifdef PROTOTYPING
+#define NOPROTO static
+#else
+#define NOPROTO
+#endif
+
+#define NOUNUSED __attribute__((unused))
+
+#include "prototypes.h"
diff --git a/prototypes.h b/prototypes.h
new file mode 100644
index 0000000..b578f9c
--- /dev/null
+++ b/prototypes.h
@@ -0,0 +1,35 @@
+/* lib_ws2812.c */
+void _delay_loop_1(uint8_t __count);
+void _delay_loop_2(uint16_t __count);
+void _delay_ms(double __ms);
+void _delay_us(double __us);
+void ws2812_sendarray(uint8_t *data, uint16_t datlen);
+/* blinky.c */
+void _delay_loop_1(uint8_t __count);
+void _delay_loop_2(uint16_t __count);
+void _delay_ms(double __ms);
+void _delay_us(double __us);
+int ramp(int j, int n);
+int main(void);
+/* util.c */
+void _delay_loop_1(uint8_t __count);
+void _delay_loop_2(uint16_t __count);
+void _delay_ms(double __ms);
+void _delay_us(double __us);
+void setup_clocks(void);
+/* uart.c */
+void _delay_loop_1(uint8_t __count);
+void _delay_loop_2(uint16_t __count);
+void _delay_ms(double __ms);
+void _delay_us(double __us);
+void uart_init(unsigned int baudrate);
+unsigned int uart_getc(void);
+void uart_putc(unsigned char data);
+void uart_puts(const char *s);
+void uart_puts_p(const char *progmem_s);
+/* stdio.c */
+void _delay_loop_1(uint8_t __count);
+void _delay_loop_2(uint16_t __count);
+void _delay_ms(double __ms);
+void _delay_us(double __us);
+void stdio_init(void);
diff --git a/stdio.c b/stdio.c
new file mode 100644
index 0000000..c12a9ab
--- /dev/null
+++ b/stdio.c
@@ -0,0 +1,24 @@
+#include "project.h"
+
+static int
+stdio_uart_putchar (char var, FILE * stream)
+{
+
+ if (var == '\n')
+ uart_putc ('\r');
+ uart_putc (var);
+ return 0;
+}
+
+
+static FILE stdio_uart_stdout =
+FDEV_SETUP_STREAM (stdio_uart_putchar, NULL, _FDEV_SETUP_WRITE);
+
+void
+stdio_init (void)
+{
+ stdout = &stdio_uart_stdout;
+
+ uart_init (UART_BAUD_SELECT (UART_BAUD_RATE, F_CPU));
+ sei ();
+}
diff --git a/uart.c b/uart.c
new file mode 100644
index 0000000..eb21b6b
--- /dev/null
+++ b/uart.c
@@ -0,0 +1,686 @@
+/*************************************************************************
+Title: Interrupt UART library with receive/transmit circular buffers
+Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury
+File: $Id: uart.c,v 1.10 2013/06/02 07:27:04 peter Exp $
+Software: AVR-GCC 4.1, AVR Libc 1.4.6 or higher
+Hardware: any AVR with built-in UART,
+License: GNU General Public License
+
+DESCRIPTION:
+ An interrupt is generated when the UART has finished transmitting or
+ receiving a byte. The interrupt handling routines use circular buffers
+ for buffering received and transmitted data.
+
+ The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE variables define
+ the buffer size in bytes. Note that these variables must be a
+ power of 2.
+
+USAGE:
+ Refere to the header file uart.h for a description of the routines.
+ See also example test_uart.c.
+
+NOTES:
+ Based on Atmel Application Note AVR306
+
+LICENSE:
+ Copyright (C) 2006 Peter Fleury
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*************************************************************************/
+#include "project.h"
+
+
+/*
+ * constants and macros
+ */
+
+/* size of RX/TX buffers */
+#define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1)
+#define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1)
+
+#if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK )
+#error RX buffer size is not a power of 2
+#endif
+#if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK )
+#error TX buffer size is not a power of 2
+#endif
+
+#if defined(__AVR_AT90S2313__) \
+ || defined(__AVR_AT90S4414__) || defined(__AVR_AT90S4434__) \
+ || defined(__AVR_AT90S8515__) || defined(__AVR_AT90S8535__) \
+ || defined(__AVR_ATmega103__)
+ /* old AVR classic or ATmega103 with one UART */
+#define AT90_UART
+#define UART0_RECEIVE_INTERRUPT UART_RX_vect
+#define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect
+#define UART0_STATUS USR
+#define UART0_CONTROL UCR
+#define UART0_DATA UDR
+#define UART0_UDRIE UDRIE
+#elif defined(__AVR_AT90S2333__) || defined(__AVR_AT90S4433__)
+ /* old AVR classic with one UART */
+#define AT90_UART
+#define UART0_RECEIVE_INTERRUPT UART_RX_vect
+#define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect
+#define UART0_STATUS UCSRA
+#define UART0_CONTROL UCSRB
+#define UART0_DATA UDR
+#define UART0_UDRIE UDRIE
+#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \
+ || defined(__AVR_ATmega323__)
+ /* ATmega with one USART */
+#define ATMEGA_USART
+#define UART0_RECEIVE_INTERRUPT USART_RXC_vect
+#define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect
+#define UART0_STATUS UCSRA
+#define UART0_CONTROL UCSRB
+#define UART0_DATA UDR
+#define UART0_UDRIE UDRIE
+#elif defined (__AVR_ATmega8515__) || defined(__AVR_ATmega8535__)
+#define ATMEGA_USART
+#define UART0_RECEIVE_INTERRUPT USART_RX_vect
+#define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect
+#define UART0_STATUS UCSRA
+#define UART0_CONTROL UCSRB
+#define UART0_DATA UDR
+#define UART0_UDRIE UDRIE
+#elif defined(__AVR_ATmega163__)
+ /* ATmega163 with one UART */
+#define ATMEGA_UART
+#define UART0_RECEIVE_INTERRUPT UART_RX_vect
+#define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect
+#define UART0_STATUS UCSRA
+#define UART0_CONTROL UCSRB
+#define UART0_DATA UDR
+#define UART0_UDRIE UDRIE
+#elif defined(__AVR_ATmega162__)
+ /* ATmega with two USART */
+#define ATMEGA_USART0
+#define ATMEGA_USART1
+#define UART0_RECEIVE_INTERRUPT USART0_RXC_vect
+#define UART1_RECEIVE_INTERRUPT USART1_RXC_vect
+#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect
+#define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect
+#define UART0_STATUS UCSR0A
+#define UART0_CONTROL UCSR0B
+#define UART0_DATA UDR0
+#define UART0_UDRIE UDRIE0
+#define UART1_STATUS UCSR1A
+#define UART1_CONTROL UCSR1B
+#define UART1_DATA UDR1
+#define UART1_UDRIE UDRIE1
+#elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__)
+ /* ATmega with two USART */
+#define ATMEGA_USART0
+#define ATMEGA_USART1
+#define UART0_RECEIVE_INTERRUPT USART0_RX_vect
+#define UART1_RECEIVE_INTERRUPT USART1_RX_vect
+#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect
+#define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect
+#define UART0_STATUS UCSR0A
+#define UART0_CONTROL UCSR0B
+#define UART0_DATA UDR0
+#define UART0_UDRIE UDRIE0
+#define UART1_STATUS UCSR1A
+#define UART1_CONTROL UCSR1B
+#define UART1_DATA UDR1
+#define UART1_UDRIE UDRIE1
+#elif defined(__AVR_ATmega161__)
+ /* ATmega with UART */
+#error "AVR ATmega161 currently not supported by this libaray !"
+#elif defined(__AVR_ATmega169__)
+ /* ATmega with one USART */
+#define ATMEGA_USART
+#define UART0_RECEIVE_INTERRUPT USART0_RX_vect
+#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect
+#define UART0_STATUS UCSRA
+#define UART0_CONTROL UCSRB
+#define UART0_DATA UDR
+#define UART0_UDRIE UDRIE
+#elif defined(__AVR_ATmega48__) || defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) \
+ || defined(__AVR_ATmega3250__) || defined(__AVR_ATmega3290__) ||defined(__AVR_ATmega6450__) || defined(__AVR_ATmega6490__)
+ /* ATmega with one USART */
+#define ATMEGA_USART0
+#define UART0_RECEIVE_INTERRUPT USART_RX_vect
+#define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect
+#define UART0_STATUS UCSR0A
+#define UART0_CONTROL UCSR0B
+#define UART0_DATA UDR0
+#define UART0_UDRIE UDRIE0
+#elif defined(__AVR_ATtiny2313__)
+#define ATMEGA_USART
+#define UART0_RECEIVE_INTERRUPT USART_RX_vect
+#define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect
+#define UART0_STATUS UCSRA
+#define UART0_CONTROL UCSRB
+#define UART0_DATA UDR
+#define UART0_UDRIE UDRIE
+#elif defined(__AVR_ATmega329__) || \
+ defined(__AVR_ATmega649__) || \
+ defined(__AVR_ATmega325__) || \
+ defined(__AVR_ATmega645__)
+ /* ATmega with one USART */
+#define ATMEGA_USART0
+#define UART0_RECEIVE_INTERRUPT USART0_RX_vect
+#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect
+#define UART0_STATUS UCSR0A
+#define UART0_CONTROL UCSR0B
+#define UART0_DATA UDR0
+#define UART0_UDRIE UDRIE0
+#elif defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega640__)
+/* ATmega with two USART */
+#define ATMEGA_USART0
+#define ATMEGA_USART1
+#define UART0_RECEIVE_INTERRUPT USART0_RX_vect
+#define UART1_RECEIVE_INTERRUPT USART1_RX_vect
+#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect
+#define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect
+#define UART0_STATUS UCSR0A
+#define UART0_CONTROL UCSR0B
+#define UART0_DATA UDR0
+#define UART0_UDRIE UDRIE0
+#define UART1_STATUS UCSR1A
+#define UART1_CONTROL UCSR1B
+#define UART1_DATA UDR1
+#define UART1_UDRIE UDRIE1
+#elif defined(__AVR_ATmega644__)
+ /* ATmega with one USART */
+#define ATMEGA_USART0
+#define UART0_RECEIVE_INTERRUPT USART0_RX_vect
+#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect
+#define UART0_STATUS UCSR0A
+#define UART0_CONTROL UCSR0B
+#define UART0_DATA UDR0
+#define UART0_UDRIE UDRIE0
+#elif defined(__AVR_ATmega164P__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega644P__)
+ /* ATmega with two USART */
+#define ATMEGA_USART0
+#define ATMEGA_USART1
+#define UART0_RECEIVE_INTERRUPT USART0_RX_vect
+#define UART1_RECEIVE_INTERRUPT USART1_RX_vect
+#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect
+#define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect
+#define UART0_STATUS UCSR0A
+#define UART0_CONTROL UCSR0B
+#define UART0_DATA UDR0
+#define UART0_UDRIE UDRIE0
+#define UART1_STATUS UCSR1A
+#define UART1_CONTROL UCSR1B
+#define UART1_DATA UDR1
+#define UART1_UDRIE UDRIE1
+#else
+#error "no UART definition for MCU available"
+#endif
+
+
+/*
+ * module global variables
+ */
+static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE];
+static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE];
+static volatile unsigned char UART_TxHead;
+static volatile unsigned char UART_TxTail;
+static volatile unsigned char UART_RxHead;
+static volatile unsigned char UART_RxTail;
+static volatile unsigned char UART_LastRxError;
+
+#if defined( ATMEGA_USART1 )
+static volatile unsigned char UART1_TxBuf[UART_TX_BUFFER_SIZE];
+static volatile unsigned char UART1_RxBuf[UART_RX_BUFFER_SIZE];
+static volatile unsigned char UART1_TxHead;
+static volatile unsigned char UART1_TxTail;
+static volatile unsigned char UART1_RxHead;
+static volatile unsigned char UART1_RxTail;
+static volatile unsigned char UART1_LastRxError;
+#endif
+
+
+
+ISR (NOPROTO UART0_RECEIVE_INTERRUPT)
+/*************************************************************************
+Function: UART Receive Complete interrupt
+Purpose: called when the UART has received a character
+**************************************************************************/
+{
+ unsigned char tmphead;
+ unsigned char data;
+ unsigned char usr;
+ unsigned char lastRxError;
+
+
+ /* read UART status register and UART data register */
+ usr = UART0_STATUS;
+ data = UART0_DATA;
+
+ /* */
+#if defined( AT90_UART )
+ lastRxError = (usr & (_BV (FE) | _BV (DOR)));
+#elif defined( ATMEGA_USART )
+ lastRxError = (usr & (_BV (FE) | _BV (DOR)));
+#elif defined( ATMEGA_USART0 )
+ lastRxError = (usr & (_BV (FE0) | _BV (DOR0)));
+#elif defined ( ATMEGA_UART )
+ lastRxError = (usr & (_BV (FE) | _BV (DOR)));
+#endif
+
+ /* calculate buffer index */
+ tmphead = (UART_RxHead + 1) & UART_RX_BUFFER_MASK;
+
+ if (tmphead == UART_RxTail)
+ {
+ /* error: receive buffer overflow */
+ lastRxError = UART_BUFFER_OVERFLOW >> 8;
+ }
+ else
+ {
+ /* store new index */
+ UART_RxHead = tmphead;
+ /* store received data in buffer */
+ UART_RxBuf[tmphead] = data;
+ }
+ UART_LastRxError |= lastRxError;
+}
+
+
+ISR (NOPROTO UART0_TRANSMIT_INTERRUPT)
+/*************************************************************************
+Function: UART Data Register Empty interrupt
+Purpose: called when the UART is ready to transmit the next byte
+**************************************************************************/
+{
+ unsigned char tmptail;
+
+
+ if (UART_TxHead != UART_TxTail)
+ {
+ /* calculate and store new buffer index */
+ tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK;
+ UART_TxTail = tmptail;
+ /* get one byte from buffer and write it to UART */
+ UART0_DATA = UART_TxBuf[tmptail]; /* start transmission */
+ }
+ else
+ {
+ /* tx buffer empty, disable UDRE interrupt */
+ UART0_CONTROL &= ~_BV (UART0_UDRIE);
+ }
+}
+
+
+/*************************************************************************
+Function: uart_init()
+Purpose: initialize UART and set baudrate
+Input: baudrate using macro UART_BAUD_SELECT()
+Returns: none
+**************************************************************************/
+void
+uart_init (unsigned int baudrate)
+{
+ UART_TxHead = 0;
+ UART_TxTail = 0;
+ UART_RxHead = 0;
+ UART_RxTail = 0;
+
+#if defined( AT90_UART )
+ /* set baud rate */
+ UBRR = (unsigned char) baudrate;
+
+ /* enable UART receiver and transmmitter and receive complete interrupt */
+ UART0_CONTROL = _BV (RXCIE) | _BV (RXEN) | _BV (TXEN);
+
+#elif defined (ATMEGA_USART)
+ /* Set baud rate */
+ if (baudrate & 0x8000)
+ {
+ UART0_STATUS = (1 << U2X); //Enable 2x speed
+ baudrate &= ~0x8000;
+ }
+ UBRRH = (unsigned char) (baudrate >> 8);
+ UBRRL = (unsigned char) baudrate;
+
+ /* Enable USART receiver and transmitter and receive complete interrupt */
+ UART0_CONTROL = _BV (RXCIE) | (1 << RXEN) | (1 << TXEN);
+
+ /* Set frame format: asynchronous, 8data, no parity, 1stop bit */
+#ifdef URSEL
+ UCSRC = (1 << URSEL) | (3 << UCSZ0);
+#else
+ UCSRC = (3 << UCSZ0);
+#endif
+
+#elif defined (ATMEGA_USART0 )
+ /* Set baud rate */
+ if (baudrate & 0x8000)
+ {
+ UART0_STATUS = (1 << U2X0); //Enable 2x speed
+ baudrate &= ~0x8000;
+ }
+ UBRR0H = (unsigned char) (baudrate >> 8);
+ UBRR0L = (unsigned char) baudrate;
+
+ /* Enable USART receiver and transmitter and receive complete interrupt */
+ UART0_CONTROL = _BV (RXCIE0) | (1 << RXEN0) | (1 << TXEN0);
+
+ /* Set frame format: asynchronous, 8data, no parity, 1stop bit */
+#ifdef URSEL0
+ UCSR0C = (1 << URSEL0) | (3 << UCSZ00);
+#else
+ UCSR0C = (3 << UCSZ00);
+#endif
+
+#elif defined ( ATMEGA_UART )
+ /* set baud rate */
+ if (baudrate & 0x8000)
+ {
+ UART0_STATUS = (1 << U2X); //Enable 2x speed
+ baudrate &= ~0x8000;
+ }
+ UBRRHI = (unsigned char) (baudrate >> 8);
+ UBRR = (unsigned char) baudrate;
+
+ /* Enable UART receiver and transmitter and receive complete interrupt */
+ UART0_CONTROL = _BV (RXCIE) | (1 << RXEN) | (1 << TXEN);
+
+#endif
+
+} /* uart_init */
+
+
+/*************************************************************************
+Function: uart_getc()
+Purpose: return byte from ringbuffer
+Returns: lower byte: received byte from ringbuffer
+ higher byte: last receive error
+**************************************************************************/
+unsigned int
+uart_getc (void)
+{
+ unsigned char tmptail;
+ unsigned char data;
+
+
+ if (UART_RxHead == UART_RxTail)
+ {
+ return UART_NO_DATA; /* no data available */
+ }
+
+ /* calculate /store buffer index */
+ tmptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK;
+ UART_RxTail = tmptail;
+
+ /* get data from receive buffer */
+ data = UART_RxBuf[tmptail];
+
+ data = (UART_LastRxError << 8) + data;
+ UART_LastRxError = 0;
+ return data;
+
+} /* uart_getc */
+
+
+/*************************************************************************
+Function: uart_putc()
+Purpose: write byte to ringbuffer for transmitting via UART
+Input: byte to be transmitted
+Returns: none
+**************************************************************************/
+void
+uart_putc (unsigned char data)
+{
+ unsigned char tmphead;
+
+
+ tmphead = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
+
+ while (tmphead == UART_TxTail)
+ {
+ ; /* wait for free space in buffer */
+ }
+
+ UART_TxBuf[tmphead] = data;
+ UART_TxHead = tmphead;
+
+ /* enable UDRE interrupt */
+ UART0_CONTROL |= _BV (UART0_UDRIE);
+
+} /* uart_putc */
+
+
+/*************************************************************************
+Function: uart_puts()
+Purpose: transmit string to UART
+Input: string to be transmitted
+Returns: none
+**************************************************************************/
+void
+uart_puts (const char *s)
+{
+ while (*s)
+ uart_putc (*s++);
+
+} /* uart_puts */
+
+
+/*************************************************************************
+Function: uart_puts_p()
+Purpose: transmit string from program memory to UART
+Input: program memory string to be transmitted
+Returns: none
+**************************************************************************/
+void
+uart_puts_p (const char *progmem_s)
+{
+ register char c;
+
+ while ((c = pgm_read_byte (progmem_s++)))
+ uart_putc (c);
+
+} /* uart_puts_p */
+
+
+/*
+ * these functions are only for ATmegas with two USART
+ */
+#if defined( ATMEGA_USART1 )
+
+ISR (NOPROTO UART1_RECEIVE_INTERRUPT)
+/*************************************************************************
+Function: UART1 Receive Complete interrupt
+Purpose: called when the UART1 has received a character
+**************************************************************************/
+{
+ unsigned char tmphead;
+ unsigned char data;
+ unsigned char usr;
+ unsigned char lastRxError;
+
+
+ /* read UART status register and UART data register */
+ usr = UART1_STATUS;
+ data = UART1_DATA;
+
+ /* */
+ lastRxError = (usr & (_BV (FE1) | _BV (DOR1)));
+
+ /* calculate buffer index */
+ tmphead = (UART1_RxHead + 1) & UART_RX_BUFFER_MASK;
+
+ if (tmphead == UART1_RxTail)
+ {
+ /* error: receive buffer overflow */
+ lastRxError = UART_BUFFER_OVERFLOW >> 8;
+ }
+ else
+ {
+ /* store new index */
+ UART1_RxHead = tmphead;
+ /* store received data in buffer */
+ UART1_RxBuf[tmphead] = data;
+ }
+ UART1_LastRxError |= lastRxError;
+}
+
+
+ISR (NOPROTO UART1_TRANSMIT_INTERRUPT)
+/*************************************************************************
+Function: UART1 Data Register Empty interrupt
+Purpose: called when the UART1 is ready to transmit the next byte
+**************************************************************************/
+{
+ unsigned char tmptail;
+
+
+ if (UART1_TxHead != UART1_TxTail)
+ {
+ /* calculate and store new buffer index */
+ tmptail = (UART1_TxTail + 1) & UART_TX_BUFFER_MASK;
+ UART1_TxTail = tmptail;
+ /* get one byte from buffer and write it to UART */
+ UART1_DATA = UART1_TxBuf[tmptail]; /* start transmission */
+ }
+ else
+ {
+ /* tx buffer empty, disable UDRE interrupt */
+ UART1_CONTROL &= ~_BV (UART1_UDRIE);
+ }
+}
+
+
+/*************************************************************************
+Function: uart1_init()
+Purpose: initialize UART1 and set baudrate
+Input: baudrate using macro UART_BAUD_SELECT()
+Returns: none
+**************************************************************************/
+void
+uart1_init (unsigned int baudrate)
+{
+ UART1_TxHead = 0;
+ UART1_TxTail = 0;
+ UART1_RxHead = 0;
+ UART1_RxTail = 0;
+
+
+ /* Set baud rate */
+ if (baudrate & 0x8000)
+ {
+ UART1_STATUS = (1 << U2X1); //Enable 2x speed
+ baudrate &= ~0x8000;
+ }
+ UBRR1H = (unsigned char) (baudrate >> 8);
+ UBRR1L = (unsigned char) baudrate;
+
+ /* Enable USART receiver and transmitter and receive complete interrupt */
+ UART1_CONTROL = _BV (RXCIE1) | (1 << RXEN1) | (1 << TXEN1);
+
+ /* Set frame format: asynchronous, 8data, no parity, 1stop bit */
+#ifdef URSEL1
+ UCSR1C = (1 << URSEL1) | (3 << UCSZ10);
+#else
+ UCSR1C = (3 << UCSZ10);
+#endif
+} /* uart_init */
+
+
+/*************************************************************************
+Function: uart1_getc()
+Purpose: return byte from ringbuffer
+Returns: lower byte: received byte from ringbuffer
+ higher byte: last receive error
+**************************************************************************/
+unsigned int
+uart1_getc (void)
+{
+ unsigned char tmptail;
+ unsigned char data;
+
+
+ if (UART1_RxHead == UART1_RxTail)
+ {
+ return UART_NO_DATA; /* no data available */
+ }
+
+ /* calculate /store buffer index */
+ tmptail = (UART1_RxTail + 1) & UART_RX_BUFFER_MASK;
+ UART1_RxTail = tmptail;
+
+ /* get data from receive buffer */
+ data = UART1_RxBuf[tmptail];
+
+ data = (UART1_LastRxError << 8) + data;
+ UART1_LastRxError = 0;
+ return data;
+
+} /* uart1_getc */
+
+
+/*************************************************************************
+Function: uart1_putc()
+Purpose: write byte to ringbuffer for transmitting via UART
+Input: byte to be transmitted
+Returns: none
+**************************************************************************/
+void
+uart1_putc (unsigned char data)
+{
+ unsigned char tmphead;
+
+
+ tmphead = (UART1_TxHead + 1) & UART_TX_BUFFER_MASK;
+
+ while (tmphead == UART1_TxTail)
+ {
+ ; /* wait for free space in buffer */
+ }
+
+ UART1_TxBuf[tmphead] = data;
+ UART1_TxHead = tmphead;
+
+ /* enable UDRE interrupt */
+ UART1_CONTROL |= _BV (UART1_UDRIE);
+
+} /* uart1_putc */
+
+
+/*************************************************************************
+Function: uart1_puts()
+Purpose: transmit string to UART1
+Input: string to be transmitted
+Returns: none
+**************************************************************************/
+void
+uart1_puts (const char *s)
+{
+ while (*s)
+ uart1_putc (*s++);
+
+} /* uart1_puts */
+
+
+/*************************************************************************
+Function: uart1_puts_p()
+Purpose: transmit string from program memory to UART1
+Input: program memory string to be transmitted
+Returns: none
+**************************************************************************/
+void
+uart1_puts_p (const char *progmem_s)
+{
+ register char c;
+
+ while ((c = pgm_read_byte (progmem_s++)))
+ uart1_putc (c);
+
+} /* uart1_puts_p */
+
+
+#endif
diff --git a/uart.h b/uart.h
new file mode 100644
index 0000000..044c45b
--- /dev/null
+++ b/uart.h
@@ -0,0 +1,183 @@
+#ifndef UART_H
+#define UART_H
+/************************************************************************
+Title: Interrupt UART library with receive/transmit circular buffers
+Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury
+File: $Id: uart.h,v 1.12 2012/11/19 19:52:27 peter Exp $
+Software: AVR-GCC 4.1, AVR Libc 1.4
+Hardware: any AVR with built-in UART, tested on AT90S8515 & ATmega8 at 4 Mhz
+License: GNU General Public License
+Usage: see Doxygen manual
+
+LICENSE:
+ Copyright (C) 2006 Peter Fleury
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+************************************************************************/
+
+/**
+ * @defgroup pfleury_uart UART Library
+ * @code #include <uart.h> @endcode
+ *
+ * @brief Interrupt UART library using the built-in UART with transmit and receive circular buffers.
+ *
+ * This library can be used to transmit and receive data through the built in UART.
+ *
+ * An interrupt is generated when the UART has finished transmitting or
+ * receiving a byte. The interrupt handling routines use circular buffers
+ * for buffering received and transmitted data.
+ *
+ * The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE constants define
+ * the size of the circular buffers in bytes. Note that these constants must be a power of 2.
+ * You may need to adapt this constants to your target and your application by adding
+ * CDEFS += -DUART_RX_BUFFER_SIZE=nn -DUART_RX_BUFFER_SIZE=nn to your Makefile.
+ *
+ * @note Based on Atmel Application Note AVR306
+ * @author Peter Fleury pfleury@gmx.ch http://jump.to/fleury
+ */
+
+/**@{*/
+#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304
+#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !"
+#endif /* */
+
+/*
+** constants and macros
+*/
+
+/** @brief UART Baudrate Expression
+ * @param xtalcpu system clock in Mhz, e.g. 4000000UL for 4Mhz
+ * @param baudrate baudrate in bps, e.g. 1200, 2400, 9600
+ */
+#define UART_BAUD_SELECT(baudRate,xtalCpu) (((xtalCpu) + 8UL * (baudRate)) / (16UL * (baudRate)) -1UL)
+
+/** @brief UART Baudrate Expression for ATmega double speed mode
+ * @param xtalcpu system clock in Mhz, e.g. 4000000UL for 4Mhz
+ * @param baudrate baudrate in bps, e.g. 1200, 2400, 9600
+ */
+#define UART_BAUD_SELECT_DOUBLE_SPEED(baudRate,xtalCpu) ( ((((xtalCpu) + 4UL * (baudRate)) / (8UL * (baudRate)) -1UL)) | 0x8000)
+
+/** Size of the circular receive buffer, must be power of 2 */
+#ifndef UART_RX_BUFFER_SIZE
+#define UART_RX_BUFFER_SIZE 32
+#endif /* */
+/** Size of the circular transmit buffer, must be power of 2 */
+#ifndef UART_TX_BUFFER_SIZE
+#define UART_TX_BUFFER_SIZE 32
+#endif /* */
+
+/* test if the size of the circular buffers fits into SRAM */
+#if ( (UART_RX_BUFFER_SIZE+UART_TX_BUFFER_SIZE) >= (RAMEND-0x60 ) )
+#error "size of UART_RX_BUFFER_SIZE + UART_TX_BUFFER_SIZE larger than size of SRAM"
+#endif /* */
+
+/*
+** high byte error return code of uart_getc()
+*/
+#define UART_FRAME_ERROR 0x1000 /* Framing Error by UART */
+#define UART_OVERRUN_ERROR 0x0800 /* Overrun condition by UART */
+#define UART_PARITY_ERROR 0x0400 /* Parity Error by UART */
+#define UART_BUFFER_OVERFLOW 0x0200 /* receive ringbuffer overflow */
+#define UART_NO_DATA 0x0100 /* no receive data available */
+
+/*
+** function prototypes
+*/
+
+/**
+ @brief Initialize UART and set baudrate
+ @param baudrate Specify baudrate using macro UART_BAUD_SELECT()
+ @return none
+*/
+// extern void uart_init(unsigned int baudrate);
+
+/**
+ * @brief Get received byte from ringbuffer
+ *
+ * Returns in the lower byte the received character and in the
+ * higher byte the last receive error.
+ * UART_NO_DATA is returned when no data is available.
+ *
+ * @param void
+ * @return lower byte: received byte from ringbuffer
+ * @return higher byte: last receive status
+ * - \b 0 successfully received data from UART
+ * - \b UART_NO_DATA
+ * <br>no receive data available
+ * - \b UART_BUFFER_OVERFLOW
+ * <br>Receive ringbuffer overflow.
+ * We are not reading the receive buffer fast enough,
+ * one or more received character have been dropped
+ * - \b UART_OVERRUN_ERROR
+ * <br>Overrun condition by UART.
+ * A character already present in the UART UDR register was
+ * not read by the interrupt handler before the next character arrived,
+ * one or more received characters have been dropped.
+ * - \b UART_FRAME_ERROR
+ * <br>Framing Error by UART
+ */
+// extern unsigned int uart_getc(void);
+
+/**
+ * @brief Put byte to ringbuffer for transmitting via UART
+ * @param data byte to be transmitted
+ * @return none
+ */
+// extern void uart_putc(unsigned char data);
+
+/**
+ * @brief Put string to ringbuffer for transmitting via UART
+ *
+ * The string is buffered by the uart library in a circular buffer
+ * and one character at a time is transmitted to the UART using interrupts.
+ * Blocks if it can not write the whole string into the circular buffer.
+ *
+ * @param s string to be transmitted
+ * @return none
+ */
+// extern void uart_puts(const char *s );
+
+/**
+ * @brief Put string from program memory to ringbuffer for transmitting via UART.
+ *
+ * The string is buffered by the uart library in a circular buffer
+ * and one character at a time is transmitted to the UART using interrupts.
+ * Blocks if it can not write the whole string into the circular buffer.
+ *
+ * @param s program memory string to be transmitted
+ * @return none
+ * @see uart_puts_P
+ */
+// extern void uart_puts_p(const char *s );
+
+/**
+ * @brief Macro to automatically put a string constant into program memory
+ */
+#define uart_puts_P(__s) uart_puts_p(PSTR(__s))
+
+/** @brief Initialize USART1 (only available on selected ATmegas) @see uart_init */
+// extern void uart1_init(unsigned int baudrate);
+/** @brief Get received byte of USART1 from ringbuffer. (only available on selected ATmega) @see uart_getc */
+// extern unsigned int uart1_getc(void);
+/** @brief Put byte to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_putc */
+// extern void uart1_putc(unsigned char data);
+/** @brief Put string to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_puts */
+// extern void uart1_puts(const char *s );
+/** @brief Put string from program memory to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_puts_p */
+// extern void uart1_puts_p(const char *s );
+/** @brief Macro to automatically put a string constant into program memory */
+#define uart1_puts_P(__s) uart1_puts_p(PSTR(__s))
+
+/**@}*/
+
+#endif // UART_H
+
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..9e82554
--- /dev/null
+++ b/util.c
@@ -0,0 +1,13 @@
+#include "project.h"
+
+void
+setup_clocks (void)
+{
+#ifdef __AVR_ATtiny10__
+ CCP = 0xD8; // configuration change protection, write signature
+ CLKPSR = 0; // set cpu clock prescaler =1 (8Mhz) (attiny 4/5/9/10)
+#else
+ CLKPR = _BV (CLKPCE);
+ CLKPR = 0; // set clock prescaler to 1 (attiny 25/45/85/24/44/84/13/13A)
+#endif
+}