Stay Ahead, Stay ONMINE

Nine Pico PIO Wats with Rust (Part 2)

This is Part 2 of an exploration into the unexpected quirks of programming the Raspberry Pi Pico PIO with Micropython. If you missed Part 1, we uncovered four Wats that challenge assumptions about register count, instruction slots, the behavior of pull noblock, and smart yet cheap hardware. Now, we continue our journey toward crafting a theremin-like musical instrument — a project that reveals some of the quirks and perplexities of PIO programming. Prepare to challenge your understanding of constants in a way that brings to mind a Shakespearean tragedy. Wat 5: Inconstant constants In the world of PIO programming, constants should be reliable, steadfast, and, well, constant. But what if they’re not? This brings us to a puzzling Wat about how the set instruction in PIO works—or doesn’t—when handling larger constants. Much like Juliet doubting Romeo’s constancy, you might find yourself wondering if PIO constants will, as she says, “prove likewise variable.” The problem: Constants are not as big as they seem Imagine you’re programming an ultrasonic range finder and need to count down from 500 while waiting for the Echo signal to drop from high to low. To set up this wait time in PIO, you might naïvely try to load the constant value directly using set: ; In Rust, be sure ‘config.shift_in.direction = ShiftDirection::Left;’ set y, 15 ; Load upper 5 bits (0b01111) mov isr, y ; Transfer to ISR (clears ISR) set y, 20 ; Load lower 5 bits (0b10100) in y, 5 ; Shift in lower bits to form 500 in ISR mov y, isr ; Transfer back to y Aside: Don’t try to understand the crazy jmp operations here. We’ll discuss those next in Wat 6. But here’s the tragic twist: the set instruction in PIO is limited to constants between 0 and 31. Moreover, the star-crossed set instruction doesn’t report an error. Instead, it silently corrupts the entire PIO instruction. This produces a nonsense result. Workarounds for inconstant constants To address this limitation, consider the following approaches: Read Values and Store Them in a Register: We saw this approach in Wat 1. You can load your constant in the osr register, then transfer it to y. For example: # Read the max echo wait into OSR. pull ; same as pull block mov y, osr ; Load max echo wait into Y Shift and Combine Smaller Values: Using the isr register and the in instruction, you can build up a constant of any size. This, however, consumes time and operations from your 32-operation budget (see Part 1, Wat 2). ; In Rust, be sure ‘config.shift_in.direction = ShiftDirection::Left;’ set y, 15 ; Load upper 5 bits (0b01111) mov isr, y ; Transfer to ISR (clears ISR) set y, 20 ; Load lower 5 bits (0b10100) in y, 5 ; Shift in lower bits to form 500 in ISR mov y, isr ; Transfer back to y Slow Down the Timing: Reduce the frequency of the state machine to stretch delays over more system clock cycles. For example, lowering the state machine speed from 125 MHz to 343 kHz reduces the timeout constant 182,216 to 500.  Use Extra Delays and (Nested) Loops: All instructions support an optional delay, allowing you to add up to 31 extra cycles. (To generate even longer delays, use loops — or even nested loops.) ; Generate 10μs trigger pulse (4 cycles at 343_000Hz) set pins, 1 [3] ; Set trigger pin to high, add delay of 3 set pins, 0 ; Set trigger pin to low voltage Use the “Subtraction Trick” to Generate the Maximum 32-bit Integer: In Wat 7, we’ll explore a way to generate 4,294,967,295 (the maximum unsigned 32-bit integer) via subtraction. Much like Juliet cautioning against swearing by the inconstant moon, we’ve discovered that PIO constants are not always as steadfast as they seem. Yet, just as their story takes unexpected turns, so too does ours, moving from the inconstancy of constants to the uneven nature of conditionals. In the next Wat, we’ll explore how PIO’s handling of conditional jumps can leave you questioning its loyalty to logic. Wat 6: Conditionals through the looking-glass In most programming environments, logical conditionals feel balanced: you can test if a pin is high or low, or check registers for equality or inequality. In PIO, this symmetry breaks down. You can jump on pin high, but not pin low, and on x!=y, but not x==y. The rules are whimsical — like Humpty Dumpty in Through the Looking-Glass: “When I define a conditional, it means just what I choose it to mean — neither more nor less.” These quirks force us to rewrite our code to fit the lopsided logic, creating a gulf between how we wish the code could be written and how we must write it. The problem: Lopsided conditionals in action Consider a simple scenario: using a range finder, you want to count down from a maximum wait time (y) until the ultrasonic echo pin goes low. Intuitively, you might write the logic like this: measure_echo_loop: jmp !pin measurement_complete ; If echo voltage is low, measurement is complete jmp y– measure_echo_loop ; Continue counting down unless timeout And when processing the measurement, if we only wish to output values that differ from the previous value, we would write: measurement_complete: jmp x==y cooldown ; If measurement is the same, skip to cool down mov isr, y ; Store measurement in ISR push ; Output ISR mov x, y ; Save the measurement in X Unfortunately, PIO doesn’t let you test !pin or x==y directly. You must restructure your logic to accommodate the available conditionals, such as pin and x!=y. The solution: The way it must be Given PIO’s limitations, we adapt our logic with a two-step approach that ensures the desired behavior despite the missing conditionals: Jump on the opposite conditional to skip two instructions forward. Next, use an unconditional jump to reach the desired target. This workaround adds one extra jump (affecting the instruction limit), but the additional label is cost-free. Here is the rewritten code for counting down until the pin goes low: measure_echo_loop: jmp pin echo_active ; if echo voltage is high continue count down jmp measurement_complete ; if echo voltage is low, measurement is complete echo_active: jmp y– measure_echo_loop ; Continue counting down unless timeout And here is the code for processing the measurement such that it will only output differing values: measurement_complete: jmp x!=y send_result ; if measurement is different, then send it. jmp cooldown ; If measurement is the same, don’t send. send_result: mov isr, y ; Store measurement in ISR push ; Output ISR mov x, y ; Save the measurement in X Lessons from Humpty Dumpty’s conditionals In Through the Looking-Glass, Alice learns to navigate Humpty Dumpty’s peculiar world — just as you’ll learn to navigate PIO’s Wonderland of lopsided conditions. But as soon as you master one quirk, another reveals itself. In the next Wat, we’ll uncover a surprising behavior of jmp that, if it were an athlete, would shatter world records. In Part 1’s Wat 1 and Wat 3, we saw how jmp x– or jmp y– is often used to loop a fixed number of times by decrementing a register until it reaches 0. Straightforward enough, right? But what happens when y is 0 and we run the following instruction? jmp y– measure_echo_loop If you guessed that it does not jump to measure_echo_loop and instead falls through to the next instruction, you’re absolutely correct. But for full credit, answer this: What value does y have after the instruction? The answer: 4,294,967,295. Why? Because y is decremented after it is tested for zero. Wat!? Aside: If this doesn’t surprise you, you likely have experience with C or C++ which distinguish between pre-increment (e.g., ++x) and post-increment (e.g., x++) operations. The behavior of jmp y– is equivalent to a post-decrement, where the value is tested before being decremented. This value, 4,294,967,295, is the maximum for a 32-bit unsigned integer. It’s as if a track-and-field long jumper launches off the takeoff board but, instead of landing in the sandpit, overshoots and ends up on another continent. Aside: As foreshadowed in Wat 5, we can use this behavior intentionally to set a register to the value 4,294,967,295. Now that we’ve learned how to stick the landing with jmp, let’s see if we can avoid getting stuck by the pins that PIO reads and sets. In Dr. Seuss’s Too Many Daves, Mrs. McCave had 23 sons, all named Dave, leading to endless confusion whenever she called out their name. In PIO programming, pin and pins can refer to completely different ranges of pins depending on the context. It’s hard to know which Dave or Daves you’re talking to. The problem: Pin ranges and subranges In PIO, both pin and pins instructions depend on pin ranges defined in Rust, outside of PIO. However, individual instructions often operate on a subrange of those pin ranges. The behavior varies depending on the command: the subrange could be the first n pins of the range, all the pins, or just a specific pin given by an index. To clarify PIO’s behavior, I created the following table: This table shows how PIO interprets the terms pin and pins in different instructions, along with their associated contexts and configurations. Example: Distance program for the range finder Here’s a PIO program for measuring the distance to an object using Trigger and Echo pins. The key features of this program are: Continuous Operation: The range finder runs in a loop as fast as possible. Maximum Range Limit: Measurements are capped at a given distance, with a return value of 4,294,967,295 if no object is detected. Filtered Outputs: Only measurements that differ from their immediate predecessor are sent, reducing the output rate. Glance over the program and notice that although it is working with two pins — Trigger and Echo — throughout the program we only see pin and pins. .program distance ; X is the last value sent. Initialize it to ; u32::MAX which means ‘echo timeout’ ; (Set X to u32::MAX by subtracting 1 from 0) set x, 0 subtraction_trick: jmp x– subtraction_trick ; Read the max echo wait into OSR pull ; same as pull block ; Main loop .wrap_target ; Generate 10μs trigger pulse (4 cycles at 343_000Hz) set pins, 0b1 [3] ; Set trigger pin to high, add delay of 3 set pins, 0b0 ; Set trigger pin to low voltage ; When the trigger goes high, start counting down until it goes low wait 1 pin 0 ; Wait for echo pin to be high voltage mov y, osr ; Load max echo wait into Y measure_echo_loop: jmp pin echo_active ; if echo voltage is high continue count down jmp measurement_complete ; if echo voltage is low, measurement is complete echo_active: jmp y– measure_echo_loop ; Continue counting down unless timeout ; Y tells where the echo countdown stopped. It ; will be u32::MAX if the echo timed out. measurement_complete: jmp x!=y send_result ; if measurement is different, then sent it. jmp cooldown ; If measurement is the same, don’t send. send_result: mov isr, y ; Store measurement in ISR push ; Output ISR mov x, y ; Save the measurement in X ; Cool down period before next measurement cooldown: wait 0 pin 0 ; Wait for echo pin to be low .wrap ; Restart the measurement loop Configuring Pins To ensure the PIO program behaves as intended: set pins, 0b1 should control the Trigger pin. wait 1 pin 0 should monitor the Echo pin. jmp pin echo_active should also monitor the Echo pin. Here’s how you can configure this in Rust (followed by an explanation): let mut distance_state_machine = pio1.sm0; let trigger_pio = pio1.common.make_pio_pin(hardware.trigger); let echo_pio = pio1.common.make_pio_pin(hardware.echo); distance_state_machine.set_pin_dirs(Direction::Out, &[&trigger_pio]); distance_state_machine.set_pin_dirs(Direction::In, &[&echo_pio]); distance_state_machine.set_config(&{ let mut config = Config::default(); config.set_set_pins(&[&trigger_pio]); // For set instruction config.set_in_pins(&[&echo_pio]); // For wait instruction config.set_jmp_pin(&echo_pio); // For jmp instruction let program_with_defines = pio_file!(“examples/distance.pio”); let program = pio1.common.load_program(&program_with_defines.program); config.use_program(&program, &[]); // No side-set pins config }); The keys here are the set_set_pins, set_in_pins, and set_jmp_pin methods on the Config struct. set_in_pins: Specifies the pins for input operations, such as wait(1, pin, …). The “in” pins must be consecutive. set_set_pins: Configures the pin for set operations, like set(pins, 1). The “set” pins must also be consecutive. set_jmp_pin: Defines the single pin used in conditional jumps, such as jmp(pin, …). As described in the table, other optional inputs include: set_out_pins: Sets the consecutive pins for output operations, such as out(pins, …). use_program: Sets a) the loaded program and b) consecutive pins for sideset operations. Sideset operations allow simultaneous pin toggling during other instructions. Configuring Multiple Pins Although not required for this program, you can configure a range of pins in PIO by providing a slice of consecutive pins. For example, suppose we had two ultrasonic range finders: let trigger_a_pio = pio1.common.make_pio_pin(hardware.trigger_a); let trigger_b_pio = pio1.common.make_pio_pin(hardware.trigger_b); config.set_set_pins(&[&trigger_a_pio, &trigger_b_pio]); A single instruction can then control both pins: set pins, 0b11 [3] # Sets both trigger pins (17, 18) high, adds delay set pins, 0b00 # Sets both trigger pins low This approach lets you efficiently apply bit patterns to multiple pins simultaneously, streamlining control for applications involving multiple outputs. Aside: The Word “Set” in Programming In programming, the word “set” is notoriously overloaded with multiple meanings. In the context of PIO, “set” refers to something to which you can assign a value — such as a pin’s state. It does not mean a collection of things, as it often does in other programming contexts. When PIO refers to a collection, it usually uses the term “range” instead. This distinction is crucial for avoiding confusion as you work with PIO. Lessons from Mrs. McCave In Too Many Daves, Mrs. McCave lamented not giving her 23 Daves more distinct names. You can avoid her mistake by clearly documenting your pins with meaningful names — like Trigger and Echo — in your comments. But if you think handling these pin ranges is tricky, debugging a PIO program adds an entirely new layer of challenge. In the next Wat, we’ll dive into the kludgy debugging methods available. Let’s see just how far we can push them. I like to debug with interactive breakpoints in VS Code. I also do print debugging, where you insert temporary info statements to see what the code is doing and the values of variables. Using the Raspberry Pi Debug Probe and probe-rs, I can do both of these with regular Rust code on the Pico. With PIO programming, however, I can do neither. The fallback is push-to-print debugging. In PIO, you temporarily output integer values of interest. Then, in Rust, you use info! to print those values for inspection. For example, in the following PIO program, we temporarily add instructions to push the value of x for debugging. We also include set and out to push a constant value, such as 7, which must be between 0 and 31 inclusive. .program distance ; X is the last value sent. Initialize it to ; u32::MAX which means ‘echo timeout’ ; (Set X to u32::MAX by subtracting 1 from 0) set x, 0 subtraction_trick: jmp x– subtraction_trick ; DEBUG: See the value of x mov isr, x push ; Read the max echo wait into OSR pull ; same as pull block ; DEBUG: Send constant value set y, 7 ; Push ‘7’ so that we know we’ve reached this point mov isr, y push ; … Back in Rust, you can read and print these values to help understand what’s happening in the PIO code (full code and project): // … distance_state_machine.set_enable(true); distance_state_machine.tx().wait_push(MAX_LOOPS).await; loop { let end_loops = distance_state_machine.rx().wait_pull().await; info!(“end_loops: {}”, end_loops); } // … Outputs: INFO Hello, debug! └─ distance_debug::inner_main::{async_fn#0} @ examplesdistance_debug.rs:27 INFO end_loops: 4294967295 └─ distance_debug::inner_main::{async_fn#0} @ examplesdistance_debug.rs:57 INFO end_loops: 7 └─ distance_debug::inner_main::{async_fn#0} @ examplesdistance_debug.rs:57 When push-to-print debugging isn’t enough, you can turn to hardware tools. I bought my first oscilloscope (a FNIRSI DSO152, for $37). With it, I was able to confirm the Echo signal was working. The Trigger signal, however, was too fast for this inexpensive oscilloscope to capture clearly. Using these methods — especially push-to-print debugging — you can trace the flow of your PIO program, even without a traditional debugger. Aside: In C/C++ (and potentially Rust), you can get closer to a full debugging experience for PIO, for example, by using the piodebug project. That concludes the nine Wats, but let’s bring everything together in a bonus Wat. Now that all the components are ready, it’s time to combine them into a working theremin-like musical instrument. We need a Rust monitor program. This program starts both PIO state machines — one for measuring distance and the other for generating tones. It then waits for a new distance measurement, maps that distance to a tone, and sends the corresponding tone frequency to the tone-playing state machine. If the distance is out of range, it stops the tone. Rust’s Place: At the heart of this system is a function that maps distances (from 0 to 50 cm) to tones (approximately B2 to F5). This function is simple to write in Rust, leveraging Rust’s floating-point math and exponential operations. Implementing this in PIO would be virtually impossible due to its limited instruction set and lack of floating-point support. Here’s the core monitor program to run the theremin (full file and project): sound_state_machine.set_enable(true); distance_state_machine.set_enable(true); distance_state_machine.tx().wait_push(MAX_LOOPS).await; loop { let end_loops = distance_state_machine.rx().wait_pull().await; match loop_difference_to_distance_cm(end_loops) { None = > { info!(“Distance: out of range”); sound_state_machine.tx().wait_push(0).await; } Some(distance_cm) = > { let tone_frequency = distance_to_tone_frequency(distance_cm); let half_period = sound_state_machine_frequency / tone_frequency as u32 / 2; info!(“Distance: {} cm, tone: {} Hz”, distance_cm, tone_frequency); sound_state_machine.tx().push(half_period); // non-blocking push Timer::after(Duration::from_millis(50)).await; } } } Using two PIO state machines alongside a Rust monitor program lets you literally run three programs at once. This setup is convenient on its own and is essential when strict timing or very high-frequency I/O operations are required. Aside: Alternatively, Rust Embassy’s async tasks let you implement cooperative multitasking directly on a single main processor. You code in Rust rather than a mixture of Rust and PIO. Although Embassy tasks don’t literally run in parallel, they switch quickly enough to handle applications like a theremin. Here’s a snippet from theremin_no_pio.rs showing a similar core loop: loop { match distance.measure().await { None = > { info!(“Distance: out of range”); sound.rest().await; } Some(distance_cm) = > { let tone_frequency = distance_to_tone_frequency(distance_cm); info!(“Distance: {} cm, tone: {} Hz”, distance_cm, tone_frequency); sound.play(tone_frequency).await; Timer::after(Duration::from_millis(50)).await; } } } See our recent article on Rust Embassy programming for more details. Now that we’ve assembled all the components, let’s watch the video again of me “playing” the musical instrument. On the monitor screen, you can see the debugging prints displaying the distance measurements and the corresponding tones. This visual connection highlights how the system responds in real time. [embedded content] Conclusion PIO programming on the Raspberry Pi Pico is a captivating blend of simplicity and complexity, offering unparalleled hardware control while demanding a shift in mindset for developers accustomed to higher-level programming. Through the nine Wats we’ve explored, PIO has both surprised us with its limitations and impressed us with its raw efficiency. While we’ve covered significant ground — managing state machines, pin assignments, timing intricacies, and debugging — there’s still much more you can learn as needed: DMA, IRQ, side-set pins, differences between PIO on the Pico 1 and Pico 2, autopush and autopull, FIFO join, and more. Recommended Resources At its core, PIO’s quirks reflect a design philosophy that prioritizes low-level hardware control with minimal overhead. By embracing these characteristics, PIO will not only meet your project’s demands but also open doors to new possibilities in embedded systems programming. Please follow Carl on Towards Data Science and on @carlkadie.bsky.social. I write on scientific programming in Rust and Python, machine learning, and statistics. I tend to write about one article per month.

This is Part 2 of an exploration into the unexpected quirks of programming the Raspberry Pi Pico PIO with Micropython. If you missed Part 1, we uncovered four Wats that challenge assumptions about register count, instruction slots, the behavior of pull noblock, and smart yet cheap hardware.

Now, we continue our journey toward crafting a theremin-like musical instrument — a project that reveals some of the quirks and perplexities of PIO programming. Prepare to challenge your understanding of constants in a way that brings to mind a Shakespearean tragedy.

Wat 5: Inconstant constants

In the world of PIO programming, constants should be reliable, steadfast, and, well, constant. But what if they’re not? This brings us to a puzzling Wat about how the set instruction in PIO works—or doesn’t—when handling larger constants.

Much like Juliet doubting Romeo’s constancy, you might find yourself wondering if PIO constants will, as she says, “prove likewise variable.”

The problem: Constants are not as big as they seem

Imagine you’re programming an ultrasonic range finder and need to count down from 500 while waiting for the Echo signal to drop from high to low. To set up this wait time in PIO, you might naïvely try to load the constant value directly using set:

; In Rust, be sure 'config.shift_in.direction = ShiftDirection::Left;'
set y, 15       ; Load upper 5 bits (0b01111)
mov isr, y      ; Transfer to ISR (clears ISR)
set y, 20       ; Load lower 5 bits (0b10100)
in y, 5         ; Shift in lower bits to form 500 in ISR
mov y, isr      ; Transfer back to y

Aside: Don’t try to understand the crazy jmp operations here. We’ll discuss those next in Wat 6.

But here’s the tragic twist: the set instruction in PIO is limited to constants between 0 and 31. Moreover, the star-crossed set instruction doesn’t report an error. Instead, it silently corrupts the entire PIO instruction. This produces a nonsense result.

Workarounds for inconstant constants

To address this limitation, consider the following approaches:

  • Read Values and Store Them in a Register: We saw this approach in Wat 1. You can load your constant in the osr register, then transfer it to y. For example:
# Read the max echo wait into OSR.
pull                    ; same as pull block
mov y, osr              ; Load max echo wait into Y
  • Shift and Combine Smaller Values: Using the isr register and the in instruction, you can build up a constant of any size. This, however, consumes time and operations from your 32-operation budget (see Part 1, Wat 2).
; In Rust, be sure 'config.shift_in.direction = ShiftDirection::Left;'

set y, 15       ; Load upper 5 bits (0b01111)
mov isr, y      ; Transfer to ISR (clears ISR)
set y, 20       ; Load lower 5 bits (0b10100)
in y, 5         ; Shift in lower bits to form 500 in ISR
mov y, isr      ; Transfer back to y
  • Slow Down the Timing: Reduce the frequency of the state machine to stretch delays over more system clock cycles. For example, lowering the state machine speed from 125 MHz to 343 kHz reduces the timeout constant 182,216 to 500
  • Use Extra Delays and (Nested) Loops: All instructions support an optional delay, allowing you to add up to 31 extra cycles. (To generate even longer delays, use loops — or even nested loops.)
; Generate 10μs trigger pulse (4 cycles at 343_000Hz)
set pins, 1 [3]       ; Set trigger pin to high, add delay of 3
set pins, 0           ; Set trigger pin to low voltage
  • Use the “Subtraction Trick” to Generate the Maximum 32-bit Integer: In Wat 7, we’ll explore a way to generate 4,294,967,295 (the maximum unsigned 32-bit integer) via subtraction.

Much like Juliet cautioning against swearing by the inconstant moon, we’ve discovered that PIO constants are not always as steadfast as they seem. Yet, just as their story takes unexpected turns, so too does ours, moving from the inconstancy of constants to the uneven nature of conditionals. In the next Wat, we’ll explore how PIO’s handling of conditional jumps can leave you questioning its loyalty to logic.

Wat 6: Conditionals through the looking-glass

In most programming environments, logical conditionals feel balanced: you can test if a pin is high or low, or check registers for equality or inequality. In PIO, this symmetry breaks down. You can jump on pin high, but not pin low, and on x!=y, but not x==y. The rules are whimsical — like Humpty Dumpty in Through the Looking-Glass: “When I define a conditional, it means just what I choose it to mean — neither more nor less.”

These quirks force us to rewrite our code to fit the lopsided logic, creating a gulf between how we wish the code could be written and how we must write it.

The problem: Lopsided conditionals in action

Consider a simple scenario: using a range finder, you want to count down from a maximum wait time (y) until the ultrasonic echo pin goes low. Intuitively, you might write the logic like this:

measure_echo_loop:
 jmp !pin measurement_complete   ; If echo voltage is low, measurement is complete
 jmp y-- measure_echo_loop       ; Continue counting down unless timeout

And when processing the measurement, if we only wish to output values that differ from the previous value, we would write:

measurement_complete:
 jmp x==y cooldown             ; If measurement is the same, skip to cool down
 mov isr, y                    ; Store measurement in ISR
 push                          ; Output ISR
 mov x, y                      ; Save the measurement in X

Unfortunately, PIO doesn’t let you test !pin or x==y directly. You must restructure your logic to accommodate the available conditionals, such as pin and x!=y.

The solution: The way it must be

Given PIO’s limitations, we adapt our logic with a two-step approach that ensures the desired behavior despite the missing conditionals:

  • Jump on the opposite conditional to skip two instructions forward.
  • Next, use an unconditional jump to reach the desired target.

This workaround adds one extra jump (affecting the instruction limit), but the additional label is cost-free.

Here is the rewritten code for counting down until the pin goes low:

measure_echo_loop:
   jmp pin echo_active     ; if echo voltage is high continue count down
   jmp measurement_complete ; if echo voltage is low, measurement is complete
echo_active:
   jmp y-- measure_echo_loop ; Continue counting down unless timeout

And here is the code for processing the measurement such that it will only output differing values:

measurement_complete:
   jmp x!=y send_result    ; if measurement is different, then send it.
   jmp cooldown            ; If measurement is the same, don't send.

send_result:
   mov isr, y              ; Store measurement in ISR
   push                    ; Output ISR
   mov x, y               ; Save the measurement in X

Lessons from Humpty Dumpty’s conditionals

In Through the Looking-Glass, Alice learns to navigate Humpty Dumpty’s peculiar world — just as you’ll learn to navigate PIO’s Wonderland of lopsided conditions.

But as soon as you master one quirk, another reveals itself. In the next Wat, we’ll uncover a surprising behavior of jmp that, if it were an athlete, would shatter world records.

In Part 1’s Wat 1 and Wat 3, we saw how jmp x-- or jmp y-- is often used to loop a fixed number of times by decrementing a register until it reaches 0. Straightforward enough, right? But what happens when y is 0 and we run the following instruction?

jmp y-- measure_echo_loop

If you guessed that it does not jump to measure_echo_loop and instead falls through to the next instruction, you’re absolutely correct. But for full credit, answer this: What value does y have after the instruction?

The answer: 4,294,967,295. Why? Because y is decremented after it is tested for zero. Wat!?

Aside: If this doesn’t surprise you, you likely have experience with C or C++ which distinguish between pre-increment (e.g., ++x) and post-increment (e.g., x++) operations. The behavior of jmp y-- is equivalent to a post-decrement, where the value is tested before being decremented.

This value, 4,294,967,295, is the maximum for a 32-bit unsigned integer. It’s as if a track-and-field long jumper launches off the takeoff board but, instead of landing in the sandpit, overshoots and ends up on another continent.

Aside: As foreshadowed in Wat 5, we can use this behavior intentionally to set a register to the value 4,294,967,295.

Now that we’ve learned how to stick the landing with jmp, let’s see if we can avoid getting stuck by the pins that PIO reads and sets.

In Dr. Seuss’s Too Many Daves, Mrs. McCave had 23 sons, all named Dave, leading to endless confusion whenever she called out their name. In PIO programming, pin and pins can refer to completely different ranges of pins depending on the context. It’s hard to know which Dave or Daves you’re talking to.

The problem: Pin ranges and subranges

In PIO, both pin and pins instructions depend on pin ranges defined in Rust, outside of PIO. However, individual instructions often operate on a subrange of those pin ranges. The behavior varies depending on the command: the subrange could be the first n pins of the range, all the pins, or just a specific pin given by an index. To clarify PIO’s behavior, I created the following table:

This table shows how PIO interprets the terms pin and pins in different instructions, along with their associated contexts and configurations.

Example: Distance program for the range finder

Here’s a PIO program for measuring the distance to an object using Trigger and Echo pins. The key features of this program are:

  • Continuous Operation: The range finder runs in a loop as fast as possible.
  • Maximum Range Limit: Measurements are capped at a given distance, with a return value of 4,294,967,295 if no object is detected.
  • Filtered Outputs: Only measurements that differ from their immediate predecessor are sent, reducing the output rate.

Glance over the program and notice that although it is working with two pins — Trigger and Echo — throughout the program we only see pin and pins.

.program distance

; X is the last value sent. Initialize it to
; u32::MAX which means 'echo timeout'
; (Set X to u32::MAX by subtracting 1 from 0)
   set x, 0
subtraction_trick:
   jmp x-- subtraction_trick

; Read the max echo wait into OSR
   pull                         ; same as pull block

; Main loop
.wrap_target
   ; Generate 10μs trigger pulse (4 cycles at 343_000Hz)
   set pins, 0b1 [3]       ; Set trigger pin to high, add delay of 3
   set pins, 0b0           ; Set trigger pin to low voltage

   ; When the trigger goes high, start counting down until it goes low
   wait 1 pin 0            ; Wait for echo pin to be high voltage
   mov y, osr              ; Load max echo wait into Y

measure_echo_loop:
   jmp pin echo_active     ; if echo voltage is high continue count down
   jmp measurement_complete ; if echo voltage is low, measurement is complete
echo_active:
   jmp y-- measure_echo_loop ; Continue counting down unless timeout

; Y tells where the echo countdown stopped. It
; will be u32::MAX if the echo timed out.
measurement_complete:
   jmp x!=y send_result    ; if measurement is different, then sent it.
   jmp cooldown            ; If measurement is the same, don't send.

send_result:
   mov isr, y              ; Store measurement in ISR
   push                    ; Output ISR
   mov x, y               ; Save the measurement in X

; Cool down period before next measurement
cooldown:
   wait 0 pin 0           ; Wait for echo pin to be low
.wrap                      ; Restart the measurement loop

Configuring Pins

To ensure the PIO program behaves as intended:

  • set pins, 0b1 should control the Trigger pin.
  • wait 1 pin 0 should monitor the Echo pin.
  • jmp pin echo_active should also monitor the Echo pin.

Here’s how you can configure this in Rust (followed by an explanation):

let mut distance_state_machine = pio1.sm0;
let trigger_pio = pio1.common.make_pio_pin(hardware.trigger);
let echo_pio = pio1.common.make_pio_pin(hardware.echo);
distance_state_machine.set_pin_dirs(Direction::Out, &[&trigger_pio]);
distance_state_machine.set_pin_dirs(Direction::In, &[&echo_pio]);
distance_state_machine.set_config(&{
   let mut config = Config::default();
   config.set_set_pins(&[&trigger_pio]); // For set instruction
   config.set_in_pins(&[&echo_pio]); // For wait instruction
   config.set_jmp_pin(&echo_pio); // For jmp instruction
   let program_with_defines = pio_file!("examples/distance.pio");
   let program = pio1.common.load_program(&program_with_defines.program);
   config.use_program(&program, &[]); // No side-set pins
   config
});

The keys here are the set_set_pins, set_in_pins, and set_jmp_pin methods on the Config struct.

  • set_in_pins: Specifies the pins for input operations, such as wait(1, pin, …). The “in” pins must be consecutive.
  • set_set_pins: Configures the pin for set operations, like set(pins, 1). The “set” pins must also be consecutive.
  • set_jmp_pin: Defines the single pin used in conditional jumps, such as jmp(pin, ...).

As described in the table, other optional inputs include:

  • set_out_pins: Sets the consecutive pins for output operations, such as out(pins, …).
  • use_program: Sets a) the loaded program and b) consecutive pins for sideset operations. Sideset operations allow simultaneous pin toggling during other instructions.

Configuring Multiple Pins

Although not required for this program, you can configure a range of pins in PIO by providing a slice of consecutive pins. For example, suppose we had two ultrasonic range finders:

let trigger_a_pio = pio1.common.make_pio_pin(hardware.trigger_a);
let trigger_b_pio = pio1.common.make_pio_pin(hardware.trigger_b);
config.set_set_pins(&[&trigger_a_pio, &trigger_b_pio]);

A single instruction can then control both pins:

set pins, 0b11 [3]  # Sets both trigger pins (17, 18) high, adds delay
set pins, 0b00      # Sets both trigger pins low

This approach lets you efficiently apply bit patterns to multiple pins simultaneously, streamlining control for applications involving multiple outputs.

Aside: The Word “Set” in Programming

In programming, the word “set” is notoriously overloaded with multiple meanings. In the context of PIO, “set” refers to something to which you can assign a value — such as a pin’s state. It does not mean a collection of things, as it often does in other programming contexts. When PIO refers to a collection, it usually uses the term “range” instead. This distinction is crucial for avoiding confusion as you work with PIO.

Lessons from Mrs. McCave

In Too Many Daves, Mrs. McCave lamented not giving her 23 Daves more distinct names. You can avoid her mistake by clearly documenting your pins with meaningful names — like Trigger and Echo — in your comments.

But if you think handling these pin ranges is tricky, debugging a PIO program adds an entirely new layer of challenge. In the next Wat, we’ll dive into the kludgy debugging methods available. Let’s see just how far we can push them.

I like to debug with interactive breakpoints in VS Code. I also do print debugging, where you insert temporary info statements to see what the code is doing and the values of variables. Using the Raspberry Pi Debug Probe and probe-rs, I can do both of these with regular Rust code on the Pico.

With PIO programming, however, I can do neither.

The fallback is push-to-print debugging. In PIO, you temporarily output integer values of interest. Then, in Rust, you use info! to print those values for inspection.

For example, in the following PIO program, we temporarily add instructions to push the value of x for debugging. We also include set and out to push a constant value, such as 7, which must be between 0 and 31 inclusive.

.program distance

; X is the last value sent. Initialize it to
; u32::MAX which means 'echo timeout'
; (Set X to u32::MAX by subtracting 1 from 0)
   set x, 0
subtraction_trick:
   jmp x-- subtraction_trick

; DEBUG: See the value of x
   mov isr, x
   push

; Read the max echo wait into OSR
   pull                         ; same as pull block

; DEBUG: Send constant value
   set y, 7           ; Push '7' so that we know we've reached this point
   mov isr, y
   push
; ...

Back in Rust, you can read and print these values to help understand what’s happening in the PIO code (full code and project):

  // ...
   distance_state_machine.set_enable(true);
   distance_state_machine.tx().wait_push(MAX_LOOPS).await;
   loop {
       let end_loops = distance_state_machine.rx().wait_pull().await;
       info!("end_loops: {}", end_loops);
   }
  // ...

Outputs:

INFO  Hello, debug!
└─ distance_debug::inner_main::{async_fn#0} @ examplesdistance_debug.rs:27
INFO  end_loops: 4294967295
└─ distance_debug::inner_main::{async_fn#0} @ examplesdistance_debug.rs:57
INFO  end_loops: 7
└─ distance_debug::inner_main::{async_fn#0} @ examplesdistance_debug.rs:57

When push-to-print debugging isn’t enough, you can turn to hardware tools. I bought my first oscilloscope (a FNIRSI DSO152, for $37). With it, I was able to confirm the Echo signal was working. The Trigger signal, however, was too fast for this inexpensive oscilloscope to capture clearly.

Using these methods — especially push-to-print debugging — you can trace the flow of your PIO program, even without a traditional debugger.

Aside: In C/C++ (and potentially Rust), you can get closer to a full debugging experience for PIO, for example, by using the piodebug project.

That concludes the nine Wats, but let’s bring everything together in a bonus Wat.

Now that all the components are ready, it’s time to combine them into a working theremin-like musical instrument. We need a Rust monitor program. This program starts both PIO state machines — one for measuring distance and the other for generating tones. It then waits for a new distance measurement, maps that distance to a tone, and sends the corresponding tone frequency to the tone-playing state machine. If the distance is out of range, it stops the tone.

Rust’s Place: At the heart of this system is a function that maps distances (from 0 to 50 cm) to tones (approximately B2 to F5). This function is simple to write in Rust, leveraging Rust’s floating-point math and exponential operations. Implementing this in PIO would be virtually impossible due to its limited instruction set and lack of floating-point support.

Here’s the core monitor program to run the theremin (full file and project):

sound_state_machine.set_enable(true);
distance_state_machine.set_enable(true);
distance_state_machine.tx().wait_push(MAX_LOOPS).await;
loop {
   let end_loops = distance_state_machine.rx().wait_pull().await;
   match loop_difference_to_distance_cm(end_loops) {
       None => {
           info!("Distance: out of range");
           sound_state_machine.tx().wait_push(0).await;
       }
       Some(distance_cm) => {
           let tone_frequency = distance_to_tone_frequency(distance_cm);
           let half_period = sound_state_machine_frequency / tone_frequency as u32 / 2;
           info!("Distance: {} cm, tone: {} Hz", distance_cm, tone_frequency);
           sound_state_machine.tx().push(half_period); // non-blocking push
           Timer::after(Duration::from_millis(50)).await;
       }
   }
}

Using two PIO state machines alongside a Rust monitor program lets you literally run three programs at once. This setup is convenient on its own and is essential when strict timing or very high-frequency I/O operations are required.

Aside: Alternatively, Rust Embassy’s async tasks let you implement cooperative multitasking directly on a single main processor. You code in Rust rather than a mixture of Rust and PIO. Although Embassy tasks don’t literally run in parallel, they switch quickly enough to handle applications like a theremin. Here’s a snippet from theremin_no_pio.rs showing a similar core loop:

loop {
       match distance.measure().await {
           None => {
               info!("Distance: out of range");
               sound.rest().await;
           }
           Some(distance_cm) => {
               let tone_frequency = distance_to_tone_frequency(distance_cm);
               info!("Distance: {} cm, tone: {} Hz", distance_cm, tone_frequency);
               sound.play(tone_frequency).await;
               Timer::after(Duration::from_millis(50)).await;
           }
       }
   }

See our recent article on Rust Embassy programming for more details.

Now that we’ve assembled all the components, let’s watch the video again of me “playing” the musical instrument. On the monitor screen, you can see the debugging prints displaying the distance measurements and the corresponding tones. This visual connection highlights how the system responds in real time.

Conclusion

PIO programming on the Raspberry Pi Pico is a captivating blend of simplicity and complexity, offering unparalleled hardware control while demanding a shift in mindset for developers accustomed to higher-level programming. Through the nine Wats we’ve explored, PIO has both surprised us with its limitations and impressed us with its raw efficiency.

While we’ve covered significant ground — managing state machines, pin assignments, timing intricacies, and debugging — there’s still much more you can learn as needed: DMA, IRQ, side-set pins, differences between PIO on the Pico 1 and Pico 2, autopush and autopull, FIFO join, and more.

Recommended Resources

At its core, PIO’s quirks reflect a design philosophy that prioritizes low-level hardware control with minimal overhead. By embracing these characteristics, PIO will not only meet your project’s demands but also open doors to new possibilities in embedded systems programming.

Please follow Carl on Towards Data Science and on @carlkadie.bsky.social. I write on scientific programming in Rust and Python, machine learning, and statistics. I tend to write about one article per month.

Shape
Shape
Stay Ahead

Explore More Insights

Stay ahead with more perspectives on cutting-edge power, infrastructure, energy,  bitcoin and AI solutions. Explore these articles to uncover strategies and insights shaping the future of industries.

Shape

EPA to end environmental justice programs, monitoring tools

Dive Brief: The Trump administration announced Wednesday it will shut down all environmental justice offices and officially end other EJ-related initiatives, a move that will impact how waste and recycling industries measure and track their environmental impact on neighboring communities. The closures include the EPA’s Office of Environmental Justice and

Read More »

Intel under Tan: What enterprise IT buyers need to know

Intel’s discrete GPU ambitions — especially in enterprise AI — have often appeared reactive rather than part of a clear strategic vision. The company entered the market late, facing Nvidia’s dominant CUDA ecosystem and AMD’s aggressive push into AI GPUs. “Tan’s background suggests he is unlikely to double down on

Read More »

SUSE expands AI tools to control workloads, LLM usage

“And every few weeks we’ll continue to add to the library,” Puri says. SUSE also announced a partnership with Infosys today. The system integrator has the Topaz AI platform, which includes a set of services and solutions to help enterprises build and deploy AI applications. SUSE is also integrating the

Read More »

D-Wave uses quantum to solve real-world problem

D-Wave published its results today, peer-reviewed in the journal Science. The classical supercomputer that D-Wave benchmarked against was the Frontier supercomputer at the Department of Energy’s Oak Ridge National Laboratory. It was, until recently, the most powerful supercomputer in the world but moved to second place in November. Two different

Read More »

Energy Bosses Shrug Off DeepSeek to Focus on Powering AI Boom

While tariffs and macroeconomic concerns weighed on the outlook for oil at a major energy conference in Houston this week, the mood around artificial intelligence and its sky-high power needs could scarcely be different. For a second year, energy executives at the CERAWeek by S&P Global gathering hailed the looming data center requirements for AI as both a huge challenge and a once-in-a-generation opportunity.  “The only way we win the AI arms race with China is if we have electricity,” US Interior Secretary Doug Burgum said in his address. “They are moving at a speed that would suggest we are in a serious cyberwar with them.” The energy world appears to have shrugged off investor doubts that emerged over the AI-power narrative in January, when Chinese startup DeepSeek released a chat bot purported to use just a fraction of the electricity required by established US rivals. Despite that wobble, many forecasts for US power demand are still unprecedented — and come after more than two decades of stable consumption. Jenny Yang, head of power and renewables research at S&P, told conference delegates Thursday that US utilities’ estimates for additional power demand coming just from data centers by 2030 are equivalent to the entire Ercot power market in Texas. “We’re seeing load forecasts that, in my experience as a state regulator, are mind-boggling,” said Mark Christie, a former energy regulator in Virginia, the data-center capital of the US, and who now chairs the Federal Energy Regulatory Commission. The so-called hyperscalers continue to race ahead with their build-out of AI infrastructure. Google parent Alphabet Inc. reported last month it plans capital expenditures of $75 billion this year.  The power demand related to that spending “is coming so fast and from so many different directions,” Alan Armstrong, chief executive officer of US pipeline operator Williams

Read More »

The Emperor’s New Clothes: BP and Shell’s duck diplomacy

BP’s (LON:BP) undressing of its energy transition goals is the latest and most significant example of an oil supermajor reneging on its green investment pledges. It is easy to speculate that companies such as BP, and similarly Shell (LON:SHEL), have attempted to diversify into renewable energy too quickly. However, diversification in the energy transition could be the very thing that pulls the cart out of danger. This week, BP’s chief executive Murray Auchincloss defended the company’s decision to jettison renewable energy pledges and increase oil and gas production. In late February, he said the oil major had accelerated “too far, too fast” in the transition to renewable energy. “Our optimism for a fast transition was misplaced,” he said, after profits fell across its low-carbon and gas division, precipitating a sudden strategic about-face. The company, which has been under pressure from analysts and shareholders to reduce its low-carbon investments and double down on its core business of oil and gas, plans to cut investment in low-carbon projects by $5 billion (£4bn), Auchincloss said. © Image: BloombergLondon’s Old Oil Stocks Diverge | BP underperforms Shell on worries about green transition, payouts. “The challenge that faces BP and Equinor, and to varying degrees Shell and Equinor, is the marked underperformance of their shares relative to that of their US peers,” says Russ Mould, investment director at AJ Bell. “Whether this is down to the relatively greater emphasis they have placed upon investment in renewables to facilitate a move away from hydrocarbons or simply down to their stock market domicile (given how US equities continue to dominate across the board) is hard to divine, but the truth may well lie somewhere between. There is a sense that shareholders are becoming restless.” BP’s shares have shown a marked underperformance relative to global peers since former

Read More »

Peterhead’s Acorn CCS key to unlocking future of Grangemouth

Grangemouth will need the Acorn Carbon Capture and Storage (CCS) development to go ahead to take full advantage of the upcoming £13 billion Project Willow plan. Colin Pritchard, sustainability and external relations director at Ineos, which runs the Grangemouth refinery Petroineos in a joint venture with PetroChina, said: “If you want to really go for all of the things that are within Willow and take them to the full extent, you will need a CO2 transportation and storage system. “In that case, the full extent of Willow needs Acorn.” Project Willow is the plan currently being developed by the UK and Scottish Governments to ameliorate the closure of the Scotland’s only oil refinery with the expected loss of 400 jobs. Due for release soon, Project Willow  will lay out nine potential projects to overhaul the Grangemouth refinery in Scotland and create a long-term sustainable future for the site. A feasibility study exploring options for overhauling the Grangemouth refinery in Scotland is reportedly set to propose £3.8bn of investments in low-carbon alternatives for the site over ten years, with a best-case scenario could see the amount rise to almost £13bn. These options include recycling plastics, the production of biomethane, sustainable aviation fuel (SAF) and renewable diesel. In turn, these are hoped to avert the shutdown of Grangemouth, scheduled for the second quarter of this year, and preserve jobs at the facility. Speaking to Energy Voice on the side-lines of the DeCarbScotland event, Pritchard added: “There are some projects there are not dependent on Acorn, but there are some projects within Willow, like e-methanol, which are.” He added that the nine projects envisioned in Project Willow are an initial project set and could evolve, making CCS essential “if you want to get the full benefit of what we put in Willow”. Based in

Read More »

EIA Reveals Latest Brent Oil Price Forecast for 2025 and 2026

The U.S. Energy Information Administration (EIA) has revealed its latest Brent spot price forecast for 2025 and 2026 in its March Short Term Energy Outlook (STEO), which was released this week. According to the STEO, the EIA now sees the Brent spot price averaging $74.22 per barrel this year and $68.47 per barrel next year. In its previous STEO, which was released in February, the EIA projected that the Brent spot price would average $74.50 per barrel in 2025 and $66.46 per barrel in 2026. The EIA outlined in its latest STEO that it sees the Brent spot price coming in at $74.89 per barrel in the first quarter of this year, $74.00 per barrel in the second quarter, $75.00 per barrel in the third quarter, $73.02 per barrel in the fourth quarter, $71.00 per barrel in the first quarter of 2026, $69.00 per barrel in the second quarter, $68.00 per barrel in the third quarter, and $66.00 per barrel in the fourth quarter. In its previous February STEO, the EIA forecast that the Brent spot price would average $77.13 per barrel in the first quarter of 2025, $75.00 per barrel in the second quarter, $74.00 per barrel in the third quarter, $72.00 per barrel in the fourth quarter, $68.97 per barrel in the first quarter of 2026, $67.33 per barrel in the second quarter, $65.68 per barrel in the third quarter, and $64.00 per barrel in the fourth quarter of next year. In its latest STEO, the EIA highlighted that the Brent crude oil spot price averaged $75 per barrel in February, which it pointed out was $4 per barrel lower than in January and $8 per barrel lower than at the same time last year. “Crude oil prices fell during February driven largely by economic growth concerns related

Read More »

Wisconsin Utilities Regulator Approves ALLETE Privatization

The Public Service Commission of Wisconsin (PSCW) on Thursday cleared power utility and renewables developer ALLETE Inc.’s acquisition by a partnership between Canada Pension Plan (CPP) Investments and Global Infrastructure Partners (GIP). The United States Federal Energy Regulatory Commission (FERC) already approved the transaction last year. Duluth, Minnesota-based ALLETE needed a separate approval from the PSCW as it owns a regulated utility supplying electricity, natural gas and water to Wisconsin customers. “ALLETE continues to work on securing the last major regulatory approval for the transaction from the Minnesota Public Utilities Commission [MPUC]”, the company, which owns Minnesota Power, said in an online statement Thursday. ALLETE expects the transaction to close mid-2025. Shareholders approved the deal August 21, 2024, with 97 percent of votes cast in favor. That represented about 74 percent of shares, according to ALLETE. “Following close, ALLETE will remain locally managed and operated”, it said Thursday. “Its utilities, Minnesota Power and SWL&P [in Wisconsin], will continue to be regulated by the MPUC, the PSCW and FERC. “The acquisition is not expected to impact retail or municipal rates for utility customers”. Under the transaction announced May 6, 2024, the CPP Investments-GIP partnership will acquire the publicly issued shares of Duluth, Minnesota-based ALLETE for $67 a unit in cash. Inclusive of ALLETE’s debt, the transaction has a total value of $6.2 billion. CPP Investments and GIP will retain ALLETE’s leadership and workforce, honor union contracts, retain ALLETE’s headquarters and continue ALLETE’s plans and goals, according to the May announcement. “Transitioning to a private company with these strong partners will not only limit our exposure to volatile financial markets, it also will ensure ALLETE has access to the significant capital needed for our planned investments now and over the long term”, ALLETE chair, president and chief executive Bethany Owen said May. James Bryce, managing director and global head of infrastructure at CPP Investments, said then, “ALLETE

Read More »

MISO overstates transmission plan benefits by excluding Invenergy project: market monitor

The Midcontinent Independent System Operator’s failure to include Invenergy Transmission’s Grain Belt Express project in its transmission planning process likely led the grid operator to overstate the benefits of a system buildout, according to MISO’s market monitor. The benefits of MISO’s roughly $10.3 billion Tranche 1 and $22 billion Tranche 2.1 transmission expansion plans would have been reduced if the proposed Grain Belt Express project was included in MISO’s planning process, David Patton, president of Potomac Economics, said in a filing at the Federal Energy Regulatory Commission on Thursday. Patton urged FERC to act on a complaint Invenergy filed in August 2022 over MISO excluding the Grain Belt Express project from its transmission expansion planning. Chicago-based Invenergy plans to build the 5-GW Grain Belt Express transmission line in phases from Kansas to Illinois. The U.S. Department of Energy in November conditionally agreed to a loan guarantee of up to $4.9 billion for the project’s first phase. Missouri Attorney General Andrew Bailey on March 6 urged the Department of Government Efficiency to cancel the loan guarantee. Overall, Patton contends that MISO’s transmission plans and business case analyses are “highly biased in favor of over-building transmission.” A “properly calculated” benefit-cost ratio for the Tranche 2.1 transmission projects would be less than 0.4, according to Patton. MISO estimated the portfolio of transmission projects — approved by the grid operator’s board in December — have a benefit-cost ratio of 1.8 to 3.5. There has been little independent oversight of how MISO develops its planning scenarios, selects transmission projects to be built, establishes its cost-benefit methodologies or sets the assumptions and inputs for its models, Patton said. MISO recently tried to limit Potomac Economics’ ability to monitor the grid operator’s transmission planning process, saying it is outside the scope of the market monitor’s duties, according to

Read More »

IBM laying foundation for mainframe as ultimate AI server

“It will truly change what customers are able to do with AI,” Stowell said. IBM’s mainframe processors The next generation of processors is expected to continue a long history of generation-to-generation improvements, IBM stated in a new white paper on AI and the mainframe. “They are projected to clock in at 5.5 GHz. and include ten 36 MB level 2 caches. They’ll feature built-in low-latency data processing for accelerated I/O as well as a completely redesigned cache and chip-interconnection infrastructure for more on-chip cache and compute capacity,” IBM wrote.  Today’s mainframes also have extensions and accelerators that integrate with the core systems. These specialized add-ons are designed to enable the adoption of technologies such as Java, cloud and AI by accelerating computing paradigms that are essential for high-volume, low-latency transaction processing, IBM wrote.  “The next crop of AI accelerators are expected to be significantly enhanced—with each accelerator designed to deliver 4 times more compute power, reaching 24 trillion operations per second (TOPS),” IBM wrote. “The I/O and cache improvements will enable even faster processing and analysis of large amounts of data and consolidation of workloads running across multiple servers, for savings in data center space and power costs. And the new accelerators will provide increased capacity to enable additional transaction clock time to perform enhanced in-transaction AI inferencing.” In addition, the next generation of the accelerator architecture is expected to be more efficient for AI tasks. “Unlike standard CPUs, the chip architecture will have a simpler layout, designed to send data directly from one compute engine, and use a range of lower- precision numeric formats. These enhancements are expected to make running AI models more energy efficient and far less memory intensive. As a result, mainframe users can leverage much more complex AI models and perform AI inferencing at a greater scale

Read More »

VergeIO enhances VergeFabric network virtualization offering

VergeIO is not, however, using an off-the-shelf version of KVM. Rather, it is using what Crump referred to as a heavily modified KVM hypervisor base, with significant proprietary enhancements while still maintaining connections to the open-source community. VergeIO’s deployment profile is currently 70% on premises and about 30% via bare-metal service providers, with a particularly strong following among cloud service providers that host applications for their customers. The software requires direct hardware access due to its low-level integration with physical resources. “Since November of 2023, the normal number one customer we’re attracting right now is guys that have had a heart attack when they got their VMware renewal license,” Crump said. “The more of the stack you own, the better our story becomes.” A 2024 report from Data Center Intelligence Group (DCIG) identified VergeOS as one of the top 5 alternatives to VMware. “VergeIO starts by installing VergeOS on bare metal servers,” the report stated. “It then brings the servers’ hardware resources under its management, catalogs these resources, and makes them available to VMs. By directly accessing and managing the server’s hardware resources, it optimizes them in ways other hypervisors often cannot.” Advanced networking features in VergeFabric VergeFabric is the networking component within the VergeOS ecosystem, providing software-defined networking capabilities as an integrated service rather than as a separate virtual machine or application.

Read More »

Podcast: On the Frontier of Modular Edge AI Data Centers with Flexnode’s Andrew Lindsey

The modular data center industry is undergoing a seismic shift in the age of AI, and few are as deeply embedded in this transformation as Andrew Lindsey, Co-Founder and CEO of Flexnode. In a recent episode of the Data Center Frontier Show podcast, Lindsey joined Editor-in-Chief Matt Vincent and Senior Editor David Chernicoff to discuss the evolution of modular data centers, the growing demand for high-density liquid-cooled solutions, and the industry factors driving this momentum. A Background Rooted in Innovation Lindsey’s career has been defined by the intersection of technology and the built environment. Prior to launching Flexnode, he worked at Alpha Corporation, a top 100 engineering and construction management firm founded by his father in 1979. His early career involved spearheading technology adoption within the firm, with a focus on high-security infrastructure for both government and private clients. Recognizing a massive opportunity in the data center space, Lindsey saw a need for an innovative approach to infrastructure deployment. “The construction industry is relatively uninnovative,” he explained, citing a McKinsey study that ranked construction as the second least-digitized industry—just above fishing and wildlife, which remains deliberately undigitized. Given the billions of square feet of data center infrastructure required in a relatively short timeframe, Lindsey set out to streamline and modernize the process. Founded four years ago, Flexnode delivers modular data centers with a fully integrated approach, handling everything from site selection to design, engineering, manufacturing, deployment, operations, and even end-of-life decommissioning. Their core mission is to provide an “easy button” for high-density computing solutions, including cloud and dedicated GPU infrastructure, allowing faster and more efficient deployment of modular data centers. The Rising Momentum for Modular Data Centers As Vincent noted, Data Center Frontier has closely tracked the increasing traction of modular infrastructure. Lindsey has been at the forefront of this

Read More »

Last Energy to Deploy 30 Microreactors in Texas for Data Centers

As the demand for data center power surges in Texas, nuclear startup Last Energy has now announced plans to build 30 microreactors in the state’s Haskell County near the Dallas-Fort Worth Metroplex. The reactors will serve a growing customer base of data center operators in the region looking for reliable, carbon-free energy. The plan marks Last Energy’s largest project to date and a significant step in advancing modular nuclear power as a viable solution for high-density computing infrastructure. Meeting the Looming Power Demands of Texas Data Centers Texas is already home to over 340 data centers, with significant expansion underway. Google is increasing its data center footprint in Dallas, while OpenAI’s Stargate has announced plans for a new facility in Abilene, just an hour south of Last Energy’s planned site. The company notes the Dallas-Fort Worth metro area alone is projected to require an additional 43 gigawatts of power in the coming years, far surpassing current grid capacity. To help remediate, Last Energy has secured a 200+ acre site in Haskell County, approximately three and a half hours west of Dallas. The company has also filed for a grid connection with ERCOT, with plans to deliver power via a mix of private wire and grid transmission. Additionally, Last Energy has begun pre-application engagement with the U.S. Nuclear Regulatory Commission (NRC) for an Early Site Permit, a key step in securing regulatory approval. According to Last Energy CEO Bret Kugelmass, the company’s modular approach is designed to bring nuclear energy online faster than traditional projects. “Nuclear power is the most effective way to meet Texas’ growing energy demand, but it needs to be deployed faster and at scale,” Kugelmass said. “Our microreactors are designed to be plug-and-play, enabling data center operators to bypass the constraints of an overloaded grid.” Scaling Nuclear for

Read More »

Data Center Jobs: Engineering and Technician Jobs Available in Major Markets

Each month Data Center Frontier, in partnership with Pkaza, posts some of the hottest data center career opportunities in the market. Here’s a look at some of the latest data center jobs posted on the Data Center Frontier jobs board, powered by Pkaza Critical Facilities Recruiting.  Data Center Facility Engineer (Night Shift Available) Ashburn, VAThis position is also available in: Tacoma, WA (Nights), Days/Nights: Needham, MA and New York City, NY. This opportunity is working directly with a leading mission-critical data center developer / wholesaler / colo provider. This firm provides data center solutions custom-fit to the requirements of their client’s mission-critical operational facilities. They provide reliability of mission-critical facilities for many of the world’s largest organizations facilities supporting enterprise clients and hyperscale companies. This opportunity provides a career-growth minded role with exciting projects with leading-edge technology and innovation as well as competitive salaries and benefits. Electrical Commissioning Engineer New Albany, OHThis traveling position is also available in: Somerset, NJ; Boydton, VA; Richmond, VA; Ashburn, VA; Charlotte, NC; Atlanta, GA; Hampton, GA; Fayetteville, GA; Des Moines, IA; San Jose, CA; Portland, OR; St Louis, MO; Phoenix, AZ;  Dallas, TX;  Chicago, IL; or Toronto, ON. *** ALSO looking for a LEAD EE and ME CxA agents.*** Our client is an engineering design and commissioning company that has a national footprint and specializes in MEP critical facilities design. They provide design, commissioning, consulting and management expertise in the critical facilities space. They have a mindset to provide reliability, energy efficiency, sustainable design and LEED expertise when providing these consulting services for enterprise, colocation and hyperscale companies. This career-growth minded opportunity offers exciting projects with leading-edge technology and innovation as well as competitive salaries and benefits. Switchgear Field Service Technician – Critical Facilities Nationwide TravelThis position is also available in: Charlotte, NC; Atlanta, GA; Dallas,

Read More »

Amid Shifting Regional Data Center Policies, Iron Mountain and DC Blox Both Expand in Virginia’s Henrico County

The dynamic landscape of data center developments in Maryland and Virginia exemplify the intricate balance between fostering technological growth and addressing community and environmental concerns. Data center developers in this region find themselves both in the crosshairs of groups worried about the environment and other groups looking to drive economic growth. In some cases, the groups are different components of the same organizations, such as local governments. For data center development, meeting the needs of these competing interests often means walking a none-too-stable tightrope. Rapid Government Action Encourages Growth In May 2024, Maryland demonstrated its commitment to attracting data center investments by enacting the Critical Infrastructure Streamlining Act. This legislation provides a clear framework for the use of emergency backup power generation, addressing previous regulatory challenges that a few months earlier had hindered projects like Aligned Data Centers’ proposed 264-megawatt campus in Frederick County, causing Aligned to pull out of the project. However, just days after the Act was signed by the governor, Aligned reiterated its plans to move forward with development in Maryland.  With the Quantum Loop and the related data center development making Frederick County a focal point for a balanced approach, the industry is paying careful attention to the pace of development and the relations between developers, communities and the government. In September of 2024, Frederick County Executive Jessica Fitzwater revealed draft legislation that would potentially restrict where in the county data centers could be built. The legislation was based on information found in the Frederick County Data Centers Workgroup’s final report. Those bills would update existing regulations and create a floating zone for Critical Digital Infrastructure and place specific requirements on siting data centers. Statewide, a cautious approach to environmental and community impacts statewide has been deemed important. In January 2025, legislators introduced SB116,  a bill

Read More »

Microsoft will invest $80B in AI data centers in fiscal 2025

And Microsoft isn’t the only one that is ramping up its investments into AI-enabled data centers. Rival cloud service providers are all investing in either upgrading or opening new data centers to capture a larger chunk of business from developers and users of large language models (LLMs).  In a report published in October 2024, Bloomberg Intelligence estimated that demand for generative AI would push Microsoft, AWS, Google, Oracle, Meta, and Apple would between them devote $200 billion to capex in 2025, up from $110 billion in 2023. Microsoft is one of the biggest spenders, followed closely by Google and AWS, Bloomberg Intelligence said. Its estimate of Microsoft’s capital spending on AI, at $62.4 billion for calendar 2025, is lower than Smith’s claim that the company will invest $80 billion in the fiscal year to June 30, 2025. Both figures, though, are way higher than Microsoft’s 2020 capital expenditure of “just” $17.6 billion. The majority of the increased spending is tied to cloud services and the expansion of AI infrastructure needed to provide compute capacity for OpenAI workloads. Separately, last October Amazon CEO Andy Jassy said his company planned total capex spend of $75 billion in 2024 and even more in 2025, with much of it going to AWS, its cloud computing division.

Read More »

John Deere unveils more autonomous farm machines to address skill labor shortage

Join our daily and weekly newsletters for the latest updates and exclusive content on industry-leading AI coverage. Learn More Self-driving tractors might be the path to self-driving cars. John Deere has revealed a new line of autonomous machines and tech across agriculture, construction and commercial landscaping. The Moline, Illinois-based John Deere has been in business for 187 years, yet it’s been a regular as a non-tech company showing off technology at the big tech trade show in Las Vegas and is back at CES 2025 with more autonomous tractors and other vehicles. This is not something we usually cover, but John Deere has a lot of data that is interesting in the big picture of tech. The message from the company is that there aren’t enough skilled farm laborers to do the work that its customers need. It’s been a challenge for most of the last two decades, said Jahmy Hindman, CTO at John Deere, in a briefing. Much of the tech will come this fall and after that. He noted that the average farmer in the U.S. is over 58 and works 12 to 18 hours a day to grow food for us. And he said the American Farm Bureau Federation estimates there are roughly 2.4 million farm jobs that need to be filled annually; and the agricultural work force continues to shrink. (This is my hint to the anti-immigration crowd). John Deere’s autonomous 9RX Tractor. Farmers can oversee it using an app. While each of these industries experiences their own set of challenges, a commonality across all is skilled labor availability. In construction, about 80% percent of contractors struggle to find skilled labor. And in commercial landscaping, 86% of landscaping business owners can’t find labor to fill open positions, he said. “They have to figure out how to do

Read More »

2025 playbook for enterprise AI success, from agents to evals

Join our daily and weekly newsletters for the latest updates and exclusive content on industry-leading AI coverage. Learn More 2025 is poised to be a pivotal year for enterprise AI. The past year has seen rapid innovation, and this year will see the same. This has made it more critical than ever to revisit your AI strategy to stay competitive and create value for your customers. From scaling AI agents to optimizing costs, here are the five critical areas enterprises should prioritize for their AI strategy this year. 1. Agents: the next generation of automation AI agents are no longer theoretical. In 2025, they’re indispensable tools for enterprises looking to streamline operations and enhance customer interactions. Unlike traditional software, agents powered by large language models (LLMs) can make nuanced decisions, navigate complex multi-step tasks, and integrate seamlessly with tools and APIs. At the start of 2024, agents were not ready for prime time, making frustrating mistakes like hallucinating URLs. They started getting better as frontier large language models themselves improved. “Let me put it this way,” said Sam Witteveen, cofounder of Red Dragon, a company that develops agents for companies, and that recently reviewed the 48 agents it built last year. “Interestingly, the ones that we built at the start of the year, a lot of those worked way better at the end of the year just because the models got better.” Witteveen shared this in the video podcast we filmed to discuss these five big trends in detail. Models are getting better and hallucinating less, and they’re also being trained to do agentic tasks. Another feature that the model providers are researching is a way to use the LLM as a judge, and as models get cheaper (something we’ll cover below), companies can use three or more models to

Read More »

OpenAI’s red teaming innovations define new essentials for security leaders in the AI era

Join our daily and weekly newsletters for the latest updates and exclusive content on industry-leading AI coverage. Learn More OpenAI has taken a more aggressive approach to red teaming than its AI competitors, demonstrating its security teams’ advanced capabilities in two areas: multi-step reinforcement and external red teaming. OpenAI recently released two papers that set a new competitive standard for improving the quality, reliability and safety of AI models in these two techniques and more. The first paper, “OpenAI’s Approach to External Red Teaming for AI Models and Systems,” reports that specialized teams outside the company have proven effective in uncovering vulnerabilities that might otherwise have made it into a released model because in-house testing techniques may have missed them. In the second paper, “Diverse and Effective Red Teaming with Auto-Generated Rewards and Multi-Step Reinforcement Learning,” OpenAI introduces an automated framework that relies on iterative reinforcement learning to generate a broad spectrum of novel, wide-ranging attacks. Going all-in on red teaming pays practical, competitive dividends It’s encouraging to see competitive intensity in red teaming growing among AI companies. When Anthropic released its AI red team guidelines in June of last year, it joined AI providers including Google, Microsoft, Nvidia, OpenAI, and even the U.S.’s National Institute of Standards and Technology (NIST), which all had released red teaming frameworks. Investing heavily in red teaming yields tangible benefits for security leaders in any organization. OpenAI’s paper on external red teaming provides a detailed analysis of how the company strives to create specialized external teams that include cybersecurity and subject matter experts. The goal is to see if knowledgeable external teams can defeat models’ security perimeters and find gaps in their security, biases and controls that prompt-based testing couldn’t find. What makes OpenAI’s recent papers noteworthy is how well they define using human-in-the-middle

Read More »