Several of my recent 8 bit microcontroller projects need multiple analogue inputs. I want a nice API that allows me to have different interfaces for getting analogue values, for example reading a straightforward pot as 0-255 or 0-1023, or a SoftPot membrane potentiometer where I may also want to track whether or not it’s
currently pressed.
Reading analogue inputs on AVR chips takes time and the lazy approach to reading an analogue value is to set up the registers to read a value and simply wait for it to come in. You do something like this:
ADMUX |= _BV(MUX0); ADMUX |= _BV(ADLAR); ADCSRA |= _BV(ADPS1) | _BV(ADPS0) | _BV(ADEN); while (ADCSRA & _BV(ADSC)); // !
That while loop is just eating cycles whilst we’re waiting for the ADC to return a result.
The best way to avoid this wait is to set up the ADC to start reading a value and when it’s ready send an interrupt to get the result.
The interrupt can either use the value immediately or stash it away in a stored value so it can be picked up later on in the main loop.
This approach saves wasting cycles but still has a problem: the ADC can only read one value at a time and I need multiple inputs.
The workaround for this is to make the interrupt run continually and constantly read each ADC value in turn.
The poll requests requests a value for a certain analogue input and when the ADC interrupt is fired off, it re-polls for the next one. This runs perpetually whilst interrupts are enabled.
The interrupt can act on the values immediately or – if we’re not concerned about keeping everything perfectly in sync – the values can simply be stored in data so it can be picked up in the main thread.
In the next post I’ll explain how I iterated this round-robin in building a fast and clean API for AVR chips.