aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--synology-autopoweron/Makefile39
-rw-r--r--synology-autopoweron/main.c118
2 files changed, 157 insertions, 0 deletions
diff --git a/synology-autopoweron/Makefile b/synology-autopoweron/Makefile
new file mode 100644
index 0000000..2646d03
--- /dev/null
+++ b/synology-autopoweron/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/synology-autopoweron/main.c b/synology-autopoweron/main.c
new file mode 100644
index 0000000..698a887
--- /dev/null
+++ b/synology-autopoweron/main.c
@@ -0,0 +1,118 @@
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/power.h>
+
+/* Pinout used:
+ * -----
+ * !reset - MCU - Vcc
+ * NA - MCU - NA
+ * NA - MCU - NA
+ * GND - MCU - (PB0) powerbutton
+ * -----
+ */
+
+static const uint8_t SLEPT_TIMEOUT = 25; /* ~2.5s */
+
+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;
+
+ISR(TIMER0_COMPA_vect)
+{
+ ++sleep_time;
+}
+
+static uint8_t get_sleep_time(void)
+{
+ return sleep_time;
+}
+
+static void reset_sleep_time(void)
+{
+ sleep_time = 0;
+}
+
+static void button_pushed()
+{
+ PORTB &= ~(1 << PB3); /* make sure reset line is disabled */
+ PORTB |= (1 << PB4); /* activate plug modules set */
+}
+
+static void button_normal()
+{
+ /* 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();
+ /* activate module reset */
+ PORTB |= (1 << PB3);
+}
+
+int main()
+{
+ cli();
+ init_timer();
+ sei();
+
+ // Normally a loop is not required but if somehow the mcu woke up from its
+ // sleep state this ensure we can do the operation again.
+ for (;;) {
+ reset_sleep_time();
+
+ PORTB = 0; // outputs set to low and input not set to internal pull-up
+
+ // digital output, pull-down for a time then go to default PB0 = Hi-Z
+ DDRB |= (1 << PB0);
+ while (get_sleep_time() <= SLEPT_TIMEOUT);
+ DDRB &= ~(1 << PB0);
+
+ /* set low power mode */
+ power_all_disable(); // disable all peripherals
+ set_sleep_mode(<mode>); // sleep mode
+ sleep_enable(); // set register to enable sleep
+ sleep_bod_disable(); // disable bod to consume even less
+ //sei(); // normally set sei to ensure wakeup but I do
+ // not want to wake up appart from a power
+ // reset
+ sleep_cpu(); // put cpu to sleep = low power mode now
+ sleep_disable(); // clear register (if somehow mcu woke up)
+ }
+
+ return 0;
+}