aboutsummaryrefslogtreecommitdiff
path: root/fsm
diff options
context:
space:
mode:
Diffstat (limited to 'fsm')
-rw-r--r--fsm/adc.c299
-rw-r--r--fsm/adc.h29
-rw-r--r--fsm/main.c112
-rw-r--r--fsm/misc.c31
-rw-r--r--fsm/misc.h4
-rw-r--r--fsm/pcint.c54
-rw-r--r--fsm/pcint.h6
-rw-r--r--fsm/spaghetti-monster.h9
-rw-r--r--fsm/wdt.c78
-rw-r--r--fsm/wdt.h7
10 files changed, 135 insertions, 494 deletions
diff --git a/fsm/adc.c b/fsm/adc.c
index 31b250f..fbe84a1 100644
--- a/fsm/adc.c
+++ b/fsm/adc.c
@@ -15,139 +15,22 @@
#include <avr/sleep.h>
-static inline void set_admux_therm() {
- #if (ATTINY == 1634)
- ADMUX = ADMUX_THERM;
- #elif (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85)
- ADMUX = ADMUX_THERM | (1 << ADLAR);
- #elif (ATTINY == 841) // FIXME: not tested
- ADMUXA = ADMUXA_THERM;
- ADMUXB = ADMUXB_THERM;
- #elif defined(AVRXMEGA3) // ATTINY816, 817, etc
- ADC0.MUXPOS = ADC_MUXPOS_TEMPSENSE_gc; // read temperature
- ADC0.CTRLC = ADC_SAMPCAP_bm | ADC_PRESC_DIV64_gc | ADC_REFSEL_INTREF_gc; // Internal ADC reference
- #else
- #error Unrecognized MCU type
- #endif
+static inline void adc_therm_mode() {
+ hwdef_set_admux_therm();
adc_channel = 1;
adc_sample_count = 0; // first result is unstable
ADC_start_measurement();
}
-inline void set_admux_voltage() {
- #if (ATTINY == 1634)
- #ifdef USE_VOLTAGE_DIVIDER // 1.1V / pin7
- ADMUX = ADMUX_VOLTAGE_DIVIDER;
- #else // VCC / 1.1V reference
- ADMUX = ADMUX_VCC;
- #endif
- #elif (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85)
- #ifdef USE_VOLTAGE_DIVIDER // 1.1V / pin7
- ADMUX = ADMUX_VOLTAGE_DIVIDER | (1 << ADLAR);
- #else // VCC / 1.1V reference
- ADMUX = ADMUX_VCC | (1 << ADLAR);
- #endif
- #elif (ATTINY == 841) // FIXME: not tested
- #ifdef USE_VOLTAGE_DIVIDER // 1.1V / pin7
- ADMUXA = ADMUXA_VOLTAGE_DIVIDER;
- ADMUXB = ADMUXB_VOLTAGE_DIVIDER;
- #else // VCC / 1.1V reference
- ADMUXA = ADMUXA_VCC;
- ADMUXB = ADMUXB_VCC;
- #endif
- #elif defined(AVRXMEGA3) // ATTINY816, 817, etc
- #ifdef USE_VOLTAGE_DIVIDER // 1.1V / ADC input pin
- // verify that this is correct!!! untested
- ADC0.MUXPOS = ADMUX_VOLTAGE_DIVIDER; // read the requested ADC pin
- ADC0.CTRLC = ADC_SAMPCAP_bm | ADC_PRESC_DIV64_gc | ADC_REFSEL_INTREF_gc; // Use internal ADC reference
- #else // VCC / 1.1V reference
- ADC0.MUXPOS = ADC_MUXPOS_INTREF_gc; // read internal reference
- ADC0.CTRLC = ADC_SAMPCAP_bm | ADC_PRESC_DIV64_gc | ADC_REFSEL_VDDREF_gc; // Vdd (Vcc) be ADC reference
- #endif
- #else
- #error Unrecognized MCU type
- #endif
+void adc_voltage_mode() {
+ hwdef_set_admux_voltage();
adc_channel = 0;
adc_sample_count = 0; // first result is unstable
ADC_start_measurement();
}
-#ifdef TICK_DURING_STANDBY
-inline void adc_sleep_mode() {
- // needs a special sleep mode to get accurate measurements quickly
- // ... full power-down ends up using more power overall, and causes
- // some weird issues when the MCU doesn't stay awake enough cycles
- // to complete a reading
- #ifdef SLEEP_MODE_ADC
- // attiny1634
- set_sleep_mode(SLEEP_MODE_ADC);
- #elif defined(AVRXMEGA3) // ATTINY816, 817, etc
- set_sleep_mode(SLEEP_MODE_STANDBY);
- #else
- #error No ADC sleep mode defined for this hardware.
- #endif
-}
-#endif
-
-inline void ADC_start_measurement() {
- #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) || (ATTINY == 841) || (ATTINY == 1634)
- ADCSRA |= (1 << ADSC) | (1 << ADIE);
- #elif defined(AVRXMEGA3) // ATTINY816, 817, etc
- ADC0.INTCTRL |= ADC_RESRDY_bm; // enable interrupt
- ADC0.COMMAND |= ADC_STCONV_bm; // Start the ADC conversions
- #else
- #error unrecognized MCU type
- #endif
-}
-
-// set up ADC for reading battery voltage
-inline void ADC_on()
-{
- #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) || (ATTINY == 1634)
- set_admux_voltage();
- #ifdef USE_VOLTAGE_DIVIDER
- // disable digital input on divider pin to reduce power consumption
- VOLTAGE_ADC_DIDR |= (1 << VOLTAGE_ADC);
- #else
- // disable digital input on VCC pin to reduce power consumption
- //VOLTAGE_ADC_DIDR |= (1 << VOLTAGE_ADC); // FIXME: unsure how to handle for VCC pin
- #endif
- #if (ATTINY == 1634)
- //ACSRA |= (1 << ACD); // turn off analog comparator to save power
- ADCSRB |= (1 << ADLAR); // left-adjust flag is here instead of ADMUX
- #endif
- // enable, start, auto-retrigger, prescale
- ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | ADC_PRSCL;
- // end tiny25/45/85
- #elif (ATTINY == 841) // FIXME: not tested, missing left-adjust
- ADCSRB = 0; // Right adjusted, auto trigger bits cleared.
- //ADCSRA = (1 << ADEN ) | 0b011; // ADC on, prescaler division factor 8.
- set_admux_voltage();
- // enable, start, auto-retrigger, prescale
- ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | ADC_PRSCL;
- //ADCSRA |= (1 << ADSC); // start measuring
- #elif defined(AVRXMEGA3) // ATTINY816, 817, etc
- VREF.CTRLA |= VREF_ADC0REFSEL_1V1_gc; // Set Vbg ref to 1.1V
- // Enabled, free-running (aka, auto-retrigger), run in standby
- ADC0.CTRLA = ADC_ENABLE_bm | ADC_FREERUN_bm | ADC_RUNSTBY_bm;
- // set a INITDLY value because the AVR manual says so (section 30.3.5)
- // (delay 1st reading until Vref is stable)
- ADC0.CTRLD |= ADC_INITDLY_DLY16_gc;
- set_admux_voltage();
- #else
- #error Unrecognized MCU type
- #endif
-}
-
-inline void ADC_off() {
- #ifdef AVRXMEGA3 // ATTINY816, 817, etc
- ADC0.CTRLA &= ~(ADC_ENABLE_bm); // disable the ADC
- #else
- ADCSRA &= ~(1<<ADEN); //ADC off
- #endif
-}
-
+#if 0
#ifdef USE_VOLTAGE_DIVIDER
static inline uint8_t calc_voltage_divider(uint16_t value) {
// use 9.7 fixed-point to get sufficient precision
@@ -162,6 +45,7 @@ static inline uint8_t calc_voltage_divider(uint16_t value) {
return result;
}
#endif
+#endif
// Each full cycle runs ~2X per second with just voltage enabled,
// or ~1X per second with voltage and temperature.
@@ -171,15 +55,11 @@ static inline uint8_t calc_voltage_divider(uint16_t value) {
#define ADC_CYCLES_PER_SECOND 2
#endif
-#ifdef AVRXMEGA3 // ATTINY816, 817, etc
-#define ADC_vect ADC0_RESRDY_vect
-#endif
// happens every time the ADC sampler finishes a measurement
ISR(ADC_vect) {
- #ifdef AVRXMEGA3 // ATTINY816, 817, etc
- ADC0.INTFLAGS = ADC_RESRDY_bm; // clear the interrupt
- #endif
+ // clear the interrupt flag
+ mcu_adc_vect_clear();
if (adc_sample_count) {
@@ -188,22 +68,11 @@ ISR(ADC_vect) {
uint8_t channel = adc_channel;
// update the latest value
- #ifdef AVRXMEGA3 // ATTINY816, 817, etc
- // Use the factory calibrated values in SIGROW.TEMPSENSE0 and SIGROW.TEMPSENSE1
- // to calculate a temperature reading in Kelvin, then left-align it.
- if (channel == 1) { // thermal, convert ADC reading to left-aligned Kelvin
- int8_t sigrow_offset = SIGROW.TEMPSENSE1; // Read signed value from signature row
- uint8_t sigrow_gain = SIGROW.TEMPSENSE0; // Read unsigned value from signature row
- uint32_t temp = ADC0.RES - sigrow_offset;
- temp *= sigrow_gain; // Result might overflow 16 bit variable (10bit+8bit)
- temp += 0x80; // Add 1/2 to get correct rounding on division below
- temp >>= 8; // Divide result to get Kelvin
- m = (temp << 6); // left align it
- }
- else { m = (ADC0.RES << 6); } // voltage, force left-alignment
-
+ #ifdef MCU_ADC_RESULT_PER_TYPE
+ if (channel) m = mcu_adc_result_temp();
+ else m = mcu_adc_result_volts();
#else
- m = ADC;
+ m = mcu_adc_result();
#endif
adc_raw[channel] = m;
@@ -235,11 +104,7 @@ void adc_deferred() {
// real-world entropy makes this a true random, not pseudo
// Why here instead of the ISR? Because it makes the time-critical ISR
// code a few cycles faster and we don't need crypto-grade randomness.
- #ifdef AVRXMEGA3 // ATTINY816, 817, etc
- pseudo_rand_seed += ADC0.RESL; // right aligned, not left... so should be equivalent?
- #else
- pseudo_rand_seed += (ADCL >> 6) + (ADCH << 2);
- #endif
+ pseudo_rand_seed += mcu_adc_lsb();
#endif
// the ADC triggers repeatedly when it's on, but we only need to run the
@@ -281,7 +146,7 @@ void adc_deferred() {
ADC_voltage_handler();
#ifdef USE_THERMAL_REGULATION
// set the correct type of measurement for next time
- if (! go_to_standby) set_admux_therm();
+ if (! go_to_standby) adc_therm_mode();
#endif
}
#endif
@@ -291,7 +156,7 @@ void adc_deferred() {
ADC_temperature_handler();
#ifdef USE_LVP
// set the correct type of measurement for next time
- set_admux_voltage();
+ adc_voltage_mode();
#endif
}
#endif
@@ -301,7 +166,7 @@ void adc_deferred() {
#ifdef USE_LVP
-static inline void ADC_voltage_handler() {
+static void ADC_voltage_handler() {
// rate-limit low-voltage warnings to a max of 1 per N seconds
static uint8_t lvp_timer = 0;
#define LVP_TIMER_START (VOLTAGE_WARNING_SECONDS*ADC_CYCLES_PER_SECOND) // N seconds between LVP warnings
@@ -344,38 +209,23 @@ static inline void ADC_voltage_handler() {
#endif
else measurement = adc_smooth[0];
- // values stair-step between intervals of 64, with random variations
- // of 1 or 2 in either direction, so if we chop off the last 6 bits
- // it'll flap between N and N-1... but if we add half an interval,
- // the values should be really stable after right-alignment
- // (instead of 99.98, 100.00, and 100.02, it'll hit values like
- // 100.48, 100.50, and 100.52... which are stable when truncated)
- //measurement += 32;
- //measurement = (measurement + 16) >> 5;
- measurement = (measurement + 16) & 0xffe0; // 1111 1111 1110 0000
-
- #ifdef USE_VOLTAGE_DIVIDER
- voltage = calc_voltage_divider(measurement);
- #else
- // calculate actual voltage: volts * 10
- // ADC = 1.1 * 1024 / volts
- // volts = 1.1 * 1024 / ADC
- voltage = ((uint16_t)(2*1.1*1024*10)/(measurement>>6)
- + VOLTAGE_FUDGE_FACTOR
- #ifdef USE_VOLTAGE_CORRECTION
- + VOLT_CORR - 7
- #endif
- ) >> 1;
- #endif
+ // convert raw ADC value to FSM voltage units: Volts * 40
+ // 0 .. 200 = 0.0V .. 5.0V
+ voltage = voltage_raw2cooked(measurement)
+ + (VOLTAGE_FUDGE_FACTOR << 1)
+ #ifdef USE_VOLTAGE_CORRECTION
+ + ((VOLT_CORR - 7) << 1)
+ #endif
+ ;
// if low, callback EV_voltage_low / EV_voltage_critical
// (but only if it has been more than N seconds since last call)
if (lvp_timer) {
lvp_timer --;
} else { // it has been long enough since the last warning
- #ifdef DUAL_VOLTAGE_FLOOR
- if (((voltage < VOLTAGE_LOW) && (voltage > DUAL_VOLTAGE_FLOOR)) || (voltage < DUAL_VOLTAGE_LOW_LOW)) {
- #else
+ #ifdef DUAL_VOLTAGE_FLOOR
+ if (((voltage < VOLTAGE_LOW) && (voltage > DUAL_VOLTAGE_FLOOR)) || (voltage < DUAL_VOLTAGE_LOW_LOW)) {
+ #else
if (voltage < VOLTAGE_LOW) {
#endif
// send out a warning
@@ -390,7 +240,7 @@ static inline void ADC_voltage_handler() {
#ifdef USE_THERMAL_REGULATION
// generally happens once per second while awake
-static inline void ADC_temperature_handler() {
+static void ADC_temperature_handler() {
// coarse adjustment
#ifndef THERM_LOOKAHEAD
#define THERM_LOOKAHEAD 4
@@ -415,19 +265,24 @@ static inline void ADC_temperature_handler() {
static uint16_t temperature_history[NUM_TEMP_HISTORY_STEPS];
static int8_t warning_threshold = 0;
- if (adc_reset) { // wipe out old data
- // ignore average, use latest sample
- uint16_t foo = adc_raw[1];
- adc_smooth[1] = foo;
-
- // forget any past measurements
- for(uint8_t i=0; i<NUM_TEMP_HISTORY_STEPS; i++)
- temperature_history[i] = (foo + 16) >> 5;
- }
+ if (adc_reset) adc_smooth[1] = adc_raw[1];
// latest 16-bit ADC reading
- uint16_t measurement = adc_smooth[1];
+ // convert raw ADC value to Kelvin << 6
+ // 0 .. 65535 = 0 K .. 1024 K
+ uint16_t measurement = temp_raw2cooked(adc_smooth[1]);
+ // let the UI see the current temperature in C
+ // (Kelvin << 6) to Celsius
+ // Why 275? Because Atmel's docs use 275 instead of 273.
+ temperature = (measurement>>6) + THERM_CAL_OFFSET + (int16_t)TH_CAL - 275;
+
+ // instead of (K << 6), use (K << 1) now
+ // TODO: use more precision, if it can be done without overflow in 16 bits
+ // (and still work on attiny85 without increasing ROM size)
+ #if 1
+ measurement = measurement >> 5;
+ #else // TODO: is this still needed?
// values stair-step between intervals of 64, with random variations
// of 1 or 2 in either direction, so if we chop off the last 6 bits
// it'll flap between N and N-1... but if we add half an interval,
@@ -437,17 +292,14 @@ static inline void ADC_temperature_handler() {
//measurement += 32;
measurement = (measurement + 16) >> 5;
//measurement = (measurement + 16) & 0xffe0; // 1111 1111 1110 0000
-
- // let the UI see the current temperature in C
- // Convert ADC units to Celsius (ish)
- #ifndef USE_EXTERNAL_TEMP_SENSOR
- // onboard sensor for attiny25/45/85/1634
- temperature = (measurement>>1) + THERM_CAL_OFFSET + (int16_t)TH_CAL - 275;
- #else
- // external sensor
- temperature = EXTERN_TEMP_FORMULA(measurement>>1) + THERM_CAL_OFFSET + (int16_t)TH_CAL;
#endif
+ if (adc_reset) { // wipe out old data after waking up
+ // forget any past measurements
+ for(uint8_t i=0; i<NUM_TEMP_HISTORY_STEPS; i++)
+ temperature_history[i] = measurement;
+ }
+
// how much has the temperature changed between now and a few seconds ago?
int16_t diff;
diff = measurement - temperature_history[history_step];
@@ -540,33 +392,58 @@ static inline void ADC_temperature_handler() {
#ifdef USE_BATTCHECK
#ifdef BATTCHECK_4bars
PROGMEM const uint8_t voltage_blinks[] = {
- 30, 35, 38, 40, 42, 99,
+ 4*30,
+ 4*35,
+ 4*38,
+ 4*40,
+ 4*42,
+ 255,
};
#endif
#ifdef BATTCHECK_6bars
PROGMEM const uint8_t voltage_blinks[] = {
- 30, 34, 36, 38, 40, 41, 43, 99,
+ 4*30,
+ 4*34,
+ 4*36,
+ 4*38,
+ 4*40,
+ 4*41,
+ 4*43,
+ 255,
};
#endif
#ifdef BATTCHECK_8bars
PROGMEM const uint8_t voltage_blinks[] = {
- 30, 33, 35, 37, 38, 39, 40, 41, 42, 99,
+ 4*30,
+ 4*33,
+ 4*35,
+ 4*37,
+ 4*38,
+ 4*39,
+ 4*40,
+ 4*41,
+ 4*42,
+ 255,
};
#endif
void battcheck() {
#ifdef BATTCHECK_VpT
- blink_num(voltage);
- #else
- uint8_t i;
- for(i=0;
- voltage >= pgm_read_byte(voltage_blinks + i);
- i++) {}
- #ifdef DONT_DELAY_AFTER_BATTCHECK
- blink_digit(i);
+ blink_num(voltage / 4);
+ #ifdef USE_EXTRA_BATTCHECK_DIGIT
+ // 0 1 2 3 --> 0 2 5 7, representing x.x00 x.x25 x.x50 x.x75
+ blink_num(((voltage % 4)<<1) + ((voltage % 4)>>1));
+ #endif
#else
- if (blink_digit(i))
- nice_delay_ms(1000);
- #endif
+ uint8_t i;
+ for(i=0;
+ voltage >= pgm_read_byte(voltage_blinks + i);
+ i++) {}
+ #ifdef DONT_DELAY_AFTER_BATTCHECK
+ blink_digit(i);
+ #else
+ if (blink_digit(i))
+ nice_delay_ms(1000);
+ #endif
#endif
}
#endif
diff --git a/fsm/adc.h b/fsm/adc.h
index 1bb67ed..02e33f8 100644
--- a/fsm/adc.h
+++ b/fsm/adc.h
@@ -17,11 +17,11 @@ volatile uint8_t adc_reset = 2;
#endif
// low-battery threshold in volts * 10
#ifndef VOLTAGE_LOW
-#define VOLTAGE_LOW 29
+#define VOLTAGE_LOW (4*29)
#endif
// battery is low but not critical
#ifndef VOLTAGE_RED
-#define VOLTAGE_RED 33
+#define VOLTAGE_RED (4*33)
#endif
// MCU sees voltage 0.X volts lower than actual, add X/2 to readings
#ifndef VOLTAGE_FUDGE_FACTOR
@@ -32,6 +32,9 @@ volatile uint8_t adc_reset = 2;
#endif
#endif
+
+void adc_voltage_mode();
+
#ifdef TICK_DURING_STANDBY
volatile uint8_t adc_active_now = 0; // sleep LVP needs a different sleep mode
#endif
@@ -46,7 +49,7 @@ uint16_t adc_smooth[2]; // lowpassed ADC measurements (0=voltage, 1=temperature
uint8_t adc_deferred_enable = 0; // stop waiting and run the deferred code
void adc_deferred(); // do the actual ADC-related calculations
-static inline void ADC_voltage_handler();
+static void ADC_voltage_handler();
uint8_t voltage = 0;
#ifdef USE_VOLTAGE_CORRECTION
#ifdef USE_CFG
@@ -98,15 +101,21 @@ int16_t temperature;
uint8_t therm_ceil = DEFAULT_THERM_CEIL;
int8_t therm_cal_offset = 0;
#endif
-static inline void ADC_temperature_handler();
+static void ADC_temperature_handler();
#endif // ifdef USE_THERMAL_REGULATION
-inline void ADC_on();
-inline void ADC_off();
-inline void ADC_start_measurement();
+//inline void ADC_on();
+#define ADC_on adc_voltage_mode
+//inline void ADC_off();
+#define ADC_off mcu_adc_off
+//inline void ADC_start_measurement();
+#define ADC_start_measurement mcu_adc_start_measurement
-#ifdef TICK_DURING_STANDBY
-inline void adc_sleep_mode();
-#endif
+// needs a special sleep mode to get accurate measurements quickly
+// ... full power-down ends up using more power overall, and causes
+// some weird issues when the MCU doesn't stay awake enough cycles
+// to complete a reading
+//inline void adc_sleep_mode();
+#define adc_sleep_mode mcu_adc_sleep_mode
diff --git a/fsm/main.c b/fsm/main.c
index 0524115..bb93862 100644
--- a/fsm/main.c
+++ b/fsm/main.c
@@ -6,108 +6,16 @@
#include "fsm/main.h"
-#if PWM_CHANNELS == 4
-#ifdef AVRXMEGA3 // ATTINY816, 817, etc
-#error 4-channel PWM not currently set up for the AVR 1-Series
-#endif
-// 4th PWM channel requires manually turning the pin on/off via interrupt :(
-ISR(TIMER1_OVF_vect) {
- //bitClear(PORTB, 3);
- PORTB &= 0b11110111;
- //PORTB |= 0b00001000;
-}
-ISR(TIMER1_COMPA_vect) {
- //if (!bitRead(TIFR,TOV1)) bitSet(PORTB, 3);
- if (! (TIFR & (1<<TOV1))) PORTB |= 0b00001000;
- //if (! (TIFR & (1<<TOV1))) PORTB &= 0b11110111;
-}
-#endif
-
-// FIXME: hw_setup() shouldn't be here ... move it entirely to hwdef files
-#if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85)
-static inline void hw_setup() {
- #if !defined(USE_GENERIC_HWDEF_SETUP)
- hwdef_setup();
- #else
- // configure PWM channels
- #if PWM_CHANNELS >= 1
- DDRB |= (1 << PWM1_PIN);
- TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
- TCCR0A = PHASE;
- #if (PWM1_PIN == PB4) // Second PWM counter is ... weird
- TCCR1 = _BV (CS10);
- GTCCR = _BV (COM1B1) | _BV (PWM1B);
- OCR1C = 255; // Set ceiling value to maximum
- #endif
- #endif
- // tint ramping needs second channel enabled,
- // despite PWM_CHANNELS being only 1
- #if (PWM_CHANNELS >= 2) || defined(USE_TINT_RAMPING)
- DDRB |= (1 << PWM2_PIN);
- #if (PWM2_PIN == PB4) // Second PWM counter is ... weird
- TCCR1 = _BV (CS10);
- GTCCR = _BV (COM1B1) | _BV (PWM1B);
- OCR1C = 255; // Set ceiling value to maximum
- #endif
- #endif
- #if PWM_CHANNELS >= 3
- DDRB |= (1 << PWM3_PIN);
- #if (PWM3_PIN == PB4) // Second PWM counter is ... weird
- TCCR1 = _BV (CS10);
- GTCCR = _BV (COM1B1) | _BV (PWM1B);
- OCR1C = 255; // Set ceiling value to maximum
- #endif
- #endif
- #if PWM_CHANNELS >= 4
- // 4th PWM channel is ... not actually supported in hardware :(
- DDRB |= (1 << PWM4_PIN);
- //OCR1C = 255; // Set ceiling value to maximum
- TCCR1 = 1<<CTC1 | 1<<PWM1A | 3<<COM1A0 | 2<<CS10;
- GTCCR = (2<<COM1B0) | (1<<PWM1B);
- // set up an interrupt to control PWM4 pin
- TIMSK |= (1<<OCIE1A) | (1<<TOIE1);
- #endif
-
- // configure e-switch
- PORTB = (1 << SWITCH_PIN); // e-switch is the only input
- PCMSK = (1 << SWITCH_PIN); // pin change interrupt uses this pin
- #endif // ifdef USE_GENERIC_HWDEF_SETUP
-}
-#elif (ATTINY == 1634) || defined(AVRXMEGA3) // ATTINY816, 817, etc
-static inline void hw_setup() {
- // this gets tricky with so many pins...
- // ... so punt it to the hwdef file
- hwdef_setup();
-}
-#else
- #error Unrecognized MCU type
-#endif
-
-
-//#ifdef USE_REBOOT
-static inline void prevent_reboot_loop() {
- // prevent WDT from rebooting MCU again
- #ifdef AVRXMEGA3 // ATTINY816, 817, etc
- RSTCTRL.RSTFR &= ~(RSTCTRL_WDRF_bm); // reset status flag
- #else
- MCUSR &= ~(1<<WDRF); // reset status flag
- #endif
- wdt_disable();
-}
-//#endif
-
int main() {
// Don't allow interrupts while booting
cli();
- //#ifdef USE_REBOOT
// prevents cycling after a crash,
// whether intentional (like factory reset) or not (bugs)
prevent_reboot_loop();
- //#endif
- hw_setup();
+ hwdef_setup();
#if 0
#ifdef HALFSPEED
@@ -124,6 +32,9 @@ int main() {
// all booted -- turn interrupts back on
PCINT_on();
+ // FIXME: support both WDT *and* RTC PIT on newer devices
+ // (WDT to recover from crashes, PIT for task scheduling)
+ // (old AVR had only WDT, newer ones split it into WDT, RTC, and PIT)
WDT_on();
ADC_on();
sei();
@@ -160,22 +71,7 @@ int main() {
// enter standby mode if requested
// (works better if deferred like this)
if (go_to_standby) {
- #ifdef USE_RAMPING
set_level(0);
- #else
- #if PWM_CHANNELS >= 1
- PWM1_LVL = 0;
- #endif
- #if PWM_CHANNELS >= 2
- PWM2_LVL = 0;
- #endif
- #if PWM_CHANNELS >= 3
- PWM3_LVL = 0;
- #endif
- #if PWM_CHANNELS >= 4
- PWM4_LVL = 255; // inverted :(
- #endif
- #endif
standby_mode();
}
diff --git a/fsm/misc.c b/fsm/misc.c
index bc10ea1..fa8ddd7 100644
--- a/fsm/misc.c
+++ b/fsm/misc.c
@@ -118,7 +118,8 @@ uint8_t blink_num(uint8_t num) {
#ifdef USE_INDICATOR_LED
void indicator_led(uint8_t lvl) {
switch (lvl) {
- #ifdef AVRXMEGA3 // ATTINY816, 817, etc
+ // FIXME: move this logic to arch/*
+ #if (MCU==0x1616) || (MCU==0x32dd20) // ATTINY816, 817, etc
case 0: // indicator off
AUXLED_PORT.DIRSET = (1 << AUXLED_PIN); // set as output
@@ -192,7 +193,8 @@ void indicator_led_auto() {
void button_led_set(uint8_t lvl) {
switch (lvl) {
- #ifdef AVRXMEGA3 // ATTINY816, 817, etc
+ // FIXME: move this logic to arch/*
+ #if (MCU==0x1616) || (MCU==0x32dd20) // ATTINY816, 817, etc
case 0: // LED off
BUTTON_LED_PORT.DIRSET = (1 << BUTTON_LED_PIN); // set as output
@@ -240,7 +242,8 @@ void rgb_led_set(uint8_t value) {
uint8_t pin = pins[i];
switch (lvl) {
- #ifdef AVRXMEGA3 // ATTINY816, 817, etc
+ // FIXME: move this logic to arch/*
+ #if (MCU==0x1616) || (MCU==0x32dd20) // ATTINY816, 817, etc
case 0: // LED off
AUXLED_RGB_PORT.DIRSET = (1 << pin); // set as output
@@ -288,25 +291,3 @@ uint8_t triangle_wave(uint8_t phase) {
}
#endif
-#ifdef USE_REBOOT
-void reboot() {
- // put the WDT in hard reset mode, then trigger it
- cli();
- #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85)
- WDTCR = 0xD8 | WDTO_15MS;
- #elif (ATTINY == 1634)
- // allow protected configuration changes for next 4 clock cycles
- CCP = 0xD8; // magic number
- // reset (WDIF + WDE), no WDIE, fastest (16ms) timing (0000)
- // (DS section 8.5.2 and table 8-4)
- WDTCSR = 0b10001000;
- #elif defined(AVRXMEGA3) // ATTINY816, 817, etc
- CCP = CCP_IOREG_gc; // temporarily disable change protection
- WDT.CTRLA = WDT_PERIOD_8CLK_gc; // Enable, timeout 8ms
- #endif
- sei();
- wdt_reset();
- while (1) {}
-}
-#endif
-
diff --git a/fsm/misc.h b/fsm/misc.h
index 8de6b29..ba1f8d9 100644
--- a/fsm/misc.h
+++ b/fsm/misc.h
@@ -62,7 +62,3 @@ void rgb_led_set(uint8_t value);
uint8_t triangle_wave(uint8_t phase);
#endif
-#ifdef USE_REBOOT
-void reboot();
-#endif
-
diff --git a/fsm/pcint.c b/fsm/pcint.c
index 131d0c3..d00b51d 100644
--- a/fsm/pcint.c
+++ b/fsm/pcint.c
@@ -13,58 +13,8 @@ uint8_t button_is_pressed() {
return value;
}
-inline void PCINT_on() {
- #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85)
- // enable pin change interrupt
- GIMSK |= (1 << PCIE);
- // only pay attention to the e-switch pin
- #if 0 // this is redundant; was already done in main()
- PCMSK = (1 << SWITCH_PCINT);
- #endif
- // set bits 1:0 to 0b01 (interrupt on rising *and* falling edge) (default)
- // MCUCR &= 0b11111101; MCUCR |= 0b00000001;
- #elif (ATTINY == 1634)
- // enable pin change interrupt
- #ifdef SWITCH2_PCIE
- GIMSK |= ((1 << SWITCH_PCIE) | (1 << SWITCH2_PCIE));
- #else
- GIMSK |= (1 << SWITCH_PCIE);
- #endif
- #elif defined(AVRXMEGA3) // ATTINY816, 817, etc)
- SWITCH_ISC_REG |= PORT_ISC_BOTHEDGES_gc;
- #else
- #error Unrecognized MCU type
- #endif
-}
-
-inline void PCINT_off() {
- #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85)
- // disable all pin-change interrupts
- GIMSK &= ~(1 << PCIE);
- #elif (ATTINY == 1634)
- // disable all pin-change interrupts
- GIMSK &= ~(1 << SWITCH_PCIE);
- #elif defined(AVRXMEGA3) // ATTINY816, 817, etc)
- SWITCH_ISC_REG &= ~(PORT_ISC_gm);
- #else
- #error Unrecognized MCU type
- #endif
-}
-
-//void button_change_interrupt() {
-#if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) || (ATTINY == 1634)
- #ifdef PCINT_vect
- ISR(PCINT_vect) {
- #else
- ISR(PCINT0_vect) {
- #endif
-#elif defined(AVRXMEGA3) // ATTINY816, 817, etc)
- ISR(SWITCH_VECT) {
- // Write a '1' to clear the interrupt flag
- SWITCH_INTFLG |= (1 << SWITCH_PIN);
-#else
- #error Unrecognized MCU type
-#endif
+ISR(SWITCH_VECT) {
+ mcu_switch_vect_clear();
irq_pcint = 1; // let deferred code know an interrupt happened
diff --git a/fsm/pcint.h b/fsm/pcint.h
index cd7ba02..62f93ab 100644
--- a/fsm/pcint.h
+++ b/fsm/pcint.h
@@ -9,7 +9,9 @@ volatile uint8_t irq_pcint = 0; // pin change interrupt happened?
#define BP_SAMPLES 32
volatile uint8_t button_last_state;
uint8_t button_is_pressed();
-inline void PCINT_on();
-inline void PCINT_off();
+//inline void PCINT_on();
+//inline void PCINT_off();
+#define PCINT_on mcu_pcint_on
+#define PCINT_off mcu_pcint_off
void PCINT_inner(uint8_t pressed);
diff --git a/fsm/spaghetti-monster.h b/fsm/spaghetti-monster.h
index c035d5b..7084ad4 100644
--- a/fsm/spaghetti-monster.h
+++ b/fsm/spaghetti-monster.h
@@ -13,10 +13,9 @@
* - ...
*/
-#include "arch/mcu.h"
+////////// include all the .h files //////////
-#include <avr/eeprom.h>
-#include <avr/power.h>
+#include "arch/mcu.h"
// include project definitions to help with recognizing symbols
#include "fsm/events.h"
@@ -39,6 +38,10 @@
#include "arch/delay.h"
#endif
+////////// include all the .c files //////////
+
+#include "arch/mcu.c"
+
#ifdef USE_DEBUG_BLINK
#define DEBUG_FLASH PWM1_LVL = 64; delay_4ms(2); PWM1_LVL = 0;
void debug_blink(uint8_t num) {
diff --git a/fsm/wdt.c b/fsm/wdt.c
index 64f006e..1095d44 100644
--- a/fsm/wdt.c
+++ b/fsm/wdt.c
@@ -7,85 +7,9 @@
#include <avr/interrupt.h>
#include <avr/wdt.h>
-// *** Note for the AVRXMEGA3 (1-Series, eg 816 and 817), the WDT
-// is not used for time-based interrupts. A new peripheral, the
-// Periodic Interrupt Timer ("PIT") is used for this purpose.
-
-void WDT_on()
-{
- #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85)
- // interrupt every 16ms
- //cli(); // Disable interrupts
- wdt_reset(); // Reset the WDT
- WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence
- WDTCR = (1<<WDIE); // Enable interrupt every 16ms
- //sei(); // Enable interrupts
- #elif (ATTINY == 1634)
- wdt_reset(); // Reset the WDT
- WDTCSR = (1<<WDIE); // Enable interrupt every 16ms
- #elif defined(AVRXMEGA3) // ATTINY816, 817, etc
- RTC.PITINTCTRL = RTC_PI_bm; // enable the Periodic Interrupt
- while (RTC.PITSTATUS > 0) {} // make sure the register is ready to be updated
- RTC.PITCTRLA = RTC_PERIOD_CYC512_gc | RTC_PITEN_bm; // Period = 16ms, enable the PI Timer
- #else
- #error Unrecognized MCU type
- #endif
-}
-
-#ifdef TICK_DURING_STANDBY
-inline void WDT_slow()
-{
- #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85)
- // interrupt slower
- //cli(); // Disable interrupts
- wdt_reset(); // Reset the WDT
- WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence
- WDTCR = (1<<WDIE) | STANDBY_TICK_SPEED; // Enable interrupt every so often
- //sei(); // Enable interrupts
- #elif (ATTINY == 1634)
- wdt_reset(); // Reset the WDT
- WDTCSR = (1<<WDIE) | STANDBY_TICK_SPEED;
- #elif defined(AVRXMEGA3) // ATTINY816, 817, etc
- RTC.PITINTCTRL = RTC_PI_bm; // enable the Periodic Interrupt
- while (RTC.PITSTATUS > 0) {} // make sure the register is ready to be updated
- RTC.PITCTRLA = (1<<6) | (STANDBY_TICK_SPEED<<3) | RTC_PITEN_bm; // Set period, enable the PI Timer
- #else
- #error Unrecognized MCU type
- #endif
-}
-#endif
-
-inline void WDT_off()
-{
- #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85)
- //cli(); // Disable interrupts
- wdt_reset(); // Reset the WDT
- MCUSR &= ~(1<<WDRF); // Clear Watchdog reset flag
- WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence
- WDTCR = 0x00; // Disable WDT
- //sei(); // Enable interrupts
- #elif (ATTINY == 1634)
- cli(); // needed because CCP, below
- wdt_reset(); // Reset the WDT
- MCUSR &= ~(1<<WDRF); // clear watchdog reset flag
- CCP = 0xD8; // enable config changes
- WDTCSR = 0; // disable and clear all WDT settings
- sei();
- #elif defined(AVRXMEGA3) // ATTINY816, 817, etc
- while (RTC.PITSTATUS > 0) {} // make sure the register is ready to be updated
- RTC.PITCTRLA = 0; // Disable the PI Timer
- #else
- #error Unrecognized MCU type
- #endif
-}
-
// clock tick -- this runs every 16ms (62.5 fps)
-#ifdef AVRXMEGA3 // ATTINY816, 817, etc
-ISR(RTC_PIT_vect) {
- RTC.PITINTFLAGS = RTC_PI_bm; // clear the PIT interrupt flag
-#else
ISR(WDT_vect) {
-#endif
+ mcu_wdt_vect_clear();
irq_wdt = 1; // WDT event happened
}
diff --git a/fsm/wdt.h b/fsm/wdt.h
index abf34c5..98eaf25 100644
--- a/fsm/wdt.h
+++ b/fsm/wdt.h
@@ -6,8 +6,11 @@
#define TICKS_PER_SECOND 62
-void WDT_on();
-inline void WDT_off();
+//void WDT_on();
+//inline void WDT_off();
+#define WDT_on mcu_wdt_active
+#define WDT_slow mcu_wdt_standby
+#define WDT_off mcu_wdt_stop
volatile uint8_t irq_wdt = 0; // WDT interrupt happened?