Open makkiato83 opened 1 year ago
From a quick glance at the ADC peripheral code, it seems like this functionality was never implemented. If you want to try to implement it and send a pull-request, that might work.
Otherwise, I can open it for voting, but I'm pretty sure it won't get much attention - the ADC has been out for more than a year, and no one every asked about the free running mode (until now, at least).
Thanks for the quick reply!
No need to open it for voting, I am exploring the Attiny features purely for educational purposes and I don't need this feature. I reported this bug just to let you know.
Keep up the great work!
From a quick glance at the ADC peripheral code, it seems like this functionality was never implemented. If you want to try to implement it and send a pull-request, that might work.
Otherwise, I can open it for voting, but I'm pretty sure it won't get much attention - the ADC has been out for more than a year, and no one every asked about the free running mode (until now, at least).
I think to make it work, one would need to add a bit to this routine to schedule another completeADCRead dependent on
ADSCRB & bit(ADATE)
:
But it gets complicated depending on the particular free running mode per ADSCRB & (0b111 << ADTS0)
The plain ADSCRB::ADTS[0:2]=0b000 free running mode trigger source might be a straightforward scheduling of a call to onADCRead(???), but the others trigger sources would seem to need something like interrupts.
completeADCRead(value: number) {
const { ADCL, ADCH, ADMUX, ADCSRA } = this.config;
this.converting = false;
this.conversionCycles = 13;
if (this.cpu.data[ADMUX] & ADLAR) {
this.cpu.data[ADCL] = (value << 6) & 0xff;
this.cpu.data[ADCH] = value >> 2;
} else {
this.cpu.data[ADCL] = value & 0xff;
this.cpu.data[ADCH] = (value >> 8) & 0x3;
}
this.cpu.data[ADCSRA] &= ~ADSC;
this.cpu.setInterruptFlag(this.ADC);
if(this.cpu.data[ADSCRA & bit(ADATE)){
switch(ADSCRB & (0b111 <<ADTS0)){
case 0b000:
this.cpu.addClockEvent(() => this.cpu.onADCRead(ADMUX???), this.sampleCycles)
break;
// 0b001-0b111 not handled
default: ;
}
}
}
Datasheet ADSCRB reference: https://onlinedocs.microchip.com/pr/GUID-0EC909F9-8FB7-46B2-BF4B-05290662B5C3-en-US-12.1.1/index.html
Here is another bug of ADC freerunning mode in 328P https://wokwi.com/projects/393410516428554241. It works, but it swaps channnels, even during the loop. Only the first loop seems to be correct.
uint16_t sArray1[16];
uint16_t sArray2[16];
int sLoopCounter;
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.print(F("sLoopCounter="));
Serial.println(sLoopCounter++);
// MVCE for https://github.com/wokwi/avr8js/issues/136
ADMUX = 0xC0; // select A0
ADCSRA = ((1 << ADEN) | (1 << ADSC) | (1 << ADATE) | (1 << ADIF) | 5);
for (unsigned int i = 0; i < 16; i++) {
loop_until_bit_is_set(ADCSRA, ADIF);
ADCSRA |= _BV(ADIF); // clear bit to enable recognizing next conversion has finished with "loop_until_bit_is_set(ADCSRA, ADIF)".
uint16_t tValue = ADCL | (ADCH << 8);
sArray1[i] = tValue; // store value at current counter index
}
ADCSRA = ((1 << ADEN) | (1 << ADIF) | 5); // Disable auto-triggering (free running mode), but the last conversion is still running
delay(1);
ADMUX = 0xC1;// select A1
ADCSRA = ((1 << ADEN) | (1 << ADSC) | (1 << ADATE) | (1 << ADIF) | 5);
for (unsigned int i = 0; i < 16; i++) {
loop_until_bit_is_set(ADCSRA, ADIF);
ADCSRA |= _BV(ADIF); // clear bit to enable recognizing next conversion has finished with "loop_until_bit_is_set(ADCSRA, ADIF)".
uint16_t tValue = ADCL | (ADCH << 8);
sArray2[i] = tValue; // store value at current counter index
}
ADCSRA = ((1 << ADEN) | (1 << ADIF) | 5); // Disable auto-triggering (free running mode), but the last conversion is still running
Serial.println(F("Print i=<ValueA0>|<ValueA1>"));
/*
We expect i=<ValueA0>|<ValueA1>, but this is only true the first time after boot,
Next loops we see i=<ValueA1>|<ValueA0>
and after 12 to 13 samples i=<ValueA0>|<ValueA0> or i=<ValueA1>|<ValueA1>
*/
for (unsigned int i = 0; i < 16; i++) {
Serial.print(i);
Serial.print('=');
Serial.print(sArray1[i]);
Serial.print('|');
Serial.print(sArray2[i]);
Serial.print(F(", "));
}
Serial.println();
delay(2000);
}
I think there is a bug in the way the simulator handles ADC in free running mode.
This is a mode, documented in the datasheet, in which the ADC keeps sampling the chosen input. In is configured using the ADCSRA and ADCSRB registers.
To reproduce the error I have prepared this sketch: https://wokwi.com/projects/353310932474416129
In the Wokwi simulation, there is only one message reaching the console.
In a physical Attiny85, the console keeps receiving messages, as it should.
BUG(?): It appears like the simulator somewhere does not properly re-start the ADC conversion. This bug might (not checked) affect not just the free-running-mode (ADCSRB =0x00) but other interrupt-driven ADC-conversions as well (other values of ADCSRB).