Code and Life

Programming, electronics and other cool tech stuff

Supported by

Supported by Picotech

Super Simple 50+ kHz Logic Analysis with ATtiny2313 and FTDI Friend

AVR & FTDI logic analyzer

While banging my head against the wall with debugging my PS/2 keyboard thingy, I really wished I had a dedicated logic analyzer (preferably with PS/2 decoder, but even raw binary data would’ve been fine). So I decided to try out a long hatched idea – combine an ATtiny2313 and FTDI for some unlimited-length logic capturing with a PC. You’ll only need:

  1. ATtiny2313
  2. 20 MHz crystal and caps (slower will also work, frequency just defines what baud rates you’ll achieve)
  3. FTDI USB/serial converter, like the FTDI friend from Adafruit
  4. Optionally, some power-stabilizing capacitors, reset pullup and ISP programming header for flashing the firmware

ATtiny2313 is ideal for this, as it has all eight port B pins on one side in numerical order – attaching up to 8 logic lines is really straightforward. With 20 MHz crystal, baud rates close to 1 Mbps can be achieved in fast serial mode. I used Adafruit’s FTDI Friend for really simple (and way faster than most cheap serial adapter dongles) serial to USB conversion – just connect ATtiny RXD pin to TX, and TXD to RX, and you can even get power from the Friend so you’re all set! For crystal and that other stuff, see my ATtiny2313 breadboard header post for schematic, the picture above should fill you in with the rest.

Firmware code

This device has some of the smallest firmware codebases ever (firmware is 128 bytes). All we need to do is to set up UART with desired speed, and have the AVR chip to fire up an interrupt whenever data has been sent, and then use that to send current state of port B (using PINB):


#include <avr/io.h>
#include <avr/interrupt.h>

void USARTInit(unsigned int ubrr_value, uint8_t x2, uint8_t stopbits) { 
  // Set baud rate
  UBRRL = ubrr_value & 255; 
  UBRRH = ubrr_value >> 8;

  // Frame Format: asynchronous, 8 data bits, no parity, 1/2 stop bits
  UCSRC = _BV(UCSZ1) | _BV(UCSZ0);
  if(stopbits == 2) UCSRC |= _BV(USBS);

  if(x2) UCSRA = _BV(U2X); // 2x

  // USART Data Register Empty Interrupt Enable
  UCSRB = _BV(UDRIE);

  // Enable The receiver and transmitter
  UCSRB |= _BV(RXEN) | _BV(TXEN);
}

int main() {
  // 230.4 kbps, 8 data bits, no parity, 2 stop bits
  USARTInit(10, 1, 2); // replace 10 with 4 to get 0.5 Mbps

  sei(); // enable interrupts

  while(1) {}
	
  return 1;
}

ISR(USART_UDRE_vect) {
  UDR = PINB;
}

If you’re not connecting all PORTB pins, you can enable pullups in the beginning of main(). For example, PORTB = 0b11111000; would only leave PB0-PB2 without pullups, so you don’t need to ground PB3-PB7 (which would also wreak havoc with ISP programming). However, should you decide to do that, be sure you don’t wire those pins to anything that might not like pullups!

PC side software

Putty serial settings

Using Putty, you can just connect to FTDI friend – select “Serial” as connection type and define detailed settings in the Serial category, and turn on logging for all packets. Then you just open the connection when you want to start capture, and close Putty when you’re done.

Another alternative is Realterm or similar terminal program. It has the option of suppressing output to terminal window, which might prove less irritating, and may help you achieve higher speeds. On *nix systems and Mac OS X, it’s possible to use screen with logging to achieve similar results (google is your friend).

Putty settings

Once you have the data captured, you can use hex editor like HxD to view it. Converting raw binary capture data to OLS format is one nice idea, as you can use Sigrok, OpenSniffer or SUMP to view it. Here’s a simple command-line C program for PC (you’ll need MinGW or similar to compile it) to convert a binary capture find to OLS format:


#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
  FILE *in;
  long size;
  int num, lastNum, pos, count, mask = 0xFF;

  if(argc < 2) {
    puts("Usage: bin2ols input.bin [hex mask] > output.ols ");
    return 1;
  }

  if(argc > 2)
    sscanf(argv[2], "%X", &mask);

  in = fopen(argv[1], "rb");

  if(in == NULL) {
    printf("Couldn't open %s!\\n", argv[1]);
    return 1;
  }

  printf(";Rate: 10000\\n");
  printf(";Channels: 8\\n");
  printf(";EnabledChannels: %d\\n", mask);

  lastNum = fgetc(in) & mask; 
  count = 1;
  pos = 1;

  while((num = fgetc(in)) != EOF) {
    num &= mask;

    if(lastNum != num) {
      if(lastNum != -1)
        printf("%02x@%d\\n", lastNum, pos);

      lastNum = num;
      pos += count;
      count = 1;
    } else count++;
  }

  printf("%02x@%d\\n", lastNum, pos);

  fclose(in);

  return 0;
}

Logic analyzer in action

To see if everything works more or less as it should, I connected Bus Pirate to DS1307 realtime clock and used the combo to retrieve time over two-channel I2C connection – I actually followed the instructions in my own post so it was pretty easy. :) After capturing the data with Putty, and converting to OLS, I was able to open the file in OpenSniffer, and was very delighted to see I2C traffic to appear:

OpenSniffer I2C

I tried to use OpenSniffer for protocol decoding the contents of the I2C messages, but unfortunately it got lost with two I2C start messages without a stop before the second. So I had to verify the communications with a commercial analyzer (Saleae Logic to be exact, I got one recently and will feature that quite soon here) — its software handled the same communications and protocol decryption without a hitch – and as you can see, the waveforms match nicely with the output from the DIY analyzer:

Saleae Logic analysis

Conclusions and Caveats

I’d rate this DIY logic analyzer a definite success in my books. The parts cost something like $25 and with a PC, the capture length is virtually unlimited. With right combination of software (see below), capture rates close to 100 kHz (1+ Mbps serial data) can be achieved. However, I found out the hard way that FTDI friend and PC or Mac software isn’t very reliable for achieving maximum speed captures:

  • I could find no simple, free piece of software that would just dump raw data from serial port to binary file. Either the program was non-free, didn’t support non-standard baud rates, or had some other issues
  • Putty with console logging is quite nice, but suppressing output to terminal is not possible, and with binary data and close to 1 Mbps, pieces of data started to drop out (could also be something with FTDI drivers). Also, Putty adds a header to log file, so you need an hex editor like HxD to remove that before analysis
  • Realterm could suppress output, but only dumps ascii hex which needs to be processed to get binary. Also, it seemed to have weird problems from time to time, and the UI really shows its age.
  • On Mac, I couldn’t reliably capture anything faster than 115.2 kbps with virtual serial port drivers. However, with D2XX drivers for FTDI did work quite nicely for higher rates, but you then have to forego the virtual serial port, as the drivers are not mutually compatible.
  • Most higher bitrates require two stop bits so the serial decoding has more of a chance to understand where the byte boundaries lie in continuous data transfer.

I also regret to note that Sigrok, for which I had high hopes in this project, failed miserably, as there are currently no easy installation options for Windows or OS X. I even tried to set up a Linux virtual machine, but it proved suprisingly hard to get modern Mint and Debian distributions to install on Virtualbox (at that point I didn’t have hours to spare for debugging). Come one Sigrok guys, could you do an installer even without hardware device support for analyzing OLS files?

The biggest limitation of this setup is the capture rate – for example, the PS/2 project communicates at 12.5 kHz, which means that to get even semi-accurate visibility to data level transitions during one clock cycle, capture rate should be at least 100 kHz (which would mean average of 4 samples for logic high and low each). This is at the maximum limit of FTDI/AVR combo, as there are 10 bits of information to send (8 data + 2 stop bits) for each byte.

18 comments

tz:

For fewer channels but higher speed:

https://github.com/tz1/partsbox/tree/master/pulserial

With the seeeduino, you can use all four ICPs – I have code somewhere but not on github.

This uses the ICP – there’s one on the ATtiny2313 – I use a 4313 to do J1850 bus decoding which is a pulse stream and V1 radar detector stuff.

You can have the ICP interrupt switch polarity sensitivity, but that will require the pulses be of minimum width. Yet you can get 2 channels on an normal Mega, 4 on a Seeed. If you parallel them, you can measure pulses down to the frequency you use.

The 2313/4313 and the FTDI can work at 2 or 3 megabaud (with the right crystals – the FTDI uses 48MHz as the prescaler), so if you want to tweak the code, you can go down to 500nS or 333nS. I’m not sure about Windows but my Linux netbook could handle it. (one of the other GitHub projects used an ATtiny85 to read I2C peripherals and send the data up).

Uwe Hermann:

Hi, I’m one of the sigrok developers. We’ve recently added (highly experimental) Windows installers for sigrok-cli and PulseView indeed: http://sigrok.org/download/binary/

However, there are various portability issues that still need to be fixed until the programs become usable in practice. You can use the PulseView installer with a very limited number of hardware devices already (see http://sigrok.org/wiki/Windows; ols is not on the list yet, though). Loading any previously saved *.sr files works fine too (other formats are not yet supported though, that’s work in progress).

Anyway, Windows support is lagging behind a bit, mostly due to the fact that lots of people want it, but only very few actually contribute to make it happen.

As for Mac OS X packages, not sure we’ll provide those directly, that’s probably better left to Macports/Fink/Homebrew/whatever developers to integrate. Shouldn’t be a big problem though, sigrok compiles and works just fine on Mac, we’re not aware of major portability issues there.

Cheers, Uwe.

Gerritv:

Did you try HyperSerialPort (http://www.hyperserialport.com/)? It can write to file. And to convert Ascii to bin, I use https://code.google.com/p/binasc/wiki/mainpage

Gerrit

serial:

I’m using “socat” for dumping binary data from serial to file all the time. Works great for me. No GUI though. ;-)

suki:

Isn’t dumping raw data from a com port to a file just
type com1: >> data.log
on the commandprompt in windows?

Joonas Pihlajamaa:

I think COM port settings need to be set somewhere first, and you cannot do special/high bitrates with stock COM port settings. It might work if that can be solved, but dedicated program with those settings is a bit nicer.

Joonas Pihlajamaa:

Thanks for the reply! I was a bit confused when I went to the Windows portion of Sigrok, as I didn’t quite understand what this PulseView is and how it is related to Sigrok. Couldn’t it just be Sigrok PulseView or even Sigrok Viewer?

Joonas Pihlajamaa:

Thanks for the comment! I didn’t know about the input capture unit (ICP) of AVR chips, seems like you can measure changes in the scale of MCU frequency.

However, continuous capture is still limited by output UART baud rate. Short bursts can be captured with ICP (or even the main() method inner loop), but AVR quickly runs out of memory if UART cannot empty the buffer fast enough. :-d

Raspberry Pi with 512 MB RAM running RTOS would be nice for this. :)

Joonas Pihlajamaa:

Thanks for the tip, I’ll try that out, too!

Wavetrain:

Very interesting article Joonas.

With a 16Mhz crystal and your code with: USARTInit(0, 1, 2);

Then a baud rate of 2Mbps is obtained according to the atTiny2313 datasheet unless I am mistaken?

I have now ordered a FTDI breakout board. If I am able to achieve 2Mbps on the PC with Linux or XP, I will post back in a few weeks time.

Joonas Pihlajamaa:

Yes, I think that is correct. I had trouble achieving 1 Mbps on OS X and Win7, but I have to admit the software I tried was just horrible (HyperTerminal must be from Windows 2.0 era :).

Thanks for your post, I’m eagerly waiting for your results!

miky:

I can’t wait the result.
I’m also looking to build my own logic analyser.

Wavetrain:

The FTDI breakout has arrived, but I also ordered, and have received a Saleae Logic clone for a few dollars. Since the latter works with the Sigrok software (and also the Saleae software) and is much faster than the atTiny2313 can be, I have not so far felt inclined to test Joonas’ software to see if 2Mbps can be achieved.

When I do the tests on the 2313 later this year, using the Saleae Logic Clone to check the results… ;) , I will report my findings.

Ralph:

If you set UCSZ = 000, you’ll only send 5 data bits (more than enough for i2c or SPI). That would get your sample rate up to ~140kHz using a 1Mbps UART speed.
If you write a small program on the PC side top log and timestamp the data, then you could increase your sampling resolution by sending only deltas.

Ralph:

p.s. the PL2303 USB-TTL adapters are a lot cheaper (~$1 ea) than FTDI. They won’t do >1Mmbps, but will handle 921.6kbps.

Ralph Doncaster:

The mode command (at least in Windows 7) supports high baud rates.

>mode com15: BAUD=3000000
Status for device COM15:
————————
Baud: 3000000
Parity: Even
Data Bits: 7
Stop Bits: 1
Timeout: OFF
XON/XOFF: OFF
CTS handshaking: OFF
DSR handshaking: OFF
DSR sensitivity: OFF
DTR circuit: ON
RTS circuit: ON

You can output data with:
copy data.bin \\.\com15:

However I can’t get it to capture the data from the com port when it is a high port number.

>copy \\.\com15: com15.log
The parameter is incorrect.

Ralph Doncaster:

I figured out they will do >1mbps – they just have a problem with exactly 1000000bps.
The only baud rates they seem to support >1M are:
1228.8k, 2457.6k, 3M, 6M

Ralph Doncaster:

I did the same kind of thing, but with a 6mbps baud rate so I can sample 2 channels 2.4 million times/sec.
http://nerdralph.blogspot.ca/2014/05/24-megasamples-per-second-continuous.html