aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--atxswitch/Makefile35
-rw-r--r--atxswitch/main.c25
-rw-r--r--atxswitch/uart.h76
-rw-r--r--avr-blinkled-atmega328p/Makefile35
-rw-r--r--avr-blinkled-atmega328p/main.c17
-rw-r--r--boo-stanby-watcher/Makefile39
-rw-r--r--boo-stanby-watcher/main.c307
-rw-r--r--powerswitch2/Makefile39
-rw-r--r--powerswitch2/main.c39
-rw-r--r--readme6
-rw-r--r--serial/Makefile35
-rw-r--r--serial/main.c25
-rw-r--r--serial/uart.h76
-rw-r--r--softserial.c33
15 files changed, 791 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f46de5a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.pyc
+*.elf
+*.hex
+*.o
diff --git a/atxswitch/Makefile b/atxswitch/Makefile
new file mode 100644
index 0000000..db8a005
--- /dev/null
+++ b/atxswitch/Makefile
@@ -0,0 +1,35 @@
+# settings for arduino nano v3
+DEVICE = atmega328p
+CLOCK = 16000000
+PORT=/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A9SBZLHD-if00-port0
+#AVRDUDE=avrdude -V -F -p m328p -c arduino -b 115200 -P$(PORT)
+#AVRDUDE=avrdude -p $(DEVICE) -c arduino -b 115200 -P $(PORT)
+AVRDUDE=avrdude -p $(DEVICE) -c arduino -b 57600 -P $(PORT)
+
+DEFS = -DF_CPU=$(CLOCK)UL
+LIBS = -Wl,--relax,--gc-sections,--print-gc-sections,--entry=main
+LIBS = -Wl,--entry=main,--gc-sections,--rela
+CFLAGS = -Wall -Werror -pedantic -std=c99
+CFLAGS += -Os -funsigned-bitfields -fpack-struct -fshort-enums
+CFLAGS += -mmcu=$(DEVICE) $(DEFS)
+#LDFLAGS = $(LIBS)
+
+all: main.hex size
+
+main.hex: main.c
+ avr-gcc -o main.elf $? $(CFLAGS) $(LDFLAGS)
+ avr-objcopy -j .text -j .data -O ihex main.elf main.hex
+
+f: flash
+flash: all
+ $(AVRDUDE) -U flash:w:main.hex:i
+
+clean:
+ rm -f *.o *.elf *.hex
+
+size:
+ avr-size --mcu=$(DEVICE) -t -A main.elf
+ avr-size --mcu=$(DEVICE) -C main.elf
+ avr-nm --size-sort main.elf
+
+
diff --git a/atxswitch/main.c b/atxswitch/main.c
new file mode 100644
index 0000000..2e9ff5c
--- /dev/null
+++ b/atxswitch/main.c
@@ -0,0 +1,25 @@
+#include <avr/io.h>
+#include "uart.h"
+
+int main(void)
+{
+ /* serial */
+ uart_init();
+
+ /* D4 = output and high (=> atx down) */
+ PORTD |= 0x10;
+ DDRD |= 0x10;
+
+ for (;;)
+ {
+ switch(uart_getchar()) {
+ case '?': break; /* useful for auto documentation */
+ case '0': PORTD |= 0x10; break;
+ case '1': PORTD &= ~0x10; break;
+ case 'T': PORTD ^= 0x10; break;
+ }
+ uart_putchar((PORTD & 0x10) ? '0' : '1');
+ }
+
+ return 0;
+}
diff --git a/atxswitch/uart.h b/atxswitch/uart.h
new file mode 100644
index 0000000..22e0655
--- /dev/null
+++ b/atxswitch/uart.h
@@ -0,0 +1,76 @@
+/* #define F_CPU 16000000UL <= defined in Makefile */
+#define BAUD 9600
+
+/* This file is *highly* inspired from:
+ * http://www.appelsiini.net/2011/simple-usart-with-avr-libc
+ */
+
+#include <util/setbaud.h>
+
+#if 0
+static inline void uart_init()
+{
+ UCSRB |= (1 << RXEN) | (1 << TXEN);
+ UCSRC |= (1 << UCSZ0) | (1 << UCSZ1);
+#define BAUD 115200
+#include <util/setbaud.h>
+ UBRRH = UBRRH_VALUE;
+ UBRRL = UBRRL_VALUE;
+#if USE_2X
+ UCSRA |= (1 << U2X);
+#else
+ UCSRA &= ~(1 << U2X);
+#endif
+}
+#endif
+
+void uart_init(void)
+{
+ UBRR0H = UBRRH_VALUE;
+ UBRR0L = UBRRL_VALUE;
+
+#if USE_2X
+ UCSR0A |= _BV(U2X0);
+#else
+ UCSR0A &= ~(_BV(U2X0));
+#endif
+
+ UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
+ UCSR0B = _BV(RXEN0) | _BV(TXEN0); /* Enable RX and TX */
+}
+
+void uart_putchar(char c)
+{
+ UDR0 = c;
+ loop_until_bit_is_set(UCSR0A, TXC0); /* Wait until transmission ready. */
+}
+
+char uart_getchar(void)
+{
+ loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
+ return UDR0;
+}
+
+#if 0
+/* alternatives for stream uses */
+void uart_putchar(char c, FILE *stream)
+{
+ if (c == '\n') {
+ uart_putchar('\r', stream);
+ }
+ loop_until_bit_is_set(UCSR0A, UDRE0);
+ UDR0 = c;
+}
+
+char uart_getchar(FILE *stream)
+{
+ loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
+ return UDR0;
+}
+#endif
+
+#if 0
+FILE uart_output = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
+FILE uart_input = FDEV_SETUP_STREAM(NULL, uart_getchar, _FDEV_SETUP_READ);
+FILE uart_io FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
+#endif
diff --git a/avr-blinkled-atmega328p/Makefile b/avr-blinkled-atmega328p/Makefile
new file mode 100644
index 0000000..864e2ec
--- /dev/null
+++ b/avr-blinkled-atmega328p/Makefile
@@ -0,0 +1,35 @@
+# settings for arduino uno
+DEVICE = atmega328p
+CLOCK = 16000000
+
+# buspirate programmer
+PORT=/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A400XJSH-if00-port0
+AVRDUDE=avrdude -p $(DEVICE) -c buspirate -P $(PORT)
+
+DEFS = -DF_CPU=$(CLOCK)UL
+LIBS = -Wl,--relax,--gc-sections,--print-gc-sections,--entry=main
+LIBS = -Wl,--entry=main,--gc-sections,--rela
+CFLAGS = -Wall -Werror -pedantic -std=c99
+CFLAGS += -Os -funsigned-bitfields -fpack-struct -fshort-enums
+CFLAGS += -mmcu=$(DEVICE) $(DEFS)
+#LDFLAGS = $(LIBS)
+
+all: main.hex size
+
+main.hex: main.c
+ avr-gcc -o main.elf $? $(CFLAGS) $(LDFLAGS)
+ avr-objcopy -j .text -j .data -O ihex main.elf main.hex
+
+f: flash
+flash: all
+ $(AVRDUDE) -U flash:w:main.hex:i
+
+clean:
+ rm -f *.o *.elf *.hex
+
+size:
+ avr-size --mcu=$(DEVICE) -t -A main.elf
+ avr-size --mcu=$(DEVICE) -C main.elf
+ avr-nm --size-sort main.elf
+
+
diff --git a/avr-blinkled-atmega328p/main.c b/avr-blinkled-atmega328p/main.c
new file mode 100644
index 0000000..8d9e288
--- /dev/null
+++ b/avr-blinkled-atmega328p/main.c
@@ -0,0 +1,17 @@
+#include <avr/io.h>
+#include <util/delay.h>
+
+int main(void)
+{
+ /* PB4 output */
+ DDRD |= _BV(PB4);
+ PORTB &= ~_BV(PB4);
+
+ for (;;)
+ {
+ _delay_ms(1000);
+ PORTB ^= _BV(PB4);
+ }
+
+ return 0;
+}
diff --git a/boo-stanby-watcher/Makefile b/boo-stanby-watcher/Makefile
new file mode 100644
index 0000000..2646d03
--- /dev/null
+++ b/boo-stanby-watcher/Makefile
@@ -0,0 +1,39 @@
+DEVICE = attiny25
+CLOCK = 1000000
+FUSES = -U lfuse:w:0x62:m -U hfuse:w:0xdd:m
+
+PROGRAMMER = avrdude
+PROGRAMMER += -c buspirate
+PROGRAMMER += -P /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A400XJSH-if00-port0
+PROGRAMMER += -p $(DEVICE) -B 4
+
+DEFS = -DF_CPU=$(CLOCK)UL
+CFLAGS = -Wall -Werror -pedantic -std=c99
+CFLAGS += -O2 -funsigned-bitfields -fpack-struct -fshort-enums
+CFLAGS += -mmcu=$(DEVICE) $(DEFS)
+#LIBS = -Wl,--relax,--gc-sections,--print-gc-sections,--entry=main
+#LIBS = -Wl,--entry=main,--gc-sections,--rela
+#LDFLAGS = $(LIBS)
+
+all: main.hex size
+
+main.hex: main.c
+ avr-gcc -o main.elf $? $(CFLAGS) $(LDFLAGS)
+ avr-objcopy -j .text -j .data -O ihex main.elf main.hex
+
+f: flash
+flash: all
+ $(PROGRAMMER) -U flash:w:main.hex:i
+
+fuse:
+ $(PROGRAMMER) $(FUSES)
+
+clean:
+ rm -f *.o *.elf *.hex
+
+size:
+ avr-size --mcu=$(DEVICE) -t -A main.elf
+ avr-size --mcu=$(DEVICE) -C main.elf
+ avr-nm --size-sort main.elf
+
+
diff --git a/boo-stanby-watcher/main.c b/boo-stanby-watcher/main.c
new file mode 100644
index 0000000..5c24c1b
--- /dev/null
+++ b/boo-stanby-watcher/main.c
@@ -0,0 +1,307 @@
+#include <avr/io.h>
+#include <avr/interrupt.h>
+
+/* Pinout used:
+ * -----
+ * reset - MCU - Vcc2
+ * module reset (PB3) - MCU - (ADC1) Vcc1 mesurement
+ * module set (PB4) - MCU - not used
+ * GND - MCU - (PB0) Amp DC control
+ * -----
+ */
+
+// assume computer is shutting down if vcc1 is below this value
+static const uint8_t ADC_DOWN_VALUE = 217;
+
+/* times are in tenth of seconds since ISR is triggered every 0.1s~
+ * see init_timer */
+static const uint8_t SLEPT1_TIMEOUT = 10; /* 1s */
+static const uint8_t SLEPT2_TIMEOUT = 35; /* 3.5s */
+static const uint8_t CAPA_TIMEOUT = 10; /* 1s */
+
+static void init_adc()
+{
+ /* this function initialises the ADC
+
+ ADC Notes
+
+ Prescaler
+
+ ADC Prescaler needs to be set so that the ADC input frequency is
+ between 50 - 200kHz.
+
+ Example prescaler values for various frequencies
+
+ Clock Available prescaler values
+ ---------------------------------------
+ 1 MHz 8 (125kHz), 16 (62.5kHz)
+ 4 MHz 32 (125kHz), 64 (62.5kHz)
+ 8 MHz 64 (125kHz), 128 (62.5kHz)
+ 16 MHz 128 (125kHz)
+
+ set prescaler to 128 for mcu running at 8MHz
+ */
+
+ ADMUX =
+ (0 << REFS1) | // Sets ref. voltage to VCC, bit 1
+ (0 << REFS0) | // Sets ref. voltage to VCC, bit 0
+ (1 << ADLAR) | // left shift result
+ (0 << REFS2) | // Sets ref. voltage to VCC, bit 2
+ (0 << MUX3) | // use ADC1 for input, MUX bit 3
+ (0 << MUX2) | // use ADC1 for input, MUX bit 2
+ (0 << MUX1) | // use ADC1 for input, MUX bit 1
+ (1 << MUX0); // use ADC1 for input, MUX bit 0
+
+ ADCSRA =
+ (1 << ADEN) | // Enable ADC
+ (0 << ADSC) | // Do not start conversion
+ (0 << ADATE) | // Do not enable Auto Trigger
+ (0 << ADIF) | // Do not set Interrupt flag
+ (0 << ADIE) | // Do not set interrupt enable
+ (1 << ADPS2) | // set prescaler to 16, bit 2
+ (0 << ADPS1) | // set prescaler to 16, bit 1
+ (0 << ADPS0); // set prescaler to 16, bit 0
+}
+
+// Value is between Vcc 3.4V (255) and GND (0).
+static uint8_t read_adc()
+{
+ ADCSRA |= (1 << ADSC); // start ADC measurement
+ while (ADCSRA & (1 << ADSC)); // wait till conversion complete
+ return ADCH; // value is between 0 (=GND) and 255 (=Vcc)
+}
+
+static void init_timer()
+{
+ /* timer_resolution = 1 / (clock_speed / prescaler)
+ * timer_resolution = 1 / (10**6 / 1024)
+ *
+ * in ctc mode, target counts:
+ *
+ * timer_counts = (target_time / timer_resolution) - 1
+ * timer_counts = (0.1 / (1/(10**6/1024))) - 1
+ * timer_counts = 96.65625000000001 =~ 97
+ *
+ * Why did we add the extra +1 to our number of timer counts? In CTC mode,
+ * when the timer matches our desired count it will reset itself to zero.
+ * This takes one clock cycle to perform, so we need to factor that into
+ * our calculations.
+ *
+ * VG notes: more simply 0 to 97 = 98 values = 98 cycles.
+ *
+ * trigger_time = (97+1) * (1/(10**6 / 1024)) =~ 0.100352s
+ *
+ * WGM0[2:0] = 010 = CTC
+ */
+ TCCR0A =
+ (1 << WGM01) | // CTC
+ (0 << WGM00); // CTC
+ TCCR0B =
+ (0 << WGM02) | // CTC
+ (1 << CS02) | // CS0[2:0] = 101 => prescaler clk/1024
+ (0 << CS01) | // CS0[2:0] = 101 => prescaler clk/1024
+ (1 << CS00); // CS0[2:0] = 101 => prescaler clk/1024
+ OCR0A = 97;
+ TIMSK =
+ (1 << OCIE0A) | // enable CTC interrupt for compare match 0A
+ (0 << OCIE0B) | // disable CTC interrupt for compare match 0B
+ (0 << TOIE0); // disable interrupt for timer0 overflow
+
+}
+
+static volatile uint8_t sleep_time;
+static volatile uint8_t capa_time;
+
+ISR(TIMER0_COMPA_vect)
+{
+ ++sleep_time;
+ ++capa_time;
+}
+
+static uint8_t get_capa_time(void)
+{
+ return capa_time;
+}
+
+static uint8_t get_sleep_time(void)
+{
+ return sleep_time;
+}
+
+static void reset_capa_time(void)
+{
+ capa_time = 0;
+}
+
+static void reset_sleep_time(void)
+{
+ sleep_time = 0;
+}
+
+static void plug_set()
+{
+ PORTB &= ~(1 << PB3); /* make sure reset line is disabled */
+ PORTB |= (1 << PB4); /* activate plug modules set */
+}
+
+static void plug_unset()
+{
+ PORTB &= ~(1 << PB4); /* deactivate plug modules set */
+}
+
+static void amp_set()
+{
+ PORTB |= (1 << PB0);
+}
+
+static void amp_plug_reset()
+{
+ /* be sure set line is not active before doing a reset else both coil will
+ * be energized at the same time and thus the behaviour may be
+ * unpredictable. */
+ plug_unset();
+ /* deactivate amp dc control and activate module reset */
+ PORTB &= ~(1 << PB0);
+ PORTB |= (1 << PB3);
+}
+
+static void amp_plug_unreset()
+{
+ PORTB &= ~(1 << PB3);
+}
+
+static enum states {
+ ST_1_AMP_PLUG_OFF,
+ ST_2_PLUG_SET,
+ ST_3_PLUG_ON,
+ ST_4_IDLE, /* when plug and amp are on we are in idle state */
+ ST_5_AMP_PLUG_RESET,
+ /* ST_OFF never reached normally :P it only appears in the diagram */
+ ST_MAX
+} current_state = ST_1_AMP_PLUG_OFF;
+
+enum events {
+ EV_1_CAPA_LOADED,
+ EV_2_SLEPT1,
+ EV_3_SLEPT2,
+ EV_4_UNLOADING, /* no more current, capa temp power unloading */
+ EV_MAX
+};
+
+static void s0_e0(void); /* do nothing */
+static void s1_e1(void);
+static void s2_e2(void);
+static void s2_e4(void);
+static void s3_e3(void);
+static void s3_e4(void);
+static void s4_e4(void);
+static void s5_e2(void);
+
+static void (*const state_table [ST_MAX][EV_MAX])(void) = {
+ {s1_e1, s0_e0, s0_e0, s0_e0},
+ {s0_e0, s2_e2, s0_e0, s2_e4},
+ {s0_e0, s0_e0, s3_e3, s3_e4},
+ {s0_e0, s0_e0, s0_e0, s4_e4},
+ {s0_e0, s5_e2, s0_e0, s0_e0},
+};
+
+static void process_event(enum events new_event)
+{
+ state_table[current_state][new_event]();
+}
+
+static void s0_e0(void) {}
+
+static void s1_e1(void) /* amp&plug off: capa loaded */
+{
+ plug_set();
+ reset_sleep_time();
+ current_state = ST_2_PLUG_SET;
+}
+
+static void s2_e2(void) /* plug set: slept1 */
+{
+ plug_unset();
+ reset_sleep_time();
+ current_state = ST_3_PLUG_ON;
+}
+
+static void s2_e4(void) /* plug set: unloading */
+{
+ amp_plug_reset();
+ reset_sleep_time();
+ current_state = ST_5_AMP_PLUG_RESET;
+}
+
+static void s3_e3(void) /* plug on: slept2 */
+{
+ amp_set();
+ current_state = ST_4_IDLE;
+}
+
+static void s3_e4(void) /* plug on: unloading */
+{
+ amp_plug_reset();
+ reset_sleep_time();
+ current_state = ST_5_AMP_PLUG_RESET;
+}
+
+static void s4_e4(void) /* idle: unloading */
+{
+ amp_plug_reset();
+ reset_sleep_time();
+ current_state = ST_5_AMP_PLUG_RESET;
+}
+
+static void s5_e2(void) /* amp&plug reset: slept1 */
+{
+ amp_plug_unreset();
+ current_state = ST_1_AMP_PLUG_OFF;
+}
+
+int main()
+{
+ uint8_t adcval;
+
+ cli();
+
+ init_adc();
+ init_timer();
+
+ // digital output
+ DDRB |=
+ (1 << PB0) | // Amp DC control
+ (1 << PB3) | // module reset
+ (1 << PB4); // module set
+ PORTB = 0; // outputs set to low and input not set to internal pull-up
+
+ // first ADC conversion may be inaccurate
+ // atmel advises to discard the result
+ adcval = read_adc();
+
+ sei();
+
+ for (;;) { /* main loop */
+
+ adcval = read_adc();
+
+ if (get_capa_time() >= CAPA_TIMEOUT) {
+ process_event(EV_1_CAPA_LOADED);
+ }
+
+ if (get_sleep_time() >= SLEPT1_TIMEOUT) {
+ process_event(EV_2_SLEPT1);
+ }
+
+ if (get_sleep_time() >= SLEPT2_TIMEOUT) {
+ process_event(EV_3_SLEPT2);
+ }
+
+ if (adcval <= ADC_DOWN_VALUE) {
+ reset_capa_time();
+ process_event(EV_4_UNLOADING);
+ }
+ }
+
+ return 0;
+}
diff --git a/powerswitch2/Makefile b/powerswitch2/Makefile
new file mode 100644
index 0000000..104f084
--- /dev/null
+++ b/powerswitch2/Makefile
@@ -0,0 +1,39 @@
+DEVICE = attiny2313
+CLOCK = 8000000
+FUSES = -U lfuse:w:0xe4:m -U hfuse:w:0xd9:m
+
+PROGRAMMER =-c stk500v2
+PROGRAMMER +=-P /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A800dAli-if00-port0
+# in ms should be at least 4 times less than clock speed
+SPEED = 4 # for default 1Mhz clock
+#SPEED = 0.34 # for 12Mhz clock
+DEFS = -DF_CPU=$(CLOCK)UL
+LIBS = -Wl,--relax,--gc-sections,--print-gc-sections,--entry=main
+LIBS = -Wl,--entry=main,--gc-sections,--rela
+CFLAGS = -Wall -Werror -pedantic -std=c99
+CFLAGS += -Os -funsigned-bitfields -fpack-struct -fshort-enums
+CFLAGS += -mmcu=$(DEVICE) $(DEFS)
+#LDFLAGS = $(LIBS)
+
+all: main.hex size
+
+main.hex: main.c
+ avr-gcc -o main.elf $? $(CFLAGS) $(LDFLAGS)
+ avr-objcopy -j .text -j .data -O ihex main.elf main.hex
+
+f: flash
+flash: all
+ avrdude $(PROGRAMMER) -p $(DEVICE) -B $(SPEED) -U flash:w:main.hex:i
+
+fuse:
+ avrdude $(PROGRAMMER) -p $(DEVICE) -B $(SPEED) $(FUSES)
+
+clean:
+ rm -f *.o *.elf *.hex
+
+size:
+ avr-size --mcu=$(DEVICE) -t -A main.elf
+ avr-size --mcu=$(DEVICE) -C main.elf
+ avr-nm --size-sort main.elf
+
+
diff --git a/powerswitch2/main.c b/powerswitch2/main.c
new file mode 100644
index 0000000..63e5d5c
--- /dev/null
+++ b/powerswitch2/main.c
@@ -0,0 +1,39 @@
+#include <avr/io.h>
+#include <util/delay.h>
+
+static inline void uart_init();
+int main()
+{
+ /* serial */
+ uart_init();
+
+ /* data input */
+ PORTB &= ~0x0F;
+ DDRB |= 0x0F;
+
+ for (;;)
+ {
+ while ((UCSRA & (1 << RXC)) == 0);
+ PORTB ^= UDR & 0x0F;
+
+ while ((UCSRA & (1 << UDRE)) == 0);
+ UDR = PORTB & 0x0F;
+ }
+
+ return 0;
+}
+
+static inline void uart_init()
+{
+ UCSRB |= (1 << RXEN) | (1 << TXEN);
+ UCSRC |= (1 << UCSZ0) | (1 << UCSZ1);
+#define BAUD 38400
+#include <util/setbaud.h>
+ UBRRH = UBRRH_VALUE;
+ UBRRL = UBRRL_VALUE;
+#if USE_2X
+ UCSRA |= (1 << U2X);
+#else
+ UCSRA &= ~(1 << U2X);
+#endif
+}
diff --git a/readme b/readme
new file mode 100644
index 0000000..5551cd5
--- /dev/null
+++ b/readme
@@ -0,0 +1,6 @@
+This is a repository containing some basic avr examples.
+
+Can be useful for quick debuging, or to validate a component or module works.
+
+Sometimes I put working avr code for modules I develop, not big enough to have
+its own repository.
diff --git a/serial/Makefile b/serial/Makefile
new file mode 100644
index 0000000..98f1efc
--- /dev/null
+++ b/serial/Makefile
@@ -0,0 +1,35 @@
+# settings for arduino
+DEVICE = atmega328p
+CLOCK = 16000000
+PORT=/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A400XJSH-if00-port0
+#AVRDUDE=avrdude -V -F -p m328p -c arduino -b 115200 -P$(PORT)
+#AVRDUDE=avrdude -p $(DEVICE) -c arduino -b 115200 -P $(PORT)
+AVRDUDE=avrdude -p $(DEVICE) -c arduino -b 57600 -P $(PORT)
+
+DEFS = -DF_CPU=$(CLOCK)UL
+LIBS = -Wl,--relax,--gc-sections,--print-gc-sections,--entry=main
+LIBS = -Wl,--entry=main,--gc-sections,--rela
+CFLAGS = -Wall -Werror -pedantic -std=c99
+CFLAGS += -Os -funsigned-bitfields -fpack-struct -fshort-enums
+CFLAGS += -mmcu=$(DEVICE) $(DEFS)
+#LDFLAGS = $(LIBS)
+
+all: main.hex size
+
+main.hex: main.c
+ avr-gcc -o main.elf $? $(CFLAGS) $(LDFLAGS)
+ avr-objcopy -j .text -j .data -O ihex main.elf main.hex
+
+f: flash
+flash: all
+ $(AVRDUDE) -U flash:w:main.hex:i
+
+clean:
+ rm -f *.o *.elf *.hex
+
+size:
+ avr-size --mcu=$(DEVICE) -t -A main.elf
+ avr-size --mcu=$(DEVICE) -C main.elf
+ avr-nm --size-sort main.elf
+
+
diff --git a/serial/main.c b/serial/main.c
new file mode 100644
index 0000000..2e9ff5c
--- /dev/null
+++ b/serial/main.c
@@ -0,0 +1,25 @@
+#include <avr/io.h>
+#include "uart.h"
+
+int main(void)
+{
+ /* serial */
+ uart_init();
+
+ /* D4 = output and high (=> atx down) */
+ PORTD |= 0x10;
+ DDRD |= 0x10;
+
+ for (;;)
+ {
+ switch(uart_getchar()) {
+ case '?': break; /* useful for auto documentation */
+ case '0': PORTD |= 0x10; break;
+ case '1': PORTD &= ~0x10; break;
+ case 'T': PORTD ^= 0x10; break;
+ }
+ uart_putchar((PORTD & 0x10) ? '0' : '1');
+ }
+
+ return 0;
+}
diff --git a/serial/uart.h b/serial/uart.h
new file mode 100644
index 0000000..22e0655
--- /dev/null
+++ b/serial/uart.h
@@ -0,0 +1,76 @@
+/* #define F_CPU 16000000UL <= defined in Makefile */
+#define BAUD 9600
+
+/* This file is *highly* inspired from:
+ * http://www.appelsiini.net/2011/simple-usart-with-avr-libc
+ */
+
+#include <util/setbaud.h>
+
+#if 0
+static inline void uart_init()
+{
+ UCSRB |= (1 << RXEN) | (1 << TXEN);
+ UCSRC |= (1 << UCSZ0) | (1 << UCSZ1);
+#define BAUD 115200
+#include <util/setbaud.h>
+ UBRRH = UBRRH_VALUE;
+ UBRRL = UBRRL_VALUE;
+#if USE_2X
+ UCSRA |= (1 << U2X);
+#else
+ UCSRA &= ~(1 << U2X);
+#endif
+}
+#endif
+
+void uart_init(void)
+{
+ UBRR0H = UBRRH_VALUE;
+ UBRR0L = UBRRL_VALUE;
+
+#if USE_2X
+ UCSR0A |= _BV(U2X0);
+#else
+ UCSR0A &= ~(_BV(U2X0));
+#endif
+
+ UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
+ UCSR0B = _BV(RXEN0) | _BV(TXEN0); /* Enable RX and TX */
+}
+
+void uart_putchar(char c)
+{
+ UDR0 = c;
+ loop_until_bit_is_set(UCSR0A, TXC0); /* Wait until transmission ready. */
+}
+
+char uart_getchar(void)
+{
+ loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
+ return UDR0;
+}
+
+#if 0
+/* alternatives for stream uses */
+void uart_putchar(char c, FILE *stream)
+{
+ if (c == '\n') {
+ uart_putchar('\r', stream);
+ }
+ loop_until_bit_is_set(UCSR0A, UDRE0);
+ UDR0 = c;
+}
+
+char uart_getchar(FILE *stream)
+{
+ loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
+ return UDR0;
+}
+#endif
+
+#if 0
+FILE uart_output = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
+FILE uart_input = FDEV_SETUP_STREAM(NULL, uart_getchar, _FDEV_SETUP_READ);
+FILE uart_io FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
+#endif
diff --git a/softserial.c b/softserial.c
new file mode 100644
index 0000000..cbec672
--- /dev/null
+++ b/softserial.c
@@ -0,0 +1,33 @@
+
+#define baud 9600
+#define serial_bit_delay 1000000/baud
+#define SERIAL_LOW() PORTB &= ~_BV(PB4)
+#define SERIAL_HIGH() PORTB |= _BV(PB4)
+
+// write out a byte as software emulated Uart
+void serial_putchar(uint8_t byte)
+{
+ uint8_t mask;
+ SERIAL_LOW(); // signal start bit
+ _delay_us(serial_bit_delay);
+ for (mask = 0x01; mask; mask <<= 1) {
+ if (byte & mask) { // choose bit
+ SERIAL_HIGH(); // send 1
+ } else {
+ SERIAL_LOW(); // send 0
+ }
+ _delay_us(serial_bit_delay);
+ }
+ SERIAL_HIGH(); //signal end bit
+ _delay_us(serial_bit_delay);
+}
+
+void serial_puts(const char* str)
+{
+ while (*str) {
+ serial_putchar((uint8_t)*str);
+ ++str;
+ }
+ serial_putchar('\r');
+ serial_putchar('\n');
+}