Bare Metal: Pico and CYW43
- 3 minutes read - 453 wordsThe “W” signifies that the board includes wireless. Interestingly, the wireless chip is an Infineon CYW43439) which is itself a microcontroller running its own ARM Cortex chip (M3). The Pico’s USB device includes another ARM microcontroller. So, with the dual Cortex (or Hazard) chips that are user programmable, and the 8 PIOs, these devices really pack a punch.
As a result of adding the wireless (microcontroller) chip to the Pico, the Pico W’s on-board LED is accessible only through the CYW43439. Yeah, weird but it makes for an interesting solution.
The Pico interacts with its wireless chip (the CYW4349) using SPI. I used the example code from the Embassy project wifi_blinky.rs
.
I find this example very interesting. It loads firmware onto the CYW43439 and it uses PIO to implement the communication between the Pico and CYW43439 even though the Pico supports 2 SPIs. This is because the protocol used by the CYW43439 is non-standard.
For consistency, I wanted to try running the 12 WS2812 pixels against the Pico but I’ve been unsuccessful. Moreover, I’ve been unsuccessful generating serial console output on wokwi so it’s extra challenging to debug. I think this should work because, even though the Pico only provides 3.3v (not the 5v required by WS2812s), I’m unsure how relevant the voltages are in the wokwi sim.
While trying (unsuccessfully) to get this to generate serial output in wokwi, I was able to get serial output (and SWD debugging) using a physical Pico.
I reverted the code to use defmt
and added:
use embassy_rp::peripherals::{PIO0,UART0};
use embedded_io::Write;
bind_interrupts!(struct Irqs {
PIO0_IRQ_0 => InterruptHandler<PIO0>;
UART0_IRQ => embassy_rp::uart::InterruptHandler<UART0>;
});
// Include carriage return (`\r`) and newline (`\n`)
#[macro_export]
macro_rules! serial_writeln {
($serial:expr) => {
core::write!($serial, "\r\n").unwrap()
};
($serial:expr, $($arg:tt)*) => {
core::write!($serial, "{}\r\n", format_args!($($arg)*)).unwrap()
};
}
And then within the embassy_executor::main
loop:
loop {
for j in 0..(256 * 5) {
for i in 0..NUM_LEDS {
data[i] = wheel((((i * 256) as u16 / NUM_LEDS as u16 + j as u16) & 255) as u8);
// Use the augmented macro defined above that includes carriage return and newline
serial_writeln!(serial, "R: {:02x} G: {:02x} B: {:02x}", data[i].r, data[i].g, data[i].b);
}
ws2812.write(&data).await;
ticker.next().await;
}
}
After
cargo run
Which resolves to:
probe-rs run \
--chip=RP2040 \
--protocol=swd \
--probe=2e8a:000c
And:
minicom -b 115200 -o -D /dev/ttyACM0
Yields e.g.:
R: 51 G: 00 B: ae
R: 90 G: 00 B: 6f
R: cf G: 00 B: 30
R: f0 G: 0f B: 00
R: b1 G: 4e B: 00
R: 72 G: 8d B: 00
R: 30 G: cf B: 00
R: 00 G: f0 B: 0f
But I get no serial output if I upload the binary to wokwi.
I’ll update this post if that changes.