mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-26 08:42:32 +00:00
1043: Rpi Pico PIO driver r=Dirbaio a=fluffware This is a driver for the two PIOs in the Pico. I've tried using the type system to get as much compile time checks as possible. There is asynchronous support for FIFOs an Irqs. No DMA support yet. There's an example that shows how to use the driver asynchronously. 1103: embassy-stm32: add rs485 driver enable to uart r=Dirbaio a=FrozenDroid Co-authored-by: Simon Berg <ksb@fluffware.se> Co-authored-by: Vincent Stakenburg <v.stakenburg@sinewave.nl>
This commit is contained in:
commit
36639e5262
@ -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,13 +474,40 @@ 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),
|
||||
Pull::Down => w.set_pde(true),
|
||||
Pull::None => {}
|
||||
}
|
||||
let (pu, pd) = match pull {
|
||||
Pull::Up => (true, false),
|
||||
Pull::Down => (false, true),
|
||||
Pull::None => (false, false),
|
||||
};
|
||||
w.set_pue(pu);
|
||||
w.set_pde(pd);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,14 @@ 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;
|
||||
#[cfg(feature = "pio")]
|
||||
pub mod relocate;
|
||||
|
||||
pub mod rom_data;
|
||||
pub mod rtc;
|
||||
pub mod spi;
|
||||
@ -102,6 +110,9 @@ embassy_hal_common::peripherals! {
|
||||
FLASH,
|
||||
|
||||
ADC,
|
||||
|
||||
PIO0,
|
||||
PIO1,
|
||||
}
|
||||
|
||||
#[link_section = ".boot2"]
|
||||
|
1259
embassy-rp/src/pio.rs
Normal file
1259
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);
|
||||
}
|
77
embassy-rp/src/relocate.rs
Normal file
77
embassy-rp/src/relocate.rs
Normal file
@ -0,0 +1,77 @@
|
||||
use core::iter::Iterator;
|
||||
|
||||
use pio::{Program, SideSet, Wrap};
|
||||
|
||||
pub struct CodeIterator<'a, I>
|
||||
where
|
||||
I: Iterator<Item = &'a u16>,
|
||||
{
|
||||
iter: I,
|
||||
offset: u8,
|
||||
}
|
||||
|
||||
impl<'a, I: Iterator<Item = &'a u16>> CodeIterator<'a, I> {
|
||||
pub fn new(iter: I, offset: u8) -> CodeIterator<'a, I> {
|
||||
CodeIterator { iter, offset }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, I> Iterator for CodeIterator<'a, I>
|
||||
where
|
||||
I: Iterator<Item = &'a u16>,
|
||||
{
|
||||
type Item = u16;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next().and_then(|&instr| {
|
||||
Some(if instr & 0b1110_0000_0000_0000 == 0 {
|
||||
// this is a JMP instruction -> add offset to address
|
||||
let address = (instr & 0b1_1111) as u8;
|
||||
let address = address + self.offset;
|
||||
assert!(
|
||||
address < pio::RP2040_MAX_PROGRAM_SIZE as u8,
|
||||
"Invalid JMP out of the program after offset addition"
|
||||
);
|
||||
instr & (!0b11111) | address as u16
|
||||
} else {
|
||||
instr
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RelocatedProgram<'a, const PROGRAM_SIZE: usize> {
|
||||
program: &'a Program<PROGRAM_SIZE>,
|
||||
origin: u8,
|
||||
}
|
||||
|
||||
impl<'a, const PROGRAM_SIZE: usize> RelocatedProgram<'a, PROGRAM_SIZE> {
|
||||
pub fn new(program: &Program<PROGRAM_SIZE>) -> RelocatedProgram<PROGRAM_SIZE> {
|
||||
let origin = program.origin.unwrap_or(0);
|
||||
RelocatedProgram { program, origin }
|
||||
}
|
||||
|
||||
pub fn new_with_origin(program: &Program<PROGRAM_SIZE>, origin: u8) -> RelocatedProgram<PROGRAM_SIZE> {
|
||||
RelocatedProgram { program, origin }
|
||||
}
|
||||
|
||||
pub fn code(&'a self) -> CodeIterator<'a, core::slice::Iter<'a, u16>> {
|
||||
CodeIterator::new(self.program.code.iter(), self.origin)
|
||||
}
|
||||
|
||||
pub fn wrap(&self) -> Wrap {
|
||||
let wrap = self.program.wrap;
|
||||
let origin = self.origin;
|
||||
Wrap {
|
||||
source: wrap.source + origin,
|
||||
target: wrap.target + origin,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn side_set(&self) -> SideSet {
|
||||
self.program.side_set
|
||||
}
|
||||
|
||||
pub fn origin(&self) -> u8 {
|
||||
self.origin
|
||||
}
|
||||
}
|
@ -244,11 +244,13 @@ fn main() {
|
||||
(("usart", "CTS"), quote!(crate::usart::CtsPin)),
|
||||
(("usart", "RTS"), quote!(crate::usart::RtsPin)),
|
||||
(("usart", "CK"), quote!(crate::usart::CkPin)),
|
||||
(("usart", "DE"), quote!(crate::usart::DePin)),
|
||||
(("lpuart", "TX"), quote!(crate::usart::TxPin)),
|
||||
(("lpuart", "RX"), quote!(crate::usart::RxPin)),
|
||||
(("lpuart", "CTS"), quote!(crate::usart::CtsPin)),
|
||||
(("lpuart", "RTS"), quote!(crate::usart::RtsPin)),
|
||||
(("lpuart", "CK"), quote!(crate::usart::CkPin)),
|
||||
(("lpuart", "DE"), quote!(crate::usart::DePin)),
|
||||
(("spi", "SCK"), quote!(crate::spi::SckPin)),
|
||||
(("spi", "MOSI"), quote!(crate::spi::MosiPin)),
|
||||
(("spi", "MISO"), quote!(crate::spi::MisoPin)),
|
||||
|
@ -89,6 +89,33 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
||||
Self::new_inner(state, peri, rx, tx, irq, tx_buffer, rx_buffer, config)
|
||||
}
|
||||
|
||||
#[cfg(not(usart_v1))]
|
||||
pub fn new_with_de(
|
||||
state: &'d mut State<'d, T>,
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
de: impl Peripheral<P = impl DePin<T>> + 'd,
|
||||
tx_buffer: &'d mut [u8],
|
||||
rx_buffer: &'d mut [u8],
|
||||
config: Config,
|
||||
) -> BufferedUart<'d, T> {
|
||||
into_ref!(de);
|
||||
|
||||
T::enable();
|
||||
T::reset();
|
||||
|
||||
unsafe {
|
||||
de.set_as_af(de.af_num(), AFType::OutputPushPull);
|
||||
T::regs().cr3().write(|w| {
|
||||
w.set_dem(true);
|
||||
});
|
||||
}
|
||||
|
||||
Self::new_inner(state, peri, rx, tx, irq, tx_buffer, rx_buffer, config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
state: &'d mut State<'d, T>,
|
||||
_peri: impl Peripheral<P = T> + 'd,
|
||||
|
@ -646,6 +646,31 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
||||
Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config)
|
||||
}
|
||||
|
||||
#[cfg(not(usart_v1))]
|
||||
pub fn new_with_de(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
de: impl Peripheral<P = impl DePin<T>> + 'd,
|
||||
tx_dma: impl Peripheral<P = TxDma> + 'd,
|
||||
rx_dma: impl Peripheral<P = RxDma> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(de);
|
||||
|
||||
T::enable();
|
||||
T::reset();
|
||||
|
||||
unsafe {
|
||||
de.set_as_af(de.af_num(), AFType::OutputPushPull);
|
||||
T::regs().cr3().write(|w| {
|
||||
w.set_dem(true);
|
||||
});
|
||||
}
|
||||
Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
@ -1040,6 +1065,7 @@ pin_trait!(TxPin, BasicInstance);
|
||||
pin_trait!(CtsPin, BasicInstance);
|
||||
pin_trait!(RtsPin, BasicInstance);
|
||||
pin_trait!(CkPin, BasicInstance);
|
||||
pin_trait!(DePin, BasicInstance);
|
||||
|
||||
dma_trait!(TxDma, BasicInstance);
|
||||
dma_trait!(RxDma, BasicInstance);
|
||||
|
@ -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"}
|
112
examples/rp/src/bin/pio_async.rs
Normal file
112
examples/rp/src/bin/pio_async.rs
Normal file
@ -0,0 +1,112 @@
|
||||
#![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 embassy_rp::relocate::RelocatedProgram;
|
||||
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 relocated = RelocatedProgram::new(&prg.program);
|
||||
let out_pin = sm.make_pio_pin(pin);
|
||||
let pio_pins = [&out_pin];
|
||||
sm.set_out_pins(&pio_pins);
|
||||
sm.write_instr(relocated.origin() as usize, relocated.code());
|
||||
pio_instr_util::exec_jmp(&mut sm, relocated.origin());
|
||||
sm.set_clkdiv((125e6 / 20.0 / 2e2 * 256.0) as u32);
|
||||
sm.set_set_range(0, 1);
|
||||
let pio::Wrap { source, target } = relocated.wrap();
|
||||
sm.set_wrap(source, target);
|
||||
|
||||
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 relocated = RelocatedProgram::new(&prg.program);
|
||||
sm.write_instr(relocated.origin() as usize, relocated.code());
|
||||
pio_instr_util::exec_jmp(&mut sm, relocated.origin());
|
||||
sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32);
|
||||
sm.set_set_range(0, 0);
|
||||
let pio::Wrap { source, target } = relocated.wrap();
|
||||
sm.set_wrap(source, target);
|
||||
|
||||
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 relocated = RelocatedProgram::new(&prg.program);
|
||||
sm.write_instr(relocated.origin() as usize, relocated.code());
|
||||
|
||||
let pio::Wrap { source, target } = relocated.wrap();
|
||||
sm.set_wrap(source, target);
|
||||
|
||||
pio_instr_util::exec_jmp(&mut sm, relocated.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();
|
||||
}
|
69
examples/rp/src/bin/pio_dma.rs
Normal file
69
examples/rp/src/bin/pio_dma.rs
Normal file
@ -0,0 +1,69 @@
|
||||
#![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::relocate::RelocatedProgram;
|
||||
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 relocated = RelocatedProgram::new(&prg.program);
|
||||
sm.write_instr(relocated.origin() as usize, relocated.code());
|
||||
pio_instr_util::exec_jmp(&mut sm, relocated.origin());
|
||||
sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32);
|
||||
let pio::Wrap { source, target } = relocated.wrap();
|
||||
sm.set_wrap(source, target);
|
||||
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());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user