diff options
| author | Simon Berg <[email protected]> | 2022-12-06 21:42:30 +0100 |
|---|---|---|
| committer | Simon Berg <[email protected]> | 2022-12-09 20:18:41 +0100 |
| commit | cd59046e6c179809ee19fb2592e65cf5a0a07980 (patch) | |
| tree | 7a51a46e07ec5a71022375a99a10d266f47e86e9 | |
| parent | 35db6e639bf5de017551164e9cbfaa2e5e46fca3 (diff) | |
Added RelocateProgram class for adjusting PIO-programs for different origins.
| -rw-r--r-- | embassy-rp/src/lib.rs | 2 | ||||
| -rw-r--r-- | embassy-rp/src/pio.rs | 19 | ||||
| -rw-r--r-- | embassy-rp/src/relocate.rs | 77 | ||||
| -rw-r--r-- | examples/rp/src/bin/pio_async.rs | 31 | ||||
| -rw-r--r-- | examples/rp/src/bin/pio_dma.rs | 10 |
5 files changed, 118 insertions, 21 deletions
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 67eb29d5e..551392725 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs | |||
| @@ -17,6 +17,8 @@ pub mod interrupt; | |||
| 17 | pub mod pio; | 17 | pub mod pio; |
| 18 | #[cfg(feature = "pio")] | 18 | #[cfg(feature = "pio")] |
| 19 | pub mod pio_instr_util; | 19 | pub mod pio_instr_util; |
| 20 | #[cfg(feature = "pio")] | ||
| 21 | pub mod relocate; | ||
| 20 | 22 | ||
| 21 | pub mod rom_data; | 23 | pub mod rom_data; |
| 22 | pub mod rtc; | 24 | pub mod rtc; |
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index f049a16e7..1a067e54f 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs | |||
| @@ -941,7 +941,10 @@ pub trait PioStateMachine: Sized + Unpin { | |||
| 941 | } | 941 | } |
| 942 | } | 942 | } |
| 943 | 943 | ||
| 944 | fn write_instr(&mut self, start: usize, instrs: &[u16]) { | 944 | fn write_instr<I>(&mut self, start: usize, instrs: I) |
| 945 | where | ||
| 946 | I: Iterator<Item = u16>, | ||
| 947 | { | ||
| 945 | let _ = self; | 948 | let _ = self; |
| 946 | write_instr( | 949 | write_instr( |
| 947 | Self::Pio::PIO_NO, | 950 | Self::Pio::PIO_NO, |
| @@ -1098,8 +1101,11 @@ impl<PIO: PioInstance> PioCommon for PioCommonInstance<PIO> { | |||
| 1098 | type Pio = PIO; | 1101 | type Pio = PIO; |
| 1099 | } | 1102 | } |
| 1100 | 1103 | ||
| 1101 | fn write_instr(pio_no: u8, start: usize, instrs: &[u16], mem_user: u32) { | 1104 | fn write_instr<I>(pio_no: u8, start: usize, instrs: I, mem_user: u32) |
| 1102 | for (i, instr) in instrs.iter().enumerate() { | 1105 | where |
| 1106 | I: Iterator<Item = u16>, | ||
| 1107 | { | ||
| 1108 | for (i, instr) in instrs.enumerate() { | ||
| 1103 | let addr = (i + start) as u8; | 1109 | let addr = (i + start) as u8; |
| 1104 | assert!( | 1110 | assert!( |
| 1105 | instr_mem_is_free(pio_no, addr), | 1111 | instr_mem_is_free(pio_no, addr), |
| @@ -1108,7 +1114,7 @@ fn write_instr(pio_no: u8, start: usize, instrs: &[u16], mem_user: u32) { | |||
| 1108 | ); | 1114 | ); |
| 1109 | unsafe { | 1115 | unsafe { |
| 1110 | PIOS[pio_no as usize].instr_mem(addr as usize).write(|w| { | 1116 | PIOS[pio_no as usize].instr_mem(addr as usize).write(|w| { |
| 1111 | w.set_instr_mem(*instr); | 1117 | w.set_instr_mem(instr); |
| 1112 | }); | 1118 | }); |
| 1113 | instr_mem_set_status(pio_no, addr, mem_user); | 1119 | instr_mem_set_status(pio_no, addr, mem_user); |
| 1114 | } | 1120 | } |
| @@ -1118,7 +1124,10 @@ fn write_instr(pio_no: u8, start: usize, instrs: &[u16], mem_user: u32) { | |||
| 1118 | pub trait PioCommon: Sized { | 1124 | pub trait PioCommon: Sized { |
| 1119 | type Pio: PioInstance; | 1125 | type Pio: PioInstance; |
| 1120 | 1126 | ||
| 1121 | fn write_instr(&mut self, start: usize, instrs: &[u16]) { | 1127 | fn write_instr<I>(&mut self, start: usize, instrs: I) |
| 1128 | where | ||
| 1129 | I: Iterator<Item = u16>, | ||
| 1130 | { | ||
| 1122 | let _ = self; | 1131 | let _ = self; |
| 1123 | write_instr(Self::Pio::PIO_NO, start, instrs, MEM_USED_BY_COMMON); | 1132 | write_instr(Self::Pio::PIO_NO, start, instrs, MEM_USED_BY_COMMON); |
| 1124 | } | 1133 | } |
diff --git a/embassy-rp/src/relocate.rs b/embassy-rp/src/relocate.rs new file mode 100644 index 000000000..f36170e03 --- /dev/null +++ b/embassy-rp/src/relocate.rs | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | use core::iter::Iterator; | ||
| 2 | |||
| 3 | use pio::{Program, SideSet, Wrap}; | ||
| 4 | |||
| 5 | pub struct CodeIterator<'a, I> | ||
| 6 | where | ||
| 7 | I: Iterator<Item = &'a u16>, | ||
| 8 | { | ||
| 9 | iter: I, | ||
| 10 | offset: u8, | ||
| 11 | } | ||
| 12 | |||
| 13 | impl<'a, I: Iterator<Item = &'a u16>> CodeIterator<'a, I> { | ||
| 14 | pub fn new(iter: I, offset: u8) -> CodeIterator<'a, I> { | ||
| 15 | CodeIterator { iter, offset } | ||
| 16 | } | ||
| 17 | } | ||
| 18 | |||
| 19 | impl<'a, I> Iterator for CodeIterator<'a, I> | ||
| 20 | where | ||
| 21 | I: Iterator<Item = &'a u16>, | ||
| 22 | { | ||
| 23 | type Item = u16; | ||
| 24 | fn next(&mut self) -> Option<Self::Item> { | ||
| 25 | self.iter.next().and_then(|&instr| { | ||
| 26 | Some(if instr & 0b1110_0000_0000_0000 == 0 { | ||
| 27 | // this is a JMP instruction -> add offset to address | ||
| 28 | let address = (instr & 0b1_1111) as u8; | ||
| 29 | let address = address + self.offset; | ||
| 30 | assert!( | ||
| 31 | address < pio::RP2040_MAX_PROGRAM_SIZE as u8, | ||
| 32 | "Invalid JMP out of the program after offset addition" | ||
| 33 | ); | ||
| 34 | instr & (!0b11111) | address as u16 | ||
| 35 | } else { | ||
| 36 | instr | ||
| 37 | }) | ||
| 38 | }) | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | pub struct RelocatedProgram<'a, const PROGRAM_SIZE: usize> { | ||
| 43 | program: &'a Program<PROGRAM_SIZE>, | ||
| 44 | origin: u8, | ||
| 45 | } | ||
| 46 | |||
| 47 | impl<'a, const PROGRAM_SIZE: usize> RelocatedProgram<'a, PROGRAM_SIZE> { | ||
| 48 | pub fn new(program: &Program<PROGRAM_SIZE>) -> RelocatedProgram<PROGRAM_SIZE> { | ||
| 49 | let origin = program.origin.unwrap_or(0); | ||
| 50 | RelocatedProgram { program, origin } | ||
| 51 | } | ||
| 52 | |||
| 53 | pub fn new_with_origin(program: &Program<PROGRAM_SIZE>, origin: u8) -> RelocatedProgram<PROGRAM_SIZE> { | ||
| 54 | RelocatedProgram { program, origin } | ||
| 55 | } | ||
| 56 | |||
| 57 | pub fn code(&'a self) -> CodeIterator<'a, core::slice::Iter<'a, u16>> { | ||
| 58 | CodeIterator::new(self.program.code.iter(), self.origin) | ||
| 59 | } | ||
| 60 | |||
| 61 | pub fn wrap(&self) -> Wrap { | ||
| 62 | let wrap = self.program.wrap; | ||
| 63 | let origin = self.origin; | ||
| 64 | Wrap { | ||
| 65 | source: wrap.source + origin, | ||
| 66 | target: wrap.target + origin, | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | pub fn side_set(&self) -> SideSet { | ||
| 71 | self.program.side_set | ||
| 72 | } | ||
| 73 | |||
| 74 | pub fn origin(&self) -> u8 { | ||
| 75 | self.origin | ||
| 76 | } | ||
| 77 | } | ||
diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index e9211db3b..45a8c73f7 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs | |||
| @@ -6,6 +6,7 @@ use embassy_executor::Spawner; | |||
| 6 | use embassy_rp::gpio::{AnyPin, Pin}; | 6 | use embassy_rp::gpio::{AnyPin, Pin}; |
| 7 | use embassy_rp::pio::{Pio0, PioPeripherial, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0, Sm1, Sm2}; | 7 | use embassy_rp::pio::{Pio0, PioPeripherial, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0, Sm1, Sm2}; |
| 8 | use embassy_rp::pio_instr_util; | 8 | use embassy_rp::pio_instr_util; |
| 9 | use embassy_rp::relocate::RelocatedProgram; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 11 | ||
| 11 | #[embassy_executor::task] | 12 | #[embassy_executor::task] |
| @@ -21,15 +22,17 @@ async fn pio_task_sm0(mut sm: PioStateMachineInstance<Pio0, Sm0>, pin: AnyPin) { | |||
| 21 | ".wrap", | 22 | ".wrap", |
| 22 | ); | 23 | ); |
| 23 | 24 | ||
| 24 | let origin = prg.program.origin.unwrap_or(0); | 25 | let relocated = RelocatedProgram::new(&prg.program); |
| 25 | let out_pin = sm.make_pio_pin(pin); | 26 | let out_pin = sm.make_pio_pin(pin); |
| 26 | let pio_pins = [&out_pin]; | 27 | let pio_pins = [&out_pin]; |
| 27 | sm.set_out_pins(&pio_pins); | 28 | sm.set_out_pins(&pio_pins); |
| 28 | sm.write_instr(origin as usize, &prg.program.code); | 29 | sm.write_instr(relocated.origin() as usize, relocated.code()); |
| 29 | pio_instr_util::exec_jmp(&mut sm, origin); | 30 | pio_instr_util::exec_jmp(&mut sm, relocated.origin()); |
| 30 | sm.set_clkdiv((125e6 / 20.0 / 2e2 * 256.0) as u32); | 31 | sm.set_clkdiv((125e6 / 20.0 / 2e2 * 256.0) as u32); |
| 31 | sm.set_set_range(0, 1); | 32 | sm.set_set_range(0, 1); |
| 32 | sm.set_wrap(prg.program.wrap.source + origin, prg.program.wrap.target + origin); | 33 | let pio::Wrap { source, target } = relocated.wrap(); |
| 34 | sm.set_wrap(source, target); | ||
| 35 | |||
| 33 | sm.set_autopull(true); | 36 | sm.set_autopull(true); |
| 34 | sm.set_out_shift_dir(ShiftDirection::Left); | 37 | sm.set_out_shift_dir(ShiftDirection::Left); |
| 35 | 38 | ||
| @@ -50,12 +53,14 @@ async fn pio_task_sm1(mut sm: PioStateMachineInstance<Pio0, Sm1>) { | |||
| 50 | // Read 0b10101 repeatedly until ISR is full | 53 | // Read 0b10101 repeatedly until ISR is full |
| 51 | let prg = pio_proc::pio_asm!(".origin 8", "set x, 0x15", ".wrap_target", "in x, 5 [31]", ".wrap",); | 54 | let prg = pio_proc::pio_asm!(".origin 8", "set x, 0x15", ".wrap_target", "in x, 5 [31]", ".wrap",); |
| 52 | 55 | ||
| 53 | let origin = prg.program.origin.unwrap_or(0); | 56 | let relocated = RelocatedProgram::new(&prg.program); |
| 54 | sm.write_instr(origin as usize, &prg.program.code); | 57 | sm.write_instr(relocated.origin() as usize, relocated.code()); |
| 55 | pio_instr_util::exec_jmp(&mut sm, origin); | 58 | pio_instr_util::exec_jmp(&mut sm, relocated.origin()); |
| 56 | sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32); | 59 | sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32); |
| 57 | sm.set_set_range(0, 0); | 60 | sm.set_set_range(0, 0); |
| 58 | sm.set_wrap(prg.program.wrap.source + origin, prg.program.wrap.target + origin); | 61 | let pio::Wrap { source, target } = relocated.wrap(); |
| 62 | sm.set_wrap(source, target); | ||
| 63 | |||
| 59 | sm.set_autopush(true); | 64 | sm.set_autopush(true); |
| 60 | sm.set_in_shift_dir(ShiftDirection::Right); | 65 | sm.set_in_shift_dir(ShiftDirection::Right); |
| 61 | sm.set_enable(true); | 66 | sm.set_enable(true); |
| @@ -79,11 +84,13 @@ async fn pio_task_sm2(mut sm: PioStateMachineInstance<Pio0, Sm2>) { | |||
| 79 | "irq 3 [15]", | 84 | "irq 3 [15]", |
| 80 | ".wrap", | 85 | ".wrap", |
| 81 | ); | 86 | ); |
| 82 | let origin = prg.program.origin.unwrap_or(0); | 87 | let relocated = RelocatedProgram::new(&prg.program); |
| 88 | sm.write_instr(relocated.origin() as usize, relocated.code()); | ||
| 89 | |||
| 90 | let pio::Wrap { source, target } = relocated.wrap(); | ||
| 91 | sm.set_wrap(source, target); | ||
| 83 | 92 | ||
| 84 | sm.write_instr(origin as usize, &prg.program.code); | 93 | pio_instr_util::exec_jmp(&mut sm, relocated.origin()); |
| 85 | sm.set_wrap(prg.program.wrap.source + origin, prg.program.wrap.target + origin); | ||
| 86 | pio_instr_util::exec_jmp(&mut sm, origin); | ||
| 87 | sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32); | 94 | sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32); |
| 88 | sm.set_enable(true); | 95 | sm.set_enable(true); |
| 89 | loop { | 96 | loop { |
diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs index bdcdf200c..b19ef4083 100644 --- a/examples/rp/src/bin/pio_dma.rs +++ b/examples/rp/src/bin/pio_dma.rs | |||
| @@ -5,6 +5,7 @@ use defmt::info; | |||
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_futures::join::join; | 6 | use embassy_futures::join::join; |
| 7 | use embassy_rp::pio::{PioPeripherial, PioStateMachine, ShiftDirection}; | 7 | use embassy_rp::pio::{PioPeripherial, PioStateMachine, ShiftDirection}; |
| 8 | use embassy_rp::relocate::RelocatedProgram; | ||
| 8 | use embassy_rp::{pio_instr_util, Peripheral}; | 9 | use embassy_rp::{pio_instr_util, Peripheral}; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 11 | ||
| @@ -32,11 +33,12 @@ async fn main(_spawner: Spawner) { | |||
| 32 | ".wrap", | 33 | ".wrap", |
| 33 | ); | 34 | ); |
| 34 | 35 | ||
| 35 | let origin = prg.program.origin.unwrap_or(0); | 36 | let relocated = RelocatedProgram::new(&prg.program); |
| 36 | sm.write_instr(origin as usize, &prg.program.code); | 37 | sm.write_instr(relocated.origin() as usize, relocated.code()); |
| 37 | pio_instr_util::exec_jmp(&mut sm, origin); | 38 | pio_instr_util::exec_jmp(&mut sm, relocated.origin()); |
| 38 | sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32); | 39 | sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32); |
| 39 | sm.set_wrap(prg.program.wrap.source + origin, prg.program.wrap.target + origin); | 40 | let pio::Wrap { source, target } = relocated.wrap(); |
| 41 | sm.set_wrap(source, target); | ||
| 40 | sm.set_autopull(true); | 42 | sm.set_autopull(true); |
| 41 | sm.set_autopush(true); | 43 | sm.set_autopush(true); |
| 42 | sm.set_pull_threshold(32); | 44 | sm.set_pull_threshold(32); |
