beginner needs some advice on ADC sampling rate and wifi module

I haven't used Arduino till now.
For my project, I need 5 ADCs with 10 bit resolution and sampling speed of 1kSps for each channel. Then I need to transfer these values to a PC via Wifi. For Wifi, I found RN-131 wifi module which can communicate with a microcontroller (aurduino) via Tx, Rx pins. My setup will be like Arduino -> RN-131 -> PC

Considering my required sampling rate of ADCs, baud rate for trasmitting data to RN131, can I choose arduino for my project?
Have people already worked on RN131 with arduino?

Arduino is sampling at about 15 kSps (the 6 input are multiplexed so you may get about 3 kSps with 5 inputs used).

I already use a RN-XV XBee from Roving Networks which is based on the RN-171 module. The two modules are probably similar enough to tell you that this will work for you. I get transfer rates of about 1Mbit/s (not from the MCU to the WiFi but direct network traffic) so your 100kbit/s (5 integer values 1000 times per second) should not pose a problem if your WiFi network is robust enough to allow that speed.

The 16 MHz Arduino clock has to be divided down to 125 KHz to get full 10-bit resolution. In auto-trigger mode it takes 13.5 cycles to get each value. That’s a little over 9000 samples per second so using Timer/Counter1 to auto-trigger an analog conversion every 200 microseconds (5000 samples per second) should not be a problem.

Getting 50,000 bits per second to your PC should be no problem if the WiFi module supports 115200 baud or higher.

johnwasser:
The 16 MHz Arduino clock has to be divided down to 125 KHz to get full 10-bit resolution. In auto-trigger mode it takes 13.5 cycles to get each value. That's a little over 9000 samples per second so using Timer/Counter1 to auto-trigger an analog conversion every 200 microseconds (5000 samples per second) should not be a problem.

Be aware though, that there is a single shared ADC and that with back to back use of it, the previous reading may impact the current. A workaround for this is to read twice, discarding the first reading. If you were to do this though, you would need to be doing 10K samples/s which, from the foregoing, won't be achievable.

wildbill:
Be aware though, that there is a single shared ADC and that with back to back use of it, the previous reading may impact the current. A workaround for this is to read twice, discarding the first reading. If you were to do this though, you would need to be doing 10K samples/s which, from the foregoing, won’t be achievable.

So what is the maximum usable sampling rate one can get for 10bits? Has anyone already tested it?
Thanx

Be aware though, that there is a single shared ADC and that with back to back use of it, the previous reading may impact the current.

That is only true if the input impedance to the ADC is significantly higher than 10K.
Keep it at 10K and you can sample at the maximum rate.

As I recall the normal sample time is 104 uS. What you can do is sample and keep processing (an interrupt will tell you when the sample is ready). Then you can be sending the previous sample while you start the next one. That way you don't have to sample, send, sample, send and so on, where the sending time will slow down the sample rate.

I would have thought that the WiFi was the limiting thing here, but perhaps not. Can you send the results in about 200 uS via WiFi?

I just checked the sampling rate by transferring via serial. With this code (below), I could get sampling rate of ~530 sps for each channel. If I read just 1 channel I get ~2100 sps.
void setup() {

  • Serial.begin(115200);*
    }
    void loop() {
  • Serial.println(analogRead(A0));*
  • Serial.println(analogRead(A1));*
  • Serial.println(analogRead(A2));*
  • Serial.println(analogRead(A3));*
    }

Is there anyway I can improve this code for better sampling rate?

How do I implement this interrupt. Could give me some more hints?

thanx

Grumpy_Mike:

Be aware though, that there is a single shared ADC and that with back to back use of it, the previous reading may impact the current.

That is only true if the input impedance to the ADC is significantly higher than 10K.
Keep it at 10K and you can sample at the maximum rate.

If you need to sample a with a source resistance greater than 10K, patching the analogRead code to add a short delay between switching the multiplexer and starting the conversion avoids the need to take 2 readings and is more effective. For example, a delay of 10us (increasing the overall anologRead time from 110us to 120us) is good for source resistance up to 100K.

libuz:
How do I implement this interrupt. Could give me some more hints?

Here:

Scroll down to "Read the Analog-to-Digital converter asynchronously".

My problem is more with the serial transfer. I am getting a very slow transfer speed. Here is my code:

Serial.begin(115200) ;
start = millis() ;
for (i = 0 ; i < 1000 ; i++)
Serial.println(analogRead(A1)) ;
}

The output is 418 msec (1000 calls) .

I tested to transfer without reading from ADCs:
Serial.println(1); gives: 248 msec (1000 calls)
Serial.println(111); gives: 418 msec (1000 calls)

which is far less than baud rate of 115200.

If I have to read 5 ADC pins and transfer via serial in every loop, that means to call Serial.println 5 times a loop, it will take more than a second to complete 200 loops. It will decrease my sampling frequency for each channel to less than 200Hz

How can I solve this problem?

The theoretical minimum time to transfer 4000 bytes (3 digits plus newline) using a 115200 baud line is 347ms. An overhead of 70ms is not that bad at all.

You could make that a lot faster by using binary transfer instead of ASCII. A 10 bit reading of an analog input doesn't have to use up to 50 bits on the line (4 digits plus newline, all times 10 bits).

You could overlap reading with sending; initiate a conversion then send the result of the previous conversion.

libuz:
Serial.println(1); gives: 248 msec (1000 calls)
Serial.println(111); gives: 418 msec (1000 calls)

which is far less than baud rate of 115200.

The println adds a carriage-return and a newline. That's another two bytes.

Since there are 10 bits per byte (8 + start + stop bits) you can transfer 11520 bytes per second, that is one per 86.8 uS.

To transfer "1" + cr + newline (3 bytes) will take 260 uS (you got 248 so you are doing well).

To transfer "111" + cr + newline (5 bytes) will take 434 uS (you got 418 so you are doing well again).

As others suggested, sending the "raw" data could be faster, although it would be important to stay in sync.

AWOL:
You could overlap reading with sending; initiate a conversion then send the result of the previous conversion.

...

Yes, good idea.

But you can see that sending 4 bytes is going to take 347 uS which is about 3 times the time it takes to take a sample. You may have to revise your expectations. Or change your design. Send one full sample and then a difference.

I just tried sending the binary, but I think I am doing the wrong way.
Serial.println(111, BIN); gives 759 msec (1000 calls)

I just tried sending the binary,

No, you just sent the decimal number 111 represented as ASCII binary, which requires seven ASCII characters plus cr/lf
Try “write” or the BYTE specifier

libuz:
I just tried sending the binary, but I think I am doing the wrong way.
Serial.println(111, BIN); gives 759 msec (1000 calls)

111 in binary would be 1101111 (7 bytes) plus carriage-return/linefeed is 9 bytes.

So that would be 86.8 * 9 = 781 uS. That sounds about right.

Thanks for the quick reply.

I tried doing this way: Serial.write(byte(111)) ;
Now, it gives: ooooooo..... ... ...... oooo78 msec (1000 calls)

I guess its because ASCII of 'o' is 111 in DEC. Am I right?

Yes you are getting closer.

got a new problem :slight_smile:

When I give more than 255, like Serial.write(1000); gives èèèè..... whose DEC value is 234.
Since ADC can have value upto 1023, this could be a problem