In order to mitigate the problem with watchdog reset, possibly caused
by timer IRQ handling taking too long, we only increment the jiffies
value in the WDT IRQ handler, and then read this value in the main
loop, compare with the previous one, and if those two are different,
we run the timer-induced operations. We can (probably) detect the
timer overrun (the difference in jiffies being greater than 1), and log
it.
The individual timer-induced operations are run in their own atomic
blocks for now, in order to be safe. The finer-grained locking is
in the TODO list :-).
#include <avr/io.h>
#include <util/delay.h>
#include <avr/io.h>
#include <util/delay.h>
+#include <util/atomic.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <avr/power.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <avr/power.h>
+static unsigned char prev_jiffies_8;
+
static void hw_setup()
{
init_battery();
static void hw_setup()
{
init_battery();
hw_setup();
power_down(mcusr_save & _BV(WDRF));
hw_setup();
power_down(mcusr_save & _BV(WDRF));
+ prev_jiffies_8 = jiffies;
+
+static void inline do_timer()
+{
+ // For now, we run them all in their own atomic blocks
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ timer_check_buttons();
+ }
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ patterns_next_tick();
+ }
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ pwm_disable_if_not_needed();
+ }
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ timer_start_slow_adcs();
+ }
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ if ((jiffies & 0x7FF) == 0)
+ ambient_log_min_max();
+ }
+}
+
static void inline main_loop_iteration()
{
static void inline main_loop_iteration()
{
+ unsigned char jiffies_8; /*
+ * we use only lower 8-bits in order to
+ * avoid the need for locking of 16-bit
+ * accesses.
+ */
+
cli();
if (TIMER1_IS_ON()) {
set_sleep_mode(SLEEP_MODE_IDLE);
cli();
if (TIMER1_IS_ON()) {
set_sleep_mode(SLEEP_MODE_IDLE);
sei();
sleep_cpu();
sleep_disable();
sei();
sleep_cpu();
sleep_disable();
+
+ jiffies_8 = jiffies;
+
+ if (jiffies_8 != prev_jiffies_8) { // was timer IRQ
+ if (jiffies_8 - prev_jiffies_8 > 1) { // overrun
+ log_byte(0xee);
+ log_byte(jiffies_8 - prev_jiffies_8);
+ log_flush();
+ }
+
+ prev_jiffies_8 = jiffies_8;
+
+ do_timer();
+ }
- ++jiffies;
-
- timer_check_buttons();
- patterns_next_tick();
- pwm_disable_if_not_needed();
- timer_start_slow_adcs();
-
- if ((jiffies & 0x7FF) == 0)
- ambient_log_min_max();
-
WDTCR |= _BV(WDIE); // avoid WDT reset next time
WDTCR |= _BV(WDIE); // avoid WDT reset next time