diff options
| author | pennae <[email protected]> | 2023-07-28 18:45:57 +0200 |
|---|---|---|
| committer | pennae <[email protected]> | 2023-07-28 19:33:02 +0200 |
| commit | cbc8871a0bb40eb5fec82e7c27ed4c0127844c3c (patch) | |
| tree | 333ab4bc2d1893d42529c6a378ea51c42f8c8d22 /embassy-rp/src | |
| parent | d752a3f9808ec9be64c720d3f80f152f0b7507df (diff) | |
rp: relocate programs implicitly during load
this removed the RelocatedProgram construction step from pio uses.
there's not all that much to be said for the extra step because the
origin can be set on the input program itself, and the remaining
information exposed by RelocatedProgram can be exposed from
LoadedProgram instead (even though it's already available on the pio_asm
programs, albeit perhaps less convenient). we do lose access to the
relocated instruction iterator, but we also cannot think of anything
this iterator would actually be useful for outside of program loading.
Diffstat (limited to 'embassy-rp/src')
| -rw-r--r-- | embassy-rp/src/lib.rs | 2 | ||||
| -rw-r--r-- | embassy-rp/src/pio.rs | 60 | ||||
| -rw-r--r-- | embassy-rp/src/relocate.rs | 5 |
3 files changed, 53 insertions, 14 deletions
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` |
| 34 | pub mod pio; | 34 | pub mod pio; |
| 35 | pub mod pio_instr_util; | 35 | pub mod pio_instr_util; |
| 36 | pub mod relocate; | 36 | pub(crate) mod relocate; |
| 37 | 37 | ||
| 38 | // Reexports | 38 | // Reexports |
| 39 | pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | 39 | pub 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; | |||
| 11 | use fixed::FixedU32; | 11 | use fixed::FixedU32; |
| 12 | use pac::io::vals::Gpio0ctrlFuncsel; | 12 | use pac::io::vals::Gpio0ctrlFuncsel; |
| 13 | use pac::pio::vals::SmExecctrlStatusSel; | 13 | use pac::pio::vals::SmExecctrlStatusSel; |
| 14 | use pio::{SideSet, Wrap}; | 14 | use pio::{Program, SideSet, Wrap}; |
| 15 | 15 | ||
| 16 | use crate::dma::{Channel, Transfer, Word}; | 16 | use crate::dma::{Channel, Transfer, Word}; |
| 17 | use crate::gpio::sealed::Pin as SealedPin; | 17 | use crate::gpio::sealed::Pin as SealedPin; |
| @@ -734,23 +734,67 @@ pub struct InstanceMemory<'d, PIO: Instance> { | |||
| 734 | 734 | ||
| 735 | pub struct LoadedProgram<'d, PIO: Instance> { | 735 | pub 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))] | ||
| 744 | pub 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 | ||
| 742 | impl<'d, PIO: Instance> Common<'d, PIO> { | 752 | impl<'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 | ||
| 43 | impl<'a, const PROGRAM_SIZE: usize> RelocatedProgram<'a, PROGRAM_SIZE> { | 43 | impl<'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 | } |
