Teensy 4.1 ADC Issue

adi1893

Member
Hi,

Am currently working on a project that requires me to read the Analog Inputs A0, A1, A2 and A3 at a 20kHz update/refresh speed. There is a current transformer connected to two of the inputs A0 and A2 and there will be a potentiometer and another sensor input on A1 and A3. The project isnt exactly noise free but we are doing what we can to suppress noise as much as possible. Also the analog input pins can be shifted to other analog input pins if necessary.

When I try with just one input (A0), it works fine and I get fairly consistent values (Using the ADC library I have set the Conversion Speed to MED_SPEED and Sampling Speed to LOW_SPEED, any faster and the input values vary quite a bit and are not as stable as in this setting. Averaging is set to 4 and Resolution is 10bits). I am using the analogRead(A0) command in an interrupt that triggers at 20kHz to update the variable with the analog input value. The project uses 2 high speed timer interrupts using the IntervalTimer library as well as two Flex timers using the Teensy_PWM library.

I have a potentiometer connected to A1 and when I try reading a second analog input (A1) after reading the first analog input the value of A0 that is read varies quite a lot and is not as steady as before. The only change done is the reading of another Analog Input.

I spoke to a mentor of mine and he mentions for fast analog reading he takes 3 or 5 readings of an analog pin and discards the first reading as it may contain noise from when the analog input pin is switched for reading the ADC value and averages out the remaining 2 or 4 readings and this gives stable results with the microcontrollers he uses (non IMXRT/Teensy microcontrollers)

If someone could help me with the ADC library or write me sample code that I can use to read multiple analog values in a way mentioned above or if there is a better way to get stable readings at the speed required, your help and any code written would be very helpful and much appreciated. I do not have much experience with DMA or with using the ADC library or analog registers other than changing the Conversion Speed, Sampling Speed, Resolution and averaging.

Thanks.
 
this sound like an input impedence issue; do you have any kind of buffer in front of the analog pins?
 
Unless you drive the ADC pins with a low impedance the ADC will take time to charge up its sample/hold capacitor when you first switch to that channel - by calling analogRead(pin) you force the system to switch channels at the last possible moment before conversion, since it doesn't know which pin till the analogRead() call, whereas you really should be switching just after the previous conversion.

So how about doing a dummy conversion immediately after the normal one, for the next pin scheduled to be sampled?
 
Unless you drive the ADC pins with a low impedance the ADC will take time to charge up its sample/hold capacitor when you first switch to that channel - by calling analogRead(pin) you force the system to switch channels at the last possible moment before conversion, since it doesn't know which pin till the analogRead() call, whereas you really should be switching just after the previous conversion.

So how about doing a dummy conversion immediately after the normal one, for the next pin scheduled to be sampled?

Thanks for the input! I'm working on putting a buffer on the circuit that connects to the analog input.

Regarding the analog reading, if I put a dummy read for every time I require an analog read it will take significantly more time and will block the Teensy from doing other processing for the code. I guess because analogRead is a blocking type command. I will still program this for two analog inputs and see the difference it makes as this method will have to be followed.

Can you give me code to do this with readSingle and startSingleRead commands? I am unable to understand the ADC examples however hard I try. Code that will read analog inputs A0, A1, A2 and A3 in an interrupt triggered by a timer will be really helpful for me to understand.

Thanks!
 
Perhaps for the "dummy" read: Read current value, then issue: startSingleRead() on the new pin, and return to other code
startSingleRead() : Starts an analog measurement on the pin and enables interrupts.
It returns immediately, get value with readSingle(). If this function interrupts a measurement, it stores the settings in adc_config
Ideally that would be done on return for the next read then issue the readSingle(), then the actual ADC..analogRead() for the same pin? ... REPEAT for next pin.

<edit> Perhaps if change of AVG is not expensive' do: ENTER : readSingle() : Averaging is set to 4 : ADC..analogRead() : Averaging is set to 1 : startSingleRead() : LEAVE
 
For the potentiometer readings have you thought about lowering the impedance with a capacitor? What impedances are the other sources?
 
Back
Top