DayOftheNewDan.com
Arduino DSO
December 22, 2011
I had an OLED LCD screen from 4D systems lying around from another project and thought it might be fun to see how hard it would be to whip up a very simple digital storage oscilloscope with an Arduino. Turns out, not too difficult, but the limitations of the Arduino do make it rather slow. The best sample rate I could achieve was about 48 kHz. Normally an analogRead() operation takes 100 microseconds, for a maximum sample rate of 10 kHz. If you change the prescale used for the ADC clock you can achieve higher rates. The following code creates a preprocessor macro to set and clear the register bits.
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
If FAST_ADC is defined, we set the prescale to 16, giving us a faster ADC clock.
void setup()
{
#if FASTADC
sbi(ADCSRA,ADPS2);
cbi(ADCSRA,ADPS1);
cbi(ADCSRA,ADPS0);
#endif
...
}
Now that we have a “fast as can be” sample rate it is time to implement the components necessary for a DSO: timebase adjustment, trigger adjustment, and drawing the captured waveform to the screen.
The timebase adjustment determines how long the Arduino should sample, and how much time is displayed on the screen. It also sets the sample rate used, there is no need to sample at 48 kHz if you are displaying 1 second of data on the screen at a time. I implemented a simple push button switch connected to a digital port on the Arduino to cycle through the 6 time bases: 0.25 ms/div, 1 ms/div, 5 ms/div, 25 ms/div, 0.25 s/div, and 1.0 s/div. The screen is composed of 4 divisions, marked by little dots (it was too slow to draw lines every time).
The trigger level tells the software when to lock on to the periodic waveform. Without the trigger the waveform will drift around on the time axis. A potentiometer was connected to an analog port to set the trigger level.
I implemented a couple of different modes of gathering data depending upon the timebase selected. If the timebase was very short, requiring a fast sample rate, all of the samples were taken consecutively in a single for loop. Also, only 48 samples were taken (compared to a maximum of 96 samples being able to be displayed on the screen). For longer time bases, over 25 ms/div, there was enough time to draw the samples as they were acquired, and also to acquire a full 96 samples per screen.
The main slow down for operation now was transferring all of the data to the LCD screen over a serial line. This capped the refresh rate to about 10 fps. There are some tricks you can do to make it faster. Instead of clearing the whole screen, keep track of which parts were drawn to on the previous frame and draw black lines or rectangles only over those areas.
In the end, this is definitely a useable DSO for very low frequency applications, but I’m sure you could buy something substantially more powerful for the same price as the components used here. Still, a fun little project, and isn’t that what we are all actually after?
Resources
More info on faster analog reads:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1208715493/11
OLED Serial LCD by 4D Systems:
http://www.4dsystems.com.au/prod.php?id=77
Wikipedia article on oscilloscopes:
http://en.wikipedia.org/wiki/Oscilloscope