Picture of Girino - Fast Arduino Oscilloscope
I am a Physicist and the nicest part of working in this field is that I get to build my own instruments. With this way of thinking, I decided to build a homebrew Arduino Oscilloscope. This instructable was written with the purpose of teaching a bit about microcontrollers and data acquisition. This is an extreme project because I wanted to squeeze out from Arduino as much velocity as I could, I have not seen any other Arduino Oscilloscope as fast as this one.

Some time ago I was working on an Arduino project and I needed to see if the output signal was into compliance with the specifics. Thus I spent some time on the internet looking for Arduino Oscilloscopes already implemented, but I did not like what I found. The projects that I found were mostly composed of a Graphical User Interface for the computer written in Processing and a very simple arduino sketch. The sketches were something like:
void setup() {

void loop() {
    int val = analogRead(ANALOG_IN);
This approach is not wrong and I do not want to insult anyone, but this is too slow for me. The serial port is slow and sending every result of an analogRead() through it is a bottleneck.

I have been studying Waveform Digitizers for some time and I know reasonably well how do they work, so I got inspiration from them. These were the starting points of the oscilloscope that I wanted to create:
  • the incoming signal should be decoupled from the arduino to preserve it;
  • with an offset of the signal it is possible to see negative signals;
  • the data should be buffered;
  • a hardware trigger is required to catch the signals;
  • a circular buffer can give the signal shape prior to the trigger (more to follow on this point);
  • using lower lever functions that the standard ones makes the program run faster.

The sketch for the Arduino is attached to this step, along with the schematic of the circuit that I made.

The name that I came up with, Girino, is a frivolous pun in Italian. Giro means rotation and adding the suffix -ino you get a small rotation, but Girino also means tadpole. This way I got a name and a mascot.
Remove these adsRemove these ads by Signing Up
1-40 of 66Next »
Chatanga2 months ago

Hi all,

project is starting to getting old, but, for those still interested in,
I've developed a(nother) small Java GUI frontend to drive the Girino:

It is not in pure Java since there is a native part to deal with the
serial communication, but it is the same as the one used by Arduino.
This way and provided you have a working Arduino IDE on your machine,
you should have no problem to run it on you Linux / Mac / Windows. Take
some time to look at the README file however since there is a lingering
problem with the 'wait duration' settings.

Chatanga Chatanga2 months ago

I’ve released a new version which mostly fixes launching problems on Mac and Windows:

I’ve also tried the optimization described by womai and it has finally allowed me to unlock the x8 and x16 prescalers. Nice! The x4 prescaler is still out of reach, but I don’t think the code could be optimized further.

Sine signal acquired on Mac.png

Hi, I'm trying to use your program to interpret Girino data, which I have already configured properly. It works great!. I'm trying to do a bluetooth signal transmitter, the problem is that the program does not detect my bt receiver port (COM4). How can I solve this? Also, is there a way I can save the read data? Thank you very much for everything, especially for sharing your work, greetings!

PD. English is not my native language sorry if you have trouble understanding me.

Did you tweak the Girino code as stated by Womai? It should allow you
to use the "yellow" sampling frequencies. Regarding your problem with
Bluetooth virtual port, I didn’t have a clue since I’ve never tried to
use one. In theory, it should at least has been been detected by the
RXTX library. As a bluetooth device seems to actually create 2 ports to
communicate (one for reading, another for writing), having it working
without change in the Girinoscope is doubtful...

Thank you very much for your answer!, I will try the fix given by Womai (where do I have to put the code "stopIndex = ADCBUFFERSIZE + 1;"?). Returning to the bluetooth problem, when I try the python code written by Caffeinomane, it works very well and it detected the BT port and I can send data. But when I use your GUI, it only detected one of the two created bluetooth ports, the one that is not reading the Arduino. Also, is there a way I can save the read data using your program? Again, I thank you a lot for taking the time to answer.

**Patch:** at the begining of the sweep (case 's' in the loop function).

**Bluetooth:** try to add the "" option in the startup script.

**Data export:** you can’t but it shouldn’t be hard to implement... You need to capture a single frame or do you have some specific needs?

womai2 years ago
Two ideas to make the code more efficient (run faster):

The calculation

ADCCounter = ( ADCCounter + 1 ) % ADCBUFFERSIZE;

involves an integer division which tends to be time consuming (at least on a Microchip PIC - I do not know Atmel as well). Instead, try

if (++ADCCounter >= ADCBUFFERSIZE) ADCCounter = 0;

Second, you can completely avoid the time required to evaluate


and live without the wait variable if you simply set stopIndex to a value that the counter never reaches, as long as you aren't yet in the post-trigger phase. I.e. during initialization (when starting a new sweep) set

stopIndex = ADCBUFFERSIZE + 1;

and when the trigger event happens then just do as you did so far, but without the boolean wait variable:

// Disable Analog Comparator interrupt
cbi( ACSR,ACIE );

// Turn on errorPin
//digitalWrite( errorPin, HIGH );
sbi( PORTB, PORTB5 );

stopIndex = ( ADCCounter + waitDuration ) % ADCBUFFERSIZE;

and the ADC ISR routine becomes

if (++ADCCounter >= ADCBUFFERSIZE) ADCCounter = 0;

if ( stopIndex == ADCCounter )
cbi( ADCSRA, ADEN );
freeze = true;

Hi there! Do I need to erase the line ADCBuffer[ADCCounter] = ADCH


if (++ADCCounter >= ADCBUFFERSIZE) ADCCounter = 0;

in the ADC ISR routine?

Also, where do I have to put the line "stopIndex = ADCBUFFERSIZE + 1;"?

Thank you very much! Sorry my english!

Jimmus womai2 months ago

I wish I had read this before I did my project. I could only get it to work with a prescaler as low as 4. I wanted to do 2, but it wouldn't respond.

After I had already torn out my test setup and put my project into production, I thought that maybe the ISR was taking too long. I looked at the assembly it created, and I came to the same conclusion that you did, that the integer division was part of the culprit. My solution would have been to set ADCBUFFERSIZE to 1024, which the compiler converted to a simple AND instruction. But I like your solution better. Isn't it funny how we sometimes write code that looks more elegant in C, but using a simple if block (that takes more code in C) actually builds more efficient machine code?

Caffeinomane (author)  womai2 years ago
Thank you very much womai for your precious advices!
This period is very though for me but I am planning to modify the project according to your suggestions.

Hi Guys

I would really like to get this project going as it looks fun and useful! I am getting an error message that I just can't get passed: Change has been rejected for parameter Threshold: 150 =/= 15. Do you know what it means?


Ok, I am passed the last error message but now I get Error 0x5...see picture.

I am running Windows 7 and using an Arduino Duemilanova. Any ideas?




Did you patch your Girino code as stated in the README ( If it the case, choosing a higher value for COMMANDDELAY could solve the problem (the communication protocol is not very elaborated).

Regarding your second problem, maybe you have a lingering java instance using your COM port?

phockney17 days ago

Brilliant guide! Very clear explanations on key concepts, very thorough, and sets a great example on how to go about structuring a project like this.

paul18fr1 month ago

Dear All,

Where can I find a bill of materials to build a girino-scope (I've the pdf file, but I don't want to forget anything) ?

I'm a biginner in electronics, and girino project is an interesting one that allows to learn many things.




I'm a newby in electronics but I'm learning (hobby) ; girino is my first main project and I'm trying to understand the design of the (great) girino scope in order to build my own one ; after reading the different documents and the schematics, I do not fgure out some key point (especially in the double power supply). ...

I think the best thing is to find somebody than has ever built his one girino scope and can explain to me different things (in PM I think)



Essentially, the Girino instructable is about how cleverly program the Arduino to achieve fast data processing. In that respect the supply list sums up to one single Arduino. Of course, another important part of an oscilloscope is the signal processing: offset, gain, impedance, protection... before safely injecting it into an arduino analog 5V pin. On the other hand, if your entry signal is already ok (per instance
if it is the output of another Arduino), you don’t need most it (the only part truly needed is for the threshold signal). To quote the instructable:

The hardware that I added to the Arduino is partly necessary, its purpose is just to form the signal for the ADC and to provide a voltage level for the trigger. If you want, you could send the signal directly to the Arduino and use some voltage reference defined by a voltage divider, or even the 3.3 V given by the Arduino itself.

That being said, an entire instructable dedicated to this "signal adaptation" part would be great!

Regarding the dual supply, It is indicated that the -30/+30 V power supply is meant for the TL084 amp op. If you use the default LM324, the instructable says that you can use the 0/+5V of the arduino own power supply... That’s not quite true. Granted, it will work for small amplitude signal, but with a full amplitude (0-5V), there will be distorsion. I’ve personnaly powered mine with a ATX -12 / +12 V supply and it works fine. Using a pair of 9V batteries should be fine too ( In fact, I don’t even see the point of using the TL084. Granted it is faster than the LM... which is already too fast for the Arduino DAC. I guess there is some reason behind it I don’t understand.

GaryD22 months ago

Great work thanks Chatanga and Caffeinomane. One glitch: the codes for the reference voltage are not correctly aligned between Girino and the GUI. I updated setVoltageReference(... in settings.cpp as follows:

switch (reference)


case 0:




//case 2: correct mismatch with GUI

case 3:





Chatanga GaryD22 months ago

Right! I missed this one. The value used by the Girino is a bit misleading, but I’ve released a new version whose code match the one used by Girino. This new version also introduces some UI refinements with more readable unit increments and the ability to change parameters while waiting for a trigger.

subatomicsushi made it!2 months ago

I built a two-channel standalone version. It features a +/- 12 V input range, adjustable gain, AC or DC coupling, automatic or manual trigger threshold, and the USB port is exposed for serial connection. Excellent project sir!

Jimmus made it!2 months ago

Thank you so much for this. I had tried multiple ways to beg or borrow a recording oscilloscope to debug one of my projects, and it just wasn't working out. Finally I broke down and built this. I was worried that I didn't have the right probe hardware, or that it wouldn't be fast enough, or that it would brick my Arduino somehow. My fears were unfounded--it worked perfectly. I had to modify it slightly to fit my project, but when all was said and done, it told me exactly what I needed.

Data6.svg is the plot (raw data sucked out of the Arduino using the supplied python script, modified, and imported into a spreadsheet and plotted from there) of the original waveform. Prescaler = 4. The project was resetting or hanging my microcontroller when I turned off the relay. The probe is between the output pin on my microcontroller and the ground. Notice the waveform bottoms out at -0.5 volts, which I expect kicks in the protection diodes, and does screwy things to the microcontroller.

I tried several different remedies. Several different capacitors, and two different diodes, and the Girino showed me exactly how each modification affected the waveform. I picked the two components that made it work the best, and used them. Instead of guessing, I could be confident that these were the proper components, with the proper values, and would actually fix the problem.

Data8.svg is the plot with a Schottky diode across the relay coil, and a 1 uF capacitor between the output pin and the ground. The wave still goes negative, but only to about -0.2 volts, and my microcontroller can handle that. My project is now working like a champ!

Again, thank you for your work on this, and for sharing it with the world so that people like me can benefit from it.

acboother2 months ago

Have a look at and see if this is of any use for your PC display. There is a lot of work in buffering the input and multitasking the display code (very different to your Python approach or one using Processing). However this version does not read binary data...

Hello! My professor and I are doing research that requires us to make an inexpensive Multi-channel analyzer. A component of the MCA is the Arduino Uno, which we want to turn into an ADC. The Uno, however, is too slow so we turned to the instructable here for the Sketch that's supposed to increase the frequency at which the Uno reads analog signals. However, when we try to run the code (with minor changes) the serial monitor outputs data that makes no sense. We used Girino.7z. Here are the changes we made;

* When we download the Girino code and turn on debugging (by setting DEBUG=1 in Girino.h), we get the expected output:


# setup()

Girino ready

# ADCCounter: 0

# stopIndex: 65535

# wait: 0

# freeze: 0



# ADCCounter: 0

# stopIndex: 65535

# wait: 0

# freeze: 0



// repeats


* However if I add a single print statement in the setup() function, then that print statement is repeatedly executed (strange) and the output is garbled.


void setup ()



Serial.println("Girino ready");

Serial.println(" X1 We're outside the loop!! XD"); //This is the line we added.




Here is our output;


Girino ready

X# setup()

Girino# setup()

Girino : etup(# setup()

Girino read# setup()

Girino# setup()


Girino #######....//pounds forever.


So as you can see the setup is printed repeatedly which should only happen once.

Any help is appreciated.

here are my system & software specs:

MacBook Pro, 12-inch, Early 2011

Processor 2.3 GHz Intel Core i5

Memory 4 GB 1333 MHz DDR3

Graphics Intel HD Graphics 3000 384 MB

We are using Arduino Uno SMD edition, software version 1.0.5

Software OS X 10.9.3 (13D65)


hitchcme made it!6 months ago

I Made it, modified it, couple transformers inside an Iomega hard drive enclosure, home etched shield, working with a mega 2650, and..... here's a labview student edition interface, and an XCode Cocoa OpenGL interface =>still in progress. it could be called the Cocoa-O-O-G-G-L-Scope or I don't know. ta da!!!!

hitchcme hitchcme6 months ago

If one was working with a Windows machine, it is possible to just copy side by side everything, recreating everything as if you had done it yourself, which... I am happy to share!

hitchcme hitchcme6 months ago

I meant a windows machine with LabView.

Kerveros7 months ago

Hello, this is nice work, i have a question, have you full schematics?

snoop9118 months ago

What are your thoughts on displaying the data? Any front-end GUI you like? There seems to be so many open source options for developing GUIs ( Juice, GTK+, wxWidgets, Feathers UI, Chico UI/JQuery, etc)... example, the PulseView logic analyzer software uses sigrok/qt.

On the backend, is the serial protocol to talk to the frontend much different than firmata? Hopefully it's a serial protocol that it's easily ported to any microcontroller with a uart!

arthujt1 year ago
Any help please?
The Huntron(octopus circuit) has been a staple on most test benchs for years(me? >40years)It uses a a transformer to cause a 60hz signal and when fed thru a three resistor network, (google: octopus circuit),then is applied to X,Y (horizontal,vertical direct inputs.) This allows the pinpointing of discrete or IC defects or damaged devices,including resistors,and capacitors.This saves alot of time troubleshooting as the circuit can be tested dead. And the device doesnt have to be unsoldered(incircuit)
I looked at some android apps , and no XY functions. Can you take the timeframing out of the picture and compare two inputs directly to each other ? If you generate a pwm(60hz)send it out and return thru another input, the result can be compared to an internal (60hz) and displayed in a horizontal vs vertical scene., just place the resistors inbetween and some wiring to test devices with and you eliminate the outside source. Or just run two inputs and use the outside coil(transformer)to gen the 60hz.
kooth1 year ago
Awesome Instructables! Very well done!
ivansouza1 year ago
Nice Work!!! Maybe this could help you in this great project...
Wow, excellently well explained Christiano--I feel I've already learned so much just reading through this in the library, and I haven't even started building! It really ties together the material I'm learning in EE, in a tangible & actionable manner. Keep up the good work!
dinoi1 year ago
Great work, but I have troubles to get it run. Could you please explain the Hardware mapping on your schematic:

ADC:1 is Analog 0 on Arduino,
PWM:1 is Analog3

but where to go with AnalogComparator:1 and Threshold:1?

Thanks a lot
I did something similar, I sent out sensor values to serial port in csv formate, I used GTK term, and logged the data in a file, that file was read at the same time by KST (an awesome plotting software) to plot the data. It has a good gui and many other options, I'm trying to make a plugin for kst that will make this process simple.
Nanico1 year ago
Can you explain how to use dual channel? What is the best way to switch from 1 ch to other
Caffeinomane (author)  Nanico1 year ago
Well if you want to use two channels at the same time the acquisition rate will go down, probably more than a factor of 2.
Given that the Arduino has only one ADC you must alternatively feed to the ADC your signals. This means that you have to use the multiplexer (see step 8). At each iteration you have to:
- Read Ch 1 with the ADC
- Switch to Ch 2
- Read Ch 2
- Switch back to Ch 1
Plus doubling the number of channels you halve the amount of available memory, because you have to store two numbers at each iteration.
konsumer1 year ago
Very informative. I am the maker of arduinoscope, which is one of the Processing scopes you mentioned. Although, the original goal of that project was to make it extremely accessible to non-tech people (I used it for teaching electronics and hardware hacking.) I think we could add some of these features to that project (especially the Arduino firmware.) I don't really like Processing (or java, which arduinoscope is written in) and would be happy to switch to something else, if it could remain fairly easy for a non-programmer/electronics newb to get their hands on and modify. I started work on node.js to make a simple GUI, but Python also seems like a good candidate. I have moved the simple serial Arduino backend (sort of similar to the code pointed out, but you are exaggerating a bit, at least in my case) to use Firmata, to get myself out of the business of maintaining the firmware, and introduce new users to the awesome Firmata library. I'd be happy to move to a more performant Arduino firmware, especially if you want to maintain that part, and offer your Girino as a "fancy" version, in terms of hardware. Do you have speed stats? How much of this can be done without adding custom hardware, so people can do it all in soft/firmware?
Caffeinomane (author)  konsumer1 year ago
Thank you for your offer! Right now I am in the middle of the writing of a thesis, so I can not dedicate time on this project. When I am done with this thesis I will surely contact you to start this collaboration.
MGreatwolf1 year ago
I am somewhat new to this so forgive the question. I was reviewing your code and found the following line in it:
ADMUX |= ( ADCPIN & 0x07 );
unfortunately I am unable to locate ADCPIN in the datasheet or any of the source files provided by the Arduino developers. I like your solution and would like to dig into it a little deeper. Could you please provide some additional detail regarding ADCPIN? What it refers to and so on...Thanks for what appears to be a lot of work documenting this instructable.
1-40 of 66Next »