~toykeeper/flashlight-firmware/fsm

« back to all changes in this revision

Viewing changes to ToyKeeper/spaghetti-monster/fsm-wdt.c

  • Committer: Selene ToyKeeper
  • Date: 2023-11-04 15:09:10 UTC
  • mfrom: (483.1.175 anduril2)
  • Revision ID: bzr@toykeeper.net-20231104150910-ddd3afw4nhfvof2l
merged anduril2 branch -> fsm, with *years* of changes
(this also means this code is now Anduril 2 instead of Anduril 1)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * fsm-wdt.c: WDT (Watch Dog Timer) functions for SpaghettiMonster.
3
 
 *
4
 
 * Copyright (C) 2017 Selene Scriven
5
 
 *
6
 
 * This program is free software: you can redistribute it and/or modify
7
 
 * it under the terms of the GNU General Public License as published by
8
 
 * the Free Software Foundation, either version 3 of the License, or
9
 
 * (at your option) any later version.
10
 
 *
11
 
 * This program is distributed in the hope that it will be useful,
12
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 * GNU General Public License for more details.
15
 
 *
16
 
 * You should have received a copy of the GNU General Public License
17
 
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 
 */
 
1
// fsm-wdt.c: WDT (Watch Dog Timer) functions for SpaghettiMonster.
 
2
// Copyright (C) 2017-2023 Selene ToyKeeper
 
3
// SPDX-License-Identifier: GPL-3.0-or-later
19
4
 
20
 
#ifndef FSM_WDT_C
21
 
#define FSM_WDT_C
 
5
#pragma once
22
6
 
23
7
#include <avr/interrupt.h>
24
8
#include <avr/wdt.h>
25
9
 
 
10
// *** Note for the AVRXMEGA3 (1-Series, eg 816 and 817), the WDT 
 
11
// is not used for time-based interrupts.  A new peripheral, the 
 
12
// Periodic Interrupt Timer ("PIT") is used for this purpose.
 
13
 
26
14
void WDT_on()
27
15
{
28
16
    #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85)
35
23
    #elif (ATTINY == 1634)
36
24
        wdt_reset();                    // Reset the WDT
37
25
        WDTCSR = (1<<WDIE);             // Enable interrupt every 16ms
 
26
    #elif defined(AVRXMEGA3)  // ATTINY816, 817, etc
 
27
        RTC.PITINTCTRL = RTC_PI_bm;   // enable the Periodic Interrupt
 
28
        while (RTC.PITSTATUS > 0) {}  // make sure the register is ready to be updated
 
29
        RTC.PITCTRLA = RTC_PERIOD_CYC512_gc | RTC_PITEN_bm; // Period = 16ms, enable the PI Timer
38
30
    #else
39
31
        #error Unrecognized MCU type
40
32
    #endif
53
45
    #elif (ATTINY == 1634)
54
46
        wdt_reset();                    // Reset the WDT
55
47
        WDTCSR = (1<<WDIE) | STANDBY_TICK_SPEED;
 
48
    #elif defined(AVRXMEGA3)  // ATTINY816, 817, etc
 
49
        RTC.PITINTCTRL = RTC_PI_bm;   // enable the Periodic Interrupt
 
50
        while (RTC.PITSTATUS > 0) {}  // make sure the register is ready to be updated
 
51
        RTC.PITCTRLA = (1<<6) | (STANDBY_TICK_SPEED<<3) | RTC_PITEN_bm; // Set period, enable the PI Timer
56
52
    #else
57
53
        #error Unrecognized MCU type
58
54
    #endif
75
71
        CCP = 0xD8;           // enable config changes
76
72
        WDTCSR = 0;           // disable and clear all WDT settings
77
73
        sei();
 
74
    #elif defined(AVRXMEGA3)  // ATTINY816, 817, etc
 
75
        while (RTC.PITSTATUS > 0) {}  // make sure the register is ready to be updated
 
76
        RTC.PITCTRLA = 0; // Disable the PI Timer
78
77
    #else
79
78
        #error Unrecognized MCU type
80
79
    #endif
81
80
}
82
81
 
83
82
// clock tick -- this runs every 16ms (62.5 fps)
 
83
#ifdef AVRXMEGA3  // ATTINY816, 817, etc
 
84
ISR(RTC_PIT_vect) {
 
85
    RTC.PITINTFLAGS = RTC_PI_bm; // clear the PIT interrupt flag 
 
86
#else
84
87
ISR(WDT_vect) {
 
88
#endif
85
89
    irq_wdt = 1;  // WDT event happened
86
90
}
87
91
 
118
122
        #ifndef USE_SLEEP_LVP
119
123
        return;  // no sleep LVP needed if nothing drains power while off
120
124
        #else
121
 
        // stop here, usually...  but proceed often enough for sleep LVP to work
122
 
        if (0 != (ticks_since_last & 0x3f)) return;
 
125
        // stop here, usually...  except during the first few seconds asleep, 
 
126
        // and once in a while afterward for sleep LVP
 
127
        if ((ticks_since_last > (8 * SLEEP_TICKS_PER_SECOND))
 
128
            && (0 != (ticks_since_last & 0x0f))) return;
123
129
 
124
130
        adc_trigger = 0;  // make sure a measurement will happen
 
131
        adc_active_now = 1;  // use ADC noise reduction sleep mode
125
132
        ADC_on();  // enable ADC voltage measurement functions temporarily
126
133
        #endif
127
134
    }
150
157
        // (first frame of a "hold" event)
151
158
        else {
152
159
            if (ticks_since_last >= HOLD_TIMEOUT) {
 
160
                ticks_since_last_event = 0;
153
161
                current_event |= B_HOLD;
154
162
                emit_current_event(0);
155
163
            }
160
168
    else if (current_event) {
161
169
        // "hold" event just ended
162
170
        // no timeout required when releasing a long-press
163
 
        // TODO? move this logic to PCINT() and simplify things here?
164
171
        if (current_event & B_HOLD) {
165
 
            //emit_current_event(0);  // should have been emitted by PCINT_inner()
 
172
            //emit_current_event(ticks_since_last);  // should have been emitted by PCINT_inner()
166
173
            empty_event_sequence();
167
174
        }
168
175
        // end and clear event after release timeout
188
195
    #endif
189
196
}
190
197
 
191
 
#endif