4/1/2022 - demo for rust raspberry pi pico pio

Rust install on fresh Ubuntu Linux sudo apt install git gdb-multiarch sudo apt install automake autoconf build-essential texinfo libtool libftdi-dev libusb-1.0-0-dev libudev-dev curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh rustc -- version (to check if rust installs successfully) rustup update rustup target install thumbv6m-none-eabi (this is for pico) cargo install flip-link cargo install elf2uf2-rs --locked note: june 26, 2022, I just installed linux liteos 6.0 and it would not install libudev-dev from above step therefore it would not install elf2uf2-rs, after researching on the internet I found this command sudo aptitude install libudev-dev and downgrade to have libudev-dev sucessfully install which in turn installed elf2uf2-rs. clink on the link to see videos demo for: ws2812 (neopixel) uart tx servo pwm exec_instruction digital command control for model trains uart_rx various rust demo for raspberry pi pico pio these are just snippets, if you're having problem compiling visit -> https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal/examples /////////////////////////////////////////////// // demo of dcc // ///////////////////////////////////////////////

main dcc pio

let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer()); let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); let mut tx = dcc::init( pins.gpio15.into_mode(), &mut pio, sm0, clocks.peripheral_clock.freq(),); // address 0x20, forward + speed - 0x76, xor - 0x56 // packet for above - 0xFFFE_203B, pio fifo is 32 bits only, can't fit // the entire packet // next 32 bits - 0x15A0_0000 - after 'A' don't care bits, this is a // continuation of the previous 32 bits // setting on the pio tx is shift direction left // dcc packet - https://www.nmra.org/sites/default/files/s-92-2004-07.pdf /*************************************** * dcc packet format for forward packet * * preamble - 11111111111111 * packet start bit - 0 * address data byte - 0010_0000 - 0x20 * data byte start bit - 0 * data byte - 0111_0110 - 0x76 (forward) * error start bit - 0 * error data byte - 0101_0110 - 0x56 (address xor data) * packect end bit - 1 * don't care bit but use to fill/align pio tx fifo * * now pack all those bits together * * bits together 1111_1111_1110_0010_0000_0011_1011_0001_0101_1010 (last 0 don't care bit) * */ loop { // forward packet - address(0x20), data(0x76), error(0x56) tx.write(0xFFFE_203Bu32); tx.write(0x15A0_0000u32); tx.write(0xFFFE_203Bu32); tx.write(0x15A0_0000u32); delay.delay_ms(3000); // delay should be idle packet every 5 millisecond // reverse packet - address(0x20), data(56), error(0x76) tx.write(0xFFFE_202Bu32); tx.write(0x1DA0_0000u32); tx.write(0xFFFE_202Bu32); tx.write(0x1DA0_0000u32); delay.delay_ms(3000);}} #######################################################################

dcc pio

use embedded_time::{ fixed_point::FixedPoint,}; use rp2040_hal::{ gpio::bank0::Gpio15, gpio::{Function, Pin, PinId}, pio::{PIOBuilder, ShiftDirection, Tx, UninitStateMachine, PIO, SM0}, pac::PIO0,}; pub fn init( _pin: Pin>, pio: &mut PIO, sm: UninitStateMachine<(PIO0, SM0)>, clock_freq: embedded_time::rate::Hertz, ) -> Tx<(PIO0, SM0)> { let program = pio_proc::pio!(32, " .wrap_target bitloop: set pins, 1 [20] out x, 1 jmp !x do_zero set pins, 0 [21] jmp bitloop do_zero: nop [16] set pins, 0 [30] nop [8] .wrap "); let installed = pio.install(&program.program).unwrap(); let div = clock_freq.integer() as f32 / 400_000 as f32; // note the clock divisor let (mut sm, _, tx) = PIOBuilder::from_program(installed) .set_pins(15,1) .autopull(true) .out_shift_direction(ShiftDirection::Left) .clock_divisor(div) .build(sm); sm.set_pindirs([(Gpio15::DYN.num, rp2040_hal::pio::PinDir::Output)]); sm.start(); tx} /////////////////////////////////////////////////////////////////////// // demo max7219 is the slowest clock (0.0) so adjust before using // // datasheet shows it can go much much faster // ///////////////////////////////////////////////////////////////////////

main max7219

let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); let mut tx = max7219::init( // example of calling function that returns tx on pio pins.gpio2.into_mode(), pins.gpio3.into_mode(), pins.gpio4.into_mode(), &mut pio, sm0, clocks.peripheral_clock.freq(),); // setup for max7219 tx.write(0x0f00); tx.write(0x0b07); // 8 digit scan tx.write(0x0a03); // brightness tx.write(0x09ff); // disable 7 seg decodeing delay.delay_ms(100); tx.write(0x0c01); // turn on display delay.delay_ms(100); // shows 0,1,2,3,4,5,6,7 loop { tx.write(0x0100); tx.write(0x0201); tx.write(0x0302); tx.write(0x0403); delay.delay_ms(200); // critical delay to show all digits, because of slow clock setting tx.write(0x0504); tx.write(0x0605); tx.write(0x0706); tx.write(0x0807); delay.delay_ms(1000); #########################################################################

pio max7219

use rp2040_hal::{ gpio::bank0::{Gpio2,Gpio3,Gpio4}, gpio::{Function, Pin, PinId}, pio::{PIOBuilder, ShiftDirection, Tx, UninitStateMachine, PIO, SM0}, pac::PIO0,}; pub fn init( _clk: Pin>, _cs: Pin>, _din: Pin>, pio: &mut PIO, sm: UninitStateMachine<(PIO0, SM0)>, clock_freq: embedded_time::rate::Hertz, ) -> Tx<(PIO0, SM0)> { // https://github.com/jamon/pico-max7219-8x8-led-matrix/blob/main/max7219.pio let program = pio_proc::pio!( 32, " .side_set 2 opt; clk, cs .wrap_target pull ifempty block nop side 0b00 ; clk low, cs low loop: out pins, 1 side 0b00 ; clk low, cs low jmp !osre loop side 0b10 ; clk high, cs low nop side 0b01 ; clk low, cs high .wrap " ); let installed = pio.install(&program.program).unwrap(); let (mut sm, _, tx) = PIOBuilder::from_program(installed) .side_set_pin_base(2) .out_pins(4, 1) .autopull(false) .out_shift_direction(ShiftDirection::Left) .clock_divisor(0f32) // slowest clock possible, adjust for your own use .build(sm); sm.set_pindirs([(Gpio2::DYN.num, rp2040_hal::pio::PinDir::Output)]); sm.set_pindirs([(Gpio3::DYN.num, rp2040_hal::pio::PinDir::Output)]); sm.set_pindirs([(Gpio4::DYN.num, rp2040_hal::pio::PinDir::Output)]); sm.start(); tx} /////////////////////////////////////////////////////////////////// // demo for neopixel ws2812 // ///////////////////////////////////////////////////////////////////

main pio ws2812

const WHITE: u32 = 0x808080; // lower brightness, 0xff max brightness (blinding) const RED: u32 = 0x008000; const BLUE: u32 = 0x800000; const GREEN: u32 = 0x000080; let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer()); let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); let mut tx = ws2812::init( pins.gpio0.into_mode(), &mut pio, sm0, clocks.peripheral_clock.freq(),); loop { tx.write(RED); delay.delay_ms(1000); tx.write(GREEN); delay.delay_ms(1000); ##################################################################

pio ws2812

use embedded_time::{ fixed_point::FixedPoint,}; use rp2040_hal::{ gpio::bank0::Gpio0, gpio::{Function, Pin, PinId}, pio::{PIOBuilder, ShiftDirection, Tx, UninitStateMachine, PIO, SM0}, pac::PIO0,}; pub fn init( pin: Pin>, pio: &mut PIO, sm: UninitStateMachine<(PIO0, SM0)>, clock_freq: embedded_time::rate::Hertz, ) -> Tx<(PIO0, SM0)> { const CYCLES_PER_BIT: u32 = (10) as u32; const FREQ: u32 = 800_000; let program = pio_proc::pio!(32, " ; https://github.com/raspberrypi/pico-examples/blob/master/pio/ws2812/ws2812.pio .side_set 1 .wrap_target bitloop: out x, 1 side 0 [2] jmp !x do_zero side 1 [1] do_one: jmp bitloop side 1 [4] do_zero: nop side 0 [4] .wrap "); let div = clock_freq.integer() as f32 / (FREQ as f32 * CYCLES_PER_BIT as f32); let installed = pio.install(&program.program).unwrap(); let (mut sm, _, tx) = PIOBuilder::from_program(installed) .side_set_pin_base(Gpio0::DYN.num) .autopull(true) .pull_threshold(24) .out_shift_direction(ShiftDirection::Right) // default is left .clock_divisor(div) .build(sm); sm.set_pindirs([(Gpio0::DYN.num, rp2040_hal::pio::PinDir::Output)]); sm.start(); tx} ///////////////////////////////////////////////////////// // demo for uart tx // // adafruit ttl 3.3v white to gpio7 for this test // // adafruit ttl 3.3v black to ground // /////////////////////////////////////////////////////////

main uart_tx

let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer()); let pin: Pin<_, FunctionPio0> = pins.gpio13.into_mode(); let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); let mut tx = UARTTx::new( pin, &mut pio, sm0, clocks.peripheral_clock.freq(),); loop { for n in 48..58 { // write to uart '0', '1', '2' ... (48 ascii is '0') tx.write(n); delay.delay_ms(500);}}} ##################################################################

pio uart tx function vs struct

use embedded_time::{ fixed_point::FixedPoint,}; use rp2040_hal::{ gpio::{Function, FunctionConfig, Pin, PinId, ValidPinMode}, pio::{PIOExt, PIOBuilder, ShiftDirection, StateMachineIndex, Tx, UninitStateMachine, PIO},}; pub struct UARTTx where I: PinId, P: PIOExt + FunctionConfig, Function

: ValidPinMode _LT_I>, SM: StateMachineIndex, { tx: Tx<(P, SM)>, _pin: Pin>, } impl UARTTx where I: PinId, P: PIOExt + FunctionConfig, Function

: ValidPinMode,

    SM: StateMachineIndex,
{
    pub fn new(
        pin: Pin>,
        pio: &mut PIO

, sm: UninitStateMachine<(P, SM)>, clock_freq: embedded_time::rate::Hertz, ) -> Self { const BAUD_RATE: u32 = 57_600; let program = pio_proc::pio!( 32, " .side_set 1 opt .wrap_target pull side 1 [7] set x, 7 side 0 [7] bitloop: out pins, 1 jmp x-- bitloop [6] .wrap "); let div = clock_freq.integer() as f32 / (8 as f32 * BAUD_RATE as f32); let installed = pio.install(&program.program).unwrap(); let (mut sm, _, tx) = PIOBuilder::from_program(installed) .side_set_pin_base(I::DYN.num) .out_pins(I::DYN.num, 1) .autopull(false) .pull_threshold(8) .out_shift_direction(ShiftDirection::Right) // default is left .clock_divisor(div) .build(sm); sm.set_pindirs([(I::DYN.num, rp2040_hal::pio::PinDir::Output)]); sm.start(); Self { tx: tx, _pin: pin } ////////////////////////////////////////////////////////////////////// // demo snippet for pio exec_instruction // // to use exec_instruction, you have to supply the raw hex for the // // instruction, look online for converter // // or pioasm from raspberry pi github, // // this must be done before sm.start() // //////////////////////////////////////////////////////////////////////

pio exec_instruction snippet

example: raw hex 0xe001 -- translate to set pins, 1 see -> https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf look under 3.4 Instruction set for decoding the raw hex let program = pio_proc::pio!(32, " nop "); let installed = pio.install(&program.program).unwrap(); let (mut sm, _, mut tx) = PIOBuilder::from_program(installed) .side_set_pin_base(16) //.set_pins(16,1) .clock_divisor(4.0f32) .build(sm); sm.set_pindirs([(Gpio16::DYN.num, rp2040_hal::pio::PinDir::Output)]); // example of exec_instruction sm.exec_instruction(0xe001); //set pins, 1 cortex_m::asm::delay(30_000_000); sm.exec_instruction(0xe000); // set pins, 0 cortex_m::asm::delay(30_000_000); sm.exec_instruction(0xe001); //set pins, 1 cortex_m::asm::delay(30_000_000); sm.exec_instruction(0xe000); // set pins 0 cortex_m::asm::delay(30_000_000); //////////////////////////////////////////////////////////////////////////// // pwm pio demo, you may need to adjust the centering of the servo // // I found out that different servo, different manufacturer has slight // // modifications, but basically rc servos are: // // // // clockwise - lower than 1500 microsecond (may need reversing) // // center - roughly 1500 microsecond // // counter clockwise - higher than 1500 microsecond (may need reversing) // // // // your pulse should be repeated every 20 millisecond // ////////////////////////////////////////////////////////////////////////////

main servo pwm

let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer()); let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); let mut tx = pwm_pio::init( pins.gpio11.into_mode(), &mut pio, sm0, clocks.peripheral_clock.freq(),); loop { tx.write(4700); delay.delay_ms(2000); tx.write(4855); // center for my servo, you may need to adjust delay.delay_ms(2000); tx.write(4950); delay.delay_ms(2000); tx.write(4855); // center delay.delay_ms(2000); ########################################################################

pio servo pwm

use embedded_time::{ fixed_point::FixedPoint,}; use rp2040_hal::{ gpio::bank0::Gpio11, gpio::{Function, Pin, PinId}, pio::{PIOBuilder, ShiftDirection, Tx, UninitStateMachine, PIO, SM0}, pac::PIO0,}; pub fn init( pin: Pin>, pio: &mut PIO, sm: UninitStateMachine<(PIO0, SM0)>, clock_freq: embedded_time::rate::Hertz, ) -> Tx<(PIO0, SM0)> { let program = pio_proc::pio!(32, " .side_set 1 opt ; blink example ; set x,31 ; set pins, 1 side 1 ;loop: ; jmp x-- loop ; set pins, 0 side 0 ; set x,31 ;loop1: ; jmp x-- loop1 .wrap_target ;pwm from micropython example ; pull noblock side 0 ; mov x, osr ; mov y, isr ;pwmloop: ; jmp x != y skip ; nop side 1 ;skip: ; jmp y-- pwmloop ;pwm from pic c example pull noblock side 0 mov x, osr mov y, isr countloop: jmp x != y noset jmp skip side 1 noset: nop skip: jmp y-- countloop .wrap "); // let div = clock_freq.integer() as f32 / (FREQ as f32 * CYCLES_PER_BIT as f32); let installed = pio.install(&program.program).unwrap(); let (mut sm, _, mut tx) = PIOBuilder::from_program(installed) .side_set_pin_base(11) //.set_pins(16,1) .clock_divisor(13.0f32) /////// adjust this for 20 ms frequency .build(sm); sm.set_pindirs([(Gpio11::DYN.num, rp2040_hal::pio::PinDir::Output)]); tx.write(0xfffd); // preload before state machine starts cortex_m::asm::delay(10_000_000); sm.exec_instruction(0x80a0); // pull block sm.exec_instruction(0xa0c7); // mov isr, osr cortex_m::asm::delay(1_000); sm.start(); tx} /////////////////////////////////////////////////////////// // pwm pio demo // // comment with micropython or c examples // // see servo pwm above to complete the pwm pio example // ///////////////////////////////////////////////////////////

main pwm

let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer()); let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); let mut tx = pwm_pio::init( pins.gpio11.into_mode(), &mut pio, sm0, clocks.peripheral_clock.freq(),); let mut level = 0; // for i in 0..256 { // from micropython // let b = u32::pow(i, 2); // tx.write(b); // delay.delay_ms(10); // tx.write(level * level); // from c example // level = (level + 1) % 256; // delay.delay_ms(10); ##################################################################

pio pwm

let installed = pio.install(&program.program).unwrap(); let (mut sm, _, mut tx) = PIOBuilder::from_program(installed) .side_set_pin_base(11) //.set_pins(16,1) .clock_divisor(13.0f32) .build(sm); sm.set_pindirs([(Gpio11::DYN.num, rp2040_hal::pio::PinDir::Output)]); ;pwm from micropython example ; pull noblock side 0 ; mov x, osr ; mov y, isr ;pwmloop: ; jmp x != y skip ; nop side 1 ;skip: ; jmp y-- pwmloop +++++++++++++++++++++++++++++++++++++++++++++++++++++ ;pwm from pic c example pull noblock side 0 mov x, osr mov y, isr countloop: jmp x != y noset jmp skip side 1 noset: nop skip: jmp y-- countloop

//////////////////////////////////////////
// uart_rx pio demo                     //
//////////////////////////////////////////

main uart_rx

let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer()); let led_pin = &mut pins.led.into_push_pull_output(); led_pin.set_high().unwrap(); let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); let mut rx = uart_rx::init( pins.gpio1.into_mode(), &mut pio, sm0, clocks.peripheral_clock.freq(),); loop { if !rx.is_empty(){ // check if there is something to read match rx.read(){ // read it u32 type None => {} Some(data) => { let b = data.to_be_bytes(); // convert to four u8 i2c.write(0x70, &[0x00, b[0],0,b[1],0,b[2],0]).unwrap(); delay.delay_ms(1000); }}}} led_pin.set_low().unwrap(); delay.delay_ms(1000); }} *****************************************

pio uart_rx

pub fn init( _pin: Pin>, pio: &mut PIO, sm: UninitStateMachine<(PIO0, SM0)>, clock_freq: embedded_time::rate::Hertz, ) -> Rx<(PIO0, SM0)> { const BAUD_RATE: u32 = 57_600; let program = pio_proc::pio!(32, " .wrap_target wait 0 pin 0 set x, 7 [10] bitloop: in pins, 1 jmp x-- bitloop [6] .wrap "); let div = clock_freq.integer() as f32 / (8 as f32 * BAUD_RATE as f32); let installed = pio.install(&program.program).unwrap(); let (mut sm, rx, _) = PIOBuilder::from_program(installed) .in_pin_base(1) .autopush(true) .push_threshold(8) .in_shift_direction(ShiftDirection::Right) // default is left .clock_divisor(div) .build(sm); sm.set_pindirs([(1, PinDir::Input)]); sm.start(); rx} ///////////////////////////////////////////////////////// // clearing pio interrupt different ways // /////////////////////////////////////////////////////////

clearing pio interrupts outside main loop

#![no_std] #![no_main] use cortex_m_rt::entry; use rp2040_hal as hal; use hal::gpio::{FunctionPio0, Pin}; use hal::pac; use hal::pio::PIOExt; use hal::Sio; use hal::pac::interrupt; use panic_halt as _; use core::ptr; #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080; #[entry] fn main() -> ! { let mut pac = pac::Peripherals::take().unwrap(); let sio = Sio::new(pac.SIO); let pins = hal::gpio::Pins::new( pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS,); let _led1: Pin<_, FunctionPio0> = pins.gpio16.into_mode(); let _led2: Pin<_, FunctionPio0> = pins.gpio17.into_mode(); // let's do some time consuming pio so we can slow down the blink for // testing purposes let program = pio_proc::pio!(32, " .side_set 2 opt .wrap_target set x, 31 nop side 0b00 delay1: jmp x-- delay1 set x, 31 nop side 0b10 delay2: jmp x-- delay2 set x, 31 nop side 0b01 delay3: jmp x-- delay3 set x, 31 nop side 0b11 delay4: jmp x-- delay4 irq wait 0 rel .wrap "); // Initialize and start PIO // two led counting to 4 let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); let installed = pio.install(&program.program).unwrap(); let div = 0f32; // as slow as possible (0 is interpreted as 65536) let (mut sm, _, _) = rp2040_hal::pio::PIOBuilder::from_program(installed) .side_set_pin_base(16) .clock_divisor(div) .build(sm0); sm.set_pindirs([(16, hal::pio::PinDir::Output)]); sm.set_pindirs([(17, hal::pio::PinDir::Output)]); sm.start(); unsafe {pac::NVIC::unmask(pac::Interrupt::PIO0_IRQ_0);} let irq = &pio.interrupts()[0]; irq.enable_sm_interrupt(0); #[allow(clippy::empty_loop)] loop {}} #[interrupt] fn PIO0_IRQ_0() { // first way of clearing interrupt inside interrupt function // write 1 to clear interrupt // find registers here --> https://docs.rs/rp2040-pac/0.3.0/rp2040_pac/pio0/struct.RegisterBlock.html // unsafe {(*pac::PIO0::ptr()).irq.modify(|r, w| { w.bits(r.bits() | 1) })}; // this will only change the one bit, the other bits would not be touched /*****************************************************************************/ // second way of clearing interrupt inside interrupt function // write 1 to clear interrupt // const PIO0_IRQ_ADDRESS:u32 = 0x5020_0030; // found on the datasheet unsafe { ptr::write_volatile(PIO0_IRQ_ADDRESS as *mut u32, 0x01u32); }; /*****************************************************************************/ // third way of clearing interrupt inside interrupt function // write 1 to clear interrupt // const PIO0_IRQ_ADDRESS:u32 = 0x5020_0030; // found on the datasheet unsafe { *(PIO0_IRQ_ADDRESS as *mut u32) = 1 << 0; }; /****************************************************************************/ } ///////////////////////////////////////////////////////////// // clearing pio interrupt different ways // // shows counter on a st7789 // // the main loop waits for the pio to issue irq // // then gets the pio y register count and display it // // the y register is loaded with 0 then decrement // // effective starting the countdown at 0xffff_ffff // // you can only load y with up to 31 value // // without side set, so this trick will count down // // from the max u32 // // maybe use this routine to get pulse width // /////////////////////////////////////////////////////////////

clearing pio interrupts inside main loop

#![no_std] #![no_main] use core::fmt::Write; use cortex_m_rt::entry; use embedded_graphics::{ mono_font::{ascii::FONT_10X20, MonoTextStyleBuilder}, pixelcolor::Rgb565, prelude::*, text::{Alignment, Text},}; use embedded_hal::digital::v2::ToggleableOutputPin; use embedded_hal::digital::v2::OutputPin; use embedded_time::rate::*; use panic_halt as _; use arrayvec::ArrayString; use hal::{ pio::PIOExt, clocks::{init_clocks_and_plls, Clock}, pac, sio::Sio, watchdog::Watchdog,}; use st7789::{Orientation, ST7789}; use display_interface_spi::SPIInterface; use rp2040_hal as hal; #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080; pub struct DummyPin; impl OutputPin for DummyPin { type Error = (); fn set_high(&mut self) -> Result<(), Self::Error> { Ok(()) } fn set_low(&mut self) -> Result<(), Self::Error> { Ok(()) } } #[entry] fn main() -> ! { let mut pac = pac::Peripherals::take().unwrap(); let core = pac::CorePeripherals::take().unwrap(); let mut watchdog = Watchdog::new(pac.WATCHDOG); let sio = Sio::new(pac.SIO); let external_xtal_freq_hz = 12_000_000u32; let clocks = init_clocks_and_plls( external_xtal_freq_hz, pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut watchdog,).ok().unwrap(); let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer()); let pins = hal::gpio::Pins::new( pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS,); let mut led = pins.gpio25.into_push_pull_output(); let _spi_sclk = pins.gpio18.into_mode::(); let _spi_mosi = pins.gpio19.into_mode::(); let spi = hal::spi::Spi::<_, _, 8>::new(pac.SPI0); let dc = pins.gpio16.into_push_pull_output(); let cs = pins.gpio17.into_push_pull_output(); let spi = spi.init( &mut pac.RESETS, clocks.peripheral_clock.freq(), 16_000_000u32.Hz(), &embedded_hal::spi::MODE_3,); let di = SPIInterface::new(spi, dc, cs); let mut display = ST7789::new(di, DummyPin, 240, 240); display.init(&mut delay).unwrap(); display.set_orientation(Orientation::Landscape).unwrap(); display.clear(Rgb565::BLACK).unwrap(); let style = MonoTextStyleBuilder::new() .font(&FONT_10X20) .text_color(Rgb565::GREEN) .background_color(Rgb565::BLACK) .build(); let mut counter:u32 = 0; // let's create time consuming pio so we can see the // actual count in the oled let program = pio_proc::pio!(32, " set y, 0 ; can only be set up to 31 .wrap_target ; but if we decrement before using ; then countdown from 0xffff_ffff (which is lot more the 31) set x, 31 delay1: jmp x-- delay1 set x, 31 delay2: jmp x-- delay2 set x, 31 delay3: jmp x-- delay3 set x, 31 delay4: jmp x-- delay4 jmp y-- dummy dummy: mov isr,y push block irq wait 0 rel .wrap "); let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); let installed = pio.install(&program.program).unwrap(); //let div = 0f32; // as slow as possible (0 is interpreted as 65536) let (mut sm, mut pio_rx, _) = rp2040_hal::pio::PIOBuilder::from_program(installed) .clock_divisor(1000_000f32) .autopush(false) .build(sm0); sm.start(); loop { if !pio_rx.is_empty() { // wait until pio push a value counter = pio_rx.read().unwrap(); // read y counter led.toggle().ok(); // toggle pin pio.clear_irq(1); // clear pio irq so it can continue } let mut buf = ArrayString::<100>::new(); writeln!(&mut buf, "Hello World").unwrap(); writeln!(&mut buf, "counter: {}", counter).unwrap(); // show the count on the // st7789 oled Text::with_alignment(&buf, Point::new(20, 30), style, Alignment::Left) .draw(&mut display) .unwrap(); } }