The ADC in the STM32F0 series of microcontrollers is pretty advanced compared to similar costing equivalents, offering features such as continuous conversion, internally and software triggered conversions, channel scanned conversions, amongst much more!
This isn’t a proper tutorial but I will be posting the code on how to achieve such a task and how I went about testing it! The main reason I wanted to figure out how to do it is in a variety of sampled systems, you want to have the ability to sample other analog inputs at the same time. The problem however comes with having clashes between consistently sampling one channel and being able to sample the other (most likely) less important channels at the same time, for example: In a digital guitar effects pedal, you want to consistently sample the audio to remove the audible effects and implications of digital jitter, whereas sampling the variable resistors – used to set the internal “slow changing” parameters, is less important as the relative frequency changes of these resistors is generally much lower than that of the audio signal and the sampled values generally stays pretty constant. Therefore, you want the ability to read these other analog channels when your main channel isn’t being read.
This is where the multiple ADC modes come in really useful. In my example, I’ve defined two different modes. The first of these is using the end of conversion interrupt from the ADC to store data in the correct memory locations with minimal overhead and the second is using DMA to move the data direct from the ADC data register to the correct memory locations. Obviously, DMA is the more efficient solution with the downsides of increased complexity.
To test each mode, I’ve connected three seperate potential dividers to my STM32F0 discovery board, a potential divider consisting of a 10k and 1k resistor, another of a 4.7k and 1k resistor and finally, one consisting of two 1k resistors. With the power supply set at a constant of 3V, the corresponding voltages at each point (under unloaded conditions – this will be explained later!) should be: 0.272V, 0.526V and 1.5V respectively. In digital terms (sampling at 12bits), these “digital” voltages should be 372, 719 and 2048, again respectively. After actually sampling, the returned values are 299, 644 and 1991! Obviously, this seems like a massive error, -19.7%, -10.4% and -2.8%, respectively. This might seem weird but is a common occurrence when you drive an analog input. In the datasheet, the internal structure of the ADC is actually shown and consists of a variety of resistors and capacitors, required for the ADCs functioning. The internal capacitances need charging up to the sampled voltage without applying a significant load to the analog input. Obviously, to achieve faster sampling rated, these internal capacitances need to be charged faster, presenting even more load on the analog input. This is generally mitigated by either buffering the input with a low impedance source, such as an op amp or if the input changes at a very slow rate, for example a potentiometer, adding a buffering capacitor between the analog input and ground. This capacitor supplies the load requirements as the input is sampled, reducing the voltage sag and reducing the error associated with it.
The amount of sag can actually be calculated and used to mitigate this error. This however is not done in this tutorial.
In both of the above examples, I’m using the debug mode to read the converted values and using a software defined flag.
As ever, you can find my code on Github! In the example, if you comment out the DMA_ADCMode, the code example will work using the interrupt mode.