Fixed… for real, this time. In the end it was just one missing character in this line. At least I thought so.
ADC0.CTRLA = ADC_ENABLE_bm | ADC_FREERUN_bm; // Enabled, free-running (aka, auto-retrigger)
Do you see it? The control register is set to the given value. But my changes to bring everything in the right order has moved one important line before this line:
// set the RUNSTDBY bit so ADC will run in standby mode
ADC0.CTRLA |= 1;
So first, bit 1 of CTRLA was set, then everything got replaced with the next line. This is totally my fault because previously the order was switched. Let’s clean this up, it’s not bad to set all control registers at one place because eventually it will result in the same outcome. And let’s use a proper definition instead of the magic number… 1… what?! Why 1?
#define ADC_RUNSTBY_bm 0x80 /* Run standby mode bit mask. */
D’oh! This can’t work, the ADC did never run in standby mode! Depending on the remaining instructions before going to sleep, it finished, or it didn’t.
To sum it up, here is my proposal that should fix this bug and cleans up control register setup a little bit.
--- a/ToyKeeper/spaghetti-monster/fsm-adc.c
+++ b/ToyKeeper/spaghetti-monster/fsm-adc.c
@@ -83,11 +83,6 @@ inline void adc_sleep_mode() {
// attiny1634
set_sleep_mode(SLEEP_MODE_ADC);
#elif defined(AVRXMEGA3) // ATTINY816, 817, etc
- // set the RUNSTDBY bit so ADC will run in standby mode
- ADC0.CTRLA |= 1;
- // set a INITDLY value because the AVR manual says so
- // (section 30.3.5)
- ADC0.CTRLD |= (1 << 5);
set_sleep_mode(SLEEP_MODE_STANDBY);
#else
#error No ADC sleep mode defined for this hardware.
@@ -133,10 +128,10 @@ inline void ADC_on()
ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | ADC_PRSCL;
//ADCSRA |= (1 << ADSC); // start measuring
#elif defined(AVRXMEGA3) // ATTINY816, 817, etc
- set_admux_voltage();
VREF.CTRLA |= VREF_ADC0REFSEL_1V1_gc; // Set Vbg ref to 1.1V
- ADC0.CTRLA = ADC_ENABLE_bm | ADC_FREERUN_bm; // Enabled, free-running (aka, auto-retrigger)
- ADC0.COMMAND |= ADC_STCONV_bm; // Start the ADC conversions
+ ADC0.CTRLA = ADC_ENABLE_bm | ADC_FREERUN_bm | ADC_RUNSTBY_bm; // Enable ADC, free running mode, run in standby
+ ADC0.CTRLD |= ADC_INITDLY_DLY16_gc; // Delay first measurement to stabilize reference
+ set_admux_voltage();
#else
#error Unrecognized MCU type
#endif
It was a combination of:
- not configuring the ADC to run in standby
- starting the conversion before configuring the delay to stabilize the reference