Your Arduino SAMD21 ADC Is Lying To You

One of the great things about the Arduino environment is that it covers a wide variety of hardware with a common interface. Importantly, this isn’t just about language, but also about abstracting away the gory details of the underlying silicon. The problem is, of course, that someone has to decode often cryptic datasheets to write that interface layer in the first place. In a recent blog post on omzlo.com, [Alain] explains how they found a bug in the Arduino SAMD21 analogRead() code which causes the output to be offset by between 25 mV and 57 mV. For a 12-bit ADC operating with a reference of 3.3 V, this represents a whopping error of up to 70 least-significant-bits!

Excerpt from the SAMD wiring_analog.c file in the Arduino Core repo.

While developing a shield that interfaces to 24 V systems, the development team noticed that the ADC readings on a SAMD21-based board were off by a consistent 35 mV; expanding their tests to a number of different analog pins and SAMD21 boards, they saw offsets between 25 mV and 57 mV. It seems like this offset was a known issue; Arduino actually provides code to calibrate the ADC on SAMD boards, which will “fix” the problem with software gain and offset factors, although this can reduce the range of the ADC slightly. Still, having to correct for this level of error on a microcontroller ADC in 2019 — or even 2015 when the code was written — seems really wrong.

After writing their own ADC read routine that produced errors of only between 1 mV and 5 mV (1 to 6 LSB), the team turned their attention to the Arduino code. That code disables the ADC between measurements, and when it is re-enabled for each measurement, the first result needs to be discarded. It turns out that the Arduino code doesn’t wait for the first, garbage, result to finish before starting the next one. That is enough to cause the observed offset issue.

It seems odd to us that such a bug would go unnoticed for so long, but we’ve all seen stranger things happen. There are instructions on the blog page on how to quickly test this bug. We didn’t have a SAMD21-based Arduino available for testing before press time, but if you’ve got one handy and can replicate these experiments to verify the results, definitely let us know in the comments section below.

If you don’t have an Arduino board with a SAMD21 uC, you can find out more about them here.