/var/log/andrey     About     Archive     Feed

Talking to the Saleae Logic16

I’m tracking down a few issues at work that require automating a logic analyzer, in this case the task is as simple as monitoring a SPI bus and looking for particular patterns. The Saleae Logic16 is a decent low-cost USB logic analyzer that can sample a four channels at 50MHz and provides a C++ API that enables you to write a custom application.

I went ahead and downloaded their API (version 1.1.14 in this case),

wget http://downloads.saleae.com/SDK/SaleaeDeviceSdk-1.1.14.zip
unzip SaleaeDeviceSdk-1.1.14.zip
cd SaleaeDeviceSdk-1.1.14

This provides a 32-bit and 64-bit library in ./lib as well as one header file in ./include. Saleae provides an example program in ./source but no Makefile (I don’t think they know how to write one, instead they provide a Python script that tries to call g++ directly, quite a mess).

“Installing” the SDK

Let’s write an application to talk to this analyzer. First copy the library and header file and run “ldconfig” to let the system know about the former:

sudo cp lib/*.so /usr/local/lib
sudo ldconfig
sudo cp include/SaleaeDeviceApi.h /usr/local/include

Makefile

Now change to a directory where you’ll develop your application and create a proper Makefile. Here’s my simple one that builds main.cpp and links against Saleae’s library:

APP = analyzer
PREFIX ?= /usr/local
CXXFLAGS += -std=c++11 -fpic -g -Wall

ifeq ($(shell uname -m),x86_64)
LDFLAGS += -lSaleaeDevice64
else
LDFLAGS += -lSaleaeDevice
endif

SRCS = main.cpp

OBJS = $(patsubst %.cpp,%.o,$(SRCS))

%.o: %.cpp
  g++ $(CXXFLAGS) -c $< -o $@

$(APP): $(OBJS)
  g++ $^ $(LDFLAGS) -o $@

install: $(APP)
  install -d $(PREFIX)/bin
  install $< $(PREFIX)/bin/$<

clean:
  @rm -f $(OBJS) $(APP)

.PHONY: install clean

Application

To use the Logic16, your C++ application simply needs to:

I tried implementing the worker thread using pthread (pass -pthread as one of the CFLAGS if you want to do that) and then used the “new” C++11 std::thread in its place, either way works fine. You can use std::queue or std::list or some other approach to buffer up data for the worker thread but whatever you choose should be thread-safe since you’re dealing with an asynchronous producer and a consumer who are using the same queue. pthread provides mutexes and semaphores for this and C++11 includes several concurrency schemes.

The Saleae API is a bit crufty and misses some common best practices but is otherwise functional and well-documented in its header file. I would like to mention a few things:

Of course with this “raw” API, you’re responsible for making sense of the data, “triggering”, and so on. You can implement that with a fairly simple state machine (for example, look for ENABLE and SCK transitions for SPI), just be sure to sample your data bits at the right time based on the bus in question and its configuration – for instance a SPI bus may be used in such a way that data is available on the falling edge of SCK and sampled on the rising edge.

comments powered by Disqus