<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="https://blog.implrust.com/feed_style.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <tabi:metadata xmlns:tabi="https://github.com/welpo/tabi">
        <tabi:base_url>https:&#x2F;&#x2F;blog.implrust.com</tabi:base_url>
        <tabi:separator>
            •
        </tabi:separator>
        <tabi:about_feeds>This is a web feed, also known as an Atom feed. Subscribe by copying the URL from the address bar into your newsreader. Visit About Feeds to learn more and get started. It&#x27;s free.</tabi:about_feeds>
        <tabi:visit_the_site>Visit website</tabi:visit_the_site>
        <tabi:recent_posts>Recent posts</tabi:recent_posts>
        <tabi:last_updated_on>Updated on $DATE</tabi:last_updated_on>
        <tabi:default_theme></tabi:default_theme>
        <tabi:post_listing_date>date</tabi:post_listing_date>
        <tabi:current_section>logic-analyzer</tabi:current_section>
    </tabi:metadata><link rel="extra-stylesheet" href="https://blog.implrust.com/skins/lowcontrast_orange.css?h=43aaccb17d8ec616ace4" /><title>impl Blog for Rust - logic-analyzer</title>
        <subtitle>impl Rust Blog Posts</subtitle>
    <link href="https://blog.implrust.com/tags/logic-analyzer/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="https://blog.implrust.com/tags/logic-analyzer/" rel="alternate" type="text/html"/>
    <generator uri="https://www.getzola.org/">Zola</generator><updated>2026-02-08T00:00:00+00:00</updated><id>https://blog.implrust.com/tags/logic-analyzer/atom.xml</id><entry xml:lang="en">
        <title>Analyzing PIO Blink Using Logic Analyzer on Raspberry Pi Pico with Embedded Rust</title>
        <published>2026-02-08T00:00:00+00:00</published>
        <updated>2026-02-08T00:00:00+00:00</updated>
        <author>
            <name>implFerris</name>
        </author>
        <link rel="alternate" href="https://blog.implrust.com/posts/2026/02/logic-analyzer-raspberry-pi-pico-pio/" type="text/html"/>
        <id>https://blog.implrust.com/posts/2026/02/logic-analyzer-raspberry-pi-pico-pio/</id>
        
            <content type="html">&lt;p&gt;In earlier posts, we used a logic analyzer to inspect simple GPIO signals and UART communication. In this post, we will use the logic analyzer to inspect a signal generated by PIO, which is specific to the Raspberry Pi Pico variants (RP2040 and RP2350 chips).&lt;&#x2F;p&gt;
&lt;p&gt;If you do not know what PIO is, I recommend checking the introduction in the &lt;a href=&quot;https:&#x2F;&#x2F;rp2040.implrust.com&#x2F;pio&#x2F;index.html&quot;&gt;“impl Rust for RP2040”&lt;&#x2F;a&gt; book. I will still give a short overview here so that we are all on the same page before looking at logic analyzer captures.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pio&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#pio&quot; aria-label=&quot;Anchor link for: pio&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
PIO&lt;&#x2F;h2&gt;
&lt;p&gt;PIO, short for Programmable I&#x2F;O, is a hardware block available on RP2040 and RP2350 microcontrollers. It allows us to write small programs that run independently of the main CPU and directly control GPIO pins.&lt;&#x2F;p&gt;
&lt;p&gt;Each PIO block contains a few state machines. A state machine executes instructions from a small instruction memory, one instruction at a time, and can drive pins, sample pins, and move data in and out through FIFOs.&lt;&#x2F;p&gt;
&lt;p&gt;The important part for this post is that PIO timing is instruction-driven. Unlike CPU code, where timing depends on compiler output, interrupts, and scheduling, PIO timing is deterministic. Each instruction takes a known number of cycles to execute.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pio-clock-divider&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#pio-clock-divider&quot; aria-label=&quot;Anchor link for: pio-clock-divider&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
PIO Clock Divider&lt;&#x2F;h3&gt;
&lt;p&gt;Each PIO state machine has its own clock divider. This divider controls how fast instructions are executed.&lt;&#x2F;p&gt;
&lt;p&gt;On RP2040, the PIO instruction clock is derived from the system clock like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;state_machine_clock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; = clk_sys &#x2F; clock_divider&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In our setup:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;System clock = 125 MHz&lt;&#x2F;li&gt;
&lt;li&gt;PIO clock divider = 65535&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So the instruction execution rate becomes:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;125,000,000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F; 65,535 ≈ 1,907.38 instructions per second&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This means the PIO state machine executes roughly 1.9 thousand instructions per second.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;instruction-cycles-and-delays&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#instruction-cycles-and-delays&quot; aria-label=&quot;Anchor link for: instruction-cycles-and-delays&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Instruction Cycles and Delays&lt;&#x2F;h3&gt;
&lt;p&gt;By default, every PIO instruction takes exactly one instruction cycle to execute.&lt;&#x2F;p&gt;
&lt;p&gt;PIO also supports an instruction delay modifier, written using square brackets. For example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-set z-shell&quot;&gt;set&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; pins, 1 &lt;span class=&quot;z-keyword z-control z-regexp z-set z-begin z-shell&quot;&gt;[&lt;&#x2F;span&gt;31&lt;span class=&quot;z-keyword z-control z-regexp z-set z-end z-shell&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This means:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;1 cycle for the instruction itself&lt;&#x2F;li&gt;
&lt;li&gt;31 additional delay cycles&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So the total execution time for that instruction is 32 instruction cycles.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;time-per-instruction&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#time-per-instruction&quot; aria-label=&quot;Anchor link for: time-per-instruction&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Time Per Instruction&lt;&#x2F;h2&gt;
&lt;p&gt;Since we know the instruction execution rate, we can compute the time taken by one instruction cycle.&lt;&#x2F;p&gt;
&lt;p&gt;With a clock divider of 65535:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F; 1,907.38 s ≈ 0.0005243 s&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That means approximately:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;0.524 ms (524,300 nanoseconds) per instruction cycle&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;project-source-code&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#project-source-code&quot; aria-label=&quot;Anchor link for: project-source-code&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Project Source Code&lt;&#x2F;h2&gt;
&lt;p&gt;You can clone the project used in this post from the following repository:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;git&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; clone https:&#x2F;&#x2F;github.com&#x2F;ImplFerris&#x2F;rp2040-projects&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-cd z-shell&quot;&gt;cd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; rp2040-projects&#x2F;embassy&#x2F;pio&#x2F;hello-blinky&#x2F;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This project contains the exact PIO program and Embassy setup used for the logic analyzer measurements shown in this post.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pio-program&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#pio-program&quot; aria-label=&quot;Anchor link for: pio-program&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Pio Program&lt;&#x2F;h3&gt;
&lt;p&gt;This is the PIO assembly program used to generate the blinking signal that we will analyze with the logic analyzer.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; prg &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;pio_asm!&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;    &lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;    set pindirs, 1
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;    loop:
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;        set pins, 1 [31]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;        nop [31]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;        nop [31]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;        nop [31]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;        nop [31]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;        nop [31]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;        nop [31]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;        nop [31]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;        set pins, 0 [30]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;        nop [31]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;        nop [31]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;        nop [31]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;        nop [31]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;        nop [31]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;        nop [31]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;        nop [31]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;        jmp loop
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This program runs in an infinite loop and drives a single GPIO pin HIGH and LOW.&lt;&#x2F;p&gt;
&lt;p&gt;The delays are added using the instruction delay modifier. Each instruction with [31] takes a total of 32 PIO cycles to execute. The one place where [30] is used is intentional. The jmp loop instruction takes one extra cycle while the pin is LOW, so reducing the delay on &lt;code&gt;set pins, 0&lt;&#x2F;code&gt; keeps the HIGH and LOW durations equal.&lt;&#x2F;p&gt;
&lt;p&gt;Because the program timing is entirely instruction-based, we can predict the exact HIGH time, LOW time, and output frequency before even connecting the logic analyzer.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hardware-setup&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#hardware-setup&quot; aria-label=&quot;Anchor link for: hardware-setup&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Hardware Setup&lt;&#x2F;h2&gt;
&lt;p&gt;The hardware setup is very simple. We connect the logic analyzer to the same GPIO pin that drives the LED, so we can observe exactly what the LED sees.&lt;&#x2F;p&gt;
&lt;p&gt;The external LED is connected to GPIO15 through a resistor. The logic analyzer channel is connected in parallel to the same GPIO pin.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Source&lt;&#x2F;th&gt;&lt;th&gt;Connected To&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;GPIO15&lt;&#x2F;td&gt;&lt;td&gt;Resistor =&amp;gt; LED =&amp;gt; GND&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Logic Analyzer CH1&lt;&#x2F;td&gt;&lt;td&gt;GPIO15&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Logic Analyzer GND&lt;&#x2F;td&gt;&lt;td&gt;Pico GND&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;With this setup, the GPIO pin drives both the LED and the logic analyzer input at the same time. The LED gives us a visual confirmation of the blinking, while the logic analyzer lets us inspect the exact timing and waveform.&lt;&#x2F;p&gt;
&lt;p&gt;Make sure the logic analyzer ground and the Pico ground are connected. Without a common ground, the captured signal will be unreliable.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;start-the-capture&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#start-the-capture&quot; aria-label=&quot;Anchor link for: start-the-capture&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Start the Capture&lt;&#x2F;h2&gt;
&lt;p&gt;Open PulseView as usual. For this capture, I have configured the sample rate to 20 kHz and the number of samples to 1 million.&lt;&#x2F;p&gt;
&lt;p&gt;Once the settings are in place, click Run to start the capture. PulseView will record the signal and automatically stop once it reaches the configured number of samples.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;measuring-timing-with-cursors-in-pulseview&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#measuring-timing-with-cursors-in-pulseview&quot; aria-label=&quot;Anchor link for: measuring-timing-with-cursors-in-pulseview&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Measuring Timing with Cursors in PulseView&lt;&#x2F;h2&gt;
&lt;p&gt;Up to this point, we have been looking at captured waveforms mainly to understand their overall shape and behavior. To measure timing more precisely, PulseView provides a cursor feature that is very useful.&lt;&#x2F;p&gt;
&lt;p&gt;When you enable &lt;code&gt;Show Cursors&lt;&#x2F;code&gt; in PulseView, two movable time markers appear on the waveform. Each cursor represents a specific point in time on the capture. By placing the cursors on two edges or points of interest, PulseView shows the exact time difference between them.&lt;&#x2F;p&gt;
&lt;p&gt;This makes it easy to measure how long a signal stays HIGH, how long it stays LOW, or the full period of a repeating waveform.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;verifying-the-timing-on-the-logic-analyzer&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#verifying-the-timing-on-the-logic-analyzer&quot; aria-label=&quot;Anchor link for: verifying-the-timing-on-the-logic-analyzer&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Verifying the Timing on the Logic Analyzer&lt;&#x2F;h2&gt;
&lt;p&gt;With the capture complete, we can now use the cursors to measure the actual timing of the signal generated by PIO.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;img&#x2F;2026&#x2F;02&#x2F;logic-analyzer-show-cursors-pio.png&quot;  alt=&quot;logic-analyzer-show-cursors-pio&quot; style=&quot;width:400px; height:auto; display:block; margin:auto;&quot;&#x2F;&gt;
&lt;p&gt;In the capture above, the cursors are placed across one full HIGH-LOW cycle of the waveform. PulseView directly shows the measured period as roughly 268 ms, which corresponds to a frequency of about 3.7 Hz.&lt;&#x2F;p&gt;
&lt;p&gt;To understand why the measured period comes out to around 268 ms, let us now work through the timing of the PIO program step by step.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;high-phase-timing&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#high-phase-timing&quot; aria-label=&quot;Anchor link for: high-phase-timing&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
High Phase Timing&lt;&#x2F;h3&gt;
&lt;p&gt;The pin goes HIGH when the &lt;code&gt;set pins, 1&lt;&#x2F;code&gt; instruction executes and stays HIGH until &lt;code&gt;set pins, 0&lt;&#x2F;code&gt; executes.&lt;&#x2F;p&gt;
&lt;p&gt;While the pin is HIGH, the following instructions run:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;set pins, 1 [31]&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
The instruction itself takes 1 cycle, and the delay adds 31 more cycles.&lt;br &#x2F;&gt;
Total: 32 cycles&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;nop [31]&lt;&#x2F;code&gt; repeated 7 times&lt;br &#x2F;&gt;
Each &lt;code&gt;nop [31]&lt;&#x2F;code&gt; takes 32 cycles.&lt;br &#x2F;&gt;
Total: 7 x 32 = 224 cycles&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So the total number of instruction cycles while the pin is HIGH is:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; + 224 = 256 cycles&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With each instruction cycle taking about 0.524 ms, the total HIGH time becomes:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; x 0.524 ms ≈ 134 ms&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;low-phase-timing&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#low-phase-timing&quot; aria-label=&quot;Anchor link for: low-phase-timing&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Low Phase Timing&lt;&#x2F;h3&gt;
&lt;p&gt;The LOW phase starts when &lt;code&gt;set pins, 0&lt;&#x2F;code&gt; executes and lasts until the program loops back and sets the pin HIGH again.&lt;&#x2F;p&gt;
&lt;p&gt;While the pin is LOW, the following instructions run:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;set pins, 0 [30]&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
The instruction itself takes 1 cycle, and the delay adds 30 more cycles.&lt;br &#x2F;&gt;
Total: 31 cycles&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;nop [31]&lt;&#x2F;code&gt; repeated 7 times&lt;br &#x2F;&gt;
Total: 7 x 32 = 224 cycles&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;jmp loop&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
This instruction takes 1 cycle&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So the total number of instruction cycles while the pin is LOW is:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;31&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; + 224 + 1 = 256 cycles&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This again gives:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; x 0.524 ms ≈ 134 ms&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;putting-it-all-together&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#putting-it-all-together&quot; aria-label=&quot;Anchor link for: putting-it-all-together&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Putting It All Together&lt;&#x2F;h3&gt;
&lt;p&gt;From the instruction count, we end up with:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;HIGH time ≈ 134 ms&lt;&#x2F;li&gt;
&lt;li&gt;LOW time ≈ 134 ms&lt;&#x2F;li&gt;
&lt;li&gt;Full period ≈ 268 ms&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This matches approximately what we measured using the logic analyzer.&lt;&#x2F;p&gt;
</content>
        <summary type="html">In this post, we use a logic analyzer to study a GPIO signal generated by a PIO state machine on the RP2040. We derive the timing from instruction cycles and validate it on real hardware with Embedded Rust.</summary>
        </entry><entry xml:lang="en">
        <title>Analyzing UART Signals in Embedded Rust Using a Cheap USB Logic Analyzer</title>
        <published>2026-01-28T00:00:00+00:00</published>
        <updated>2026-01-28T00:00:00+00:00</updated>
        <author>
            <name>implFerris</name>
        </author>
        <link rel="alternate" href="https://blog.implrust.com/posts/2026/01/analyze-uart-embedded-rust-with-usb-logic-analyzer/" type="text/html"/>
        <id>https://blog.implrust.com/posts/2026/01/analyze-uart-embedded-rust-with-usb-logic-analyzer/</id>
        
            <content type="html">&lt;p&gt;In my &lt;a href=&quot;https:&#x2F;&#x2F;blog.implrust.com&#x2F;posts&#x2F;2026&#x2F;01&#x2F;using-logic-analyzer-embedded-rust-pico-esp32&#x2F;&quot;&gt;previous blog post&lt;&#x2F;a&gt;, I introduced the USB logic analyzer, showed how to set up the software, and used a simple GPIO toggle to get familiar with how a logic analyzer works. In this post, we look at UART and see how serial data appears on the wire by analyzing the transmit (TX) signal and understanding how bytes are sent.&lt;&#x2F;p&gt;
&lt;p&gt;I initially planned to explain I2C right after the introduction, but I felt that UART is much simpler to start with and provides a gentler introduction to using protocol decoders in PulseView.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-uart&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#what-is-uart&quot; aria-label=&quot;Anchor link for: what-is-uart&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
What is UART?&lt;&#x2F;h2&gt;
&lt;p&gt;You might already be familiar with UART. Still, let me give a short introduction.&lt;&#x2F;p&gt;
&lt;p&gt;UART stands for Universal Asynchronous Receiver-Transmitter. It is a simple serial communication method used to send data between two devices. Data is sent one bit at a time, rather than in parallel.&lt;&#x2F;p&gt;
&lt;p&gt;UART typically uses two signal lines: one for transmitting data (TX) and one for receiving data (RX). The TX pin of one device is connected to the RX pin of the other, so data sent on TX is received on RX.&lt;&#x2F;p&gt;
&lt;p&gt;Unlike some other protocols, UART does not use a clock signal. So a natural question is how the receiver knows when data starts, when it ends, and how to interpret the bits correctly.&lt;&#x2F;p&gt;
&lt;p&gt;Let us look at a simple UART signal to understand this.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;img&#x2F;2026&#x2F;01&#x2F;uart-data-transmission.png&quot;  alt=&quot;uart data transmission&quot; style=&quot;width:400px; height:auto; display:block; margin:auto;&quot;&#x2F;&gt;
&lt;p&gt;We can assign LOW state to 0 and HIGH to 1, but this alone is not enough. For example, suppose we want to transmit the value 0x52 (binary 0101_0010). If two or more bits in a row have the same value, such as two consecutive zeros, how does the receiver know whether it is seeing one long zero or multiple zeros?&lt;&#x2F;p&gt;
&lt;p&gt;This is where three important UART things come into play: the data length, the start and stop bits, and the transmission speed (baud rate). These three define how many bits make up a byte, and how the beginning and end of a byte are identified, how fast the data is sent.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;baud-rate-transmission-speed&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#baud-rate-transmission-speed&quot; aria-label=&quot;Anchor link for: baud-rate-transmission-speed&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Baud Rate (Transmission Speed)&lt;&#x2F;h3&gt;
&lt;p&gt;The baud rate defines how fast bits are transmitted on the wire. It specifies how many bits are sent per second. For example, a baud rate of 115200 means that 115200 bits are transmitted every second.&lt;&#x2F;p&gt;
&lt;p&gt;Both the transmitter and receiver must use the same baud rate. If the baud rate does not match, the receiver will sample the signal at the wrong times and decode incorrect data.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;data-length&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#data-length&quot; aria-label=&quot;Anchor link for: data-length&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Data Length&lt;&#x2F;h3&gt;
&lt;p&gt;The data length specifies how many data bits are sent for each character. The most common configuration is 8 data bits, but other values like 5 to 9 bits are also possible.&lt;&#x2F;p&gt;
&lt;p&gt;If the data length is set to 8 bits, then exactly 8 data bits are transmitted for each byte, one after another, starting with the least significant bit.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;start-and-stop-bits&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#start-and-stop-bits&quot; aria-label=&quot;Anchor link for: start-and-stop-bits&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Start and Stop Bits&lt;&#x2F;h3&gt;
&lt;p&gt;When the UART line is idle, it stays in the HIGH state. A transmission always begins with a start bit, which is a transition from HIGH to LOW.  This LOW level tells the receiver that a new byte is starting. Once the receiver detects the start bit, it uses the baud rate to time when to read the following data bits.&lt;&#x2F;p&gt;
&lt;p&gt;After all data bits are transmitted, the sender adds one or more stop bits. A stop bit is simply the line returning to the HIGH state for a fixed duration.&lt;&#x2F;p&gt;
&lt;p&gt;The stop bit marks the end of the byte and gives the receiver time to finish processing the current byte before the next one begins.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;example&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#example&quot; aria-label=&quot;Anchor link for: example&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Example&lt;&#x2F;h3&gt;
&lt;img src=&quot;&#x2F;img&#x2F;2026&#x2F;01&#x2F;uart-data-transmission-with-details.png&quot;  alt=&quot;uart data transmission with details&quot; style=&quot;width:400px; height:auto; display:block; margin:auto;&quot;&#x2F;&gt;
&lt;p&gt;The above diagram shows the transmission of a single UART data byte. Before any data is sent, the signal stays in the idle state, which is HIGH.&lt;&#x2F;p&gt;
&lt;p&gt;The transmission begins with the start bit. The start bit is represented by pulling the signal LOW for exactly one bit duration. This transition from HIGH to LOW tells the receiver that a new byte is about to start.&lt;&#x2F;p&gt;
&lt;p&gt;Immediately after the start bit, the actual data bits are transmitted. In this example, the byte being sent is 0x52, which in binary is 0101_0010. UART sends data least significant bit first, so the first data bit sent is 0.&lt;&#x2F;p&gt;
&lt;p&gt;Because the start bit is LOW and the first data bit is also 0, the signal stays LOW for two consecutive bit periods. From the waveform alone, these two consecutive LOW levels appear as one continuous LOW signal. The receiver does not get confused because it does not rely on signal edges to count bits. Instead, it relies on timing.&lt;&#x2F;p&gt;
&lt;p&gt;This is where the baud rate comes in. The baud rate defines how long one bit lasts. For example, at a baud rate of 115200, each bit lasts for about 8.68 microseconds. The receiver measures time from the start bit and samples the signal at fixed intervals, once per bit period. By sampling at these precise times, it knows when one bit ends and the next bit begins, even if the signal level does not change.&lt;&#x2F;p&gt;
&lt;p&gt;After all data bits are transmitted, the signal returns to HIGH for the stop bit. The stop bit marks the end of the byte and brings the line back to the idle state. If another byte is sent, the process repeats with another start bit.&lt;&#x2F;p&gt;
&lt;p&gt;As long as both sides agree on the baud rate and data format, the receiver can correctly interpret a continuous stream of HIGH and LOW levels as individual bits and bytes.&lt;&#x2F;p&gt;
&lt;div class=&quot;admonition tip&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-tip&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;TIP&lt;&#x2F;strong&gt;
        &lt;p&gt;I intentionally avoided many details of UART in this post. I only covered what is necessary for our purpose here and skipped other topics such as parity bits and other. If you want to go deeper, I recommend reading more about UART separately.&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;hardware-setup&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#hardware-setup&quot; aria-label=&quot;Anchor link for: hardware-setup&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Hardware Setup&lt;&#x2F;h2&gt;
&lt;p&gt;For this post, I am focusing only on the transmit (TX) pin. The receive (RX) pin works in the same way, just in the opposite direction.&lt;&#x2F;p&gt;
&lt;p&gt;Once again, I am using a Raspberry Pi Pico. I will use one of the UART TX pins available on the Pico. In this example, I am using GPIO16 as the UART TX pin. You are free to use a different UART TX pin if you prefer, but you will need to adjust the code accordingly.&lt;&#x2F;p&gt;
&lt;p&gt;Connect CH1 of the logic analyzer to GPIO16 on the Pico. Also connect the logic analyzer ground to any ground pin on the Pico.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Logic Analyzer&lt;&#x2F;th&gt;&lt;th&gt;Raspberry Pi Pico&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;GND&lt;&#x2F;td&gt;&lt;td&gt;GND&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CH1&lt;&#x2F;td&gt;&lt;td&gt;GPIO16&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;code-snippet&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#code-snippet&quot; aria-label=&quot;Anchor link for: code-snippet&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Code Snippet&lt;&#x2F;h2&gt;
&lt;p&gt;Flash the program onto the Pico, then power up the board and connect the USB logic analyzer to the computer.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-annotation z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-rust&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-annotation z-rust&quot;&gt;embassy_executor&lt;&#x2F;span&gt;::&lt;span class=&quot;z-variable z-annotation z-rust&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;async &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;_spawner&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;&#x2F;span&gt; Spawner&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; p &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;embassy_rp&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;init&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Default&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;default&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;&#x2F;span&gt; uart_config &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;UartConfig&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;default&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; This is default baud rate in the embassy-rp, i just want to explicitly show 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    uart_config&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;baudrate &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;115200&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;  
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;&#x2F;span&gt; uart_tx &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;UartTx&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;new_blocking&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;p&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-rust&quot;&gt;UART0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; p&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-rust&quot;&gt;PIN_16&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; uart_config&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-rust&quot;&gt;loop&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        uart_tx
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;            &lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;blocking_write&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Rust&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;as_bytes&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;            &lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;unable to write into uart&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Timer&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;after_secs&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;await&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;number-of-samples-and-sample-rate&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#number-of-samples-and-sample-rate&quot; aria-label=&quot;Anchor link for: number-of-samples-and-sample-rate&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Number of Samples and Sample Rate&lt;&#x2F;h2&gt;
&lt;p&gt;In our example, the UART baud rate is 115200. To capture the signal reliably, we use a sample rate of 1 MHz, which is comfortably higher than the baud rate and works well with PulseView.&lt;&#x2F;p&gt;
&lt;p&gt;The program sends the string “Rust” once every second and then stays idle in between. Because of this, the capture window must be long enough to include at least one transmission.&lt;&#x2F;p&gt;
&lt;p&gt;Using 5 million samples at a 1 MHz sample rate gives a capture duration of about 5 seconds. This ensures that several UART transmissions are captured without having to worry about timing the capture manually.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;img&#x2F;2026&#x2F;01&#x2F;uart-number-of-samples-sample-rate.png&quot;  alt=&quot;sample rate and number of samples&quot; style=&quot;width:400px; height:auto; display:block; margin:auto;&quot;&#x2F;&gt;
&lt;h2 id=&quot;start-the-capture&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#start-the-capture&quot; aria-label=&quot;Anchor link for: start-the-capture&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Start the Capture&lt;&#x2F;h2&gt;
&lt;p&gt;Since the program transmits the text “Rust” once every second, the capture contains multiple UART transmissions spread across the entire capture window. Because we are viewing several seconds of data at once, the waveform is zoomed out by default.&lt;&#x2F;p&gt;
&lt;p&gt;At first glance, it might look like nothing happened. The signal appears mostly flat, with a few thin vertical-looking shapes. These vertical shapes are not single lines. Each one represents a short burst of UART activity where the “Rust” string was transmitted.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;img&#x2F;2026&#x2F;01&#x2F;uart-logic-analyzer-multiple-samples.png&quot;  alt=&quot;uart sample with logic analyzer&quot; style=&quot;width:400px; height:auto; display:block; margin:auto;&quot;&#x2F;&gt;
&lt;p&gt;To see what is actually happening, zoom in horizontally on one of these regions (you can use the mouse scroll wheel while the cursor is over the signal). Once you zoom in far enough , the individual signal transitions become visible. At this level, you can see the structure of each UART transmission, but not the meaning of individual bits. To make sense of the data, we will use the protocol decoder feature.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;protocol-decoder&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#protocol-decoder&quot; aria-label=&quot;Anchor link for: protocol-decoder&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Protocol Decoder&lt;&#x2F;h2&gt;
&lt;p&gt;Looking at the raw UART signal helps confirm that data is being transmitted, but it does not tell us what the data actually is.&lt;&#x2F;p&gt;
&lt;p&gt;PulseView provides protocol decoders for many common digital protocols such as UART, I2C, and SPI. These decoders interpret raw signals and display the data in a readable form.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;img&#x2F;2026&#x2F;01&#x2F;logic-analyzer-protocl-decoder.png&quot;  alt=&quot;pulseview protocol decoder&quot; style=&quot;width:400px; height:auto; display:block; margin:auto;&quot;&#x2F;&gt;
&lt;p&gt;To add a protocol decoder, click the small decoder icon next to the “sample rate” selection, as highlighted in the image above. This opens the Decoder selector.  In the search box, type &lt;code&gt;UART&lt;&#x2F;code&gt; and double-click the UART decoder. This adds a new UART decoder row to the main window.&lt;&#x2F;p&gt;
&lt;p&gt;After adding it, you will see a message saying that no channels are assigned to the decoder. At this point, PulseView knows which protocol to use, but it does not yet know which signal line to decode.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;img&#x2F;2026&#x2F;01&#x2F;uart-pulseview-protocol-decoder.png&quot;  alt=&quot;pulseview UART decoder&quot; style=&quot;width:400px; height:auto; display:block; margin:auto;&quot;&#x2F;&gt;
&lt;p&gt;Click on the UART label on the left side to open the decoder settings. Here, we need to configure the decoder to match our UART setup. Set the baud rate to 115200. The default values for data bits, parity, and stop bits are fine for this example.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;img&#x2F;2026&#x2F;01&#x2F;uart-pulseview-protocol-decoder-options.png&quot;  alt=&quot;pulseview UART decoder&quot; style=&quot;width:400px; height:auto; display:block; margin:auto;&quot;&#x2F;&gt;
&lt;p&gt;By default, the decoded data format is shown in hexadecimal. Since we are transmitting ASCII text, change the data format to ASCII.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, assign the signal channel to the decoder. We have connected the UART TX pin to CH1, which corresponds to D0 in PulseView. Select D0 from the dropdown next to the TX option.&lt;&#x2F;p&gt;
&lt;p&gt;Once this is done, PulseView will decode the captured UART signal and display the transmitted data.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;decoded-data&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#decoded-data&quot; aria-label=&quot;Anchor link for: decoded-data&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Decoded Data&lt;&#x2F;h2&gt;
&lt;p&gt;PulseView decodes the captured UART signal and displays the data in a readable form. Along with the decoded characters (in ASCII, as we configured), it also shows the individual data bits as 0 and 1.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;img&#x2F;2026&#x2F;01&#x2F;uart-logic-analyzer-decoded-data.png&quot;  alt=&quot;pulseview UART decoder&quot; style=&quot;width:400px; height:auto; display:block; margin:auto;&quot;&#x2F;&gt;
&lt;p&gt;PulseView also highlights the start bit with an “S” label (shown in yellow) and the stop bit with a “T” label.&lt;&#x2F;p&gt;
</content>
        <summary type="html">In this post, we analyze UART signals from an embedded Rust project using a cheap USB logic analyzer and PulseView. We capture UART data, look at the raw signal on the wire, and use protocol decoding to understand how bytes are transmitted.</summary>
        </entry><entry xml:lang="en">
        <title>How to Use a Logic Analyzer in Embedded Rust Projects</title>
        <published>2026-01-26T00:00:00+00:00</published>
        <updated>2026-01-26T00:00:00+00:00</updated>
        <author>
            <name>implFerris</name>
        </author>
        <link rel="alternate" href="https://blog.implrust.com/posts/2026/01/using-logic-analyzer-embedded-rust-pico-esp32/" type="text/html"/>
        <id>https://blog.implrust.com/posts/2026/01/using-logic-analyzer-embedded-rust-pico-esp32/</id>
        
            <content type="html">&lt;p&gt;I am a hobbyist embedded Rust developer. While researching and learning, I often came across people using oscilloscopes to analyze signals. I might have used one during my college lab days, but honestly, I do not remember much about it anymore. It has been a long time.&lt;&#x2F;p&gt;
&lt;p&gt;I was curious to try one again, but I did not want a large oscilloscope sitting on my desk. At least for now, it felt unnecessary. At some point, while looking for simpler ways to inspect digital signals, I came across USB logic analyzers. I do not remember exactly where I first saw one, but it immediately felt like a practical alternative. They are small, inexpensive, and much easier to keep around.&lt;&#x2F;p&gt;
&lt;p&gt;There are already plenty of tutorials and videos showing how to use logic analyzers, mostly with Arduino-based examples that you can follow step by step. I decided to write this post for my usual reason: the more I write and explain something, the more I understand it myself. Hopefully, you will find it useful too.&lt;&#x2F;p&gt;
&lt;div class=&quot;admonition info&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-info&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;INFO&lt;&#x2F;strong&gt;
        &lt;p&gt;The Rust code is only a small part of this blog post. Most of the content focuses on understanding the logic analyzer, setting up the software, and learning how to capture and analyze digital signals.&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;what-is-a-logic-analyzer&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#what-is-a-logic-analyzer&quot; aria-label=&quot;Anchor link for: what-is-a-logic-analyzer&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
What is a Logic Analyzer?&lt;&#x2F;h2&gt;
&lt;p&gt;A logic analyzer is a tool used to capture and inspect digital signals. It records whether a signal is in a logical HIGH or LOW state over time and how different signal lines, such as clock and data wires, relate to each other during communication.&lt;&#x2F;p&gt;
&lt;p&gt;For embedded development, this is especially useful when working with digital protocols such as I2C, SPI, or UART. Instead of relying on assumptions or print-based debugging, a logic analyzer lets you inspect the actual signal behavior on the wire.&lt;&#x2F;p&gt;
&lt;p&gt;Unlike an oscilloscope, which focuses on the exact voltage shape of a signal, a logic analyzer treats signals as digital values. It does not care about the precise voltage level or waveform details, only whether the signal is interpreted as a zero or a one. For most protocol-level debugging, this level of detail is sufficient and much easier to work with.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;meet-the-hardware-8-channel-usb-logic-analyzer&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#meet-the-hardware-8-channel-usb-logic-analyzer&quot; aria-label=&quot;Anchor link for: meet-the-hardware-8-channel-usb-logic-analyzer&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Meet the Hardware: 8-Channel USB Logic Analyzer&lt;&#x2F;h2&gt;
&lt;p&gt;The logic analyzer I am using is a small 8-channel USB logic analyzer with a maximum sampling frequency of 24 MHz. You should be able to find one on online marketplaces for under 400 INR (under $10).&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;img&#x2F;2026&#x2F;01&#x2F;8-channel-usb-logic-analyzer.png&quot;  alt=&quot;8 ch USB Logic Analyzer&quot; style=&quot;width:400px; height:auto; display:block; margin:auto;&quot;&#x2F;&gt;
&lt;p&gt;As the name implies, the analyzer allows capturing up to eight digital signals at the same time, which makes it possible to observe how multiple related signals change together.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-a-logic-analyzer-captures-data&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#how-a-logic-analyzer-captures-data&quot; aria-label=&quot;Anchor link for: how-a-logic-analyzer-captures-data&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
How a Logic Analyzer Captures Data&lt;&#x2F;h2&gt;
&lt;p&gt;A logic analyzer repeatedly checks the state of each connected signal and records whether it is HIGH or LOW. These checks happen at regular intervals, based on the selected sampling rate(will see it later).&lt;&#x2F;p&gt;
&lt;p&gt;The logic analyzer itself does not understand protocols or signal meaning. It only records state changes. Interpreting those changes and decoding protocols is done later using software on the computer.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;channels&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#channels&quot; aria-label=&quot;Anchor link for: channels&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Channels&lt;&#x2F;h2&gt;
&lt;p&gt;A logic analyzer has multiple input channels. Each channel is a separate input that can be connected to a signal wire or a microcontroller pin. When the analyzer captures data, it records the state of each channel independently.&lt;&#x2F;p&gt;
&lt;p&gt;When connecting the analyzer, each channel should be connected to one signal of interest, such as a data line or a clock line. The exact choice of signals depends on what you are trying to observe. For now, the important point is that each channel corresponds to one physical wire or pin.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;software-setup&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#software-setup&quot; aria-label=&quot;Anchor link for: software-setup&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Software Setup&lt;&#x2F;h2&gt;
&lt;p&gt;I am on Linux, so I will describe the setup steps for Linux here. If you are using a different operating system, you can follow similar steps using the appropriate tools and packages for your OS.&lt;&#x2F;p&gt;
&lt;p&gt;There are two commonly mentioned software options when working with USB logic analyzers. Which one makes sense depends on the hardware you are using.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;option-1-pulseview-sigrok-open-source&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#option-1-pulseview-sigrok-open-source&quot; aria-label=&quot;Anchor link for: option-1-pulseview-sigrok-open-source&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Option 1: PulseView (sigrok, Open Source)&lt;&#x2F;h3&gt;
&lt;p&gt;For inexpensive 8-channel USB logic analyzers like the one I am using, the most practical software is PulseView, which is part of the open-source sigrok project. PulseView supports many generic logic analyzers and provides the basic tools needed to view captured signals and decode common digital protocols.&lt;&#x2F;p&gt;
&lt;p&gt;On Debian or Ubuntu-based systems, you can install PulseView using the package manager:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; apt install pulseview sigrok&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Official documentation for sigrok and PulseView is available here:
&lt;a href=&quot;https:&#x2F;&#x2F;sigrok.org&#x2F;wiki&#x2F;Main_Page&quot;&gt;https:&#x2F;&#x2F;sigrok.org&#x2F;wiki&#x2F;Main_Page&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You can also refer to the PulseView user manual for more details:
&lt;a href=&quot;https:&#x2F;&#x2F;sigrok.org&#x2F;doc&#x2F;pulseview&#x2F;unstable&#x2F;manual.html&quot;&gt;https:&#x2F;&#x2F;sigrok.org&#x2F;doc&#x2F;pulseview&#x2F;unstable&#x2F;manual.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I will be using PulseView throughout this blog post.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;option-2-saleae-logic-software-proprietary&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#option-2-saleae-logic-software-proprietary&quot; aria-label=&quot;Anchor link for: option-2-saleae-logic-software-proprietary&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Option 2: Saleae Logic Software (Proprietary)&lt;&#x2F;h3&gt;
&lt;p&gt;Saleae provides software specifically designed for their logic analyzers, though it may also work with some compatible devices.&lt;&#x2F;p&gt;
&lt;p&gt;You can download the Linux AppImage from the Saleae website:
&lt;a href=&quot;https:&#x2F;&#x2F;www.saleae.com&#x2F;downloads&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.saleae.com&#x2F;downloads&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Make it executable and run:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;chmod&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; +x Logic-&lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;*&lt;&#x2F;span&gt;.AppImage&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;.&#x2F;Logic-*.AppImage&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;toggling-a-gpio-test-signal&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#toggling-a-gpio-test-signal&quot; aria-label=&quot;Anchor link for: toggling-a-gpio-test-signal&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Toggling a GPIO (Test Signal)&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s start by generating a very simple test signal by toggling a GPIO pin. This helps confirm that the logic analyzer, software, and wiring are all working correctly before moving on to more complex signals.&lt;&#x2F;p&gt;
&lt;p&gt;I will be using a Raspberry Pi Pico here, but any other board will work.&lt;&#x2F;p&gt;
&lt;p&gt;We will flash a small program that toggles a GPIO pin between high and low states with a delay of 500 milliseconds.&lt;&#x2F;p&gt;
&lt;p&gt;For the HAL, I will be using Embassy. You are free to use any other HAL, such as rp-hal. The choice of HAL does not matter here, as long as you can toggle a GPIO pin at a known interval and observe the change on the logic analyzer.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;code-snippet&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#code-snippet&quot; aria-label=&quot;Anchor link for: code-snippet&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Code snippet&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; p &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;embassy_rp&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;init&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Default&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;default&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;&#x2F;span&gt; pin &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Output&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;new&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;p&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-rust&quot;&gt;PIN_15&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Level&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;Low&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-keyword z-control z-rust&quot;&gt;loop&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    pin&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;set_high&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Timer&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;after_millis&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;500&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;await&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    pin&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;set_low&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Timer&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;after_millis&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;500&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;await&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;div class=&quot;admonition tip&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-tip&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;TIP&lt;&#x2F;strong&gt;
        &lt;p&gt;If you are not familiar with creating a project or flashing embedded Rust code onto a board, you may want to go through the basics first. I recommend starting with the &lt;a href=&quot;https:&#x2F;&#x2F;pico.implrust.com&#x2F;&quot;&gt;Pico Pico book&lt;&#x2F;a&gt; or the &lt;a href=&quot;https:&#x2F;&#x2F;esp32.implrust.com&#x2F;&quot;&gt;impl Rust for ESP32&lt;&#x2F;a&gt; book.&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;connecting-pico-with-logic-analyzer&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#connecting-pico-with-logic-analyzer&quot; aria-label=&quot;Anchor link for: connecting-pico-with-logic-analyzer&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Connecting Pico with Logic Analyzer&lt;&#x2F;h3&gt;
&lt;p&gt;First, connect the ground wire of the logic analyzer to one of the ground pins on the Raspberry Pi Pico. The logic analyzer and the Pico must share a common ground for the signals to be interpreted correctly.&lt;&#x2F;p&gt;
&lt;p&gt;Next, connect one channel (lets say CH1) of the logic analyzer to GPIO15 on the Pico. For this test, I am using GPIO15, but you can use any other GPIO pin.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Logic Analyzer&lt;&#x2F;th&gt;&lt;th&gt;Raspberry Pi Pico&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;GND&lt;&#x2F;td&gt;&lt;td&gt;GND&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CH1&lt;&#x2F;td&gt;&lt;td&gt;GPIO15&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Power the Pico, then connect the logic analyzer to the computer.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;opening-pulseview-and-detecting-the-logic-analyzer&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#opening-pulseview-and-detecting-the-logic-analyzer&quot; aria-label=&quot;Anchor link for: opening-pulseview-and-detecting-the-logic-analyzer&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Opening PulseView and Detecting the Logic Analyzer&lt;&#x2F;h2&gt;
&lt;p&gt;Now lets open PulseView and make sure the logic analyzer is detected correctly.&lt;&#x2F;p&gt;
&lt;p&gt;Start PulseView after connecting the logic analyzer to your computer. When PulseView opens, it should automatically try to detect connected devices.  If the logic analyzer is detected, you should see it selected as the active device in the toolbar.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;img&#x2F;2026&#x2F;01&#x2F;pulseview-logic-analyzer-detected.png&quot;  alt=&quot;Pulseview detected the logic analyzer&quot; style=&quot;width:400px; height:auto; display:block; margin:auto;&quot;&#x2F;&gt;
&lt;p&gt;If no device is selected, open the device selection menu and choose the generic logic analyzer entry, which usually appears as fx2lafw (generic driver). Once selected, PulseView should show the available channels for that device.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;configuring-sampling-rate-and-number-of-samples&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#configuring-sampling-rate-and-number-of-samples&quot; aria-label=&quot;Anchor link for: configuring-sampling-rate-and-number-of-samples&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Configuring Sampling Rate and Number of Samples&lt;&#x2F;h2&gt;
&lt;p&gt;Once the logic analyzer is detected in PulseView, the next step is to configure how data will be captured. Two important settings here are the “sample rate” and the “number of samples to capture”.&lt;&#x2F;p&gt;
&lt;p&gt;To understand these settings, it helps to know what a sample actually is.&lt;&#x2F;p&gt;
&lt;p&gt;A sample is a single recorded value of the signal. At that moment, the logic analyzer simply reads the wire and records whether the signal is HIGH or LOW. Each recorded HIGH or LOW value is one sample.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;img&#x2F;2026&#x2F;01&#x2F;number-of-samples-sampel-rate-logic-analyzer-pulseview.png&quot;  alt=&quot;Number of Samples - Sample Rate&quot; style=&quot;width:400px; height:auto; display:block; margin:auto;&quot;&#x2F;&gt;
&lt;h3 id=&quot;number-of-samples&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#number-of-samples&quot; aria-label=&quot;Anchor link for: number-of-samples&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Number of Samples&lt;&#x2F;h3&gt;
&lt;p&gt;The number of samples tells the logic analyzer how many samples to record in total before stopping.&lt;&#x2F;p&gt;
&lt;p&gt;For example, if you set this to 100k, the logic analyzer will record 100,000 values (each value being either HIGH or LOW) and then stop automatically. Increasing this value makes the recording last longer. Decreasing it makes the recording shorter.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sample-rate&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#sample-rate&quot; aria-label=&quot;Anchor link for: sample-rate&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Sample Rate&lt;&#x2F;h3&gt;
&lt;p&gt;The sample rate tells the logic analyzer how many samples to take every second.&lt;&#x2F;p&gt;
&lt;p&gt;For example, a sample rate of 20 kHz means the logic analyzer records 20,000 samples every second. That means it reads the signal 20,000 times per second and saves each result.&lt;&#x2F;p&gt;
&lt;p&gt;A higher sample rate means the signal is read and recorded more frequently. This is important when the signal changes quickly. A lower sample rate means the signal is read less often, which is usually fine for slow signals.&lt;&#x2F;p&gt;
&lt;div class=&quot;admonition tip&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-tip&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;TIP&lt;&#x2F;strong&gt;
        &lt;p&gt;&lt;strong&gt;From the Manual:&lt;&#x2F;strong&gt; The sample rate you choose must at least be twice that of the highest frequency you want to capture - ideally 3 to 5 times as much so that you have some margin. That way, a jittering signal won’t ruin your measurements.&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;how-they-work-together&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#how-they-work-together&quot; aria-label=&quot;Anchor link for: how-they-work-together&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
How They Work Together&lt;&#x2F;h3&gt;
&lt;p&gt;These two settings answer two different questions:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;“The sample rate” answers how fast samples are taken&lt;&#x2F;li&gt;
&lt;li&gt;“The number of samples” answers how many samples are taken&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Together, they decide how long the signal is recorded.&lt;&#x2F;p&gt;
&lt;p&gt;PulseView shows this relationship using the capture duration:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;capture&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; duration = number of samples &#x2F; sample rate&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Suppose you set the sample rate to 20 kHz and the number of samples to 100k. At a 20 kHz sample rate, the logic analyzer records 20,000 samples every second. With 100,000 samples in total, the recording will last for about 5 seconds before stopping.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; class=&quot;language-sh z-code&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;capture&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; duration = 100,000 &#x2F; 20,000 = 5 seconds&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We will use this setting only for our test. It is sufficient here because we are just toggling the GPIO every 500 milliseconds.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;starting-the-capture-and-verifying-the-signal&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#starting-the-capture-and-verifying-the-signal&quot; aria-label=&quot;Anchor link for: starting-the-capture-and-verifying-the-signal&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
Starting the Capture and Verifying the Signal&lt;&#x2F;h2&gt;
&lt;p&gt;With the logic analyzer connected and the capture settings configured, we can now start the capture.&lt;&#x2F;p&gt;
&lt;p&gt;In PulseView, click Run in the top bar (next to the Session label). The logic analyzer will begin recording samples and will automatically stop once it reaches the configured number of samples.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;img&#x2F;2026&#x2F;01&#x2F;logic-analyzer-signal-captured.png&quot;  alt=&quot;Logic Analyzer Signal Captured&quot; style=&quot;width:400px; height:auto; display:block; margin:auto;&quot;&#x2F;&gt;
&lt;p&gt;After the capture stops, you should see a waveform on the enabled channel. In our program, the GPIO state is toggled every 500 milliseconds. As shown in the capture, the signal stays HIGH for 500 ms, then LOW for 500 ms, repeating this pattern consistently.&lt;&#x2F;p&gt;
&lt;p&gt;Since the total capture duration is 5 seconds, this results in 5 HIGH periods and 5 LOW periods across the entire waveform.&lt;&#x2F;p&gt;
&lt;p&gt;Even though the waveform shows only a few visible transitions, the logic analyzer actually recorded all 100,000 samples. Each HIGH or LOW section in the waveform represents many individual samples taken during that time. PulseView automatically zooms out to show the overall shape of the signal rather than displaying every sample at once.&lt;&#x2F;p&gt;
&lt;p&gt;If you zoom in horizontally, you will see that each flat HIGH or LOW region is made up of many samples. This confirms that the GPIO toggling, sampling configuration, and capture duration are all working together as expected.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-s-next&quot;&gt;&lt;a class=&quot;header-anchor no-hover-padding&quot; href=&quot;#what-s-next&quot; aria-label=&quot;Anchor link for: what-s-next&quot;&gt;&lt;span class=&quot;link-icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;a&gt;
What’s Next&lt;&#x2F;h2&gt;
&lt;p&gt;In this post, we focused on getting familiar with the logic analyzer and basic signal capture. I am planning to write a follow-up post focused on analyzing I2C signals, and later cover other protocols as well.&lt;&#x2F;p&gt;
</content>
        <summary type="html">In this post, we take a practical look at using a logic analyzer when working on embedded Rust projects. We cover what a logic analyzer does, how to interpret captured signals, and how it can be used to debug common protocols like I2C, SPI, and UART.</summary>
        </entry>
</feed>
