From 6708da2661d693f855b6f56d69af1e2fb8502463 Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Tue, 23 Sep 2014 17:24:57 +0200 Subject: Add wakeup source mechanism Should reduce amount of cpu wakeups with expensive computations. --- Makefile | 2 +- accel.c | 18 +++++++++++++----- common.c | 4 ++++ common.h | 22 ++++++++++++++++++++++ gyro.c | 18 +++++++++++++----- i2c.c | 3 +++ pwm.c | 5 +++-- timer.c | 6 +++++- ui.c | 13 +++---------- 9 files changed, 67 insertions(+), 24 deletions(-) create mode 100644 common.c diff --git a/Makefile b/Makefile index 56998e1..6d1783d 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/accel.c b/accel.c index bd73043..ed2aa81 100644 --- a/accel.c +++ b/accel.c @@ -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; + diff --git a/common.h b/common.h index 5957da3..fb53d4d 100644 --- a/common.h +++ b/common.h @@ -23,5 +23,27 @@ } \ } +#include + +/* 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 +#define disableWakeup(x) \ + ATOMIC_BLOCK (ATOMIC_FORCEON) { \ + wakeup &= ~(1 << x); \ + } + #endif /* COMMON_H */ diff --git a/gyro.c b/gyro.c index f31385d..fdf2d1f 100644 --- a/gyro.c +++ b/gyro.c @@ -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; } } diff --git a/i2c.c b/i2c.c index 00dee14..a94b3a0 100644 --- a/i2c.c +++ b/i2c.c @@ -255,5 +255,8 @@ ISR(TWI_vect) { assert (0 && "nope\n"); break; } + if (twr.status == TWST_ERR || twr.status == TWST_OK) { + enableWakeup (WAKE_I2C); + } } diff --git a/pwm.c b/pwm.c index 568ed73..944720e 100644 --- a/pwm.c +++ b/pwm.c @@ -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) { diff --git a/timer.c b/timer.c index ce30b60..8de6157 100644 --- a/timer.c +++ b/timer.c @@ -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; diff --git a/ui.c b/ui.c index 7bd393d..9175133 100644 --- a/ui.c +++ b/ui.c @@ -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 (), -- cgit v1.2.3