Higher ADC clock frequencies cause issue with ADC multiplexer on Arduino Nano

This will be a longer message, but I hope that some of you will find it useful.

With the default use of the Arduino library software, you got no issue. Then an ADC clock frequency of 125 kHz is used, and the ADC conversion time then becomes about 104 usec. However, according to this document page 10 from the the producer of the chip, Microchip,

“The ADC accuracy also depends on the ADC clock. The recommended maximum ADC clock frequency is limited by the internal DAC in the conversion circuitry. For optimum performance, the ADC clock should not exceed 200kHz. However, frequencies up to 1MHz do not reduce the ADC resolution significantly. Operating the ADC with frequencies greater than 1MHz is not characterized.”

Many other sources confirm the use up to 1 MHz ADC clock frequency, but I discovered, that you get a serious problem with the ADC multiplexer of the analog inputs, when you use this higher frequency without a correction. Perhaps this has been reported before, but then I did not find it. The multiplexer is set by writing to the ADMUX register, and it is normally done by the AnalogRead() function just before the AD-convertion is started. The problem is, that the multiplexer needs time to shift the input. You have 1½ clock cycle for the multiplexer and sample hold circuit to work, and at 1 MHz it is 1.5 usec. This is not sufficient and you partly gets some analog signal from the previous input. When you use the same analog input all the time, you will not see this issue.

When you measure the input voltage of supply of +5V and GND on each of two inputs and exchange the pin reading every time, you see the measured values come like this from analogReadread:

ADC result High = 995 ADC result Low = 0
ADC result High = 1003 ADC result Low = 0
ADC result High = 1003 ADC result Low = 0
ADC result High = 995 ADC result Low = 0
ADC result High = 995 ADC result Low = 79
ADC result High = 995 ADC result Low = 0
ADC result High = 1003 ADC result Low = 0
ADC result High = 1003 ADC result Low = 0
ADC result High = 1004 ADC result Low = 0

The right results are 1023 and 0.

In this link you find a test code, that is used to show this problem. I hope that some of you will try to test for the same problem on your Arduino:
https://forum.arduino.cc/t/arduino-nano-adc-clock-and-quantization-error/1204040/45

I suggest a solution to this problem with a minor change to the code for analogRead(), that is written in the library file wiring_analog.c. You can find the code in your library provided. In order to show the code in some more readable way, I have removed code not relevant for the 328P chip here:

int analogRead(uint8_t pin) {
  if (pin >= 14) pin -= 14; // allow for channel or pin numbers
	ADMUX = (analog_reference << 6) | (pin & 0x07);

	// without a delay, we seem to read from the wrong channel
	//delay(1); 

 	ADMUX = (analog_reference << 6) | (pin & 0x07);	// 8 lines inserted more to make some time
	ADMUX = (analog_reference << 6) | (pin & 0x07); // consumption of 1 usec extra for 1 MHz 
	ADMUX = (analog_reference << 6) | (pin & 0x07); // ADC clock on Arduino Nano. Measurements reveal 
	ADMUX = (analog_reference << 6) | (pin & 0x07); // each line of this code is 2 16 MHz clock cycles.
	ADMUX = (analog_reference << 6) | (pin & 0x07); // With 2 MHz ADC clock you would need to add 6 
	ADMUX = (analog_reference << 6) | (pin & 0x07); // more lines.
	ADMUX = (analog_reference << 6) | (pin & 0x07);
	ADMUX = (analog_reference << 6) | (pin & 0x07);

	// start the conversion
	sbi(ADCSRA, ADSC);

	// ADSC is cleared when the conversion finishes
	while (bit_is_set(ADCSRA, ADSC));

	// ADC macro takes care of reading ADC register.
	// avr-gcc implements the proper reading order: ADCL is read first.
	return ADC;
}

You find 8 lines extra lines of code, that I put in only for the purpose of consuming 1 us of execution time. In this way this problem disappears. I measured the time difference of 15 lines of this code and 75 lines of this code by setting of a digital output and use of an oscilloscope. The time difference was about 8 usec meaning 0.133 us each extra code line. Two CPU clock cycles are 0.125 us, so it is the right value for each line of this repeated code. Perhaps someone would suggest the use of some other kind of code. Actually the problem was solved at 6 extra lines of code on my Arduino, but I added extra two line to put in extra safety. Some other Arduino Nano might need some more or less time. Furthermore two other combinations of two analog inputs may also perform somewhat different.

Actually the original code already got a remark about this problem, and a possible solution by delay(1), but this delay will be about 1000 times longer than needed.

I did not find specifications in the datasheet regarding the needed time. But the datasheet recommends to use a clock frequency of max 200 kHz for “maximum performance”. The first 1½ ADC clock cycle is part of the time for this mux change and the sample hold circuit, and it is 1.5 us at 1 MHz. But I could see that 1 us more was needed, so you needed 2.5 us in all.

A test at 2 MHz ADC clock was tried. Then you need 0.75 us + 1.75 us = 2.5 us to get right results. In this way the extra code should consume 1.75 us. At 500 kHz ADC clock, you already have got 3 usec, and then no extra code is needed.

This has been discussed many times, in various places over the years (including this forum), but it doesn't hurt to repeat the basic information.

Thank you for your comment.

I did try by searching this forum and by google to find information about how to deal with this combined problem of the analog multiplexer and use of higher ADC frequencies with the classic Arduino. I found the information only by doing measurements on my one Arduino Nano.

Therefore I would love to see a reference or two about the same issue, because then there must be more solutions and perhaps other kinds of guidelines to solve this issue.

I's not clear to me exactly what the problem is you are trying to solve.

You state:

With the default use of the Arduino library software, you got no issue.

For an application, I like to use an ADC frequency of 1 MHz, because I need higher rate of obtaining ADC values. Therefore I started to set the ADC prescaler to 16 in order to get this faster frequency. Later on I discovered, that I had a serious problem with the received ADC values, and they were influenced by other input values measured in this application, that use 6 analog inputs. Sometimes the values were right and sometimes they were wrong.

So I isolated the problem to be, that internal analog multiplexer needed more time to switch from one analog input to another input. When I used analogRead(), I got a mix of both input values. I could rectify the problem by including some code that cause a small time delay to make time for this analog multiplexer to change over in the 328P chip.

I hope this make more sense for you now.

If you are going to use the 328P outside of the Arduino IDE context, then you are basically on your own.
I don't see that what you describe is a "problem", as there is no Arduino function to change the ADC clock frequency for the 328P.
If you decide to use direct register manipulation to change ADC parameters, then there is no reason to expect that any of the Arduino functions will still function correctly.

I have found many posts in this forum, that discuss issues or problems that go beyond the direct use of the Arduino IDE context. I suppose it is allowed to share ideas about that in this forum too, and we are allowed to help each other on matters like that. Therefore I do not think, that you are alone like that in this forum. I have seen several users, that try to use a 1 MHz ADC clock with the classic Arduino. I newer expected, that the responsible for the Arduino brand or core software, should in any way feel obliged to solve problems related to such issues. It is not a problem for them.

I felt a bit obliged to report to other forum members here, that try to use 1 MHz ADC clock (or perhaps even higher frequencies), that they should know about this multiplexer problem.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.