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?
If you find this content useful please consider a small donation via bitcoin: bitcoin:1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2?amount=0.001&message=Donation Scraping git contents via cgit is very resource intensive. The continued hosting of these git repositories is entirely financed by your bitcoin contributions. For donations of a least 1 mBTC you include your IP address in the message of your bitcoin donation. This will remove this message in the future for requests from your IP, which will significantly reduce token usage. In any case, any contributions to bitcoin address 1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2 are very welcome. Thanks in advance for you contribution to a self-sustaining ecosystem.