aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-07-28 17:47:34 +0000
committerGitHub <[email protected]>2023-07-28 17:47:34 +0000
commite3cc0d168c1455d63df55f758cd875d78120f04d (patch)
tree0a5f85332dc115fdd13e4a2e0195c8c7d18c17ed
parente97b14c068b5e5f7975311d4aef41c854ef4e16c (diff)
parentcbc8871a0bb40eb5fec82e7c27ed4c0127844c3c (diff)
Merge pull request #1707 from pennae/rp-pio-load
rp: relocate programs implicitly during load
-rw-r--r--cyw43-pio/src/lib.rs8
-rw-r--r--embassy-rp/src/lib.rs2
-rw-r--r--embassy-rp/src/pio.rs60
-rw-r--r--embassy-rp/src/relocate.rs5
-rw-r--r--examples/rp/src/bin/pio_async.rs10
-rw-r--r--examples/rp/src/bin/pio_dma.rs4
-rw-r--r--examples/rp/src/bin/pio_hd44780.rs7
-rw-r--r--examples/rp/src/bin/pio_uart.rs41
-rw-r--r--examples/rp/src/bin/pio_ws2812.rs4
-rw-r--r--tests/rp/src/bin/pio_irq.rs4
-rw-r--r--tests/rp/src/bin/pio_multi_load.rs126
11 files changed, 200 insertions, 71 deletions
diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs
index dca30c74d..830a5b44a 100644
--- a/cyw43-pio/src/lib.rs
+++ b/cyw43-pio/src/lib.rs
@@ -8,7 +8,6 @@ use cyw43::SpiBusCyw43;
8use embassy_rp::dma::Channel; 8use embassy_rp::dma::Channel;
9use embassy_rp::gpio::{Drive, Level, Output, Pin, Pull, SlewRate}; 9use embassy_rp::gpio::{Drive, Level, Output, Pin, Pull, SlewRate};
10use embassy_rp::pio::{Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine}; 10use embassy_rp::pio::{Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine};
11use embassy_rp::relocate::RelocatedProgram;
12use embassy_rp::{pio_instr_util, Peripheral, PeripheralRef}; 11use embassy_rp::{pio_instr_util, Peripheral, PeripheralRef};
13use fixed::FixedU32; 12use fixed::FixedU32;
14use pio_proc::pio_asm; 13use pio_proc::pio_asm;
@@ -88,8 +87,6 @@ where
88 ".wrap" 87 ".wrap"
89 ); 88 );
90 89
91 let relocated = RelocatedProgram::new(&program.program);
92
93 let mut pin_io: embassy_rp::pio::Pin<PIO> = common.make_pio_pin(dio); 90 let mut pin_io: embassy_rp::pio::Pin<PIO> = common.make_pio_pin(dio);
94 pin_io.set_pull(Pull::None); 91 pin_io.set_pull(Pull::None);
95 pin_io.set_schmitt(true); 92 pin_io.set_schmitt(true);
@@ -102,7 +99,8 @@ where
102 pin_clk.set_slew_rate(SlewRate::Fast); 99 pin_clk.set_slew_rate(SlewRate::Fast);
103 100
104 let mut cfg = Config::default(); 101 let mut cfg = Config::default();
105 cfg.use_program(&common.load_program(&relocated), &[&pin_clk]); 102 let loaded_program = common.load_program(&program.program);
103 cfg.use_program(&loaded_program, &[&pin_clk]);
106 cfg.set_out_pins(&[&pin_io]); 104 cfg.set_out_pins(&[&pin_io]);
107 cfg.set_in_pins(&[&pin_io]); 105 cfg.set_in_pins(&[&pin_io]);
108 cfg.set_set_pins(&[&pin_io]); 106 cfg.set_set_pins(&[&pin_io]);
@@ -142,7 +140,7 @@ where
142 sm, 140 sm,
143 irq, 141 irq,
144 dma: dma.into_ref(), 142 dma: dma.into_ref(),
145 wrap_target: relocated.wrap().target, 143 wrap_target: loaded_program.wrap.target,
146 } 144 }
147 } 145 }
148 146
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index ebec9fec6..45156458d 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -33,7 +33,7 @@ pub mod watchdog;
33// TODO: move `pio_instr_util` and `relocate` to inside `pio` 33// TODO: move `pio_instr_util` and `relocate` to inside `pio`
34pub mod pio; 34pub mod pio;
35pub mod pio_instr_util; 35pub mod pio_instr_util;
36pub mod relocate; 36pub(crate) mod relocate;
37 37
38// Reexports 38// Reexports
39pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 39pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs
index 464988b27..3de398af7 100644
--- a/embassy-rp/src/pio.rs
+++ b/embassy-rp/src/pio.rs
@@ -11,7 +11,7 @@ use fixed::types::extra::U8;
11use fixed::FixedU32; 11use fixed::FixedU32;
12use pac::io::vals::Gpio0ctrlFuncsel; 12use pac::io::vals::Gpio0ctrlFuncsel;
13use pac::pio::vals::SmExecctrlStatusSel; 13use pac::pio::vals::SmExecctrlStatusSel;
14use pio::{SideSet, Wrap}; 14use pio::{Program, SideSet, Wrap};
15 15
16use crate::dma::{Channel, Transfer, Word}; 16use crate::dma::{Channel, Transfer, Word};
17use crate::gpio::sealed::Pin as SealedPin; 17use crate::gpio::sealed::Pin as SealedPin;
@@ -734,23 +734,67 @@ pub struct InstanceMemory<'d, PIO: Instance> {
734 734
735pub struct LoadedProgram<'d, PIO: Instance> { 735pub struct LoadedProgram<'d, PIO: Instance> {
736 pub used_memory: InstanceMemory<'d, PIO>, 736 pub used_memory: InstanceMemory<'d, PIO>,
737 origin: u8, 737 pub origin: u8,
738 wrap: Wrap, 738 pub wrap: Wrap,
739 side_set: SideSet, 739 pub side_set: SideSet,
740}
741
742#[derive(Clone, Copy, PartialEq, Eq, Debug)]
743#[cfg_attr(feature = "defmt", derive(defmt::Format))]
744pub enum LoadError {
745 /// Insufficient consecutive free instruction space to load program.
746 InsufficientSpace,
747 /// Loading the program would overwrite an instruction address already
748 /// used by another program.
749 AddressInUse(usize),
740} 750}
741 751
742impl<'d, PIO: Instance> Common<'d, PIO> { 752impl<'d, PIO: Instance> Common<'d, PIO> {
743 pub fn load_program<const SIZE: usize>(&mut self, prog: &RelocatedProgram<SIZE>) -> LoadedProgram<'d, PIO> { 753 /// Load a PIO program. This will automatically relocate the program to
754 /// an available chunk of free instruction memory if the program origin
755 /// was not explicitly specified, otherwise it will attempt to load the
756 /// program only at its origin.
757 pub fn load_program<const SIZE: usize>(&mut self, prog: &Program<SIZE>) -> LoadedProgram<'d, PIO> {
744 match self.try_load_program(prog) { 758 match self.try_load_program(prog) {
745 Ok(r) => r, 759 Ok(r) => r,
746 Err(at) => panic!("Trying to write already used PIO instruction memory at {}", at), 760 Err(e) => panic!("Failed to load PIO program: {:?}", e),
747 } 761 }
748 } 762 }
749 763
764 /// Load a PIO program. This will automatically relocate the program to
765 /// an available chunk of free instruction memory if the program origin
766 /// was not explicitly specified, otherwise it will attempt to load the
767 /// program only at its origin.
750 pub fn try_load_program<const SIZE: usize>( 768 pub fn try_load_program<const SIZE: usize>(
751 &mut self, 769 &mut self,
752 prog: &RelocatedProgram<SIZE>, 770 prog: &Program<SIZE>,
771 ) -> Result<LoadedProgram<'d, PIO>, LoadError> {
772 match prog.origin {
773 Some(origin) => self
774 .try_load_program_at(prog, origin)
775 .map_err(|a| LoadError::AddressInUse(a)),
776 None => {
777 // naively search for free space, allowing wraparound since
778 // PIO does support that. with only 32 instruction slots it
779 // doesn't make much sense to do anything more fancy.
780 let mut origin = 0;
781 while origin < 32 {
782 match self.try_load_program_at(prog, origin as _) {
783 Ok(r) => return Ok(r),
784 Err(a) => origin = a + 1,
785 }
786 }
787 Err(LoadError::InsufficientSpace)
788 }
789 }
790 }
791
792 fn try_load_program_at<const SIZE: usize>(
793 &mut self,
794 prog: &Program<SIZE>,
795 origin: u8,
753 ) -> Result<LoadedProgram<'d, PIO>, usize> { 796 ) -> Result<LoadedProgram<'d, PIO>, usize> {
797 let prog = RelocatedProgram::new_with_origin(prog, origin);
754 let used_memory = self.try_write_instr(prog.origin() as _, prog.code())?; 798 let used_memory = self.try_write_instr(prog.origin() as _, prog.code())?;
755 Ok(LoadedProgram { 799 Ok(LoadedProgram {
756 used_memory, 800 used_memory,
@@ -760,7 +804,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
760 }) 804 })
761 } 805 }
762 806
763 pub fn try_write_instr<I>(&mut self, start: usize, instrs: I) -> Result<InstanceMemory<'d, PIO>, usize> 807 fn try_write_instr<I>(&mut self, start: usize, instrs: I) -> Result<InstanceMemory<'d, PIO>, usize>
764 where 808 where
765 I: Iterator<Item = u16>, 809 I: Iterator<Item = u16>,
766 { 810 {
diff --git a/embassy-rp/src/relocate.rs b/embassy-rp/src/relocate.rs
index 9cb279ccd..b35b4ed72 100644
--- a/embassy-rp/src/relocate.rs
+++ b/embassy-rp/src/relocate.rs
@@ -41,11 +41,6 @@ pub struct RelocatedProgram<'a, const PROGRAM_SIZE: usize> {
41} 41}
42 42
43impl<'a, const PROGRAM_SIZE: usize> RelocatedProgram<'a, PROGRAM_SIZE> { 43impl<'a, const PROGRAM_SIZE: usize> RelocatedProgram<'a, PROGRAM_SIZE> {
44 pub fn new(program: &Program<PROGRAM_SIZE>) -> RelocatedProgram<PROGRAM_SIZE> {
45 let origin = program.origin.unwrap_or(0);
46 RelocatedProgram { program, origin }
47 }
48
49 pub fn new_with_origin(program: &Program<PROGRAM_SIZE>, origin: u8) -> RelocatedProgram<PROGRAM_SIZE> { 44 pub fn new_with_origin(program: &Program<PROGRAM_SIZE>, origin: u8) -> RelocatedProgram<PROGRAM_SIZE> {
50 RelocatedProgram { program, origin } 45 RelocatedProgram { program, origin }
51 } 46 }
diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs
index c001d6440..a6d6144be 100644
--- a/examples/rp/src/bin/pio_async.rs
+++ b/examples/rp/src/bin/pio_async.rs
@@ -8,7 +8,6 @@ use embassy_executor::Spawner;
8use embassy_rp::bind_interrupts; 8use embassy_rp::bind_interrupts;
9use embassy_rp::peripherals::PIO0; 9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine}; 10use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine};
11use embassy_rp::relocate::RelocatedProgram;
12use fixed::traits::ToFixed; 11use fixed::traits::ToFixed;
13use fixed_macro::types::U56F8; 12use fixed_macro::types::U56F8;
14use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
@@ -29,9 +28,8 @@ fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a,
29 ".wrap", 28 ".wrap",
30 ); 29 );
31 30
32 let relocated = RelocatedProgram::new(&prg.program);
33 let mut cfg = Config::default(); 31 let mut cfg = Config::default();
34 cfg.use_program(&pio.load_program(&relocated), &[]); 32 cfg.use_program(&pio.load_program(&prg.program), &[]);
35 let out_pin = pio.make_pio_pin(pin); 33 let out_pin = pio.make_pio_pin(pin);
36 cfg.set_out_pins(&[&out_pin]); 34 cfg.set_out_pins(&[&out_pin]);
37 cfg.set_set_pins(&[&out_pin]); 35 cfg.set_set_pins(&[&out_pin]);
@@ -65,9 +63,8 @@ fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a,
65 ".wrap", 63 ".wrap",
66 ); 64 );
67 65
68 let relocated = RelocatedProgram::new(&prg.program);
69 let mut cfg = Config::default(); 66 let mut cfg = Config::default();
70 cfg.use_program(&pio.load_program(&relocated), &[]); 67 cfg.use_program(&pio.load_program(&prg.program), &[]);
71 cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed(); 68 cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed();
72 cfg.shift_in.auto_fill = true; 69 cfg.shift_in.auto_fill = true;
73 cfg.shift_in.direction = ShiftDirection::Right; 70 cfg.shift_in.direction = ShiftDirection::Right;
@@ -96,9 +93,8 @@ fn setup_pio_task_sm2<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a,
96 "irq 3 [15]", 93 "irq 3 [15]",
97 ".wrap", 94 ".wrap",
98 ); 95 );
99 let relocated = RelocatedProgram::new(&prg.program);
100 let mut cfg = Config::default(); 96 let mut cfg = Config::default();
101 cfg.use_program(&pio.load_program(&relocated), &[]); 97 cfg.use_program(&pio.load_program(&prg.program), &[]);
102 cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed(); 98 cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed();
103 sm.set_config(&cfg); 99 sm.set_config(&cfg);
104} 100}
diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs
index 9ab72e1f3..86e5017ac 100644
--- a/examples/rp/src/bin/pio_dma.rs
+++ b/examples/rp/src/bin/pio_dma.rs
@@ -8,7 +8,6 @@ use embassy_executor::Spawner;
8use embassy_futures::join::join; 8use embassy_futures::join::join;
9use embassy_rp::peripherals::PIO0; 9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; 10use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection};
11use embassy_rp::relocate::RelocatedProgram;
12use embassy_rp::{bind_interrupts, Peripheral}; 11use embassy_rp::{bind_interrupts, Peripheral};
13use fixed::traits::ToFixed; 12use fixed::traits::ToFixed;
14use fixed_macro::types::U56F8; 13use fixed_macro::types::U56F8;
@@ -46,9 +45,8 @@ async fn main(_spawner: Spawner) {
46 ".wrap", 45 ".wrap",
47 ); 46 );
48 47
49 let relocated = RelocatedProgram::new(&prg.program);
50 let mut cfg = Config::default(); 48 let mut cfg = Config::default();
51 cfg.use_program(&common.load_program(&relocated), &[]); 49 cfg.use_program(&common.load_program(&prg.program), &[]);
52 cfg.clock_divider = (U56F8!(125_000_000) / U56F8!(10_000)).to_fixed(); 50 cfg.clock_divider = (U56F8!(125_000_000) / U56F8!(10_000)).to_fixed();
53 cfg.shift_in = ShiftConfig { 51 cfg.shift_in = ShiftConfig {
54 auto_fill: true, 52 auto_fill: true,
diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs
index 8aedd24b6..d80c5c24b 100644
--- a/examples/rp/src/bin/pio_hd44780.rs
+++ b/examples/rp/src/bin/pio_hd44780.rs
@@ -14,7 +14,6 @@ use embassy_rp::pio::{
14 Config, Direction, FifoJoin, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, 14 Config, Direction, FifoJoin, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine,
15}; 15};
16use embassy_rp::pwm::{self, Pwm}; 16use embassy_rp::pwm::{self, Pwm};
17use embassy_rp::relocate::RelocatedProgram;
18use embassy_rp::{bind_interrupts, into_ref, Peripheral, PeripheralRef}; 17use embassy_rp::{bind_interrupts, into_ref, Peripheral, PeripheralRef};
19use embassy_time::{Duration, Instant, Timer}; 18use embassy_time::{Duration, Instant, Timer};
20use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
@@ -127,9 +126,8 @@ impl<'l> HD44780<'l> {
127 126
128 sm0.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]); 127 sm0.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]);
129 128
130 let relocated = RelocatedProgram::new(&prg.program);
131 let mut cfg = Config::default(); 129 let mut cfg = Config::default();
132 cfg.use_program(&common.load_program(&relocated), &[&e]); 130 cfg.use_program(&common.load_program(&prg.program), &[&e]);
133 cfg.clock_divider = 125u8.into(); 131 cfg.clock_divider = 125u8.into();
134 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); 132 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
135 cfg.shift_out = ShiftConfig { 133 cfg.shift_out = ShiftConfig {
@@ -201,9 +199,8 @@ impl<'l> HD44780<'l> {
201 "# 199 "#
202 ); 200 );
203 201
204 let relocated = RelocatedProgram::new(&prg.program);
205 let mut cfg = Config::default(); 202 let mut cfg = Config::default();
206 cfg.use_program(&common.load_program(&relocated), &[&e]); 203 cfg.use_program(&common.load_program(&prg.program), &[&e]);
207 cfg.clock_divider = 8u8.into(); // ~64ns/insn 204 cfg.clock_divider = 8u8.into(); // ~64ns/insn
208 cfg.set_jmp_pin(&db7); 205 cfg.set_jmp_pin(&db7);
209 cfg.set_set_pins(&[&rs, &rw]); 206 cfg.set_set_pins(&[&rs, &rw]);
diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs
index ca1c7f394..5fddbe292 100644
--- a/examples/rp/src/bin/pio_uart.rs
+++ b/examples/rp/src/bin/pio_uart.rs
@@ -222,8 +222,8 @@ mod uart {
222 mut common, sm0, sm1, .. 222 mut common, sm0, sm1, ..
223 } = Pio::new(pio, Irqs); 223 } = Pio::new(pio, Irqs);
224 224
225 let (tx, origin) = PioUartTx::new(&mut common, sm0, tx_pin, baud, None); 225 let tx = PioUartTx::new(&mut common, sm0, tx_pin, baud);
226 let (rx, _) = PioUartRx::new(&mut common, sm1, rx_pin, baud, Some(origin)); 226 let rx = PioUartRx::new(&mut common, sm1, rx_pin, baud);
227 227
228 PioUart { tx, rx } 228 PioUart { tx, rx }
229 } 229 }
@@ -240,7 +240,6 @@ mod uart_tx {
240 use embassy_rp::gpio::Level; 240 use embassy_rp::gpio::Level;
241 use embassy_rp::peripherals::PIO0; 241 use embassy_rp::peripherals::PIO0;
242 use embassy_rp::pio::{Common, Config, Direction, FifoJoin, PioPin, ShiftDirection, StateMachine}; 242 use embassy_rp::pio::{Common, Config, Direction, FifoJoin, PioPin, ShiftDirection, StateMachine};
243 use embassy_rp::relocate::RelocatedProgram;
244 use embedded_io::asynch::Write; 243 use embedded_io::asynch::Write;
245 use embedded_io::Io; 244 use embedded_io::Io;
246 use fixed::traits::ToFixed; 245 use fixed::traits::ToFixed;
@@ -256,9 +255,8 @@ mod uart_tx {
256 mut sm_tx: StateMachine<'a, PIO0, 0>, 255 mut sm_tx: StateMachine<'a, PIO0, 0>,
257 tx_pin: impl PioPin, 256 tx_pin: impl PioPin,
258 baud: u64, 257 baud: u64,
259 origin: Option<u8>, 258 ) -> Self {
260 ) -> (Self, u8) { 259 let prg = pio_proc::pio_asm!(
261 let mut prg = pio_proc::pio_asm!(
262 r#" 260 r#"
263 .side_set 1 opt 261 .side_set 1 opt
264 262
@@ -272,17 +270,14 @@ mod uart_tx {
272 jmp x-- bitloop [6] ; Each loop iteration is 8 cycles. 270 jmp x-- bitloop [6] ; Each loop iteration is 8 cycles.
273 "# 271 "#
274 ); 272 );
275 prg.program.origin = origin;
276 let tx_pin = common.make_pio_pin(tx_pin); 273 let tx_pin = common.make_pio_pin(tx_pin);
277 sm_tx.set_pins(Level::High, &[&tx_pin]); 274 sm_tx.set_pins(Level::High, &[&tx_pin]);
278 sm_tx.set_pin_dirs(Direction::Out, &[&tx_pin]); 275 sm_tx.set_pin_dirs(Direction::Out, &[&tx_pin]);
279 276
280 let relocated = RelocatedProgram::new(&prg.program);
281
282 let mut cfg = Config::default(); 277 let mut cfg = Config::default();
283 278
284 cfg.set_out_pins(&[&tx_pin]); 279 cfg.set_out_pins(&[&tx_pin]);
285 cfg.use_program(&common.load_program(&relocated), &[&tx_pin]); 280 cfg.use_program(&common.load_program(&prg.program), &[&tx_pin]);
286 cfg.shift_out.auto_fill = false; 281 cfg.shift_out.auto_fill = false;
287 cfg.shift_out.direction = ShiftDirection::Right; 282 cfg.shift_out.direction = ShiftDirection::Right;
288 cfg.fifo_join = FifoJoin::TxOnly; 283 cfg.fifo_join = FifoJoin::TxOnly;
@@ -290,18 +285,7 @@ mod uart_tx {
290 sm_tx.set_config(&cfg); 285 sm_tx.set_config(&cfg);
291 sm_tx.set_enable(true); 286 sm_tx.set_enable(true);
292 287
293 // The 4 state machines of the PIO each have their own program counter that starts taking 288 Self { sm_tx }
294 // instructions at an offset (origin) of the 32 instruction "space" the PIO device has.
295 // It is up to the programmer to sort out where to place these instructions.
296 // From the pio_asm! macro you get a ProgramWithDefines which has a field .program.origin
297 // which takes an Option<u8>.
298 //
299 // When you load more than one RelocatedProgram into the PIO,
300 // you load your first program at origin = 0.
301 // The RelocatedProgram has .code().count() which returns a usize,
302 // for which you can then use as your next program's origin.
303 let offset = relocated.code().count() as u8 + origin.unwrap_or_default();
304 (Self { sm_tx }, offset)
305 } 289 }
306 290
307 pub async fn write_u8(&mut self, data: u8) { 291 pub async fn write_u8(&mut self, data: u8) {
@@ -329,7 +313,6 @@ mod uart_rx {
329 use embassy_rp::gpio::Level; 313 use embassy_rp::gpio::Level;
330 use embassy_rp::peripherals::PIO0; 314 use embassy_rp::peripherals::PIO0;
331 use embassy_rp::pio::{Common, Config, Direction, FifoJoin, PioPin, ShiftDirection, StateMachine}; 315 use embassy_rp::pio::{Common, Config, Direction, FifoJoin, PioPin, ShiftDirection, StateMachine};
332 use embassy_rp::relocate::RelocatedProgram;
333 use embedded_io::asynch::Read; 316 use embedded_io::asynch::Read;
334 use embedded_io::Io; 317 use embedded_io::Io;
335 use fixed::traits::ToFixed; 318 use fixed::traits::ToFixed;
@@ -345,9 +328,8 @@ mod uart_rx {
345 mut sm_rx: StateMachine<'a, PIO0, 1>, 328 mut sm_rx: StateMachine<'a, PIO0, 1>,
346 rx_pin: impl PioPin, 329 rx_pin: impl PioPin,
347 baud: u64, 330 baud: u64,
348 origin: Option<u8>, 331 ) -> Self {
349 ) -> (Self, u8) { 332 let prg = pio_proc::pio_asm!(
350 let mut prg = pio_proc::pio_asm!(
351 r#" 333 r#"
352 ; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and 334 ; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and
353 ; break conditions more gracefully. 335 ; break conditions more gracefully.
@@ -369,10 +351,8 @@ mod uart_rx {
369 push ; important in case the TX clock is slightly too fast. 351 push ; important in case the TX clock is slightly too fast.
370 "# 352 "#
371 ); 353 );
372 prg.program.origin = origin;
373 let relocated = RelocatedProgram::new(&prg.program);
374 let mut cfg = Config::default(); 354 let mut cfg = Config::default();
375 cfg.use_program(&common.load_program(&relocated), &[]); 355 cfg.use_program(&common.load_program(&prg.program), &[]);
376 356
377 let rx_pin = common.make_pio_pin(rx_pin); 357 let rx_pin = common.make_pio_pin(rx_pin);
378 sm_rx.set_pins(Level::High, &[&rx_pin]); 358 sm_rx.set_pins(Level::High, &[&rx_pin]);
@@ -387,8 +367,7 @@ mod uart_rx {
387 sm_rx.set_config(&cfg); 367 sm_rx.set_config(&cfg);
388 sm_rx.set_enable(true); 368 sm_rx.set_enable(true);
389 369
390 let offset = relocated.code().count() as u8 + origin.unwrap_or_default(); 370 Self { sm_rx }
391 (Self { sm_rx }, offset)
392 } 371 }
393 372
394 pub async fn read_u8(&mut self) -> u8 { 373 pub async fn read_u8(&mut self) -> u8 {
diff --git a/examples/rp/src/bin/pio_ws2812.rs b/examples/rp/src/bin/pio_ws2812.rs
index 3de2bd48d..bc87016ec 100644
--- a/examples/rp/src/bin/pio_ws2812.rs
+++ b/examples/rp/src/bin/pio_ws2812.rs
@@ -12,7 +12,6 @@ use embassy_rp::peripherals::PIO0;
12use embassy_rp::pio::{ 12use embassy_rp::pio::{
13 Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, 13 Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine,
14}; 14};
15use embassy_rp::relocate::RelocatedProgram;
16use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef}; 15use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef};
17use embassy_time::{Duration, Timer}; 16use embassy_time::{Duration, Timer};
18use fixed::types::U24F8; 17use fixed::types::U24F8;
@@ -73,8 +72,7 @@ impl<'d, P: Instance, const S: usize, const N: usize> Ws2812<'d, P, S, N> {
73 cfg.set_out_pins(&[&out_pin]); 72 cfg.set_out_pins(&[&out_pin]);
74 cfg.set_set_pins(&[&out_pin]); 73 cfg.set_set_pins(&[&out_pin]);
75 74
76 let relocated = RelocatedProgram::new(&prg); 75 cfg.use_program(&pio.load_program(&prg), &[&out_pin]);
77 cfg.use_program(&pio.load_program(&relocated), &[&out_pin]);
78 76
79 // Clock config, measured in kHz to avoid overflows 77 // Clock config, measured in kHz to avoid overflows
80 // TODO CLOCK_FREQ should come from embassy_rp 78 // TODO CLOCK_FREQ should come from embassy_rp
diff --git a/tests/rp/src/bin/pio_irq.rs b/tests/rp/src/bin/pio_irq.rs
index 45004424a..bdea63eaa 100644
--- a/tests/rp/src/bin/pio_irq.rs
+++ b/tests/rp/src/bin/pio_irq.rs
@@ -9,7 +9,6 @@ use embassy_executor::Spawner;
9use embassy_rp::bind_interrupts; 9use embassy_rp::bind_interrupts;
10use embassy_rp::peripherals::PIO0; 10use embassy_rp::peripherals::PIO0;
11use embassy_rp::pio::{Config, InterruptHandler, Pio}; 11use embassy_rp::pio::{Config, InterruptHandler, Pio};
12use embassy_rp::relocate::RelocatedProgram;
13use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
14 13
15bind_interrupts!(struct Irqs { 14bind_interrupts!(struct Irqs {
@@ -35,9 +34,8 @@ async fn main(_spawner: Spawner) {
35 "irq wait 1", 34 "irq wait 1",
36 ); 35 );
37 36
38 let relocated = RelocatedProgram::new(&prg.program);
39 let mut cfg = Config::default(); 37 let mut cfg = Config::default();
40 cfg.use_program(&common.load_program(&relocated), &[]); 38 cfg.use_program(&common.load_program(&prg.program), &[]);
41 sm.set_config(&cfg); 39 sm.set_config(&cfg);
42 sm.set_enable(true); 40 sm.set_enable(true);
43 41
diff --git a/tests/rp/src/bin/pio_multi_load.rs b/tests/rp/src/bin/pio_multi_load.rs
new file mode 100644
index 000000000..356f16795
--- /dev/null
+++ b/tests/rp/src/bin/pio_multi_load.rs
@@ -0,0 +1,126 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
6
7use defmt::info;
8use embassy_executor::Spawner;
9use embassy_rp::bind_interrupts;
10use embassy_rp::peripherals::PIO0;
11use embassy_rp::pio::{Config, InterruptHandler, LoadError, Pio};
12use {defmt_rtt as _, panic_probe as _};
13
14bind_interrupts!(struct Irqs {
15 PIO0_IRQ_0 => InterruptHandler<PIO0>;
16});
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) {
20 let p = embassy_rp::init(Default::default());
21 let pio = p.PIO0;
22 let Pio {
23 mut common,
24 mut sm0,
25 mut sm1,
26 mut sm2,
27 irq_flags,
28 ..
29 } = Pio::new(pio, Irqs);
30
31 // load with explicit origin works
32 let prg1 = pio_proc::pio_asm!(
33 ".origin 4"
34 "nop",
35 "nop",
36 "nop",
37 "nop",
38 "nop",
39 "nop",
40 "nop",
41 "irq 0",
42 "nop",
43 "nop",
44 );
45 let loaded1 = common.load_program(&prg1.program);
46 assert_eq!(loaded1.origin, 4);
47 assert_eq!(loaded1.wrap.source, 13);
48 assert_eq!(loaded1.wrap.target, 4);
49
50 // load without origin chooses a free space
51 let prg2 = pio_proc::pio_asm!("nop", "nop", "nop", "nop", "nop", "nop", "nop", "irq 1", "nop", "nop",);
52 let loaded2 = common.load_program(&prg2.program);
53 assert_eq!(loaded2.origin, 14);
54 assert_eq!(loaded2.wrap.source, 23);
55 assert_eq!(loaded2.wrap.target, 14);
56
57 // wrapping around the end of program space automatically works
58 let prg3 =
59 pio_proc::pio_asm!("nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "irq 2",);
60 let loaded3 = common.load_program(&prg3.program);
61 assert_eq!(loaded3.origin, 24);
62 assert_eq!(loaded3.wrap.source, 3);
63 assert_eq!(loaded3.wrap.target, 24);
64
65 // check that the programs actually work
66 {
67 let mut cfg = Config::default();
68 cfg.use_program(&loaded1, &[]);
69 sm0.set_config(&cfg);
70 sm0.set_enable(true);
71 while !irq_flags.check(0) {}
72 sm0.set_enable(false);
73 }
74 {
75 let mut cfg = Config::default();
76 cfg.use_program(&loaded2, &[]);
77 sm1.set_config(&cfg);
78 sm1.set_enable(true);
79 while !irq_flags.check(1) {}
80 sm1.set_enable(false);
81 }
82 {
83 let mut cfg = Config::default();
84 cfg.use_program(&loaded3, &[]);
85 sm2.set_config(&cfg);
86 sm2.set_enable(true);
87 while !irq_flags.check(2) {}
88 sm2.set_enable(false);
89 }
90
91 // instruction memory is full now. all loads should fail.
92 {
93 let prg = pio_proc::pio_asm!(".origin 0", "nop");
94 match common.try_load_program(&prg.program) {
95 Err(LoadError::AddressInUse(0)) => (),
96 _ => panic!("program loaded when it shouldn't"),
97 };
98
99 let prg = pio_proc::pio_asm!("nop");
100 match common.try_load_program(&prg.program) {
101 Err(LoadError::InsufficientSpace) => (),
102 _ => panic!("program loaded when it shouldn't"),
103 };
104 }
105
106 // freeing some memory should allow further loads though.
107 unsafe {
108 common.free_instr(loaded3.used_memory);
109 }
110 {
111 let prg = pio_proc::pio_asm!(".origin 0", "nop");
112 match common.try_load_program(&prg.program) {
113 Ok(_) => (),
114 _ => panic!("program didn't loaded when it shouldn"),
115 };
116
117 let prg = pio_proc::pio_asm!("nop");
118 match common.try_load_program(&prg.program) {
119 Ok(_) => (),
120 _ => panic!("program didn't loaded when it shouldn"),
121 };
122 }
123
124 info!("Test OK");
125 cortex_m::asm::bkpt();
126}