ADC Library - faster conversions

Status
Not open for further replies.

GiGiUK

Active member
Hi all
I'm working on a music midi project using Teensy 3.2. I have 22 sensors, 16 of which are monitored by pin A1 using a 16 channel Multiplexer and the remaining sensors using the ADC channels on the Teensy board. Everything works, but it seems that the sampling is just not quick enough to measure all the sensors quick enough for the speed of my fingers. For example 1/32 note at tempo 180, there are missed notes. I've been looking at Pedvides ADC Library and this seems to be the key, as I am currently just using analogRead... However, there doesn't seem to be much information on how to use the library. Can anyone offer me a road map on how to use this library. Also, I have attached a snippet from my code and I would be most grateful if any of you more experienced programmers could offer me some support.

Thank you in advance.
Ged.


Code:
//---------------------------------------------------------------------------//

void readSwitches() {    

    //First read value of all Key Sensors
    digitalWrite(4, LOW);   //S0    //Sample from MUX 1
    digitalWrite(3, LOW);   //S1              //0000
    digitalWrite(1, LOW);   //S2
    digitalWrite(0, LOW);   //S3
    U11 = analogRead(A1);   //Samples through MUX_I0 channel

    digitalWrite(4, HIGH);   //S0              //0001
    digitalWrite(3, LOW);   //S1 
    digitalWrite(1, LOW);   //S2
    digitalWrite(0, LOW);   //S3
    U10 = analogRead(A1);   //Samples through MUX_I1 channel

    digitalWrite(4, LOW);   //S0              //0010
    digitalWrite(3, HIGH);   //S1 
    digitalWrite(1, LOW);   //S2
    digitalWrite(0, LOW);   //S3
    U8 = analogRead(A1);   //Samples through MUX_I2 channel

    digitalWrite(4, HIGH);   //S0              //0011
    digitalWrite(3, HIGH);   //S1 
    digitalWrite(1, LOW);   //S2
    digitalWrite(0, LOW);   //S3
    U9 = analogRead(A1);   //Samples through MUX_I3 channel

    digitalWrite(4, LOW);   //S0              //0100
    digitalWrite(3, LOW);   //S1 
    digitalWrite(1, HIGH);   //S2
    digitalWrite(0, LOW);   //S3
    U4 = analogRead(A1);   //Samples through MUX_I4 channel

    digitalWrite(4, HIGH);   //S0              //0101
    digitalWrite(3, LOW);   //S1 
    digitalWrite(1, HIGH);   //S2
    digitalWrite(0, LOW);   //S3
    U5 = analogRead(A1);   //Samples through MUX_I5 channel

    digitalWrite(4, LOW);   //S0              //0110
    digitalWrite(3, HIGH);   //S1 
    digitalWrite(1, HIGH);   //S2
    digitalWrite(0, LOW);   //S3
    U12 = analogRead(A1);    //Samples through MUX_I6 channel    

    digitalWrite(4, HIGH);   //S0              //0111
    digitalWrite(3, HIGH);   //S1 
    digitalWrite(1, HIGH);   //S2
    digitalWrite(0, LOW);   //S3
    U13 = analogRead(A1);   //Samples through MUX_I7 channel

    digitalWrite(4, LOW);   //S0              //1000
    digitalWrite(3, LOW);   //S1 
    digitalWrite(1, LOW);   //S2
    digitalWrite(0, HIGH);   //S3
    U3 = analogRead(A1);    //Samples through MUX_I8 channel

    digitalWrite(4, HIGH);   //S0              //1001
    digitalWrite(3, LOW);   //S1 
    digitalWrite(1, LOW);   //S2
    digitalWrite(0, HIGH);   //S3
    U2 = analogRead(A1);   //Samples through MUX_I9 channel

    digitalWrite(4, LOW);   //S0              //1010
    digitalWrite(3, HIGH);   //S1 
    digitalWrite(1, LOW);   //S2
    digitalWrite(0, HIGH);   //S3
    U1 = analogRead(A1);   //Samples through MUX_I10 channel

    digitalWrite(4, HIGH);   //S0              //1011
    digitalWrite(3, HIGH);   //S1 
    digitalWrite(1, LOW);   //S2
    digitalWrite(0, HIGH);   //S3
    U14 = analogRead(A1);   //Samples through MUX_I11 channel

    digitalWrite(4, LOW);   //S0              //1100
    digitalWrite(3, LOW);   //S1 
    digitalWrite(1, HIGH);   //S2
    digitalWrite(0, HIGH);   //S3
    U16 = analogRead(A1);    //Samples through MUX_I12 channel 

    digitalWrite(4, HIGH);   //S0              //1101
    digitalWrite(3, LOW);   //S1 
    digitalWrite(1, HIGH);   //S2
    digitalWrite(0, HIGH);   //S3
    U15 = analogRead(A1);   //Samples through MUX_I13 channel

    digitalWrite(4, LOW);   //S0              //1110
    digitalWrite(3, HIGH);   //S1 
    digitalWrite(1, HIGH);   //S2
    digitalWrite(0, HIGH);   //S3
    U7 = analogRead(A1);   //Samples through MUX_I14 channel

    digitalWrite(4, HIGH);   //S0              //1111
    digitalWrite(3, HIGH);   //S1 
    digitalWrite(1, HIGH);   //S2
    digitalWrite(0, HIGH);   //S3
    U6 = analogRead(A1);   //Samples through MUX_I15 channel

    U17 = analogRead(A2);
    U18 = analogRead(A3);
    U19 = analogRead(A4);

    U20 = analogRead(A5);
    U21 = analogRead(A6);
    U22 = analogRead(A7);
 
Last edited:
Using digitalWriteFast() instead of digitalWrite() would get the output bits set faster.

Seems there should be some delay for the Mux to settle new output before reading after changing the digitalWrite()'s.

How many bits are needed - was Resolution set?

How many Avg Samples are needed - was Average set?

Code:
analogReadResolution(12);  // set #bits 8 to 16
analogReadAveraging(1); // 1,4,8,16,32
 
Hi defragster
No Resolution has been set, but I think I could get away with eight bit. I'm not sure about the average samples, I think one sample would be enough as the ADC is just monitoring a sensor that provides an analog output.

What would I think would help is:
1. having both ADC0 and ADC1 sampling at the same time
2. DMA transfer
3. a way of testing how fast my code is running

but, I dont know how to do that, any thoughts?
 
Given the MUX presents a single value - it can only be read on one channel. With two mux units that could be done.

All of the native analog pins could be read in pairs - based on proper channel association.

16 on MUX and 6 on native pins could be interleaved to some degree, especially if the 6 other pins are available on the 'other' channel different from the MUX input pin

there is a piezo drum sample reading lots of paired channels sample I wrote - and revisited recently - using the ADC library.

This looks to be that thread and some code that is not at all directed at this problem but could morph it seems:
pjrc.com/threads/61561-Teensy-4-Global-vs-local-variables-speed-of-execution

Rather than indexing the PIN on BOTH channels it would use one channel for the mux and change the digital address pins, and then on the other channel ( where the pins can be found } it would change the pin# and then initiate the no wait read and return when they are complete and continue the cycle. Again some short wait for the MUX output to change/settle would be needed it seems before starting the read.
 
> a way of testing how fast my code is running

+1 on measuring before you start optimizing.

digitalWrite(3, LOW); //S1 //0000
...
digitalWrite(3, LOW); //S1

You are doing a lot of writes that do nothing. But it won't make much difference.
 
Check the MUX sheet - it may note some time before output is stable after input changes. That time should be honored before the read or the value will not be true.

If the MUX works well enough - putting 11 input on two of them could present them to a pair of analog inputs with one on ADC0 and the other on ADC1

The same address lines could feed both MUX's

Then there would be symmetry in the read cycle process:
> set Mux address
> wait for MUX settling stable output
> start both ADC channel Async reads
-->> Return when reads complete and repeat indexing MUX inputs 1 through 11

Linked ADC code was reading "10 pins read 157556 times per second "
> that would be slowed by the MUX cycle time - Some microseconds delay for output settling time

The ADC read happens in the background so those cycles are free to use manipulating the data.

If the current setup is better than 2 MUX units - then 6 pins on one channel and the MUX on the other that should work as well - just proportionately longer for the cycle of 16 to complete as p#4 suggests
 
Hi
I`m using the CD74HC4067 16 channel MUX. According to the data sheet there is a “Break-Before-Make” Switching time of 6ns (Typ) at 4.5V, so I have added a 10uS delay between switching channels, should be plenty. I will also simplify my digitalWrites (thanks jonr for pointing this out).

This might sound like a silly question but how fast will my code be circulating, am I write to assume the code runs at the speed of the Teensy clock, which for a Teensy 3.2 will be 72MHz?
 
Hi

Would this be a correct assumption:

ADC Clock Teensy 3.2 = 400Khz

1 / 400Khz = 2.5uS
So the ADC can sample a sensor value every 2.5uS.

ADC0 needs to sample 11 sensors before sending the data through USBMidi, so if

11 * 2.5uS = 27.5uS. This is the time it will take to sample all 11 sensors, theoretically.

does this sound correct?
 
With a few lines of code, you could measure (vs assume). Search for ARM_DWT_CYCCNT.
 
Status
Not open for further replies.
Back
Top