// LogicAnalyzerDemonstration.ino
//
// 12 March 2022, Version 1, by Koepel, Public Domain
// 14 March 2022, Version 2, by Koepel, Public Domain
// Added a tone() output and a serial toggle output.
// Added "Advanced" to the Instructions for some in-depth analysis of the signals.
// 4 Nov 2022, Version 3, The VCD file has now channel names.
//
// The Guide how to use the Logic Analyzer in PulseView:
// https://docs.wokwi.com/guides/logic-analyzer
// The documentation for the Logic Analyzer in the circuit:
// https://docs.wokwi.com/parts/wokwi-logic-analyzer
//
// This sketch provides signals for the Logic Analyzer.
//
// Instructions:
// -------------
// Let the sketch run for a few seconds.
// Stop the sketch.
// If you are asked to store the file, store it on your computer.
// Open the *.vcd file in PulseView with "import Value Change Dump data".
// Set the "Downsampling factor" to 10 (or 50 if you have a slow computer).
// Add a decoder "UART", it will automatically select the "TX" channel.
// Channel "TX" is D1 on the Logic Analyzer, it is the second channel.
// Set it to 115200 Baud rate and "ascii" Data format.
// Add a decoder "I²C", it will automatically select channels SCL and SDA.
// Channel "SCL" is at D2 and "SDA" is at D3.
//
// Advanced:
// (1)
// When the Serial.print("Hello World"); is used with a long text,
// it will be transmitted after the the other code has finished.
// That is because the data is copied into a 64 byte buffer,
// and the bytes are transmitted on a interrupt basis.
//
// (2)
// Add a decoder "UART" and set the TX to channel "toggleTX" at D5.
// Select the "ascii" Data format and 9600 Baud rate.
// Move the serialToggle("Wokwi"); to the middle of the sketch and see what happens.
// Since the serialToggle() turns off the interrupts now and then,
// it influences all interrupt driven signals (Serial, I2C, tone).
//
// (3)
// Notice how the pulses for a single byte of the Serial and I2C bus
// are not influenced by the other interrupts, but the tone() pulses are.
// That is because the bytes for the Serial and I2C signals
// are generated by hardware and every tone() pulse is
// generated in a software interrupt.
//
#include <Wire.h>
void setup()
{
pinMode( 13, OUTPUT); // for a start pulse and stop pulse
pinMode( 11, OUTPUT); // for a pin toggle serial output
digitalWrite( 11, HIGH); // A serial signal is idle high
Serial.begin( 115200);
Wire.begin();
delay( 100);
// A pulse to identify the start.
// Arduino pin 13 is connected to D1 of the Logic Analyzer.
digitalWrite( 13, HIGH);
digitalWrite( 13, LOW);
// Set a tone output of 20kHz on pin 8.
// Arduino pin 8 is connected to D4 of the Logic Analyzer.
tone(8, 20000);
// Serial output on TX.
// Arduino pin 1 (TX) is connected to D1 of the Logic Analyzer.
Serial.print( "Hello World");
// A I2C write to an address that does not exist (no acknowledge).
// The I2C bus is at Arduino pins A4 and A5.
// Pin A4 is SDA and is connected to D3 of the Logic Analyzer.
// Pin A5 is SCL and is connected to D2 of the Logic Analyzer.
Wire.beginTransmission( 8);
Wire.endTransmission();
// A small gap between the I2C sessions to be able to distinguish them better.
delayMicroseconds( 100);
// A I2C write to a I2C address.
Wire.beginTransmission( 0x68);
Wire.write( 0);
Wire.endTransmission();
// a small gap between the I2C sessions.
delayMicroseconds( 100);
// A I2C read from a I2C address.
Wire.requestFrom( 0x68, 1);
// Stop the tone output on pin 8
noTone( 8);
// Send a pin toggle to pin 11 that makes a Serial signal.
// Arduino pin 11 is connected to D5 of the Logic Analyzer.
serialToggle( "Wokwi");
// A pulse to identify the end
digitalWrite( 13, HIGH);
digitalWrite( 13, LOW);
}
void loop() {}
// Function: serialToggle()
// Using a digital pin to toggle a signal to produce serial output.
// This will only work on a Arduino Uno and only for a low baudrate and short texts.
// It is not accurate.
// The digital pin should already be set as output and high.
//
// Pin 11 is PB3 for a Arduino Uno
#define serialToggleHIGH bitSet(PORTB,3)
#define serialToggleLOW bitClear(PORTB,3)
#define serialToggleCYCLES 1665
void serialToggle( char *text)
{
for( int i=0; i<strlen(text); i++) // the characters of the text string
{
noInterrupts(); // disable interrupts to keep the delays accurate
serialToggleLOW; // start pulse
__builtin_avr_delay_cycles(serialToggleCYCLES); // width of the start pulse
for( int j=0; j<8; j++) // the bits of a character, starting with lowest bit
{
if( bitRead( text[i], j) == 0)
{
serialToggleLOW;
}
else
{
serialToggleHIGH;
}
__builtin_avr_delay_cycles(serialToggleCYCLES); // width of a data pulse
}
serialToggleHIGH; // stop bit
// A stop-bit is the same as a "idle" and is a gap between the pulses so the
// receiver can synchronize with the start-bit.
// Since the baudrate of this function might be slower, two stopbits are used.
__builtin_avr_delay_cycles( 2 * serialToggleCYCLES);
interrupts();
}
}