diff options
Diffstat (limited to 'fsm')
| -rw-r--r-- | fsm/adc.c | 299 | ||||
| -rw-r--r-- | fsm/adc.h | 29 | ||||
| -rw-r--r-- | fsm/main.c | 112 | ||||
| -rw-r--r-- | fsm/misc.c | 31 | ||||
| -rw-r--r-- | fsm/misc.h | 4 | ||||
| -rw-r--r-- | fsm/pcint.c | 54 | ||||
| -rw-r--r-- | fsm/pcint.h | 6 | ||||
| -rw-r--r-- | fsm/spaghetti-monster.h | 9 | ||||
| -rw-r--r-- | fsm/wdt.c | 78 | ||||
| -rw-r--r-- | fsm/wdt.h | 7 |
10 files changed, 135 insertions, 494 deletions
@@ -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 @@ -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 @@ -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(); } @@ -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 - @@ -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) { @@ -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 } @@ -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? |
