Obtaining Arduino Due Analog inputs

Hi Im trying to read four voltages connected to analog inputs 0,1,2,3 as fast as possible and send them through serial. If I read only one channel, the value is correct, but if I read several channels the values appear to come from one channel or a mixed voltage, it is a very simple code so whats going on?

void setup()
{
  analogReadResolution(12);
  Serial.begin(9600);
}
void loop()
{
  Serial.println(analogRead(2));   
  Serial.println(analogRead(3));   
  delay(100);
}

I wonder if you might have already solved this?

However, In case you haven't.

Disclaimer: the following is from memory - you can find the details searching through the forum or google

I believe the arduinos use a multiplexer in order to expand the number of analogue pins available. In actual hardware there are only 2 ADCs available. When you read from 2 ports at roughly the same time you get a cross over effect as the multiplexer changes. In order to avoid this, you need to allow the signal to settle after an analog read (say roughly 50 microseconds?)

I also believe I've read somewhere that the maximum sample rate for the Due is 50,000 samples per second (50kHz) - which would be roughly every 20 microseconds.

You can use delayMicroseconds function (works the same as delay) and test accordingly

void setup()
{
  analogReadResolution(12);
  Serial.begin(9600);
}
void loop()
{
  Serial.println(analogRead(2));   
  delayMicroseconds(50);
  Serial.println(analogRead(3));   
  delay(100);
}

Also, Serial prints can take a number of milliseconds depending on the size you print and your baud rate. A quick upgrade would be to up your Serial.begin(9600) to Serial.begin(115200) - remember to adjust the IDE Serial Monitor to match! Good Luck!

JW

If the impedance of your source is high then there is not time to charge up the input capacitor once you switch to it.
The code above will not work because the delay is in the wrong place.
Either change your hardware or read each channel twice and just use the second reading.
If that is not enough insert the dealy between the two readings of the same channel.

Grumpy_Mike: The code above will not work because the delay is in the wrong place.

Are you referring to my code?

JWScotSat:

Grumpy_Mike: The code above will not work because the delay is in the wrong place.

Are you referring to my code?

Yes.

Because the switching of channels only occurs on the call to the analogue read, then the delay as you put it will occur after the channel has switched. Then the channel is switched again and a reading taken. So your delays do nothing to improve the situation of not having enough time to charge the input capacitor of the sample and hold circuit on the front of the A/D converter. You need to switch the channel, then delay, then take the reading. As there is not a separate "switch channel call" except through writing one specifically then the delays you put are in the wrong place.

Grumpy_Mike:

JWScotSat:

Grumpy_Mike: The code above will not work because the delay is in the wrong place.

Are you referring to my code?

Yes.

Because the switching of channels only occurs on the call to the analogue read, then the delay as you put it will occur after the channel has switched. Then the channel is switched again and a reading taken. So your delays do nothing to improve the situation of not having enough time to charge the input capacitor of the sample and hold circuit on the front of the A/D converter. You need to switch the channel, then delay, then take the reading. As there is not a separate "switch channel call" except through writing one specifically then the delays you put are in the wrong place.

Good to know, thanks.

Just to correct this:

the AurduinoDues Atmel SAM3X8E device contains 1 ADC with 16 multiplexed channels and a sample rate of up to 1MSPS.

My opinion on arduino code around ADC: It would have been better, if it had been implemented in the way that the sampling and storing of values would have been completely done in background (thru ISRs) instead of having the multiplex set, started the ADC, waited until ADC sampling & conversion got finished and returned directly the read value synchronously.

It would have required a method to set up the ADC channels to be used, sample rate, resolution etc. and on call to readAnalog(pin) just give back the already sampled value - like done in industry. This is still independent of architecture or device.

sample rate of up to 1MSPS.

Yes but you can not get samples at anything like that rate. That is only the bit rate not the sample rate.

Well you could, it may be a mixture of MSPS vs. MHZ in Atmel documentation about the ADC that might have led you to the wrong direction.

Given the pre conditions that you have a measurable voltage source of enough strength to source with pretty steep edges your timing contraints of the ADC are as follows:

track&hold time: 160ns conversion time: typical 20 * ADC clock (up to 20Mhz are specified: ^= 50ns * 20 => 1000ns) settling time: 200ns

sums up to a typical of about 1360ns or about 735kHz.

assuming a shorter conversion time (which is possible in respect to expected accuracy) you might also get up to 1MHz samling rate as also specified by Atmel in the datasheet.

Got some code that will sample that fast?

Yes for sure, its pretty easy:

static uint16_t APP_AdcChannelValue[4096];
static uint16_t APP_AdcChannelValueCnt = 0;

    adc_init(ADC, 84000000, 20000000, 1000);
    adc_configure_timing(ADC, 0, ADC_SETTLING_TIME_0, 0);
    adc_configure_trigger(ADC, ADC_TRIG_SW, 1); // Disable hardware trigger.
    adc_disable_interrupt(ADC, 0xFFFFFFFF); // Disable all ADC interrupts.
    adc_disable_all_channel(ADC);
    adc_enable_channel(ADC, ADC_CHANNEL_0);
    adc_start(ADC);

    for (;;)
    {
        if (adc_get_channel_status(ADC, ADC_CHANNEL_0) & 0x00000001)
        {
            APP_AdcChannelValue[APP_AdcChannelValueCnt] = adc_get_channel_value(ADC, ADC_CHANNEL_0);
            APP_AdcChannelValueCnt = (APP_AdcChannelValueCnt + 1) & 4095;
        }
    }

With that code and a simple sine wave signal generator i get the attached picture.
Number of sample points for full wave is 246.
With known signal frequency of 4.583kHz i get a calculated samplepoint diff time of about 887ns.
This is more than 1 MSPS 8)

… here is another picture of measuring a 100kHz sine wave signal.

I counted for 40 full wave repetitions (as only 10 sample points per full sine wave periode are expected, and that would look a little lousy) about 454 sample points.
→ even 881ns per sample.

For sure, it might look worse when it comes to full scale jumps near the sample frequency (depending on the impedance, oh by the way i used 50 Ohm) but what i’d like to say is, that the ADC is indeed not that bad as mentioned above regarding a maximum of 50kHz sampling frequency.

Edit: attached also the look of the 100kHz sine wave on a real DSO. This makes the attenuation visible. I have to admit, that i used an unshielded 3m wire to connect from test bench to arduino due :wink:

If the impedance of your source is high then there is not time to charge up the input capacitor once you switch to it. The code above will not work because the delay is in the wrong place. Either change your hardware or read each channel twice and just use the second reading. If that is not enough insert the dealy between the two readings of the same channel.

I have the same problem, could you write an example sketch?

Are you serious? It is just two reads of the same port one after the other.

It is easy but it still do not work, did you rtied? I

rtied?

What means this word?

However, if you mean have I tried this then yes I have used this technique many times.

Steinhoff: Hi Im trying to read four voltages connected to analog inputs 0,1,2,3 as fast as possible and send them through serial. If I read only one channel, the value is correct, but if I read several channels the values appear to come from one channel or a mixed voltage, it is a very simple code so whats going on?

Which version of the Arduino software are you using? Previous versions have had broken analogRead() implementations - are you on the most recent?

problem solved ... all the fault of the old 1.5.5 software! (now it works with 3 channels, without delay) :)