New oscilloscope for arduino (linux-only for now)

Hi :slight_smile:

I started a new oscilloscope project for arduino. The UI frontend only runs in GTK for now, and it's quite poor.

Features:

  • Fast sampling rate, using self-triggered ADC. It's independent of serial baud rate.
  • Trigger support (inside arduino), with holdoff and auto-trigger. More to come.
  • Fully configurable through the UI (in progress).

For those starting with arduino, code implements some "paradigms":

  • Finite-state machines
  • Packet-oriented serial communication, with error detection.

You can get code here:

You will need gtk+2 and cairo to build UI successfully.

Awaiting your feedback :slight_smile:

Álvaro

Hi Alvaro,

What arduino board are you using ?
Can you explain self-trigger ADC ?
What is max sampling speed and how many quatize bits precision do you get ?

Hi there :slight_smile:

What arduino board are you using ?

Duemilenove.

Can you explain self-trigger ADC ?

Sure. ATMEGA328 ADC can trigger interrupts when a conversion ends, and can route this end-of-conversion interrupt signal (ADIF) to trigger start of conversion. This is so-called the Free Running Mode. So, whenever a conversion ends, another conversion starts. I call it "self-trigger" because it triggers based on its own output signal.

What is max sampling speed and how many quatize bits precision do you get ?

Max sampling speed is maximum ADC sampling speed in Free Running Mode - which is 13 ADC clock cycles + 1 for the self-trigger. If you use the max. prescaler (128) you get an ADC clock speed of 125KHz. This makes about 9Ksamples/second. Doubles whenever you divide the prescaler by two (meaning a prescaler of 64 will give you almost 18ksamples/s). See page 254 of ATMEGA datasheet for more details.

The current resolution is 8-bit, but can easily be increased to 10-bit, if needed.

Álvaro

Max sampling speed is maximum ADC sampling speed in Free Running Mode - which is 13 ADC clock cycles + 1 for the self-trigger. If you use the max. prescaler (128) you get an ADC clock speed of 125KHz. This makes about 9Ksamples/second. Doubles whenever you divide the prescaler by two (meaning a prescaler of 64 will give you almost 18ksamples/s). See page 254 of ATMEGA datasheet for more details.

The current resolution is 8-bit, but can easily be increased to 10-bit, if needed.

What is max ADC clock speed can I set on arduino boards in Free Running-mode and what would be then the associated bit resolution ?

What is best method to download then display the fastest sampled stream to a Macintosh with either a duamilanove board or mega board which i'm using in my projects ?

Great!

Do you plan to make support multiple channels as well?

Do you plan to make support multiple channels as well?

Yes, either interpolating (sample A,B,A,B...) or framed (trigger A, sample 512A, trigger again A, sample 512B). The former scenario is more accurate, but only gives half sample rate, latter has full sample rate but might not work well if your two channels are of different frequencies.

Álvaro

Alvaro -

This is really a good design. It avoids the timing problems of using a serial packet to trigger the acquisition. The FTDI USB/Serial driver has issues with buffering on the chip side (384 bytes), the driver side (64-4K bytes) and when the buffers are flushed to the application ( 1 msec polled).

Could you describe the serial protocol a little bit more ? So I can try to interface your Arduino code with a PC Processing oscope program.

Keep up the good work !!

This is really a good design. It avoids the timing problems of using a serial packet to trigger the acquisition. The FTDI USB/Serial driver has issues with buffering on the chip side (384 bytes), the driver side (64-4K bytes) and when the buffers are flushed to the application ( 1 msec polled).

Could you describe the serial protocol a little bit more ? So I can try to interface your Arduino code with a PC Processing oscope program.

Lemme try:

--- Serial protocol definition for arduino-oscope --

Arduino and display device (PC) communicate over a serial link, using a
simple packet-oriented protocol. The protocol is the same for both
directions.

Packet description:

+--------------+----------+---------------------+----------+
| Payload Size | Command | Payload | Checksum |
| (2 bytes) | (1 byte) | (0 to payload size) | 1 byte |
+--------------+----------+---------------------+----------+

  • Payload size
  • Size of payload, in big-endian. Can be zero for simple commands (i.e.,
    no payload at all)
  • Command
  • Command or reply. 1 byte long. See list below for supported commands.
  • Payload
  • Variable size payload for this packet. Size is depicted by Payload
    Size. If Payload Size is zero, this field is not present in packet.
  • Checksum
  • Packet checksum, using XOR with 0 as start value. To compute checksum
    for an outgoing packet, XOR all values of the packet except for the
    checksum itself. To validate checksum of a packet, XOR all bytes
    received including checksum. If result is zero, then packet has no
    errors.

Packets received by arduino have a size limit, due to memory size constraints.
Any packet received with size greater than this limit is ignored.

Supported commands (version 1.2):

  • COMMAND_PING 0x3E

Payload size: variable

Request a ping from arduino. Arduino will reply with COMMAND_PONG and
same payload.

  • COMMAND_GET_VERSION 0x40

Payload size: 0

Request arduino oscope version. Arduino will reply with
COMMAND_VERSION_REPLY.

  • COMMAND_START_SAMPLING 0x41

Payload size: 0

Request arduino to start sampling. Arduino will reply with
COMMAND_BUFFER_SEG once sampling is done.

  • COMMAND_SET_TRIGGER 0x42

Payload size: 1

Set trigger level. Payload byte 0 depicts the desired trigger level.

  • COMMAND_SET_HOLDOFF 0x43

Payload size: 1

Set holdoff value. Payload byte 0 depicts the desired holdoff samples.

  • COMMAND_SET_TRIGINVERT 0x44

Payload size: 1

Set invert trigger flag. Payload byte 0 depicts if trigger is not
inverted (a 0 value) or if it is inverted (a 1 value).

  • COMMAND_SET_VREF 0x45

Payload size: 1

Set VREF source for Arduino. Payload byte 0 defines VREF source value.
Values can be 0 (AREF), 1 (AVcc) or 3 (Internal 1.1v).

  • COMMAND_SET_PRESCALER 0x46

Payload size: 1

Set ADC prescaler value. Payload byte 0 defines the log2 of the
desired prescaler value (7 gives prescaler of 128, 6 prescaler of 64,
and so on). Minimum prescaler value is 2.

  • COMMAND_GET_PARAMETERS 0x47

Payload size: 0

Request configured parameters from arduino oscope. Arduino will reply
with COMMAND_PARAMETERS_REPLY

  • COMMAND_VERSION_REPLY 0x80

Payload size: 2

Arduino reply with version. Payload byte 0 depicts upper version,
and byte 1 lower version.

  • COMMAND_BUFFER_SEG 0x81

Payload size: NUM_SAMPLES

Arduino reply with sampled data. Packet size may vary depending on
number of samples configured. This data is unsigned 8-bit (higher
ADC sampled values).

  • COMMAND_PARAMETERS_REPLY 0x87

Payload size: 6

Current configured values. Payload will contain the following values
at byte offset:

0 - Trigger level
1 - Holdoff samples
2 - ADC reference
3 - ACD prescaler
4,5 - Number of samples (NUM_SAMPLES). Big-endian.

  • COMMAND_PONG 0xE3

Payload size: variable

Arduino reply to PING command. Payload is the same as ping request.

  • COMMAND_ERROR 0xFF

Payload size: 0

Arduino reply to some unknown command.

Álvaro

Hi,

I've changed some parameters, like number of samples (which was increased to 962, so we can have a much nicer timebase).

To test the timebase, I added a simple grid to the scope, and a time indicator. I then connected the arduino to a signal generator, with a 1KHz sinewave output. Here are the results for different prescales, and zoom:

Prescaler 128, no zoom:

Prescaler 64, no zoom:

Prescaler 32, zoom 2x:

Prescaler 32, zoom 10x:

Hope you enjoy it.

Questions ?

Álvaro

That's an excellent interface definition. Looks like you are defining an "Arduino/PC Interface Standard". Do you have a standards review process in mind ?

The packet structure is concise and could be used for many things. How about a src/dest field so that a UI could combine data from several independent sources ? Like multiple boards on different USB/Serial channels.

Why big-endian ? Seems like Serial.write(0xDEAD) is little-endian with AD byte sent first followed by DE. Are the AVR 32-bit or ARM processors big-endian?

That's an excellent interface definition. Looks like you are defining an "Arduino/PC Interface Standard". Do you have a standards review process in mind ?

Not actually. But yes, this might be useful for other projects, but I'll have to rethink some smaller parts (like start checksum and maybe reduce size field).

The packet structure is concise and could be used for many things. How about a src/dest field so that a UI could combine data from several independent sources ? Like multiple boards on different USB/Serial channels.

That would only make sense if you were to use a shared transmission medium. Serial links like these one are point to point, so there is no much point on doing that.

Why big-endian ? Seems like Serial.write(0xDEAD) is little-endian with AD byte sent first followed by DE. Are the AVR 32-bit or ARM processors big-endian?

I have actually not tried Serial.write() with larger values than 8 bits. But yes, AVR32 is big-endian, and ARM is bi-endian.

TCP/IP also uses big-endian byte order, so that made more sense to me.

Álvaro

What is max ADC clock speed can I set on arduino boards in Free Running-mode and what would be then the associated bit resolution ?

For ATMEGA328, you need up to 200KHz to get full 10 bit resolution. Higher frequencies only give you 8-bit resolution (no mention about max frequency however). At much higher frequencies we must make sure ADC is still slower converting that we processing the ISR.

What is best method to download then display the fastest sampled stream to a Macintosh with either a duamilanove board or mega board which i'm using in my projects ?

See my post about the protocol I'm using. You don't actually need a faster serial link for this. If you do however need to sample constantly (and that is not what a scope does) you will need some other sort of protocol, maybe with compression, or use a parallel port.

Álvaro

hey Alvaro, the way I understand your project but i could be wrong:

  • free Running-mode ADC totally independent of the way you'll transfer the samples to a computer via USB
  • a specific arduino sketch to capture the ADC samples via ISR management so the samples are stored inside arduino local memory
  • a special fast transfer protocol to send samples from local arduino memory to a computer via USB
  • miror protocol on the computer able to decode protocol then display nicely on the screen a scope like
    so there are 4 distincts modules.

I was asking you about high sampling frequency because my project involves tuning non-linear parametric oscillators via arduino control so I need to have a scope view of a phenomae which is periodic. This means I can have have low ADC resolution and high frequency time synchronize many captures then average mean the samples to increase bits precision by software. Please note this would not be feasible if the visualize scope signal is non-peridoic or rapidly changing shape through short time.

Not easy to explain by mail plus i'm not englihs native. I'm using my arduino as special frequency generator to control different PWM outputs connected to mosfet-drivers and other electro-magnetci components,.... On the other hand, i wish to scope monitor specific voltages from my electro-magnetic oscilator device to perform parametric tuning. This means but i don't know if it is feasible: I need to trigger the free-running ADC on the same phase of my oscillator so then, I can integrate in phase & get more scope sample definition.

  • free Running-mode ADC totally independent of the way you'll transfer the samples to a computer via USB

True

  • a specific arduino sketch to capture the ADC samples via ISR management so the samples are stored inside arduino local memory

True. the ISR also performs trigger and holdoff.

a special fast transfer protocol to send samples from local arduino memory to a computer via USB

Fast and safe.

miror protocol on the computer able to decode protocol then display nicely on the screen a scope like

Yes, protocol is implemented in both Arduino and PC. Code is actually similar.

I was asking you about high sampling frequency because my project involves tuning non-linear parametric oscillators via arduino control so I need to have a scope view of a phenomae which is periodic. This means I can have have low ADC resolution and high frequency time synchronize many captures then average mean the samples to increase bits precision by software. Please note this would not be feasible if the visualize scope signal is non-peridoic or rapidly changing shape through short time.

I wonder if undersampling might help here (see Undersampling - Wikipedia.

Not easy to explain by mail plus i'm not englihs native. I'm using my arduino as special frequency generator to control different PWM outputs connected to mosfet-drivers and other electro-magnetci components,.... On the other hand, i wish to scope monitor specific voltages from my electro-magnetic oscilator device to perform parametric tuning. This means but i don't know if it is feasible: I need to trigger the free-running ADC on the same phase of my oscillator so then, I can integrate in phase & get more scope sample definition.

You can trigger sampling start based on any pin, or you can use the analog comparator for this.

I actually designed this so I can take a look at back-EMF from a motor, driven by two or three half-bridges. I'll let you know my progress.

Álvaro

You can trigger sampling start based on any pin, or you can use the analog comparator for this.

What i'm looking is to arduino internally trigger since my arduino is the frequency generator & the ADC capturer. By software, i know exactly when i'll hit a new period of my generated signal so I would need the ADC to capture N samples from that specific moment.

I actually designed this so I can take a look at back-EMF from a motor, driven by two or three half-bridges. I'll let you know my progress.

Great, my projects involve special management & joule stealing from BMEF spikes.

Is there any chance you can compile your computer code so it can be run on my Macintosh ?

Ok, I did some upgrades to both sketch and UI and this is how it looks right now. Changes are not yet pushed to github.

New features:

  • Single shot (triggered) - nice to observe transients.
  • Freeze/unfreeze.
  • Dual channel (YEAY!). A-B-A-B sampling method with trigger support on channel 0. Will work on full-frame A-B later, A-B-A-B has some drawbacks at low prescale values.

What you can see on this specific screenshot is a triggered sample (frozen) of arduino PWM output set at 190, and a 9.63KHz sinewave generated by my function generator. As 9.63 is slightyly above nyquist frequency [1] (depicted as fMax/chan since we use two channels) you can easily see the aliasing. I'm planning to add windowing functions [2] later to filter this out. I already have a somehow working frequency analiser using FFTW3 also. When it's ready I'll post and upload.

Comments and sugestions ?

selfonlypath: I'm still working to get you a Mac OS X version. Only a small problem yet which should be overcome this week. I'll let you know.

[1] Nyquist frequency - Wikipedia
[2] Window function - Wikipedia

Alvaro -

Is there some way to compile your gtk+ oscilloscope program for Windows ?

Is there some way to compile your gtk+ oscilloscope program for Windows ?

Yes, think so. You'll need some extra DLL to run, but I'll try to build a version for you.

I just have to figure out first how I can access the USB serial device, but should not be very hard.

Álvaro

Ok, my friends.

I have spent weekend mocking up a java version of the scope for you to enjoy. This reminded me how much I hate Java btw :slight_smile:

This is only a preliminary version - it does not yet support all features - only trigger level, holdoff, and dual channel.

Dual channel has a bug - the first one (or two?) samples of the second channel belong to the first channel. This is hard to overcome because there is some latency changing channels and we always trigger on the 1st channel before swithing to second, whose sample only comes 2 ADC cycles later. I'll work on it when I have time.

This should work in Linux, Windows, and MacOS.
You should have arduino java interface installed, you'll need some files from there.

(1) First, download the .jar file and the "run.sh" or "run.bat" script here:

http://www.alvarolopes.com/resources/oscope/

(2) Save them in some folder.

(3) Now, scan your arduino (not sketchbook, the place where it is installed) for a file named "RXTXcomm.jar". Copy this file inside the oscope directory you created on step (3)

(4) Now, depending on your system, you'll need a .so (linux), .dll (windows). This file is named librxtxSerial.so (linux) or rxtxSerial.dll (windows). Copy this file also to folder (2). Not sure about mac here. In doubt, see RXTX homepage (www.rxtx.org).

(5) Connect your arduino and upload the sketch.

(6) Start application by calling "run.sh" or "run.bat". Or alternatively do
java -jar arduino-oscope.jar.

(7) Select serial port from the menu.

(8) Play :slight_smile:

Please send me some feedback and bugs you find. Either here or use email " alvieboy at alvie dot com ".

Álvaro

I have not received any feedback yet, are you able to run it at least ?

Just found some page about a PC oscilloscope that has a number of interesting features:

http://www.accimt.ac.lk/electronics/PC%20based%20Oscilloscope%20-%20Information.pdf

I think most of them are feasible for arduino oscope. What do yout think of it ? And what you think are the most interesting features on that list ?

Álvaro