1

I'm very new at this and I need some help. This is a college project that I must do and not even the professor knows for certain if it is possible.

I have to sample two signals at a fixed sampling rate so there is no aliasing effect and it must be done at the same time (switching the ADC from one analog input to another)..

The signal would be then transmitted via USB to my computer. I guess that the transmission rate would be too slow to do this in real time. I will have to store this somewhere in the Arduino board so it can be transmitted afterwards.

Requirements:

  • It could be done with 8 bit resolution.
  • Sampling rate of at least 4.8kHz.
  • Record both signals for at least 0.1 second.

Is this even possible to do with my Arduino UNO R3? If it isn't, it would be with a sampling rate of 1.2kHz?

PS: I could try to lower the sampling frequency necessary by changing the aliasing filter that I built. The theoretical limit would be at about 1.2kHz for the best filter possible.

2
  • You can make the arduino sample faster and use a fast enough serial link. For instance setting the prescaler to the value like in the linked post will give you 16us per analog read. You call the two analogread one after the other (32us), then send both data through the serial interface at 512kbps. For instance, if you send 3 bytes (one to sync, the other with the data) you will spend around 58us in the sending. Total: 90us. To achieve a 4.8kHz sampling rate you need to repeat sampling every 208us, so you have time for calculations too
    – frarugi87
    Jun 20, 2017 at 14:07
  • While this probably can be done on an ATmega328p + serial converter classic arduino, it may in practice be simpler with an ARM-based board having a faster ADC, more speed and resources, and native USB. The advantage of the ATmega solutions is their ubiquity and wide collection of code that works "well enough" for many needs. There's no actual cost advantage when considering comparable suppliers. Jun 21, 2017 at 18:21

2 Answers 2

1

It is not possible to sample two signals at the exact same time with an Arduino Uno. The Arduino has only one ADC, so you have to sample one signal, switch channels, sample the other, switch channels again, etc. If this is acceptable for your project, then yes, it is perfectly feasible with an Arduino Uno. But you will have to dig into the datasheet and program the ATmega328P low-level.

Regarding the sampling rate, you want the ADC to take 9600 samples per second (4.8 kS/s × 2 channels). This means one sample every 104 µs. You are lucky: in the default Arduino configuration, the ADC conversions take exactly 104 µs. frarugi87 and Jot suggest you reconfigure the ADC for faster sampling. This is useless: the default sampling speed is already optimal for you application. Leave it as is.

You also require a fixed sampling rate. This is not possible to do with software. Configuring the ADC in auto trigger mode is the only way to get a really steady rate. The ADC can be triggered by a timer, but in your particular case, it is just simpler to have it trigger itself. This is called free running mode and it gives a sampling rate of exactly one sample every 104 µs. Perfect for your application.

Jot also suggests disabling interrupts. Do not do that! Interrupts are harmless because the ADC manages its own timing. And they are actually useful: I would use the ADC interrupt to retrieve the conversion result, send it through the serial port and switch channels in the multiplexer.

If you are happy with 8-bit resolution, I recommend you enable the left adjust result mode. This way you can retrieve the 8-bit result from the ADCH register and you won't need to do bit shifts.

I guess that the transmission rate would be too slow to do this in real time. I will have to store this somewhere in the Arduino board so it can be transmitted afterwards.

Both options are possible. If you send the data in binary, you will need a baud rate of at least 9600 bytes/s × 10 bits/byte = 96 kb/s. You can opt for 115.2 kb/s, which is standard and widely supported. If you want to store the data, then you will need 9600 bytes/s × 0.1 s = 960 bytes, or about half the Arduino RAM. This is fine, as the program can be quite simple, so it won't need more than half the available RAM.

Just to give you some inspiration, I suggest you take a look at this sound-meter sketch of mine. It configures the ADC in free-running mode at 9.6 kS/s and retrieves the result using the ADC interrupt. I would use the same ADC configuration for your project, only with left-adjust and with channel switching performed by the interrupt handler.


Edit: I just wrote a “dual channel oscilloscope” program along the lines of this answer: dual-scope.c. It's written in plain C, but it can also be compiled as a regular .ino file. I only tested it with constant voltage inputs though.

The program ended up being tiny: it uses about 1% of the flash, 1.4% of the RAM and 3.4% of the CPU power on an Arduino Uno. Meaning you could add stuff to it if you feel so inclined.

4
  • Are you sure that you can achieve this rate with the stock software when switching channels and never be delayed in switching by a timer interrupt being in progress at the key time? If the ADC block can handle the channel switching automatically, the answer may be yes, if not, the answer is no, and those ideas you are dismissing as "useless" may actually be required. Jun 21, 2017 at 18:18
  • @ChrisStratton: Yes, I tested it, it works. When the ADC finishes the (n)-th conversion, it triggers ISR(ADC_vect) and immediately starts the (n+1)-st. In the ISR, you process that (n)-th reading, and you set the MUX for the (n+2)-nd conversion. The trick is: the ADC ignores the new MUX setting until it is ready to start a new conversion. I will shortly upload a program demonstrating the approach. Jun 21, 2017 at 18:53
  • Could ISR_NAKED be used ? Perhaps asm code is needed to prevent that unknown local/register variables are used.
    – Jot
    Jun 21, 2017 at 21:17
  • @Jot: Yes, you could use ISR_NAKED, and that would save a few bytes of flash and RAM, and about 1.9% of CPU power. But then the ISR would clobber some CPU registers. That would be OK with the program as it is, since outside the ISR it does nothing but sleep, but it would be problematic as soon as you add code to the main loop. And no, you cannot avoid clobbering registers: it's a load/store architecture. Jun 21, 2017 at 21:33
0

The Arduino Uno uses a slow 8-bit microcontroller ATmega328P. The Due, Zero, M0 boards use a faster processor.

However, the ATmega328P microcontroller has many option for sampling analog data. It can easily do what you want. It's all in the datasheet.

The Arduino functions are often slow. For example the analogRead uses 112µs. For two channels you might get near the 4kHz with some luck.

I suggest to write a sketch that reads two channels and stores the data, and see how fast it will be. Note that the Timer0 interrupt will happen during that time. Arduino uses Timer0 for millis. You could disable the interrupts with noInterrupts.
After that, try the prescaler option as mentioned by @frurigi87. It seems to be an easy way to get a higher sample rate.
The next option is to write your own code and use the registers directly. There is code to make a simple oscilloscope with a high sample rate that you can use as an example. For example at avrfreaks.net, click on "projects" and search for "oscilloscope".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.