Data acquisition over USB based on an ATTiny: review

easylogger_sceenshotData acquisition peripherals for computers make a lot of science experiments easier and open up new ways of automation. In other words, they’re fun. I’ve recently come across a really cool AVR project done by Jacques Lepot, The cheapest dual trace scope in the galaxy, and I felt that I need to build one. Although his original blog post lacks quite some details, reading the comments and doing a bit of research revealed most of them. Here I’d like to present a collection of links with the key information which helps in debugging, and also provide a new software on the PC side to collect data (supporting Windows 7, unlike the one presented in the original post). As others already noted, calling it an o’scope is a slight exaggeration. According to my experience, one can get a sampling rate of ~60 Hz, which makes it a decent DC acquisition device. The internal analog-to-digital converter of the microcontroller is much faster than that, but all the USB communication is implemented in the firmware (see the V-USB project) rendering the data acquisition much slower. An issue many people faced is the USB voltage level problem: after plugging the device into the USB port, the LED lits up for a second then it goes dark. It’s discussed in the comments, but on the V-USB wiki there is a nice summary with solutions. The original schematic included two 3.6 V Zener diodes for this reason. I used two 1N4448 diodes in series with the +5 V of the USB port providing a voltage drop of 1.45 V (solution A, quick and dirty version). It works just fine with my desktop PC and my notebook too, however, please note that this solution is not advised since we want to use the ADC of the microcontroller. The C source of the firmware and the .hex file are provided in the blog post, and it is also emphasized to set the system clock to use the internal high frequency PLL clock by writing the proper fuses (crucial for the USB timing). Here is an excerpt from the Makefile explaining the fuse settings (apparently a lot of code is inherited from the Easylogger example project).

# Fuse high byte:
# 0xdd = 1 1 0 1   1 1 0 1
#        ^ ^ ^ ^   ^ \-+-/
#        | | | |   |   +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V)
#        | | | |   +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved)
#        | | | +-------------- WDTON (watchdog timer always on -> disable)
#        | | +---------------- SPIEN (enable serial programming -> enabled)
#        | +------------------ DWEN (debug wire enable)
#        +-------------------- RSTDISBL (disable external reset -> enabled)
# Fuse low byte:
# 0xe1 = 1 1 1 0   0 0 0 1
#        ^ ^ \+/   \--+--/
#        | |  |       +------- CKSEL 3..0 (clock selection -> HF PLL)
#        | |  +--------------- SUT 1..0 (BOD enabled, fast rising power)
#        | +------------------ CKOUT (clock output on CKOUT pin -> disabled)
#        +-------------------- CKDIV8 (divide clock by 8 -> don't divide)

An other important fuse setting is the reset disabling. It makes it possible to use the reset pin as a GPIO, but after that the ATTiny cannot be programmed over ISP, you will need a high voltage parallel or serial programmer for that (like the fuse doctor, or you can use an Arduino as well). My host software Although the project contains a host program written in C#, I was motivated to write a new data acquisition software for the PC because of two reasons: I have Windows 7 running on my notebook which is not supported by original host program and I wanted to write the measured data to file for later processing. I wrote the new software too in C#, I chose the LibUsbDotNet library for the USB communication and ZedGraph for plotting. The latter one provides a very useful export option of the graph. Using libusb has one disadvantage, namely, one has to install a driver for the hardware which causes the device to disappear from the USB HID list in the device manager, making it unusable with the original host software. The driver can be created with the inf_wizard.exe found in the lib-usb-win32 package. After installing it, a new group will appear containing our hardware. easylogger_devmngnt Here is a screenshot of the program. Around t=4 s I applied +5 V to the Ch1, making it go to saturation, after ~2 s I let it float, then I repeated the same to the other channel. You can see that the signals saturated both times around 2.56 V which is the internal reference of the ADC. The datasheet of the ATTiny45 says that this value is somewhere between 2.3 and 2.8 V, therefore it’s reasonable to calibrate the device. easylogger_sceenshot

It’s a bit weird, but seemingly there is a crosstalk between the channels. When I applied the voltage only to the Ch1, the Ch2 also raised up to the same value. The other way around, when I put the input on Ch2, a small voltage appeared on Ch1 as well. However, this crosstalk if not visible when the other channel is not floating.

An exponential function fits really nicely to the decay on Ch2 around t=11 s with a time constant of ~0,2 s. It’s coming from the 10 nF filter capacitors on the inputs (the crosstalk seems to be unrelated to them).

I took the relevant part of USB handling from the original project. The related objects definitions and functions:

        public static UsbDeviceFinder MyUsbFinder = new UsbDeviceFinder(0x4242, 0x2);
        public static UsbDevice MyUsbDevice;

Then in the InitUSB() function the basic configuration takes place:

        private void InitUSB()
            // the code below is based on the example code provided on the LibUsbDotNet website

            MyUsbDevice = UsbDevice.OpenUsbDevice(MyUsbFinder);

            if (MyUsbDevice == null)
                throw new Exception("Device Not Found.");

                toolStripStatusLabel1.Text = "Device found";

            // If this is a "whole" usb device (libusb-win32, linux libusb-1.0)
            // it exposes an IUsbDevice interface. If not (WinUSB) the
            // 'wholeUsbDevice' variable will be null indicating this is
            // an interface of a device; it does not require or support
            // configuration and interface selection.
            IUsbDevice wholeUsbDevice = MyUsbDevice as IUsbDevice;
            if (!ReferenceEquals(wholeUsbDevice, null))
                // This is a "whole" USB device. Before it can be used,
                // the desired configuration and interface must be selected.

                // Select config #1

                // Claim interface #0.

            // open read endpoint 1.
            reader = MyUsbDevice.OpenEndpointReader(ReadEndpointID.Ep01);

            reader.DataReceived += (OnRxEndPointData);
            reader.DataReceivedEnabled = true;


In the last few lines we added an event function for handling the received data. In this function we convert the raw integer value of the ADC to a floating point number (note that the number 0.009988f is a factor of calibration which I found for my specific device to yield a more precise value). After that we just plot the new data point. As the USB device is spitting out data as fast as it can, this code keeps up with plotting on the PC.

        private void OnRxEndPointData(object sender, EndpointDataEventArgs e)

            double captureval1 = ((int)(e.Buffer[0] * 256 + e.Buffer[1]) * .0009988f);
            double captureval2 = ((int)(e.Buffer[2] * 256 + e.Buffer[3]) * .0009988f);

            MeasTime = DateTime.Now;

            ElapsedTime = MeasTime - StartTime;
            AddPoint(ElapsedTime.TotalMilliseconds * 0.001, captureval1, captureval2);

A more mature project

A very similar, but much more mature project is the IViny Compact Data Acquisition Device. As you see on the picture, they even 3D printed a case for the electronics. The host sofware is written in Python, it has a nice GTK GUI, the plotting is done using Cairo. Github links:

Unlike the previous project, it is based on ATTiny85 (not ATTiny45).

Little Wire

Let’s not forget about the Little Wire, which is not just a data acquisition device, but a swiss army knife for microcontroller programming and messing around with electronics. It is an usbtinyisp compatible AVR programmer (essentially this is why I built one in the first place), an ADC, ISP/I2C/1-wire interface with 4 GPIO/2 PWM output. Not at the same time, of course, but it’s pretty neat for an IC with 8 pins. The overcome the reset pin disabling issue, it’s recommended to burn the bootloader first, the webpage has instructions for using micronucleus.  Regarding the PC side software, there are some plain C example programs on the GitHub repo, and there is a Ruby library as well.

Here is my build on a breadboard. Instead of the 1N4448 diodes in series, I used 3.6 V Zener diodes here. I added the electrolytic capacitor later, after having issues many times when connecting circuits with AVR microcontrollers for in-system programming. I haven’t had similar problems since that. The other end of the flat ribbon cable is a standard AVR ISP programming header. I shortly played a bit once with controlling a servo, it worked nicely, but didn’t have luck with the I2C interface. I believe the problem was that the I2C device (a thermometer) was sensitive for sending/not sending acknowledgments in its protocol.



In an nutshell, I recommend building the Little Wire for general purposes, but if your interest is data acqusition only, go for the iviny project.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s