PIO support for RPi Pico
This commit is contained in:
		| @@ -26,6 +26,7 @@ time-driver = [] | ||||
| rom-func-cache = [] | ||||
| intrinsics = [] | ||||
| rom-v2-intrinsics = [] | ||||
| pio = ["dep:pio", "dep:pio-proc"] | ||||
|  | ||||
| # Enable nightly-only features | ||||
| nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"] | ||||
| @@ -64,3 +65,10 @@ embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["un | ||||
| embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} | ||||
| embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true} | ||||
| embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true} | ||||
|  | ||||
| paste = "1.0" | ||||
| pio-proc = {version= "0.2", optional = true} | ||||
| pio = {version= "0.2", optional = true} | ||||
|  | ||||
| [patch.crates-io] | ||||
| pio = {git = "https://github.com/rp-rs/pio-rs.git"} | ||||
| @@ -48,6 +48,21 @@ pub enum Pull { | ||||
|     Down, | ||||
| } | ||||
|  | ||||
| /// Drive strength of an output | ||||
| #[derive(Debug, Eq, PartialEq)] | ||||
| pub enum Drive { | ||||
|     _2mA, | ||||
|     _4mA, | ||||
|     _8mA, | ||||
|     _12mA, | ||||
| } | ||||
| /// Slew rate of an output | ||||
| #[derive(Debug, Eq, PartialEq)] | ||||
| pub enum SlewRate { | ||||
|     Fast, | ||||
|     Slow, | ||||
| } | ||||
|  | ||||
| /// A GPIO bank with up to 32 pins. | ||||
| #[derive(Debug, Eq, PartialEq)] | ||||
| pub enum Bank { | ||||
| @@ -459,7 +474,7 @@ impl<'d, T: Pin> Flex<'d, T> { | ||||
|     #[inline] | ||||
|     pub fn set_pull(&mut self, pull: Pull) { | ||||
|         unsafe { | ||||
|             self.pin.pad_ctrl().write(|w| { | ||||
|             self.pin.pad_ctrl().modify(|w| { | ||||
|                 w.set_ie(true); | ||||
|                 match pull { | ||||
|                     Pull::Up => w.set_pue(true), | ||||
| @@ -470,6 +485,31 @@ impl<'d, T: Pin> Flex<'d, T> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Set the pin's drive strength. | ||||
|     #[inline] | ||||
|     pub fn set_drive_strength(&mut self, strength: Drive) { | ||||
|         unsafe { | ||||
|             self.pin.pad_ctrl().modify(|w| { | ||||
|                 w.set_drive(match strength { | ||||
|                     Drive::_2mA => pac::pads::vals::Drive::_2MA, | ||||
|                     Drive::_4mA => pac::pads::vals::Drive::_4MA, | ||||
|                     Drive::_8mA => pac::pads::vals::Drive::_8MA, | ||||
|                     Drive::_12mA => pac::pads::vals::Drive::_12MA, | ||||
|                 }); | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Set the pin's slew rate. | ||||
|     #[inline] | ||||
|     pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { | ||||
|         unsafe { | ||||
|             self.pin.pad_ctrl().modify(|w| { | ||||
|                 w.set_slewfast(slew_rate == SlewRate::Fast); | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Put the pin into input mode. | ||||
|     /// | ||||
|     /// The pull setting is left unchanged. | ||||
|   | ||||
| @@ -12,6 +12,12 @@ pub mod dma; | ||||
| pub mod gpio; | ||||
| pub mod i2c; | ||||
| pub mod interrupt; | ||||
|  | ||||
| #[cfg(feature = "pio")] | ||||
| pub mod pio; | ||||
| #[cfg(feature = "pio")] | ||||
| pub mod pio_instr_util; | ||||
|  | ||||
| pub mod rom_data; | ||||
| pub mod rtc; | ||||
| pub mod spi; | ||||
| @@ -102,6 +108,9 @@ embassy_hal_common::peripherals! { | ||||
|     FLASH, | ||||
|  | ||||
|     ADC, | ||||
|  | ||||
|     PIO0, | ||||
|     PIO1, | ||||
| } | ||||
|  | ||||
| #[link_section = ".boot2"] | ||||
|   | ||||
							
								
								
									
										1250
									
								
								embassy-rp/src/pio.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1250
									
								
								embassy-rp/src/pio.rs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										90
									
								
								embassy-rp/src/pio_instr_util.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								embassy-rp/src/pio_instr_util.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | ||||
| use pio::{InSource, InstructionOperands, JmpCondition, OutDestination, SetDestination}; | ||||
|  | ||||
| use crate::pio::PioStateMachine; | ||||
|  | ||||
| pub fn set_x<SM: PioStateMachine>(sm: &mut SM, value: u32) { | ||||
|     const OUT: u16 = InstructionOperands::OUT { | ||||
|         destination: OutDestination::X, | ||||
|         bit_count: 32, | ||||
|     } | ||||
|     .encode(); | ||||
|     sm.push_tx(value); | ||||
|     sm.exec_instr(OUT); | ||||
| } | ||||
|  | ||||
| pub fn get_x<SM: PioStateMachine>(sm: &mut SM) -> u32 { | ||||
|     const IN: u16 = InstructionOperands::IN { | ||||
|         source: InSource::X, | ||||
|         bit_count: 32, | ||||
|     } | ||||
|     .encode(); | ||||
|     sm.exec_instr(IN); | ||||
|     sm.pull_rx() | ||||
| } | ||||
|  | ||||
| pub fn set_y<SM: PioStateMachine>(sm: &mut SM, value: u32) { | ||||
|     const OUT: u16 = InstructionOperands::OUT { | ||||
|         destination: OutDestination::Y, | ||||
|         bit_count: 32, | ||||
|     } | ||||
|     .encode(); | ||||
|     sm.push_tx(value); | ||||
|     sm.exec_instr(OUT); | ||||
| } | ||||
|  | ||||
| pub fn get_y<SM: PioStateMachine>(sm: &mut SM) -> u32 { | ||||
|     const IN: u16 = InstructionOperands::IN { | ||||
|         source: InSource::Y, | ||||
|         bit_count: 32, | ||||
|     } | ||||
|     .encode(); | ||||
|     sm.exec_instr(IN); | ||||
|  | ||||
|     sm.pull_rx() | ||||
| } | ||||
|  | ||||
| pub fn set_pindir<SM: PioStateMachine>(sm: &mut SM, data: u8) { | ||||
|     let set: u16 = InstructionOperands::SET { | ||||
|         destination: SetDestination::PINDIRS, | ||||
|         data, | ||||
|     } | ||||
|     .encode(); | ||||
|     sm.exec_instr(set); | ||||
| } | ||||
|  | ||||
| pub fn set_pin<SM: PioStateMachine>(sm: &mut SM, data: u8) { | ||||
|     let set: u16 = InstructionOperands::SET { | ||||
|         destination: SetDestination::PINS, | ||||
|         data, | ||||
|     } | ||||
|     .encode(); | ||||
|     sm.exec_instr(set); | ||||
| } | ||||
|  | ||||
| pub fn set_out_pin<SM: PioStateMachine>(sm: &mut SM, data: u32) { | ||||
|     const OUT: u16 = InstructionOperands::OUT { | ||||
|         destination: OutDestination::PINS, | ||||
|         bit_count: 32, | ||||
|     } | ||||
|     .encode(); | ||||
|     sm.push_tx(data); | ||||
|     sm.exec_instr(OUT); | ||||
| } | ||||
| pub fn set_out_pindir<SM: PioStateMachine>(sm: &mut SM, data: u32) { | ||||
|     const OUT: u16 = InstructionOperands::OUT { | ||||
|         destination: OutDestination::PINDIRS, | ||||
|         bit_count: 32, | ||||
|     } | ||||
|     .encode(); | ||||
|     sm.push_tx(data); | ||||
|     sm.exec_instr(OUT); | ||||
| } | ||||
|  | ||||
| pub fn exec_jmp<SM: PioStateMachine>(sm: &mut SM, to_addr: u8) { | ||||
|     let jmp: u16 = InstructionOperands::JMP { | ||||
|         address: to_addr, | ||||
|         condition: JmpCondition::Always, | ||||
|     } | ||||
|     .encode(); | ||||
|     sm.exec_instr(jmp); | ||||
| } | ||||
| @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" | ||||
| embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } | ||||
| embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } | ||||
| embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | ||||
| embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver"] } | ||||
| embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "pio"] } | ||||
| embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | ||||
| embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } | ||||
| embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | ||||
| @@ -34,6 +34,11 @@ embedded-io = { version = "0.4.0", features = ["async", "defmt"] } | ||||
| embedded-storage = { version = "0.3" } | ||||
| static_cell = "1.0.0" | ||||
| log = "0.4" | ||||
| pio-proc = "0.2" | ||||
| pio = "0.2" | ||||
|  | ||||
| [profile.release] | ||||
| debug = true | ||||
|  | ||||
| [patch.crates-io] | ||||
| pio = {git = "https://github.com/rp-rs/pio-rs.git"} | ||||
							
								
								
									
										105
									
								
								examples/rp/src/bin/pio_async.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								examples/rp/src/bin/pio_async.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | ||||
| #![no_std] | ||||
| #![no_main] | ||||
| #![feature(type_alias_impl_trait)] | ||||
| use defmt::info; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_rp::gpio::{AnyPin, Pin}; | ||||
| use embassy_rp::pio::{Pio0, PioPeripherial, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0, Sm1, Sm2}; | ||||
| use embassy_rp::pio_instr_util; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| #[embassy_executor::task] | ||||
| async fn pio_task_sm0(mut sm: PioStateMachineInstance<Pio0, Sm0>, pin: AnyPin) { | ||||
|     // Setup sm0 | ||||
|  | ||||
|     // Send data serially to pin | ||||
|     let prg = pio_proc::pio_asm!( | ||||
|         ".origin 16", | ||||
|         "set pindirs, 1", | ||||
|         ".wrap_target", | ||||
|         "out pins,1 [19]", | ||||
|         ".wrap", | ||||
|     ); | ||||
|  | ||||
|     let origin = prg.program.origin.unwrap_or(0); | ||||
|     let out_pin = sm.make_pio_pin(pin); | ||||
|     let pio_pins = [&out_pin]; | ||||
|     sm.set_out_pins(&pio_pins); | ||||
|     sm.write_instr(origin as usize, &prg.program.code); | ||||
|     pio_instr_util::exec_jmp(&mut sm, origin); | ||||
|     sm.set_clkdiv((125e6 / 20.0 / 2e2 * 256.0) as u32); | ||||
|     sm.set_set_range(0, 1); | ||||
|     sm.set_wrap(prg.program.wrap.source + origin, prg.program.wrap.target + origin); | ||||
|     sm.set_autopull(true); | ||||
|     sm.set_out_shift_dir(ShiftDirection::Left); | ||||
|  | ||||
|     sm.set_enable(true); | ||||
|  | ||||
|     let mut v = 0x0f0caffa; | ||||
|     loop { | ||||
|         sm.wait_push(v).await; | ||||
|         v ^= 0xffff; | ||||
|         info!("Pushed {:032b} to FIFO", v); | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[embassy_executor::task] | ||||
| async fn pio_task_sm1(mut sm: PioStateMachineInstance<Pio0, Sm1>) { | ||||
|     // Setupm sm1 | ||||
|  | ||||
|     // Read 0b10101 repeatedly until ISR is full | ||||
|     let prg = pio_proc::pio_asm!(".origin 8", "set x, 0x15", ".wrap_target", "in x, 5 [31]", ".wrap",); | ||||
|  | ||||
|     let origin = prg.program.origin.unwrap_or(0); | ||||
|     sm.write_instr(origin as usize, &prg.program.code); | ||||
|     pio_instr_util::exec_jmp(&mut sm, origin); | ||||
|     sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32); | ||||
|     sm.set_set_range(0, 0); | ||||
|     sm.set_wrap(prg.program.wrap.source + origin, prg.program.wrap.target + origin); | ||||
|     sm.set_autopush(true); | ||||
|     sm.set_in_shift_dir(ShiftDirection::Right); | ||||
|     sm.set_enable(true); | ||||
|     loop { | ||||
|         let rx = sm.wait_pull().await; | ||||
|         info!("Pulled {:032b} from FIFO", rx); | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[embassy_executor::task] | ||||
| async fn pio_task_sm2(mut sm: PioStateMachineInstance<Pio0, Sm2>) { | ||||
|     // Setup sm2 | ||||
|  | ||||
|     // Repeatedly trigger IRQ 3 | ||||
|     let prg = pio_proc::pio_asm!( | ||||
|         ".origin 0", | ||||
|         ".wrap_target", | ||||
|         "set x,10", | ||||
|         "delay:", | ||||
|         "jmp x-- delay [15]", | ||||
|         "irq 3 [15]", | ||||
|         ".wrap", | ||||
|     ); | ||||
|     let origin = prg.program.origin.unwrap_or(0); | ||||
|  | ||||
|     sm.write_instr(origin as usize, &prg.program.code); | ||||
|     sm.set_wrap(prg.program.wrap.source + origin, prg.program.wrap.target + origin); | ||||
|     pio_instr_util::exec_jmp(&mut sm, origin); | ||||
|     sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32); | ||||
|     sm.set_enable(true); | ||||
|     loop { | ||||
|         sm.wait_irq(3).await; | ||||
|         info!("IRQ trigged"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(spawner: Spawner) { | ||||
|     let p = embassy_rp::init(Default::default()); | ||||
|     let pio = p.PIO0; | ||||
|  | ||||
|     let (_, sm0, sm1, sm2, ..) = pio.split(); | ||||
|  | ||||
|     spawner.spawn(pio_task_sm0(sm0, p.PIN_0.degrade())).unwrap(); | ||||
|     spawner.spawn(pio_task_sm1(sm1)).unwrap(); | ||||
|     spawner.spawn(pio_task_sm2(sm2)).unwrap(); | ||||
| } | ||||
							
								
								
									
										67
									
								
								examples/rp/src/bin/pio_dma.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								examples/rp/src/bin/pio_dma.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| #![no_std] | ||||
| #![no_main] | ||||
| #![feature(type_alias_impl_trait)] | ||||
| use defmt::info; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_futures::join::join; | ||||
| use embassy_rp::pio::{PioPeripherial, PioStateMachine, ShiftDirection}; | ||||
| use embassy_rp::{pio_instr_util, Peripheral}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
|  | ||||
| fn swap_nibbles(v: u32) -> u32 { | ||||
|     let v = (v & 0x0f0f_0f0f) << 4 | (v & 0xf0f0_f0f0) >> 4; | ||||
|     let v = (v & 0x00ff_00ff) << 8 | (v & 0xff00_ff00) >> 8; | ||||
|     (v & 0x0000_ffff) << 16 | (v & 0xffff_0000) >> 16 | ||||
| } | ||||
|  | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_rp::init(Default::default()); | ||||
|     let pio = p.PIO0; | ||||
|     let (_, mut sm, ..) = pio.split(); | ||||
|  | ||||
|     let prg = pio_proc::pio_asm!( | ||||
|         ".origin 0", | ||||
|         "set pindirs,1", | ||||
|         ".wrap_target", | ||||
|         "set y,7", | ||||
|         "loop:", | ||||
|         "out x,4", | ||||
|         "in x,4", | ||||
|         "jmp y--, loop", | ||||
|         ".wrap", | ||||
|     ); | ||||
|  | ||||
|     let origin = prg.program.origin.unwrap_or(0); | ||||
|     sm.write_instr(origin as usize, &prg.program.code); | ||||
|     pio_instr_util::exec_jmp(&mut sm, origin); | ||||
|     sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32); | ||||
|     sm.set_wrap(prg.program.wrap.source + origin, prg.program.wrap.target + origin); | ||||
|     sm.set_autopull(true); | ||||
|     sm.set_autopush(true); | ||||
|     sm.set_pull_threshold(32); | ||||
|     sm.set_push_threshold(32); | ||||
|     sm.set_out_shift_dir(ShiftDirection::Right); | ||||
|     sm.set_in_shift_dir(ShiftDirection::Left); | ||||
|  | ||||
|     sm.set_enable(true); | ||||
|  | ||||
|     let mut dma_out_ref = p.DMA_CH0.into_ref(); | ||||
|     let mut dma_in_ref = p.DMA_CH1.into_ref(); | ||||
|     let mut dout = [0x12345678u32; 29]; | ||||
|     for i in 1..dout.len() { | ||||
|         dout[i] = (dout[i - 1] & 0x0fff_ffff) * 13 + 7; | ||||
|     } | ||||
|     let mut din = [0u32; 29]; | ||||
|     loop { | ||||
|         join( | ||||
|             sm.dma_push(dma_out_ref.reborrow(), &dout), | ||||
|             sm.dma_pull(dma_in_ref.reborrow(), &mut din), | ||||
|         ) | ||||
|         .await; | ||||
|         for i in 0..din.len() { | ||||
|             assert_eq!(din[i], swap_nibbles(dout[i])); | ||||
|         } | ||||
|         info!("Swapped {} words", dout.len()); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user