Logic analyzers are used to record and analyze digital communication signals. They work in a similar manner to an Oscilloscope, but the data is processed and displayed with additional data that is calculated by the software to help with this analysis. With the Analog Discovery 2 and Waveforms 2015, you can record and decipher most types of digital communication signals.

For this Instructable you will need:

-chipKIT microcontroller

-Arduino IDE with chipKIT core installed

- Pmod with serial communication. This could be SPI, UART, or I2C. I will be using the Pmod CLS, a 2X16 LCD display.

- USB cable

-Analog Discovery 2*

-Waveforms 2015 software

- a computer with USB port to run the software

*You may also use the original Analog Discovery or the Electronics Explorer Board with Waveforms 2015. There are some slight differences in functionality between the AD1, AD2, and EEBoard, but nothing that will prevent you from following along if you have one of the other tools.

Step 1: The Logic Analyzer

If you want some help getting your AD2 set up and calibrated, or installing Waveforms 2015, check out this quick start I'ble collection.

Once you have your AD2 and Waveforms 2015 all set up, open the Logic Analyzer by clicking on the "Logic" button.

This will open the Logic Analyzer window.

Along the top you'll see the "File", "Control", "View", and "Window" options.

Under "File" you'll see several options.

You can add a new instance of the logic analyzer, either by cloning the current analyzer settings or opening an empty instance with default settings. You can also "Save" the current logic analyzer settings, or "Open" a previously saved project. "Export" lets you save the current logic analyzer plot data, either as an image of the window in most common formats, e.g. *.bmp, *.jpg, *.tif, etc., or as a data file with the plot window information in either *.csv, *.txt, or *.tdms formats. "Close Logic" will close the logic analyzer window. This will not clear the current settings as long as you don't close Waveforms 2015 completely. Just click on the "Logic" button again and the window will pop back open with all of the same settings.

Under "Control", you have access to the tool's Single, Run, and Stop acquisition commands.

"View" opens different windows to let you view and analyze the captured data.

"Data" shows a table with 2048 data samples from the current plot. Changing the plot Base value in the upper right corner will change the amount of time between data samples, but the tool will automatically divide the plot into 2048 samples and record the data in this table.

"Events" displays a table of all state change events currently view-able in the plot window. Options are available to change between different signals or busses under observation and to filter results based on various conditions.

"Logging" allows you to export the data as a .csv file. Several options are available for choosing when to save the file, which acquisition is exported, and what data within each acquisition is saved.

"Cursors" allows you to add cursors to the plot window much like you can for several other Waveforms tools. You can make the cursors independent of each other, or link them together so that changing one cursor changes all of its dependent cursors.

"Window" lets you switch between the Help window, the Waveforms 2015 welcome window, or any tool windows currently open.

Next you'll see the logic analyzer controls.

"Single" allows you to capture one window worth of data. To capture more data, adjust the time base of the plot window.

"Run" will start the tool for continuous acquisition. This button becomes "Stop" once the tool is running.

The "Mode" box lets you change how the data is displayed in the plot window, either one full plot at a time, real-time that wraps around once the end is reached, real-time side-scrolling, or you can record data. The example project will utilize the record function, so stay tuned for that.

The Logic Analyzer uses the computer memory to store past data acquisitions in a buffer. keeps a running tally of which buffer you are currently using. Clicking lets you save the currently shown acquisition data to a new tab. The name of the tab can be edited by double clicking the tab header.

You can trigger the Logic Analyzer several different ways by clicking the "Trigger" box.

"Auto" is selected by default. The tool will wait approximately 2 seconds once started. If no trigger is detected, acquisition will start automatically. "Normal" will place the tool in "Armed" mode once started. The tool will wait indefinitely for the determined trigger condition, at which point acquisition begins. "None" will ignore trigger settings and immediately start acquiring data once the tool is started.

You can set the source of your trigger by clicking the "Source" box.

"Digital", "Scope", "Wavegen 1", "Wavegen 2", and "Patterns" refer to the Static I/O, Oscilloscope, Waveform Generator, and Pattern Generator tools of the AD2. "Manual" refers to the button at the bottom left of the Waveforms window. "External 1" and "External 2" correspond to the trigger pins T1 and T2, respectively, on the AD2's 30-pin header and allow you to connect any other external trigger source you wish.

Clicking opens the pulse configuration window. It is not recommended you use the Pulse or Advanced windows if you can avoid it. Protocol specific trigger "wizards" are available from the grid setting options, which are covered in the next step.

The "Glitch" tab is selected by default and triggers the acquisition when a signal pulse shorter than the specified time is registered.

"Timeout" triggers the acquisition when a signal pulse longer than the specified time is registered.

"Length" triggers the acquisition when a signal pulse of exact length with the given hysteresis is registered.

"Counter" looks for a set number of specified edges before starting acquisition.

The button opens a window for advanced trigger settings.

Each protocol has its own specific trigger wizard, which are covered in the next steps relating to each protocol. Since the wizards will configure the advanced options as needed, it is recommended that the wizards are utilized to set advanced options.

In order to adjust or apply an advanced options, you will need to have added a channel to the grid. I will go over that in the next step. Also be sure that is checked. Clicking will clear all settings to default, including unchecking .

Click the "Reset Condition" to set the trigger reset conditions for the tool.

Your choices will appear in the grid in the "R" column. Once you click you will also see a text based logic equation in the box next to the "Reset Condition" button in the "Trigger" window.

Click the "Trigger Event" button to set the trigger event condition for the tool.

Your choices will appear in the grid in the "T" column. Once you click you will also see a text based logic equation in the box next to the "Trigger Event" button in the "Trigger" window.

specifies how many edge counts should be ignored before triggering acquisition. You can specify up to 215 (32,768) counts.

Check to restart the counter once the count has been reached.

With unchecked, specifies the filter time for which a trigger containing an edge condition (rise, fall, or edge) does not detect further events. This also delays the sampling rate for deserializer. For a trigger without an edge condition (rise, fall, or edge), specifies the minimum stable period. is not used for a trigger with an edge condition. For a trigger without an edge condition, it specifies the maximum stable period.

With checked, specifies the bit length. Sampling rate for the deserializer is also at half this time length. specifies the protocol timeout. tells the analyzer to skip the bit after the specified number of consecutive equal bits. You can specify up to 128 bits.

Check to use the deserializer unit. This function internally converts the serial data into parallel data, allowing the system to look at all the bits at once. There is no user access to this parallel data. specifies the pin from which to read the incoming serial data. and are used together to mask the deserialized bits to compare to value. You can enter the values for Value and Mask in decimal, binary, or hexadecimal and the program will convert it and display it in hex format. Use this option to check specific bit states in a serial signal and then use that exact condition as your trigger.

Step 2: The Grid (part I)

The next section is the grid itself.

Click to open a menu where you can select which type of data protocol you would like to analyze. Details on each choice are a bit farther down in this step. For our example, we will be analyzing a UART signal.

Click to delete a selected protocol, or click to clear the entire grid. You can also press the delete key on your keyboard to delete a selected protocol.

opens the properties editor for whichever protocol channel is selected in the grid. This is the same window that opens when you first select a protocol to add to the grid.

drops down the basic trigger settings. You have to have a specific DIO channel selected within the protocol being analyzed to use this menu. You can choose "X" to ignore this channel, "L" to trigger when the signal is low, "H" to trigger when the signal is high, "R" to trigger when the signal rises from low to high, "F" to trigger when the signal falls from high to low, or "E" to trigger on any falling or rising edge. These settings can be set accessed in multiple ways, and most protocols have their own specific trigger settings utilizing a trigger wizard, so if you don't see what you want here, keep reading.

Use the scroll bar above the plot window to move the data window left/right once the data has been captured. Click on the arrows to change the position by a base span and double click to set the leftmost or rightmost position. Double click on the scroll area to reset the time to show the entire acquisition.

Below the scroll bar and to the left is the acquisition state indicator . It's simply a visual indicator of the tool state, showing information such as whether the trigger is armed and ready or whether the tool is done collecting data. To the right of that you'll see a print out of the number of samples, sample rate, and time of acquisition for the last acquisition captured. The data displayed here will also change to display data specific to each protocol as you move your mouse cursor over the data captured in each channel in the plot window below.

To the far right of the screen you have two buttons, one for hot track and one to change plot window settings . Hot track is explained a bit later with the demonstration example. From the plot window settings you can adjust the plot background color between "light" (white), "dark" (black), or "default" (dark gray). You can adjust the size, from 1-4 point, of the data plotted. You can also adjust and reset where the analyzer starts interpreting the captured data. This can also be accomplished by simply right clicking on the plot where you want to begin analyzing and selecting "Start from here". All previous data will be ignored and the remaining data will be interpreted accordingly. The following two images illustrate this with a UART signal.

Original UART data captured. Notice how the data 8-bit data packets are clearly interpreted and displayed above as both hexadecimal (h1B, h5B, h6A, h1B, h5B) and ASCII characters ("ESC", "[", "j", "ESC", "[").

Now telling the tool to adjust where to start reading the UART data, beginning where it "sees" a UART Start bit. Notice how the data displays incorrectly, missing one packet entirely and complaining of framing errors and skipping some bits. But by the fifth packet (second "[") the tool had zeroed in on the correct UART sequence of bits and was able to decipher the remaining data correctly.


Now let's add protocols to the grid. By clicking you can add several different protocols to the grid.

Be aware that you can assign DIO channels to multiple protocols, i.e. you can use DIO 0 to watch your UART data signal as well as your I2C SCL signal. Notice the * in the colored box in the IO column to indicate that the DIO is doubled up.

Whatever data is captured will be displayed wherever that particular DIO is assigned. Luckily you have 16 DIO pins (32 with the EEBoard), so you should have no problem spacing out your protocols across the pins. Try and avoid doubling up if you can help it.

The first protocol in the list is Signal. Note that selecting any protocol will first open a small property editor window.

Select one or multiple signals using the "Shift" and/or "Ctrl" keys on your keyboard. Once you have your channels selected, click to add the selected signals to the grid.

You can edit each channel by double clicking it on the grid, or clicking either edit button, in the grid next to the signal name or above the grid . For Signal, the only thing you can edit is the name of the channel. You can change the trigger condition from the grid by clicking on the symbol in the "T" column. "X" is set by default, but the same options described above apply here as well.


The next protocol option is "Bus".

Select the channels you want to use for your bus in the left table. Click to add them to the table on the right. Remove any channel from the right hand side by selecting it and clicking . Clicking or with a channel selected allows you to change the order of the channels in the bus.

selects an optional enable pin and polarity.

selects the optional clock pin and sampling edge.

allows you to choose the numerical format for how the interpreted data is displayed. There are a number of formats to choose from.

sets how the data is interpreted, either MSB first or LSB first.

and set the values for the first and last indices. The minimum for LSB is -32 and the maximum for MSB is +31. Changing either will change both, maintaining a separation difference equal to the number of channels assigned to the bus. This tool works like bit shifting the interpreted data, adjusting up/down the max/min values interpreted by the bus by a factor of 2 with each increase/decrease of the indices.

Click on to open the trigger wizard.

With this wizard you can set the trigger condition to look for a specific set of bits, corresponding to the number entered in the box. You can also set the individual trigger for any of the bus channels simply by clicking on the trigger symbol in the "T" column. Note that the tool will only trigger if the trigger settings for all channels in the bus have been met when the data sample is taken.


Next on the list of protocols is Serial Peripheral Interface, or SPI, which is used extensively in embedded applications for synchronous serial communication.

Set the for your SPI.

Assign a DIO to to watch the slave select signal and set the status as high or low.

Set a second DIO to watch the clock signal and set it to on either the clock rising or falling edge.

Set a third DIO to watch the signal (either MISO or MOSI) and set whether the bit in the data packet is the MSB or LSB.

lets you set the bit size of your data packet (1-32 bits).

allows you to choose the numerical format for how the interpreted data is displayed. There are a number of formats to choose from.

lets you set how many leading bits should be skipped when calculating the data value. Similarly, sets how many trailing bits should be skipped when calculating the data value.

Using you can delay the start of acquisition with respect to the first sample.

Once you have your SPI defined, click to add it to the grid. Once there, you can edit the SPI properties by double-clicking any of the SPI channels, or by clicking either or .

Open the SPI trigger wizard by clicking in the "T" column.

You can set it to on SPI start, SPI Stop, or when a specific Value appears in the data packet. If you choose Value, define what value to look for in the box.


The next protocol on the list is Inter-Intergrated Circuit, or I2C. This protocol is also known as Two-Wire Interface, or TWI. Like SPI, I2C is also used extensively in embedded systems communication.

As the alternate name Two-Wire Interface implies, I2C only uses two wires, so the protocol is really easy to set up. Define the of the protocol and set the and channels.

Once you have your I2C defined, click to add the protocol to the grid. Once there, you can edit the I2C properties by double-clicking any of the I2C channels, or by clicking either or .

Open the I2C trigger wizard by clicking in the "T" column.

The default setting is to trigger once the I2C signal starts. But you can choose from several other options as well.

"Start" and "Stop" have no additional settings to define.

"Any ACK/NAK" will trigger acquisition on an ACKnowledge or Not AcKnowledge signal. You can also set the option to Ignore any ACK/NAK signal.

"Address & Data" makes use of all options in the trigger wizard.

can be set to look for a specific peripheral device address. Valid address values are between h00 and h7F.

Set to trigger when reading or writing data to/from the device at the specified address, or set to ignore.

Set and to look for specific bytes in the data packet.

All three options look for the ACK or NAK data with the specified option. These can also be set to ignore the ACK/NAK data.

Step 3: The Grid (part II)


Next is Universal Asynchronous Reciever/Transmitter, or UART. If you are familiar with microcontrollers in either the chipKIT or Arduino families, the Serial library uses UART to transmit/receive data.

Name the UART protocol whatever you want in the box.

Set the AD2 DIO pin with to monitor the data being sent or received. You can only monitor either the TX or RX line with one instance of UART with the Logic Analyzer. If you need or want to monitor both TX and RX at the same time, simply add another instance of UART to the grid, assigning the second data line to the second instance.

Define how many bits are in your data packet with . You have a range of 1-32 bits for the data packet size.

is defined as Odd, Even, Mark, or Space depending on the settings of the signal under observation. Select None if no parity bit is used.

lets you define how many stop bits are present in the signal.

The default baud rate is set at 9600, but set to "Manual" to manually set the to a different setting.

Set a delay in data interpretation using . The interpreter will not begin until that much time has passed with respect to the first sample.

Once you have your UART defined, click to add it to the grid.

To edit the UART protocol, double click the Data channel in the grid or click on either in the grid or above the grid. Make the appropriate edits, then click to return to the grid.

Click to open the trigger wizard.

You can set the tool to trigger on Break, Idle, or a Value. If Value is chosen, enter the value of the data packet in the box. Click to return to the grid.


Next is Controlled Area Network, or CAN, which is used in automotive and robotic applications to communicate with all of the peripheral devices on one main bus.

Name the CAN protocol whatever you want in the box.

Set the AD2 DIO pin with to monitor the data.

Set the to either High or Low.

Adjust to whatever rate you have your signal set at.

Set a delay in data interpretation using . The interpreter will not begin until that much time has passed with respect to the first sample.

Once you have your CAN defined, click to add it to the grid.

To edit the CAN protocol, double click the Data channel in the grid or click on either in the grid or above the grid. Make the appropriate edits, then click to return to the grid.

Click to open the trigger wizard.

You can set the to Error, Break, or Identifier. The remaining fields only apply if Identifier is selected as the trigger.

Choose between 11-bit or 29-bit identifier in the box.

Define the identifier value in the box.

In the select between Data and Remote request types. You can select Ignore if you wish to ignore requests.

In the you can define the data section byte length, or choose to ignore this field.

Once the CAN trigger is defined, click to return to the grid.


The last defined protocol on the list is Inter-IC Sound, or I2S, which was designed to transmit digital audio data. It is not related to the I2C protocol, so be sure not to confuse the two.

Set the name of your protocol in the box.

sets the DIO pin to monitor the Word Select line. determines which channel, left or right, is active when Select is low.

sets the DIO pin to monitor the Wlock line. Set to determine which edge of the clock, rising or falling, is the sample edge.

allows you to set whether the data bits are shifted with respect to the clock signal.

sets the DIO pin to monitor the Data line. Use to set whether the first bit in the data packet is MSB or LSB. lets you set whether the data packet is right or left aligned with respect to the data frame edges.

Set the size, in bits, of the data packet in the box. Values can range from 1 to 32 bits.

determines which numerical format to use to display the interpreted data on the plot.

Once you have your I2S defined, click to add it to the grid.

To edit the I2S protocol, double click any I2S channel in the grid or click on either in the grid or above the grid. Make the appropriate edits, then click to return to the grid.

Click to open the trigger wizard.

Set the , right or left, to use as the trigger source.

Set a specific watch value in the box. You can also ignore data packets if you wish. The value range corresponds to the number of bits defined in the data packet in the properties window.

Use to specify clock cycles in a frame. This is independent of data packet size and can range from 0-128.

Once the I2S trigger is defined, click to return to the grid.


The last protocol option is Custom, which lets you define your own protocol interpreter.

Waveforms is coded using JavaScript. Utilizing the SDK that downloads with Waveforms, custom applications can be built and included with your own installed version of the Waveforms application. For more on that, see the SDK PDF that downloads with Waveforms 2015 and the Waveforms reference manual.

Step 4: An Example.

I've talked about showing an example several times now, so let's get to that.

The Pmod CLS is a great device to use for this example because you can communicate with it using SPI, UART, or I2C. For this example I'll use UART, and from the reference manual I know that with CLS Revision E (, found on the underside of the PCB), I need to set the communication selection jumpers like so:

There are two 6-pin Pmod headers on the CLS, J1 and J2. The silkscreen on the bottom shows the different communication protocol connections.

Since I'm using UART, I will need to use the RX pin on J2. I won't be expecting to receive data from the CLS, so the TX pin doesn't need to be connected. Also on J2 are the SCL and SDA pins for I2C communication. Use J1 for SPI communication. Both J1 and J2 have 2 power (V and G) pins for powering the Pmod.

Using a 6-pin MTE cable, connect the CLS to the ChipKIT board. The image shows a uC32.

Be sure to connect the RX pin on the CLS to the TX pin (1) on the uC32.

The CLS has a number of commands in the user guide that can be used for some basic set up. Once that is done, you can start sending text to it. The following code is a very simple example of this.

// ASCII values are in HEX, but can be converted to chars by typing a single apostrophe (')
// before and after the char, e.g. '['. Note that 'ESC' won't work.
byte setup_display[] = {0x1B, 0x5B, 0x6A, 0x1B, 0x5B, 0x30, 0x68, 0x1B, 0x5B, 0x32, 0x63};
                      // ESC,   [,    j,   ESC,   [,   0,     h,   ESC,   [,    2,    c
byte clear_display[] = {0x1B, 0x5B, 0x6A};
                      // ESC,   [,    j
void setup() {
  Serial.write(setup_display, 11);
  Serial.write("Hello World. How are you today?");
  Serial.write(clear_display, 3);
  Serial.write("I'm fine, thank you.");
void loop() {}

Download the code to the uC32 and the messages should display on the LCD.

Utilizing a mini grabber test clip, you can piggyback on the uC32 TX signal to analyze it with the Logic Analyzer. Be sure to also connect one of the AD2 GND wires to a GND pin on the uC32.

Set up a UART protocol interpreter with the Logic Analyzer tool. The default property settings will work fine here.

Click on the "X" in the trigger column and select "Fall."

The UART data line holds logic high when not in use. The start bit of the data frame is indicated by dropping the line to logic low, so we know that we are about to get a data packet when the line goes low and the tool will trigger on that first falling edge.

In the box, select Normal so that the tool will wait for the trigger and not automatically begin acquiring data.

At the top right of the plot window, enter 4.5 ms in the box. This will center the plot at 4.5 ms, shifting 0 ms to the left to allow us to see more data.

Click and the tool will wait for the trigger condition to be met, indicated by the status indicator . Reset the microcontroller to begin sending serial data on the TX line. The tool will trigger and acquire 9.5 ms of data.

We can see that the analyzer correctly interpreted the data packets and the hex value along with the ASCII character is displayed along the top.

The only problem is that we know that we sent a lot more bytes of data than the 9 we can see in the plot. Using the record function, we can capture the entire data stream. Let's look at that.

Select Record from the box. The plot will likely resize, but don't worry the data is all still there. Save it, export it, whatever, but we'll get another sample in a minute.

Click to configure the record function. A configuration window will open.

Our serial baud rate is set at 9600, which is essentially 9.6 kHz. We want the sample rate to be significantly higher than that in order to capture the data. The default should be 200 kHz, but any value higher than 10X baud is fine, just don't go to high or you won't have enough samples in the buffer to record enough data for the time required.

Set the number of to determine how long the tool will record. Multiply your rate by the time required for acquisition to get you samples. In this case I already know that the uC32 is finished transmitting data to the CLS after about 2.5 seconds, so with a rate of 200 kHz, that leaves me with 500,000 samples.

is set by the tool in this case, so don't worry about it.

Use the box to set the position on the plot of the first sample. 0% is far left, 100% is far right, and 50% is right in the middle. For this example, set it to 5%.

Once everything is set, click to begin acquisition. The tool will buffer a few samples and then wait in status. Reset the uC32 to begin transmitting to the CLS. The plot should look like this once it finishes.

It doesn't look like much, but luckily we recorded it, so we can zoom in to see the data stream.

Use the scroll bar above the plot window to move left or right through the recorded data plot.

Notice that the data packets have been interpreted by the tool and both the hexadecimal and ASCII values are displayed at the top of the plot window.

Click on the hot track button at the top right of the plot window. Zoom in on the recorded data stream and hover the mouse over it. Measurements and associated labels will appear on the plot, showing information like the data pulse width, period, etc.

Step 5: That's It!

As you can see, the Logic Analyzer on the Analog Discovery 2 is a powerful tool for helping test and analyze digital communication protocols.

As always, thanks for reading. If you have questions, please ask them in the comments below, though PMs are always welcome as well. You just never know when someone else has the same question and that way we can all learn and help each other get better. Have fun building!

Also, please check out the Digilent blog where I contribute from time to time.

About This Instructable




Bio: I've always loved to figure out how things work, so hacking and making just fits for me. I'm an intern at Digilent Inc ... More »
More by brmarcum:Programming Digilent FPGAs Using NI Multisim Monitoring Digital Circuits With the Digital Discovery Using the Voltmeter With the Analog Discovery 2 
Add instructable to: