Firmware Debugger

Ask Us:
Contact Us:

EE101 Embedded Firmware Debugger Users Manual

This document details the operation of the EE101 Embedded Firmware Debugger.


System Overview

An EE101 Debugger is a tool for debugging todays embedded firmware systems. It gives you clear, concise insight into your designs operation so you can find and fix bugs quickly.  It captures and displays Logic Analyzer digital data, Oscilloscope analog data, I2C, SPI and UART decoded data and the new EE101 Debugger interface.  The EE101 Debugger uses a simple interface to your firmware using 2 wires and simple "printf" like calls.  This gives you access to data that is not contained on an external bus and shows you the internal information that only your embedded firmware knows.  It also streams data to disk allowing captures that can outlast you and ensure your elusive bug is captured.

The EE101 Debugger pod is a box that attaches to your computer using a USB cable.  It also attaches to your circuit under test using the provided test leads and clips.  Your microprocessor then sends debug information to be displayed using the EE101 Software.


The EE101 can capture Logic Analyzer digital inputs, Oscilloscope analog inputs, I2C, SPI, UART Decoded data and the new EE101 Debugger Bus. 

The EE101 Debugger Bus

There are 2 types of data captured over the EE101 wires: EE101 Text and EE101 Value (as well as the standard logic and analog inputs)

EE101 Text is character strings and are identical to traditional "printf" output.  They are graphed over time as well as listed vertically.

Each debug text output is created by a simple source code line such as:


EE101 Value is value data that is then graphed versus time for a visual representation of the data.

Each data point on the waveform is created by a simple source code line such as:

The label on the left of each waveline can also be set from your firmware by calling the EE101TextLabel and EE101ValueLabel functions.  These functions send the label every 256 times this routine is called so that it does not use bandwidth but is updated periodically on the display.

Typical Applications

The EE101 Embedded Firmware Debugger makes it a One Source Line Change and One Button Press to automatically view:

  • Accelerometer Data read from the I2C or SPI Bus graphed over time

  • Temperature Data measured over the entire weekend

  • Battery Voltage during extended operation

  • RSSI Values for each received packet graphed over time

  • Transmit Channel Frequency while frequency hopping

  • System State, memory level, FIFO depth or bit error counts over time

... and ANY other firmware knowledge such as value, result, informative message, error condition, sensor data, link status, button press, etc.

Installing the Software

To install the software on your computer you must download the installation package from below.

The current software version is 2.1.

Windows download - On Windows Vista and 7 you can also install drivers from the executable directory after installation.  Win 8 and later do not require drivers.

MAC OS X download - OS X does not require drivers.

Linux download is planned for a future version.

Connecting the Hardware

To connect the EE101 to your computer, use the included USB A to micro-B cable and plug it into any available USB port.  Your computer will find and install the appropriate driver (the CDC USB Com Port Driver).  On earlier Windows versions you will need to update the driver using the one included in the Drivers directory of the installation.  If your circuit is also attached to the same computer over USB, make sure that it is on a different USB Hub.

Now connect the EE101 to your target device.  Below are the pinouts of the EE101 Embedded Firmware Debugger pod.


  • GND - You MUST connect this signal to the ground of your circuit.  This provides the reference 0 level for the entire device.
  • Device A inputs are shown in Blue and Device B are shown in Yellow.
  • EE101 device inputs  Each device (A or B) uses 2 signals for communication (clock and data).  The two signals for each device are automatically determined and swapped so you do not need to determine which is which.
  • I2C inputs - Clock (SCL) and Data (SDA) 
  • SPI inputs - Select (SS#), Clock (SCK), Output (MOSI) and Input (MISO).  Both data lines are actually inputs to the EE101 device. 
  • UART - 1 and 2 channel.  You can use one or both at a time for each device.
  • Channels not used by Device A or Device B (set to Logic) become General Purpose Logic Analyzer Inputs
  • Analog In 1 and 2 - Analog Input channels
  • Analog Out 1 - Analog Output Channel (AWG)

The included test leads have matching colors for most of the the label colors.  These colors are important as they match the colors on the software display.  To connect the lead to the EE101, plug the square end of the wire onto the pin inside the EE101 through the slot on the top.  Then use the clip to connect to your circuit IC's, headers or discrete components you want to measure.  If you have the luxury of designing a board, you can put a 3 pin header for easy access to the GND and two EE101 signals.


The following are the technical specifications of the EE101 System.

Number of EE101 Debug Ports: 2 (Device A and Device B)
EE101 Debug Pins Per Port: 2 (one clock and one data)
EE101 Debug Port Input Range: -0.5 to 7.0V
EE101 Debug Port Logic Threshold: Variable between 0V and 4V with 0.1V hysteresis.
EE101 Debug Pins Drive current required: 1mA
EE101 Debug Lines Input Impedance: >10K ohm || 10pF
EE101 Debug Port Maximum Clock Frequency: 10MHz
EE101 Debug Port Maximum Text Debug Message Length: 250 characters
EE101 Debug Port Number Of Text Channels: 8 per device
EE101 Debug Port Number Of Data Channels: 8 per device
EE101 Debug Port Data Channel Output Values: --2,147,483,648 to 2,147,483,647
EE101 Debug Timestamp Resolution: 1us

I2C Maximum Clock Rate: 10MHz
I2C Maximum Ports: 2
I2C Signals Required: SCL and SDA
I2C Input Range: -0.5 to 7.0V
I2C Logic Threshold: Variable between 0V and 4V with 0.1V hysteresis.
I2C Input Impedance: >10K || 10pF
I2C Maximum Data Transfer Size Decoded per Transaction: 30 bytes

SPI Maximum Clock Rate: 10MHz
SPI Maximum Ports: 2
SPI Signals Required: SS, SCK and at least one data line
SPI Input Range: -0.5 to 7.0V
SPI Logic Threshold: Variable between 0V and 4V with 0.1V hysteresis.
SPI Input Impedance: >10K || 10pF
SPI Maximum Data Transfer Size Decoded per Transaction: 250 bytes
SPI Polarity Settings: SCK Sample Edge Falling or Rising, SS Active Low
SPI Number Of Data Channels: 2, MOSI and MISO

UART Maximum Baud Rate: 3Mbaud
UART Baud Rate Selection Method: Autobaud determines baud rate Automatically
UART Settings: 8 Data Bits, No Parity
UART Input Range: -0.5 to 7.0V
UART Logic Threshold: Variable between 0V and 4V with 0.1V hysteresis.
UART Input Impedance: >10K || 10pF
UART Maximum Transfer Size per Transaction: 250 bytes
UART Number Of Data Channels: 2, Tx and Rx

Logic Analyzer Inputs: Up to 8.  2 inputs are used by each of the EE101 Debug Ports.
Logic Analyzer Input Range: -0.5 to 7.0V
Logic Analyzer Threshold: Variable between 0V and 4V with 0.1V hysteresis.
Logic Analyzer Input Impedance: >10K || 10pF
Logic Analyzer Sample Rate: Up to 90k samples per second.  Samples are taken when no other EE101 Debug Data is available.

Analog Inputs: 2
Analog Input Range: 0V to 5V measurable. -0.5 to 7.0V tolerant.
Analog Measurement Resolution: 1.22mV (12 bit ADC over 5V)
Analog Sample Rate: Up to 90k samples per second.  Samples are taken when no other EE101 Debug Data is available.

Size: 2.75" x 1.5" x 0.6"
Package: Custom Designed ABS plastic
Overcurrent Protection: Resettable Polyfuse
Connection to computer: USB Full Speed A to micro-B cable (included)
Test Leads and Clips: Ten 9" leads with Minigrabber text clips (included)

Sample Storage Location During Capture:  Disk Drive
Maximum Number of Samples: Unlimited up to the size of your disk drive storage limit
Maximum Data Transfer Rate: 500,000 bytes per second (All channels captured)

Supported Operating Systems:  Windows Vista, 7, 8.x, 10, 32 and 64 bit, OS X.  Linux support is planned future release.

Software Operation

The EE101 Embedded Debugger Software runs and displays the captured data from your embedded system.  The software comes up in the following state, ready to capture your data.


To capture data from your circuit, make sure the EE101 Pod is connected via USB and press the Capture button.  You will see the data being captured scrolling into view. 

Prior to capture you can select what data to capture.  Select the type of data you want Device A or Device B to capture (logic inputs, EE101 Debug Data, I2C, SPI or UART decoded data).  Select Analog to measure the 2 analog input channels when the pod is not busy reading EE101 debug data.  Select Logic to capture the digital level of the Logic Analyzer signals when the pod is not busy reading EE101 debug data.  Below is a trace capturing just the 2 analog inputs.

Changing the type of bus for Device A and B may require a short delay while the EE101 downloads a new configuration to the device.   The download occurs when the Capture Button is pressed.

The Logic Voltage threshold level can also be chosen by selecting the logic family you are using (1V to 5V) in the bottom right.  This level affects the Logic Analyzer Inputs as well as the EE101 Device Inputs.

Once the Capture is in progress you can scroll and view it as it is being captured.  Be aware that all of the data is continuously being stored to your disk (in your Users/AppData or Users/Library directory).  The total number of captured bytes is displayed at the bottom during capture.

If you have an older, slow computer or a slow disk drive, you can uncheck the Live checkbox to capture the data without the real-time view active.  This will allow capture without dropping data.

Only signals and channels that are used are shown on the display automatically.  So if your firmware only outputs data on one channel, only that channel will be shown.  This eliminates any setup of the wavelines displayed.  Selecting Analog will automatically show the two Analog Inputs.  Selecting Logic will automatically show the Logic Analyzer Inputs.

When you have gathered enough data to your liking, you press the same button (now labeled Stop) to terminate the capture. 

Pressing Capture again will erase the previous capture and start a new capture.

Navigating the Trace

Once you have a trace captured you can navigate around the trace a number of ways. 

To view the entire trace in a single window, press the Zoom All button.  This will scale the data so it all fits from the first sample to the last on the timeline.

To zoom in or out on the data, hover over the waveforms and use the mouse scroll wheel or trackpad scroll gesture. 

To pan the waveforms to the left or right, click and drag the waveforms with the mouse.

It is much quicker to navigate by zooming out and back in than to pan long distances.

You can reorder the wavelines by clicking and dragging them by the left tab.  You can rename the wavelines by selecting and entering new text.

Navigating the EE101 Text List

All of the EE101 Text output is displayed as well in a vertical window on the right side of the screen.  The vertical scrollbar can be changed to widen the list to view all of your data.  The Device A text is aligned on the left side, while the Device B text is aligned on the right.  They are listed in chronological order starting at the left of the waveform data.

To scroll the EE101 Text output window, hover over the window and use the scroll wheel to scroll up and down.  You can also use the arrow up/down and the Page Up/Down buttons on the keyboard.

This window can be moved and undocked by clicking and dragging the top of the window.  To put it back just move it back to the original position.


Measurements are done using two cursors that you can place anywhere in the trace buffer.  You place the cursors by hovering over the timeline bar at the top of the window and pressing either the Left (for X1) or Right (for X2) mouse buttons.

The resulting time delta and equivalent frequency is then displayed between the cursors.

Each Analog line (either Analog input or EE101 Value waveform) can also have a measurement marker that shows the value at that sample. 



In the EE101 Text List you can filter the results based on the text channel.  To turn on or off that channel click the color boxes at the top of the text window.


To search the EE101 Text output for a certain value, type your search string in the edit box at the bottom and press Enter or click Search.  It will search forward in time from the left side of the waveform screen and find the next occurrence of the search string.  If it finds it it will place it at the left side of the screen with the text line at the top of the text window.

The search obeys the filters set in the text window for its search algorithm.

If you want to search the entire trace, press Zoom All first.

The text search is a partial match algorithm.  If the entered text matches anywhere in the debug string it will declare it a match. 

File Open and Save

Once you have a trace that contains valuable information, you can save that to a file by pressing the Save Button at the bottom.

You can then Open that file by pressing the Open Button at the bottom.

File Export

The EE101 Text output that is between the cursors can also be Exported to a CSV (comma delimited text) file.  The Export saves all of the Text output that is between the two cursors in order to save disk space.

CSV files can be easily opened in Excel or Numbers for further analysis.

Embedded Firmware

A key component to the EE101 system is the firmware that runs on your embedded microcontroller.  The microcontroller sends debug information out a pair of general purpose I/O lines (GPIO) whenever you want to see a state, location or variable of your code in real-time operation.  To send out this data you call one of 3 API routines that we provide below. 

The firmware source code below is embedded in your firmware project and provides simple API routines that can be called any time your firmware wants to output information.  Similar to printf(...), you can quickly add single lines of code to output a new set of information at exactly the correct time.

To use this firmware source code, copy the source into your project (either inline or in a new source file).  Then modify the contents between the MAKE YOUR CHANGES comments.  These modifications define how to set the output level of the two GPIO signals as well as other platform specific settings.  See the source code comments below for more details.

Program and Data Usage

The following source code uses the following resources (ROM and RAM) for these various processors and compilers.

             (ROM)    (RAM)
 Processor   Program  Data   Notes
 ----------  -------  ----   -------------------------------------
 Arduino       2132    268   With VARIABLE_ARGUMENT_SUPPORT
 Arduino        554     14   Without VARIABLE_ARGUMENT_SUPPORT
 PSoC 5LP      3072    368   With VARIABLE_ARGUMENT_SUPPORT
 PSoC 5LP       512     19   Without VARIABLE_ARGUMENT_SUPPORT
 STM EFM32      920      9   Without VARIABLE_ARGUMENT_SUPPORT
 PIC XC32     15684    628   With VARIABLE_ARGUMENT_SUPPORT
 PIC XC32      2096     16   Without VARIABLE_ARGUMENT_SUPPORT

Source Code

The following is the source code to include in your firmware project.  To save the files to your PC, right click on the link below and choose Save As.  Then add them to your firmware project.

ee101.c - C source file that includes the code below

ee101.h - C Header file that declares the routines for use in your files

/* =============================================================

EE101 Embedded Firmware Debugger
Firmware Library
Provided by

This file is to be included in your embedded firmware project to
send debug information to the EE101 Embedded Firmware Debugger.

It uses 2 signals (a clock and data line) although it does not
matter which is which since the EE101 Debugger autoselects the
correct polarity.

The 2 signals are General Purpose I/O pins (GPIO) which are
available on most microprocessors. Only output is required.
The output high voltage level can be anywhere from 1V to 5V.

You must modify this file in a few places to specify how to set
and clear the GPIO and how to enable/disable interrupts (if you
need to). The EE101 Debugger can read data at up to 10MHz clock


If you have any questions or issues, please email us at


//************** MAKE YOUR CHANGES BELOW ONLY *************************
// These defines are an example using the Cypress PSoC5LP Microcontroller

#define EE101_DEBUG_ON // Comment this line out to turn off the EE101 Debug outputs

// Change #1 - Add any includes that you need for the below defines
#include "project.h"

// CHANGE #2 - How to disable Interrupts. Only needed if you have debug
// output in interrupts.  Make sure if you do disable interrupts that it
// is done in a way that does not lose the interrupts (keeps the interrupt
// flags active) so that when the interrupt is re-enabled the interrupt will
// be serviced. 
#define EE101IntDisable     ;        // No interrupt debug
#define EE101IntEnable      ;
//#define EE101IntDisable     CyGlobalIntDisable;    // Interrupt Debugging
//#define EE101IntEnable      CyGlobalIntEnable;

// CHANGE #3 - Defines that set the GPIO pins to High and Low levels and Toggles
// These should be as fast as possible, but not faster than 50ns (20MHz)
// These two GPIO are a Clock and a Data line.  They must be setup as outputs
// elsewhere in your firmware during system initialization.
// The Data line toggle must invert the current state of the GPIO line
#define EE101ClockLow       EE101_CLOCK_DR &= ~(1 << EE101_CLOCK_SHIFT);          // PSoC Version
#define EE101ClockHigh      EE101_CLOCK_DR |= (1 << EE101_CLOCK_SHIFT);           // PSoC Version
#define EE101DataLow        EE101_DATA_DR &= ~(1 << EE101_DATA_SHIFT);            // PSoC Version
#define EE101DataHigh       EE101_DATA_DR |= (1 << EE101_DATA_SHIFT);             // PSoC Version
#define EE101DataToggle     EE101_DATA_DR ^= (1 << EE101_DATA_SHIFT);             // PSoC Version
//#define EE101ClockLow     digitalWrite(10, LOW);                                // Arduino Version
//#define EE101ClockHigh    digitalWrite(10, HIGH);                               // Arduino Version
//#define EE101DataLow      digitalWrite(11, LOW);                                // Arduino Version
//#define EE101DataHigh     digitalWrite(11, HIGH);                               // Arduino Version
//#define EE101DataToggle   digitalWrite(11, !digitalRead(11));                   // Arduino Version
//#define EE101ClockLow     GPIO_PinOutClear(EE101_CLOCK_PORT, EE101_CLOCK_PIN)   // STM EFM32 Version
//#define EE101ClockHigh    GPIO_PinOutSet(EE101_CLOCK_PORT, EE101_CLOCK_PIN)     // STM EFM32 Version
//#define EE101DataLow      GPIO_PinOutClear(EE101_DATA_PORT, EE101_DATA_PIN)     // STM EFM32 Version
//#define EE101DataHigh     GPIO_PinOutSet(EE101_DATA_PORT, EE101_DATA_PIN)       // STM EFM32 Version
//#define EE101DataToggle   GPIO_PinOutToggle(EE101_DATA_PORT, EE101_DATA_PIN)    // STM EFM32 Version
//#define EE101ClockLow     PORTCbits.RC12 = 0;                                   // PIC X32 Version
//#define EE101ClockHigh    PORTCbits.RC12 = 1;                                   // PIC X32 Version
//#define EE101DataLow      PORTCbits.RC13 = 0;                                   // PIC X32 Version
//#define EE101DataHigh     PORTCbits.RC13 = 1;                                   // PIC X32 Version
//#define EE101DataToggle   PORTCbits.RC13 = !PORTCbits.RC13;                     // PIC X32 Version

// CHANGE #4 - Enable/Disable Variable Argument support for SendEE101printf
#define VARIABLE_ARGUMENT_SUPPORT // Comment out this line if your compiler does not
                                  // have va_list, va_start, vsprintf, and va_end support
                                  // as defined in stdarg.h

#define MAX_STRING_LENGTH 250 // How much RAM to use for the SendEE101printf buffer
                              // This must not be greater than 250
                              // This defines the maximum length of any debug text message

#ifdef VARIABLE_ARGUMENT_SUPPORT // Includes required by the va_list, va_start, vsprintf, and va_end
#include <stdio.h>    // vsprintf
#include <stdarg.h>   // va_list, va_start, and va_end

// CHANGE #5 - Type defines for your platform
// Copy these defines and function prototypes to your header files to define the API
#define euint8   unsigned char    // unsigned 8 bit value
#define eint8    signed char      // signed 8 bit value
#define eint32   signed long      // signed 32 bit value
#define echar    char             // bytes within a string
void EE101Value( euint8 channel, eint32 value );            // Output a Value for this channel
void EE101Text( euint8 channel, echar *string );            // Output Text for this channel
void EE101ValueLabel( euint8 channel, echar *string );      // Set the label for this Value Channel (sent every 256 times)
void EE101TextLabel( euint8 channel, echar *string );       // Set the label for this Text Channel (sent every 256 times)
#ifdef VARIABLE_ARGUMENT_SUPPORT                           
void EE101printf( euint8 channel, echar *format, ... );     // printf-like function with variable argument list

//************** MAKE YOUR CHANGES ABOVE ONLY *************************

#define EE101_SYNC 0x50
#define EE101_VALUE_TYPE 0x80
#define EE101_TEXT_TYPE 0x00
#define EE101_LABEL 0x08

void SendEE101Byte( euint8 value )
    if (value & 0x80) {EE101DataHigh;} else {EE101DataLow;} EE101ClockHigh; EE101ClockLow;
    if (value & 0x40) {EE101DataHigh;} else {EE101DataLow;} EE101ClockHigh; EE101ClockLow;
    if (value & 0x20) {EE101DataHigh;} else {EE101DataLow;} EE101ClockHigh; EE101ClockLow;
    if (value & 0x10) {EE101DataHigh;} else {EE101DataLow;} EE101ClockHigh; EE101ClockLow;
    if (value & 0x08) {EE101DataHigh;} else {EE101DataLow;} EE101ClockHigh; EE101ClockLow;
    if (value & 0x04) {EE101DataHigh;} else {EE101DataLow;} EE101ClockHigh; EE101ClockLow;
    if (value & 0x02) {EE101DataHigh;} else {EE101DataLow;} EE101ClockHigh; EE101ClockLow;
    if (value & 0x01) {EE101DataHigh;} else {EE101DataLow;} EE101ClockHigh; EE101ClockLow;

void EE101Value( euint8 channel, eint32 value )
#ifdef EE101_DEBUG_ON
    SendEE101Byte( (channel & 0x07) | EE101_VALUE_TYPE | EE101_SYNC);
    if ((value > 32767L) || (value < -32768L))
        SendEE101Byte( value >> 24);
        SendEE101Byte( value >> 16);
    if ((value > 127L) || (value < -128L))
        SendEE101Byte( value >> 8);
    SendEE101Byte( value );

void EE101Text( euint8 channel, echar *string )
#ifdef EE101_DEBUG_ON
    euint8 bytes = 1;

    SendEE101Byte( (channel&0x07) | EE101_SYNC | EE101_TEXT_TYPE);
        if (bytes++ > MAX_STRING_LENGTH)
        SendEE101Byte( *string++ );

void EE101TextLabel( euint8 channel, echar *string )
#ifdef EE101_DEBUG_ON
    static euint8 timeout[8] = {0,0,0,0,0,0,0,0};
    euint8 bytes = 1;

    channel &= 0x07;
    if ( timeout[channel] != 1 ) return;
    SendEE101Byte( channel | EE101_SYNC | EE101_TEXT_TYPE | EE101_LABEL);
        if (bytes++ > MAX_STRING_LENGTH)
        SendEE101Byte( *string++ );

void EE101ValueLabel( euint8 channel, echar *string )
#ifdef EE101_DEBUG_ON
    static euint8 timeout[8] = {0,0,0,0,0,0,0,0};
    euint8 bytes = 1;

    channel &= 0x07;
    if ( timeout[channel] != 1 ) return;
    SendEE101Byte( channel | EE101_SYNC | EE101_VALUE_TYPE | EE101_LABEL);
        if (bytes++ > MAX_STRING_LENGTH)
        SendEE101Byte( *string++ );

echar EE101str[MAX_STRING_LENGTH];
void EE101printf( euint8 channel, echar *format, ... )
#ifdef EE101_DEBUG_ON
    va_list arglist;
    va_start( arglist, format );
    vsprintf( EE101str, format, arglist );
    va_end( arglist );
    EE101Text( channel, EE101str );