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:
However all of them are geared for one specific architecture and therefore are not portable.
I wanted to come up with a better design and provide a basic 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 supporting
- AVR Processors
- ESP32
- ESP8266
- Raspberry Pico
The Arduino Sketch
The basic Arduino Sketch for the logic-analyzer is quite simple. We just need to call the begin method on a LogicAnalyzer object and add the command handler in the loop(). The provided implementation just uses the default values which are defined in the config:
#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.setDescription(DESCRIPTION);
logicAnalyzer.begin(Serial, &capture, MAX_CAPTURE_SIZE, pinStart, numberOfPins);
}
void loop() {
if (Serial) logicAnalyzer.processCommand();
}
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);
Adding Additional Functionality
An easy way to extend the functionality 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 specific config file, that contains the following information:
- Defines for the processor specific (resource) settings (e.g. MAX_CAPTURE_SIZE, SERIAL_SPEED …)
- A typedef for PinBitArray which defines the recorded data size
- An implementation of the class PinReader which reads all pins in one shot
Here is the config_esp32.h which serves as an example.
Class Documentation
The complete generated class documentation can be found on Github.
Connecting to Pulseview
- Start the Arduino “logic-analyzer” Sketch
- Start Pulseview
- Select “Connect to a Device”:
- Choose the Driver: Openbench Logic Sniffer & SUMP Compatibles
- Choose the Interface: Select Serial Port with the Port to your Arduino Device and the frequency defined in the config
.h (e.g. the ESP32 uses 921600) - Click on “Scan for Devices using driver above” button
- Select the Device – “Arduino” which should be available and confirm with OK
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
I have tested the functionality with the following processors:
Processor | Max Freq | Max Samples | Pins |
---|---|---|---|
ESP32 | 2463700 | 100000 | 8 |
ESP8266 | 1038680 | 50000 | 4 |
AVR Processors (Nano) | 109170 | 500 | 8 |
Raspberry Pico | 2203225 | 100000 | 8 |
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!
You can find my project on Github.
0 Comments