pschatzmann / logic-analyzer

Arduino Logic Analyzer API supporting the SUMP protocol (for sigrok, pulseview)
GNU General Public License v3.0
107 stars 15 forks source link
arduino-library logic-analyzer

A flexible Arduino SUMP Logic Analyzer Library

Recently, when I started to research the topic of Logic Analyzers, I found the incredible PulseView Project. However, I did not want to invest in additional hardware but just use one of my favorite microprocessors (ESP32, Raspberry Pico) as capturing device.

There are quite a few logic analyzer projects with a similar goal:

Howerver all of them are geared for one specific architecture and therfore are not portable.

I wanted to come up with a better design and provide a simple Arduino C++ Library that implements the SUMP protocol and clearly separates the generic functionality from the processor specific in order to support an easy rollout to new architectures: The only common precondition is the Arduino API.

I am currently providing implementations for

The Basic Arduino Sketch

The basic Arduino Sketch for the logic-analyzer is quite simple. We just need create a LogicAnalyzer and a Capture object. In the setup we call the begin method on the LogicAnalyzer object which provides all mandatory parameters. The provided implementation just uses the default values which are defined in the config. Finally we add the command handler in the loop():

#include "Arduino.h"
#include "logic_analyzer.h"

using namespace logic_analyzer;  

int pinStart=START_PIN;
int numberOfPins=PIN_COUNT;
LogicAnalyzer logicAnalyzer;
Capture capture(MAX_FREQ, MAX_FREQ_THRESHOLD);

void setup() {
    Serial.begin(SERIAL_SPEED);  
    Serial.setTimeout(SERIAL_TIMEOUT);
    logicAnalyzer.begin(Serial, &capture, MAX_CAPTURE_SIZE, pinStart, numberOfPins);
}

void loop() {
    if (Serial) logicAnalyzer.processCommand();
}

Adding Additional Functionality

Logging

You can actvate the logging by assigning a Stream to the LogicAnalyzer object by calling logicAnalyzer.setLogger():

// setup logger
Serial1.begin(115200, SERIAL_8N1, 16, 17);
logicAnalyzer.setLogger(Serial1);

Using Events

An easy way to extend the functionalty is by adding an event handler. The following acts on a status change event by activating the LED dependent on the actual status:

// Use Event handler to control the LED
void onEvent(Event event) {
    if (event == STATUS) {
        switch (logicAnalyzer.status()) {
            case ARMED:
                digitalWrite(LED_BUILTIN, LOW);
                break;
            case STOPPED:
                digitalWrite(LED_BUILTIN, LOW);
                break;
        }
    }
}

and we can just activate it by calling:

logicAnalyzer.setEventHandler(&onEvent);

Custom Capturing

I am providing a default implementation for the capturing with the Capture class. It's main goal is portability because it should work on all Arduino Boards. To come up with a dedicated improved capturing is easy. Just implement your own class:

class YourFastCapture : public AbstractCapture {
    public:
        /// Default Constructor
        YourFastCapture() : AbstractCapture(){
        }

        /// starts the capturing of the data
        virtual void capture(){
            /// your implementation
        }
}

Supporting new Architectures

In order to support a new architecture you need to implement a simple config file, that must contains the following information:

Here is the config_esp32.h.

Class Documentation

The complete generated class documentation can be found on Github.

Connecting to Pulseview

Installation

You can download the library as zip and call include Library -> zip library. Or you can git clone this project into the Arduino libraries folder e.g. with

cd  ~/Documents/Arduino/libraries
git clone pschatzmann/logic-analyzer.git

Supported Boards

Processor Max Freq Max Samples Pins GPIO
ESP32 2940052 65535 8 GPIO19-26
ESP8266 1038680 50000 4 GPIO12-15
AVR Processors (Nano) 109170 500 8 GPIO0-7
Raspberry Pico 2508420 65535 8 GPIO6-13
Raspberry Pico - PIO 125000000 65535 8 GPIO6-13

Please note, that SUMP supports only max 65535 samples.

Summary

The basic implementation is only using a single core. While capturing is in process we do not support any cancellation triggered from Pulseview. In order to support this, we would just need to extend the functionality in a specific sketch to run the capturing on one core and the command handling on the second core. And this is exactly the purpose of this library: to be able to build a custom optimized logic analyzer implementation with minimal effort!

Please check out the examples directory for some dedicated implementations. And if you come up with your own implementation, please share it with the community...