Quick intro to WaveForms scripting
During one of the electronic prototyping projects I found myself yearning for logic analyser, as one does sometimes. Debugging over a serial connection is all good but has it’s limitations. So I embarked on a quest for perfect logic analyser.
Gathering tools is one of the greatest pleasures in life and can soon become a hobby itself. But when the (desk-)space is scarce one has to carefully consider every item. Today’s specimen is compact but also brings more to the table then one can expect. Although it comes at a price.
Analog Discovery 2
This device was released in 2016 it’s still an interesting candidate for a all-in-one lab instrument. Currently priced at 399 USD (279 USD for US students) its not cheap. But, in a small package we get “USB oscilloscope, logic analyser, and multi-function instrument that allows users to measure, visualize, generate, record, and control mixed-signal circuits of all kinds”. It’s targeted mostly at students and hobbyists. And it shows, in a good way. It is accompanied by the WaveForms app that will be the focus of this text.
One of the most interesting features of this device & software combo is an ability to automate it using JavaScript. This allows you to orchestrate multiple instruments together to run a test that, for example, requires some I2C communication before taking the measurement.
While whole thing is generally very well designed and documented but the scripting feature has a significant learning curve. My hope is that going through an example project with me will help you evaluate a potential buy or make the first steps without too much stumbling around.
Design
Scripting
The scripting language is JavaScript, based on the ECMAScript, ECMA-262 standard.
The Script tool is intended to automate some operations to extend the GUI features. There is no need to setup all the interface from Script as the Script is saved together with other instruments in workspace. What can be done in the GUI, is easier to do there, like: setup channels, naming, static configuration. Then, use the Script to adjust parameters that need to be changed, such as changing PWM duty based on some scope measurements.
Task at hand
Goal
Let’s say we have two microcontrollers connected to fictitious 2-wire serial data bus. One of the wires is a two-way UART TX/RX and the second one is a chip-select (CS) signal. To send any data, the microcontroller has to send the CS signal first.
The microcontroller (ATMega328p in my case) is programmed to send out 3 bytes of information over UART while setting the CS pin. Next it will wait for an acknowledgement of the data being received correctly.
Our goal is to detect the CS signal, receive the data and in response, set the CS pin and send an ACK packet consisting of first 2 of the received bytes.
The microcontroller will retry to send out the packet of information until successful. If successful, it will communicate the success over another serial connection.
On the bench
A microcontroller (ATMega328p in my case) powered from AD2 built-in power supply. UART RX/TX pins and CS pin are connected to AD2.
Arduino Pro Mini does not have an onboard USB connector for debugging and I prefer to program it using ISP so, the microcontroller is also connected to the PC using a serial-to-USB converter (Bus Pirate) and a USBASP ISP programmer.
On the virtual bench
Supplies: set to 5V and enabled Logic: UART TX and an additional pin added, triggering configured and tested to work correctly. Protocol: UART tab open, tested to receive and send the data.
The script
clear();
print("Start");
Logic.single();
Logic.wait();
var data = dedupe(Logic.Channels.UART.data); // dedupe function included below
print("RX: " + data);
StaticIO.Channel0.DIO3.text = "0";
Protocol.UART.SendArray(Array(0, data[1], data[2]), false);
wait(0.1);
StaticIO.Channel0.DIO3.text = "Z";
print("End");
Quirks
- I was unable to generate a pulse shorter then 0.1s (100 ms) using StaticIO and wait(). This makes sense as scripting requires a round-trip through the USB to PC (and its OS) and back.
- Sending data over AD2 UART disables the Logic analyser. It can be re-enabled but it requires some “warm-up”.
Code snippets
Getting data out of Logic Analyser
When reading out interpreted data form Logic analyser it is returned in a same format as it is presented in the Data tab. In case of UART the same value is repeated for every sample. It is necessery to clean it up by removing repeating values:
function dedupe(raw) {
var prev = "";
var data = [];
raw.forEach(function(sample){
if(sample != prev){
prev = sample;
if(sample != "X") {
data.push(sample);
}
}
})
return data;
}
Usage:
Logic.single();
Logic.wait();
var data = dedupe(Logic.Channels.UART.data);