aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpennae <[email protected]>2023-04-25 20:40:18 +0200
committerpennae <[email protected]>2023-05-01 12:58:57 +0200
commitf4ade6af8bb2571ce2de0531d9c9715a7b8b941c (patch)
tree08ae76de328feabf6406e6ad7f79b7d23bbe035e
parentfa1ec29ae61df78a74be4bffb47f400fa35e49f1 (diff)
rp/pio: write instr memory only from common
instruction memory is a shared resource. writing it only from PioCommon clarifies this, and perhaps makes it more obvious that multiple state machines can share the same instructions. this also allows *freeing* of instruction memory to reprogram the system, although this interface is not entirely safe yet. it's safe in the sense rusts understands things, but state machines may misbehave if their instruction memory is freed and rewritten while they are running. fixing this is out of scope for now since it requires some larger changes to how state machines are handled. the interface provided currently is already unsafe in that it lets people execute instruction memory that has never been written, so this isn't much of a drawback for now.
-rw-r--r--embassy-rp/src/pio.rs104
-rw-r--r--examples/rp/src/bin/pio_async.rs28
-rw-r--r--examples/rp/src/bin/pio_dma.rs6
-rw-r--r--examples/rp/src/bin/ws2812-pio.rs4
4 files changed, 63 insertions, 79 deletions
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs
index 8492ca31d..7faec10b5 100644
--- a/embassy-rp/src/pio.rs
+++ b/embassy-rp/src/pio.rs
@@ -772,19 +772,6 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
772 } 772 }
773 } 773 }
774 774
775 fn write_instr<I>(&mut self, start: usize, instrs: I)
776 where
777 I: Iterator<Item = u16>,
778 {
779 write_instr(
780 Self::Pio::PIO,
781 Self::Pio::PIO_NO,
782 start,
783 instrs,
784 MEM_USED_BY_STATEMACHINE | Self::Sm::SM_NO as u32,
785 );
786 }
787
788 fn wait_push<'a>(&'a mut self, value: u32) -> FifoOutFuture<'a, Self::Pio, Self> { 775 fn wait_push<'a>(&'a mut self, value: u32) -> FifoOutFuture<'a, Self::Pio, Self> {
789 FifoOutFuture::new(self, value) 776 FifoOutFuture::new(self, value)
790 } 777 }
@@ -880,71 +867,59 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
880 } 867 }
881} 868}
882 869
883/* 870pub struct PioCommonInstance<PIO: PioInstance> {
884This is a bit array containing 4 bits for every word in the PIO instruction memory. 871 instructions_used: u32,
885*/ 872 pio: PhantomData<PIO>,
886// Bit 3-2
887//const MEM_USE_MASK: u32 = 0b1100;
888const MEM_NOT_USED: u32 = 0b0000;
889const MEM_USED_BY_STATEMACHINE: u32 = 0b0100;
890const MEM_USED_BY_COMMON: u32 = 0b1000;
891
892// Bit 1-0 is the number of the state machine
893//const MEM_STATE_MASK: u32 = 0b0011;
894
895// Should use mutex if running on multiple cores
896static mut INSTR_MEM_STATUS: &'static mut [[u32; 4]; 2] = &mut [[0; 4]; 2];
897
898fn instr_mem_get_status(pio_no: u8, addr: u8) -> u32 {
899 ((unsafe { INSTR_MEM_STATUS[pio_no as usize][(addr >> 3) as usize] }) >> ((addr & 0x07) * 4)) & 0xf
900}
901
902fn instr_mem_set_status(pio_no: u8, addr: u8, status: u32) {
903 let w = unsafe { &mut INSTR_MEM_STATUS[pio_no as usize][(addr >> 3) as usize] };
904 let shift = (addr & 0x07) * 4;
905 *w = (*w & !(0xf << shift)) | (status << shift);
906}
907
908fn instr_mem_is_free(pio_no: u8, addr: u8) -> bool {
909 instr_mem_get_status(pio_no, addr) == MEM_NOT_USED
910} 873}
911 874
912pub struct PioCommonInstance<PIO: PioInstance> { 875pub struct PioInstanceMemory<PIO: PioInstance> {
876 used_mask: u32,
913 pio: PhantomData<PIO>, 877 pio: PhantomData<PIO>,
914} 878}
915 879
916impl<PIO: PioInstance> sealed::PioCommon for PioCommonInstance<PIO> { 880impl<PIO: PioInstance> sealed::PioCommon for PioCommonInstance<PIO> {
917 type Pio = PIO; 881 type Pio = PIO;
918} 882}
919impl<PIO: PioInstance> PioCommon for PioCommonInstance<PIO> {} 883impl<PIO: PioInstance> PioCommon for PioCommonInstance<PIO> {
920 884 fn write_instr<I>(&mut self, start: usize, instrs: I) -> PioInstanceMemory<Self::Pio>
921fn write_instr<I>(pio: &pac::pio::Pio, pio_no: u8, start: usize, instrs: I, mem_user: u32) 885 where
922where 886 I: Iterator<Item = u16>,
923 I: Iterator<Item = u16>, 887 {
924{ 888 let mut used_mask = 0;
925 for (i, instr) in instrs.enumerate() { 889 for (i, instr) in instrs.enumerate() {
926 let addr = (i + start) as u8; 890 let addr = (i + start) as u8;
927 assert!( 891 let mask = 1 << (addr as usize);
928 instr_mem_is_free(pio_no, addr), 892 assert!(
929 "Trying to write already used PIO instruction memory at {}", 893 self.instructions_used & mask == 0,
930 addr 894 "Trying to write already used PIO instruction memory at {}",
931 ); 895 addr
932 unsafe { 896 );
933 pio.instr_mem(addr as usize).write(|w| { 897 unsafe {
934 w.set_instr_mem(instr); 898 PIO::PIO.instr_mem(addr as usize).write(|w| {
935 }); 899 w.set_instr_mem(instr);
936 instr_mem_set_status(pio_no, addr, mem_user); 900 });
901 }
902 used_mask |= mask;
937 } 903 }
904 self.instructions_used |= used_mask;
905 PioInstanceMemory {
906 used_mask,
907 pio: PhantomData,
908 }
909 }
910
911 fn free_instr(&mut self, instrs: PioInstanceMemory<Self::Pio>) {
912 self.instructions_used &= !instrs.used_mask;
938 } 913 }
939} 914}
940 915
941pub trait PioCommon: sealed::PioCommon + Sized { 916pub trait PioCommon: sealed::PioCommon + Sized {
942 fn write_instr<I>(&mut self, start: usize, instrs: I) 917 fn write_instr<I>(&mut self, start: usize, instrs: I) -> PioInstanceMemory<Self::Pio>
943 where 918 where
944 I: Iterator<Item = u16>, 919 I: Iterator<Item = u16>;
945 { 920
946 write_instr(Self::Pio::PIO, Self::Pio::PIO_NO, start, instrs, MEM_USED_BY_COMMON); 921 // TODO make instruction memory that is currently in use unfreeable
947 } 922 fn free_instr(&mut self, instrs: PioInstanceMemory<Self::Pio>);
948 923
949 fn is_irq_set(&self, irq_no: u8) -> bool { 924 fn is_irq_set(&self, irq_no: u8) -> bool {
950 assert!(irq_no < 8); 925 assert!(irq_no < 8);
@@ -1027,6 +1002,7 @@ pub trait PioPeripheral: sealed::PioPeripheral + Sized {
1027 ) { 1002 ) {
1028 ( 1003 (
1029 PioCommonInstance { 1004 PioCommonInstance {
1005 instructions_used: 0,
1030 pio: PhantomData::default(), 1006 pio: PhantomData::default(),
1031 }, 1007 },
1032 PioStateMachineInstance { 1008 PioStateMachineInstance {
diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs
index 3cfeec71f..1b075b8fd 100644
--- a/examples/rp/src/bin/pio_async.rs
+++ b/examples/rp/src/bin/pio_async.rs
@@ -28,7 +28,7 @@ fn setup_pio_task_sm0(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachin
28 let out_pin = pio.make_pio_pin(pin); 28 let out_pin = pio.make_pio_pin(pin);
29 let pio_pins = [&out_pin]; 29 let pio_pins = [&out_pin];
30 sm.set_out_pins(&pio_pins); 30 sm.set_out_pins(&pio_pins);
31 sm.write_instr(relocated.origin() as usize, relocated.code()); 31 pio.write_instr(relocated.origin() as usize, relocated.code());
32 pio_instr_util::exec_jmp(sm, relocated.origin()); 32 pio_instr_util::exec_jmp(sm, relocated.origin());
33 sm.set_clkdiv((125e6 / 20.0 / 2e2 * 256.0) as u32); 33 sm.set_clkdiv((125e6 / 20.0 / 2e2 * 256.0) as u32);
34 sm.set_set_range(0, 1); 34 sm.set_set_range(0, 1);
@@ -51,16 +51,15 @@ async fn pio_task_sm0(mut sm: PioStateMachineInstance<Pio0, Sm0>) {
51 } 51 }
52} 52}
53 53
54#[embassy_executor::task] 54fn setup_pio_task_sm1(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachineInstance<Pio0, Sm1>) {
55async fn pio_task_sm1(mut sm: PioStateMachineInstance<Pio0, Sm1>) {
56 // Setupm sm1 55 // Setupm sm1
57 56
58 // Read 0b10101 repeatedly until ISR is full 57 // Read 0b10101 repeatedly until ISR is full
59 let prg = pio_proc::pio_asm!(".origin 8", "set x, 0x15", ".wrap_target", "in x, 5 [31]", ".wrap",); 58 let prg = pio_proc::pio_asm!(".origin 8", "set x, 0x15", ".wrap_target", "in x, 5 [31]", ".wrap",);
60 59
61 let relocated = RelocatedProgram::new(&prg.program); 60 let relocated = RelocatedProgram::new(&prg.program);
62 sm.write_instr(relocated.origin() as usize, relocated.code()); 61 pio.write_instr(relocated.origin() as usize, relocated.code());
63 pio_instr_util::exec_jmp(&mut sm, relocated.origin()); 62 pio_instr_util::exec_jmp(sm, relocated.origin());
64 sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32); 63 sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32);
65 sm.set_set_range(0, 0); 64 sm.set_set_range(0, 0);
66 let pio::Wrap { source, target } = relocated.wrap(); 65 let pio::Wrap { source, target } = relocated.wrap();
@@ -68,6 +67,10 @@ async fn pio_task_sm1(mut sm: PioStateMachineInstance<Pio0, Sm1>) {
68 67
69 sm.set_autopush(true); 68 sm.set_autopush(true);
70 sm.set_in_shift_dir(ShiftDirection::Right); 69 sm.set_in_shift_dir(ShiftDirection::Right);
70}
71
72#[embassy_executor::task]
73async fn pio_task_sm1(mut sm: PioStateMachineInstance<Pio0, Sm1>) {
71 sm.set_enable(true); 74 sm.set_enable(true);
72 loop { 75 loop {
73 let rx = sm.wait_pull().await; 76 let rx = sm.wait_pull().await;
@@ -75,8 +78,7 @@ async fn pio_task_sm1(mut sm: PioStateMachineInstance<Pio0, Sm1>) {
75 } 78 }
76} 79}
77 80
78#[embassy_executor::task] 81fn setup_pio_task_sm2(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachineInstance<Pio0, Sm2>) {
79async fn pio_task_sm2(mut sm: PioStateMachineInstance<Pio0, Sm2>) {
80 // Setup sm2 82 // Setup sm2
81 83
82 // Repeatedly trigger IRQ 3 84 // Repeatedly trigger IRQ 3
@@ -90,13 +92,17 @@ async fn pio_task_sm2(mut sm: PioStateMachineInstance<Pio0, Sm2>) {
90 ".wrap", 92 ".wrap",
91 ); 93 );
92 let relocated = RelocatedProgram::new(&prg.program); 94 let relocated = RelocatedProgram::new(&prg.program);
93 sm.write_instr(relocated.origin() as usize, relocated.code()); 95 pio.write_instr(relocated.origin() as usize, relocated.code());
94 96
95 let pio::Wrap { source, target } = relocated.wrap(); 97 let pio::Wrap { source, target } = relocated.wrap();
96 sm.set_wrap(source, target); 98 sm.set_wrap(source, target);
97 99
98 pio_instr_util::exec_jmp(&mut sm, relocated.origin()); 100 pio_instr_util::exec_jmp(sm, relocated.origin());
99 sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32); 101 sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32);
102}
103
104#[embassy_executor::task]
105async fn pio_task_sm2(mut sm: PioStateMachineInstance<Pio0, Sm2>) {
100 sm.set_enable(true); 106 sm.set_enable(true);
101 loop { 107 loop {
102 sm.wait_irq(3).await; 108 sm.wait_irq(3).await;
@@ -109,9 +115,11 @@ async fn main(spawner: Spawner) {
109 let p = embassy_rp::init(Default::default()); 115 let p = embassy_rp::init(Default::default());
110 let pio = p.PIO0; 116 let pio = p.PIO0;
111 117
112 let (mut pio0, mut sm0, sm1, sm2, ..) = pio.split(); 118 let (mut pio0, mut sm0, mut sm1, mut sm2, ..) = pio.split();
113 119
114 setup_pio_task_sm0(&mut pio0, &mut sm0, p.PIN_0.degrade()); 120 setup_pio_task_sm0(&mut pio0, &mut sm0, p.PIN_0.degrade());
121 setup_pio_task_sm1(&mut pio0, &mut sm1);
122 setup_pio_task_sm2(&mut pio0, &mut sm2);
115 spawner.spawn(pio_task_sm0(sm0)).unwrap(); 123 spawner.spawn(pio_task_sm0(sm0)).unwrap();
116 spawner.spawn(pio_task_sm1(sm1)).unwrap(); 124 spawner.spawn(pio_task_sm1(sm1)).unwrap();
117 spawner.spawn(pio_task_sm2(sm2)).unwrap(); 125 spawner.spawn(pio_task_sm2(sm2)).unwrap();
diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs
index 145e4a656..7d4919f75 100644
--- a/examples/rp/src/bin/pio_dma.rs
+++ b/examples/rp/src/bin/pio_dma.rs
@@ -4,7 +4,7 @@
4use defmt::info; 4use defmt::info;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_futures::join::join; 6use embassy_futures::join::join;
7use embassy_rp::pio::{PioPeripheral, PioStateMachine, ShiftDirection}; 7use embassy_rp::pio::{PioCommon, PioPeripheral, PioStateMachine, ShiftDirection};
8use embassy_rp::relocate::RelocatedProgram; 8use embassy_rp::relocate::RelocatedProgram;
9use embassy_rp::{pio_instr_util, Peripheral}; 9use embassy_rp::{pio_instr_util, Peripheral};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
@@ -19,7 +19,7 @@ fn swap_nibbles(v: u32) -> u32 {
19async fn main(_spawner: Spawner) { 19async fn main(_spawner: Spawner) {
20 let p = embassy_rp::init(Default::default()); 20 let p = embassy_rp::init(Default::default());
21 let pio = p.PIO0; 21 let pio = p.PIO0;
22 let (_, mut sm, ..) = pio.split(); 22 let (mut pio0, mut sm, ..) = pio.split();
23 23
24 let prg = pio_proc::pio_asm!( 24 let prg = pio_proc::pio_asm!(
25 ".origin 0", 25 ".origin 0",
@@ -34,7 +34,7 @@ async fn main(_spawner: Spawner) {
34 ); 34 );
35 35
36 let relocated = RelocatedProgram::new(&prg.program); 36 let relocated = RelocatedProgram::new(&prg.program);
37 sm.write_instr(relocated.origin() as usize, relocated.code()); 37 pio0.write_instr(relocated.origin() as usize, relocated.code());
38 pio_instr_util::exec_jmp(&mut sm, relocated.origin()); 38 pio_instr_util::exec_jmp(&mut sm, relocated.origin());
39 sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32); 39 sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32);
40 let pio::Wrap { source, target } = relocated.wrap(); 40 let pio::Wrap { source, target } = relocated.wrap();
diff --git a/examples/rp/src/bin/ws2812-pio.rs b/examples/rp/src/bin/ws2812-pio.rs
index 211c60c49..041e8ae11 100644
--- a/examples/rp/src/bin/ws2812-pio.rs
+++ b/examples/rp/src/bin/ws2812-pio.rs
@@ -19,7 +19,7 @@ pub struct Ws2812<P: PioInstance, S: SmInstance> {
19} 19}
20 20
21impl<P: PioInstance, S: SmInstance> Ws2812<P, S> { 21impl<P: PioInstance, S: SmInstance> Ws2812<P, S> {
22 pub fn new(pio: PioCommonInstance<P>, mut sm: PioStateMachineInstance<P, S>, pin: gpio::AnyPin) -> Self { 22 pub fn new(mut pio: PioCommonInstance<P>, mut sm: PioStateMachineInstance<P, S>, pin: gpio::AnyPin) -> Self {
23 // Setup sm0 23 // Setup sm0
24 24
25 // prepare the PIO program 25 // prepare the PIO program
@@ -50,7 +50,7 @@ impl<P: PioInstance, S: SmInstance> Ws2812<P, S> {
50 let prg = a.assemble_with_wrap(wrap_source, wrap_target); 50 let prg = a.assemble_with_wrap(wrap_source, wrap_target);
51 51
52 let relocated = RelocatedProgram::new(&prg); 52 let relocated = RelocatedProgram::new(&prg);
53 sm.write_instr(relocated.origin() as usize, relocated.code()); 53 pio.write_instr(relocated.origin() as usize, relocated.code());
54 pio_instr_util::exec_jmp(&mut sm, relocated.origin()); 54 pio_instr_util::exec_jmp(&mut sm, relocated.origin());
55 55
56 // Pin config 56 // Pin config