Reading the value of multiple sensors as fast as possible.

Hello everyone,

I have five piezoelectric elements attached to my Arduino Mega at the ANALOG IN-Ports. There is a 1M-Ohms resistor parallel to each of those piezos. The values of the sensors are being read with the following code:

int y;
int input[5] = {A0,A1,A2,A3,A4};


void setup() { 
}

void loop() {

  for(y = 0; y <= 5; y++) {
    
    
    input[y] = analogRead(y);
    
    }
}

Everything works fine and as expected. Now my problem is, that the values aren’t being updated as fast as I need them to be updated. I read multiple posts about multithreading and that it isn’t possible to do with the Arduino, so my question is, is there a faster way of updating all five values than the one stated above? This one seems to be the fastest I could do.

Thanks for you Time.

That's about as fast as you can go. Really that's faster than you can go. Often times when reading analog inputs one right after the other you need to put an additional read in between and throw that value away. The first value you read right after switching the multiplexer can sometimes be off.

That code there should get all 5 sensors read in a little over half a millisecond. How fast do you really need them? Why?

int input[5] = {A0,A1,A2,A3,A4};

Why do you start out with this array populated with pin numbers and then later use it to store results?

Um you aren’t reading the pins you are reading pin y and putting that value in your pin array.

int y;
const int input[5] = {A0,A1,A2,A3,A4}; //using a constant would keep you from making your error

int result[5];

void setup() { 
}

void loop() {

  for(y = 0; y <= 5; y++) {
   result[y] = analogRead(input[y]);
    }
}

Add an array to save your readings.

Jimmy60:
Um you aren't reading the pins you are reading pin y and putting that value in your pin array.

Actually he is. If you'll notice, his pins are sequential from analog 0 through 4. So the for loop works to read those. Remember that analogRead will take numbers from 0 to 5 and add 14 to them to get the analog pin numbers.

That's true but it's still bad practice. Something I found out when trying to use a similar approach with a Leonardo where if I remember correctly A0 is not pin 14.

I'm sorry, I forgot to implement the value-array.

@ Delta_G
I need them really as fast as possible. Now if one sensor is being hit (I use the sensors to precisely detect hits on a surface.) the chance that you skip and don't read its peak value is pretty high due to the shortness of the signal an the interrupts.

Reading direct through those weird register adresses might be faster. I haven't grasped it well, but maybe you can.

SpaceForOne:
I need them really as fast as possible.

You need to define what that means in terms of samples per second.
You need to study the Atmel datasheet to understand what is possible with the ADC - especially as you are using the ADC to take samples from different pins.

The maximum sample rate from a single pin at full resolution is 15,000 samples per second.

You may need to use a higher performance external ADC for your application.

...R

Do you need to know whether a sensor has been hit or how hard it has been hit ? If so, do you need to use analogRead() or could you get away with digitalRead() which is faster in operation.

@ Robin2
Well, I can't tell you exactly how many samples per second but if only one or two sensors are attched, it reads the values frequent enough for good values.

@ UKHeilBob
I need to know how hard it was hit, so I can't use the digital inputs.

SpaceForOne:
@ Robin2
Well, I can't tell you exactly how many samples per second but if only one or two sensors are attched, it reads the values frequent enough for good values.

It would be easy to add a crude delayMicroseconds() into the code and try different values to figure out what makes it too slow to be useful. That should give you a good ball-park answer to my question.

...R

@ Robin2
I understand what you're thinking about but it doesn't help me to know how fast I have to read the values, because I know that with one sensor it works just fine, ok with two but it isn't fast enough for more than three sensors. Since the way of reading the values I mentioned above seems to be the fastest possible way of analogRead() (no other suggestions yet) I can't really work around it, I will probably make it work with multiple Arduinos.

SpaceForOne:
@ Robin2
I understand what you're thinking about but it doesn't help me to know how fast I have to read the values, because I know that with one sensor it works just fine, ok with two but it isn't fast enough for more than three sensors. Since the way of reading the values I mentioned above seems to be the fastest possible way of analogRead() (no other suggestions yet) I can't really work around it, I will probably make it work with multiple Arduinos.

Can you get your hands on an oscilloscope? You could look at the waveform that you get when you hit the sensor and see how long the pulse is.

Analogread() on an Arduino is normally 10 bits resolution at about 8000 samples per second.

You can speed up the analogread by reducing the number of bits resolution you want.

from my code archive I got this trick to reduce the sample time.

you need to add this line
ADCSRA = (ADCSRA | 0x07) & (0xF8 | _prescale);
_prescale is a byte 2…7 ==> 2 is fast and 7 is slow.

const int input[5] = {A0, A1, A2, A3, A4}; //using a constant would keep you from making your error

int result[5];

uint32_t start;
uint32_t stop;

byte _prescale = 2;

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  ADCSRA = (ADCSRA | 0x07) & (0xF8 | _prescale);

  start = micros();
  for (byte y = 0; y < 5; y++)
  {
    result[y] = analogRead(input[y]);
  }
  stop = micros();

  Serial.print("_prescale:\t");
  Serial.println(_prescale);
  Serial.print("Time used:\t");
  Serial.println(stop - start);

  for (byte y = 0; y < 5; y++)
  {
    Serial.print("\t");
    Serial.print(result[y]);
  }
  Serial.println();

  _prescale++;
  if (_prescale > 7)
  {
    _prescale = 2;
  }
  delay(1000);
}

give it a try

sample output

_prescale:	2
Time used:	40
	391	312	255	227	199
_prescale:	3
Time used:	52
	359	368	376	384	352
_prescale:	4
Time used:	88
	461	476	502	526	483
_prescale:	5
Time used:	156
	357	347	345	348	350
_prescale:	6
Time used:	284
	243	224	208	196	221
_prescale:	7
Time used:	560
	252	245	242	241	255

note 1: lines are floating.
note 2: see that different values for prescale give different timing (factor 10 in speed)
note 3: dive into the datasheet for the details

check - http://www.microsmart.co.za/technical/2014/03/01/advanced-arduino-adc/

@ Delta_G
I don't think in the near future but if I get the opportunity to get my hand on one I'm going to measure the length of a signal.

@ robtillaart
Wow, that looks very promising, thank you! I'm going to try it out and post if it worked for my purpose odd not.

SpaceForOne:
I understand what you're thinking about but it doesn't help me to know how fast I have to read the values,

I'm wondering if the Atmel chip can work a bit faster if programmed directly, rather than with analogRead().

However there is clearly a limit to how fast the Atmel chip can work and if you conclude that you really need something faster it would be a complete waste of time trying to get your project to work without external hardware.

...R

Hi,
The obvious question.

What is your application, real world.
Why do you need near instantaneous scanning of the inputs.

Tom.... :slight_smile:

I answered this in a similar topic just a few minutes ago. It depends on how many sensors you wish to use:

  1. for up to 5-10 sensors you can use a multiplexer. Above that it gets unreliable in the cheap versions.

  2. for an unlimited (yes almost unlimited) number of sensors, you can use the photon-pixel coupling method which is a new thing, 2019 level stuff. It allows you to read all the sensors in parallel.

Specifically for 1 ms sampling (for lets say 4000 sensors or how ever many you want) you can use the photon-pixel coupling method which requires a video camera. In your case, unfortunately, for 1ms you will need a 1000 fps video camera (which Arduino can not tolerate). If you wish to sample these sensors in 41 milliseconds, you can use any webcam or the Arduino camera at 24 fps.

Arduino camera can go to a maximum of 60 fps, and that means that the maximum sampling speed will be of 16 milliseconds (which is pretty good since you can read a huge array of sensors in parallel). But you say you need 1 millisecond, and that requires a 1000 fps camera :o

To summarize this:

| | Sensor sampling | | 1 ms | | 16 ms | | 41 ms |
| - | - | - | - |
| | Video camera | | 1000 fps | | 60 fps | | 24 fps |

Read this for exact explanation on the principles and the implementation: P.A. Gagniuc et al. Photon-pixel coupling: A method for parallel acquisition of electrical signals in scientific investigations. MethodsX, 6:968-979, 2019.