arduino / ArduinoCore-samd

Arduino Core for SAMD21 CPU
GNU Lesser General Public License v2.1
470 stars 718 forks source link

Arduino Zero ADC Sample Time Too Long #327

Open ghost opened 6 years ago

ghost commented 6 years ago

The conversion time for the Arduino Zero is currently around 426us, at 12-bit resolution.

This value can be calculated from the SAMD21 datasheet:

1) ADC Sample Time Calculation

Take the processor clock at (approximately) 48MHz and divide by the ADC prescaler set at 512:

ADC Clock Frequency = 48MHz / 512 = 93750Hz

Therefore the ADC clock period is 10.66us (1 / 93750).

The default ADC sample time is half the ADC clock period, so normally the sample time is:

Default ADC sample time = 10.66us / 2 = 5.33us

However, in the “wiring.c” file the ADC's SAMPLEN bitfield in the SAMPCTRL register that extends the sample time, has been set to 63, (0x3F hex). This determines the number of half ADC cycles taken to complete the sample given by the formula:

Adjusted ADC sample time = (63 + 1) * (10.66us / 2) = 341.12us

2) ADC Conversion Time Calculation

For the ADC configured for a 0.5 gain, in single ended mode, as on the Arduino Zero, the delay gain is 1.5. (Table 33-1 in the SAMD21 datasheet).

Using the formula in the datasheet, at 12-bits resolution and a delay gain of 1.5, the propagation delay or in other words the number full ADC clock cycles to complete a conversion for the ADC is:

Propagation Delay (ADC Conversion Time) = (1 + 12 / 2 + 1.5) / 93750 = 90.66us

As the propagation delay includes the sample time (half ADC clock period) at 5.33us, the total ADC conversion time is:

ADC Conversion Time = 341.12us + 90.66us – 5.33us = 426us

3) The SAMPCTRL register and ADC prescaler

The issue is that the SAMPCTRL register's SAMPLEN bitfield has been set at a maximum value of 63, this allows the maximum input source resistance, but at the expense of a hugely increased sample time.

In the electrical characteristics of the SAMD21 datasheet, the criteria for setting the sample time at 12-bit resolution is given by the formula:

T(sample) >= (R(source) + R(sample)) C(sample) 9.02

where R and C sample are characteristics of the ADC input (taken from the SAMD21 datasheet): R(sample) = 3.5kOhms C(sample) = 3.5pF R(source) = source resistance T(sample) = sample time (usually half ADC clock period)

Using this equation, even if the SAMPCTRL register were to be set to 0, giving an ADC sample time of 5.33us, this would allow a maximum source resistance of:

R(source) = 5.33us / (3.5pF * 9.02) – 3.5kOhms = 165331 Ohms

The resultant ADC conversion time of 90.66us, is more than a four fold decrease on the current value.

Furthermore, decreasing the ADC clock prescaler to say 128, instead of 512:

ADC Sample Time = (1 / ( 2 * 48MHz / 128)) = 1.33us

ADC Conversion Time = 8.5 * 2.66us = 22.67us

In practice the however the conversion time takes around just less than 30us, as the analogRead() function enables and disables the ADC each time it's called. (Using register manipulation it does take around 23us).

The maximum source resistance would be:

R(source) = 1.33us / (3.5pF * 9.02) – 3.5kOhms = 38628 Ohms

In my opinion, the ADC conversion time could be vastly reduced to around 30us without any noticeable effect for the vast majority of Arduino Zero users, unless of course they're using some voltage divider with large resistor values.

Muplex commented 5 years ago

Your calculation is perfect. I didnt understand why the lock up at very very slow sample rate. =(

mamama1 commented 2 years ago

I have found out with the SAM21 being in deep sleep, it needs more than 100ms after wakeup for the ADC to give usable measurements. Not 100% related to this but should be taken into consideration when making the sampling time even shorter.