diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | accel.c | 18 | ||||
-rw-r--r-- | common.c | 4 | ||||
-rw-r--r-- | common.h | 22 | ||||
-rw-r--r-- | gyro.c | 18 | ||||
-rw-r--r-- | i2c.c | 3 | ||||
-rw-r--r-- | pwm.c | 5 | ||||
-rw-r--r-- | timer.c | 6 | ||||
-rw-r--r-- | ui.c | 13 |
9 files changed, 67 insertions, 24 deletions
@@ -3,7 +3,7 @@ CFLAGS=-Os -Wall -Wextra all: sanduhr.hex -sanduhr.elf: main.c i2c.c i2c.h uart.c uart.h timer.c timer.h gyro.c gyro.h accel.c accel.h common.h pwm.c pwm.h ui.c ui.h +sanduhr.elf: main.c i2c.c i2c.h uart.c uart.h timer.c common.c timer.h gyro.c gyro.h accel.c accel.h common.h pwm.c pwm.h ui.c ui.h avr-gcc -std=gnu99 -mmcu=$(MCU) $(CFLAGS) -o $@ $^ sanduhr.hex: sanduhr.elf @@ -51,7 +51,13 @@ static bool reading = false; /* data ready interrupt */ ISR(PCINT1_vect) { - /* empty */ + const bool interrupt = (PINC >> PINC1) & 0x1; + /* low-active */ + if (!interrupt) { + enableWakeup (WAKE_ACCEL); + } else { + disableWakeup (WAKE_ACCEL); + } } void accelInit () { @@ -79,6 +85,7 @@ void accelStart () { } sleepwhile (twr.status == TWST_WAIT); puts ("accelStart done"); + disableWakeup (WAKE_I2C); } /* register shake gesture @@ -154,25 +161,26 @@ static void accelProcessHorizon () { } bool accelProcess () { - if (reading) { + if (reading && shouldWakeup (WAKE_I2C)) { + disableWakeup (WAKE_I2C); + reading = false; if (twr.status == TWST_OK) { accelProcessHorizon (); accelProcessShake (); /* new data transfered */ - reading = false; return true; } else if (twr.status == TWST_ERR) { puts ("accel i2c error: "); fwrite ((void *) &twr.error, sizeof (twr.error), 1, stdout); - reading = false; } } else { - if (!((PINC >> PINC1) & 0x1) && twr.status == TWST_OK) { + if (shouldWakeup (WAKE_ACCEL) && twr.status == TWST_OK) { /* new data available in device buffer and bus is free */ if (!twRequest (TWM_READ, LIS302DL, LIS302DL_OUTZ, (uint8_t *) &zval, sizeof (zval))) { puts ("cannot start read"); } else { + /* wakeup source is disabled by isr to prevent race condition */ reading = true; } } diff --git a/common.c b/common.c new file mode 100644 index 0000000..e3f3195 --- /dev/null +++ b/common.c @@ -0,0 +1,4 @@ +#include "common.h" + +volatile uint8_t wakeup = 0; + @@ -23,5 +23,27 @@ } \ } +#include <stdbool.h> + +/* global wakeup flag, incremented by functions that interact with the main + * loop (i.e. not pwm) */ +extern volatile uint8_t wakeup; + +/* wakeup sources */ +enum { + WAKE_ACCEL = 0, + WAKE_GYRO = 1, + WAKE_I2C = 2, + WAKE_TIMER = 3, +}; + +#define shouldWakeup(x) (wakeup & (1 << x)) +#define enableWakeup(x) wakeup |= 1 << x; +#include <util/atomic.h> +#define disableWakeup(x) \ + ATOMIC_BLOCK (ATOMIC_FORCEON) { \ + wakeup &= ~(1 << x); \ + } + #endif /* COMMON_H */ @@ -31,7 +31,13 @@ static bool reading = false; /* data ready interrupt */ ISR(PCINT0_vect) { - /* empty */ + const bool interrupt = (PINB >> PINB1) & 0x1; + /* high-active */ + if (interrupt) { + enableWakeup (WAKE_GYRO); + } else { + disableWakeup (WAKE_GYRO); + } } void gyroInit () { @@ -60,6 +66,7 @@ void gyroStart () { } sleepwhile (twr.status == TWST_WAIT); puts ("gyroStart done"); + disableWakeup (WAKE_I2C); } /* calculate ticks for z rotation @@ -84,7 +91,9 @@ static void gyroProcessTicks () { /* process gyro sensor data, returns true if new data is available */ bool gyroProcess () { - if (reading) { + if (reading && shouldWakeup (WAKE_I2C)) { + disableWakeup (WAKE_I2C); + reading = false; if (twr.status == TWST_OK) { /* new data transfered, process it */ /* poor man's noise filter */ @@ -92,19 +101,18 @@ bool gyroProcess () { zaccum += zval; } gyroProcessTicks (); - reading = false; return true; } else if (twr.status == TWST_ERR) { puts ("gyro i2c error"); - reading = false; } } else { - if (((PINB >> PINB1) & 0x1) && twr.status == TWST_OK) { + if (shouldWakeup (WAKE_GYRO) && twr.status == TWST_OK) { /* new data available in device buffer and bus is free */ if (!twRequest (TWM_READ, L3GD20, L3GD20_OUTZ, (uint8_t *) &zval, sizeof (zval))) { puts ("cannot start read"); } else { + /* wakeup source is disabled by isr to prevent race condition */ reading = true; } } @@ -255,5 +255,8 @@ ISR(TWI_vect) { assert (0 && "nope\n"); break; } + if (twr.status == TWST_ERR || twr.status == TWST_OK) { + enableWakeup (WAKE_I2C); + } } @@ -19,7 +19,6 @@ static const uint8_t offbits[2] = {(uint8_t) ~((1 << PB6) | (1 << PB7)), (uint8_t) ~((1 << PD2) | (1 << PD3) | (1 << PD4) | (1 << PD5) | (1 << PD6))}; ISR(TIMER0_COMPA_vect) { -#warning "speaker works now, led1 and 2 do not work" if (speakerCount > 0) { --speakerCount; /* stop speaker after beep */ @@ -36,6 +35,8 @@ ISR(TIMER0_COMPA_vect) { /* auto wrap-around */ count = (count+1) & (PWM_MAX_BRIGHTNESS-1); + + /* no wakeup */ } static uint8_t ledToArray (const uint8_t i) { @@ -105,7 +106,7 @@ void pwmSet (const uint8_t i, const uint8_t value) { } } -void speakerStart (const speakerMode mode) { +void speakerStart (const speakerMode mode __unused__) { /* 12.8ms */ speakerCount = 100; for (uint8_t i = 0; i < PWM_MAX_BRIGHTNESS; i += 2) { @@ -22,13 +22,17 @@ ISR(TIMER1_COMPA_vect) { time += OCR1A * US_PER_TICK; if (hits == maxhits-1) { OCR1A = lastcount; + } else if (hits >= maxhits) { + enableWakeup (WAKE_TIMER); } } /* Check if timer was hit, return time since last restart or 0 if not hit yet */ uint32_t timerHit () { - if (hits >= maxhits) { + if (shouldWakeup (WAKE_TIMER)) { + disableWakeup (WAKE_TIMER); + const uint32_t ret = time; /* reset timer, start again */ hits = 0; @@ -266,14 +266,6 @@ static void doInit () { } } -/* Sleep CPU - */ -static void cpuSleep () { - sleep_enable (); - sleep_cpu (); - sleep_disable (); -} - /* Main loop */ void uiLoop () { @@ -329,7 +321,7 @@ void uiLoop () { while (1) { processSensors (); - + horizon newh = accelGetHorizon (); if (newh != h) { horizonChanged = true; @@ -367,7 +359,8 @@ void uiLoop () { assert (0 && "invalid ui mode"); break; } - cpuSleep (); + + sleepwhile (wakeup == 0); #if 0 printf ("t=%i, h=%i, s=%i\n", gyroGetZTicks (), accelGetHorizon (), |