diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-05-21 21:34:50 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-05-21 21:34:50 +0000 |
| commit | ae49e58993ff12ba3d4c9a8dc1140aa551f3c7c3 (patch) | |
| tree | 52c2c9e164561659e2bc4fe11e7eb3d383574319 | |
| parent | 4b5026e197ae681ae2e3e5d9f4ce913a4d9ff7d9 (diff) | |
| parent | afd61ed610293b1f41bc926bf3a0fa35d78a8815 (diff) | |
Merge pull request #2777 from taunusflieger/feature/HSEM
HSEM support for embassy-stm32
| -rw-r--r-- | embassy-stm32/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/hsem/mod.rs | 182 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 2 |
3 files changed, 186 insertions, 2 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index a7137d132..5ef2366d9 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -72,7 +72,7 @@ rand_core = "0.6.3" | |||
| 72 | sdio-host = "0.5.0" | 72 | sdio-host = "0.5.0" |
| 73 | critical-section = "1.1" | 73 | critical-section = "1.1" |
| 74 | #stm32-metapac = { version = "15" } | 74 | #stm32-metapac = { version = "15" } |
| 75 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f1297385e91f061fcb6134bb25f51e12d8abff93" } | 75 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-34c0188a682b32c32ff147d377e0629b1ebe8318" } |
| 76 | 76 | ||
| 77 | vcell = "0.1.3" | 77 | vcell = "0.1.3" |
| 78 | nb = "1.0.0" | 78 | nb = "1.0.0" |
| @@ -97,7 +97,7 @@ proc-macro2 = "1.0.36" | |||
| 97 | quote = "1.0.15" | 97 | quote = "1.0.15" |
| 98 | 98 | ||
| 99 | #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} | 99 | #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} |
| 100 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f1297385e91f061fcb6134bb25f51e12d8abff93", default-features = false, features = ["metadata"]} | 100 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-34c0188a682b32c32ff147d377e0629b1ebe8318", default-features = false, features = ["metadata"]} |
| 101 | 101 | ||
| 102 | [features] | 102 | [features] |
| 103 | default = ["rt"] | 103 | default = ["rt"] |
diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs new file mode 100644 index 000000000..b77a3415b --- /dev/null +++ b/embassy-stm32/src/hsem/mod.rs | |||
| @@ -0,0 +1,182 @@ | |||
| 1 | //! Hardware Semaphore (HSEM) | ||
| 2 | |||
| 3 | // TODO: This code works for all HSEM implemenations except for the STM32WBA52/4/5xx MCUs. | ||
| 4 | // Those MCUs have a different HSEM implementation (Secure semaphore lock support, | ||
| 5 | // Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute), | ||
| 6 | // which is not yet supported by this code. | ||
| 7 | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||
| 8 | |||
| 9 | use crate::rcc::RccPeripheral; | ||
| 10 | use crate::{pac, Peripheral}; | ||
| 11 | |||
| 12 | /// HSEM error. | ||
| 13 | #[derive(Debug)] | ||
| 14 | pub enum HsemError { | ||
| 15 | /// Locking the semaphore failed. | ||
| 16 | LockFailed, | ||
| 17 | } | ||
| 18 | |||
| 19 | /// CPU core. | ||
| 20 | /// The enum values are identical to the bus master IDs / core Ids defined for each | ||
| 21 | /// chip family (i.e. stm32h747 see rm0399 table 95) | ||
| 22 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] | ||
| 23 | #[repr(u8)] | ||
| 24 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 25 | pub enum CoreId { | ||
| 26 | #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))] | ||
| 27 | /// Cortex-M7, core 1. | ||
| 28 | Core0 = 0x3, | ||
| 29 | |||
| 30 | #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))] | ||
| 31 | /// Cortex-M4, core 2. | ||
| 32 | Core1 = 0x1, | ||
| 33 | |||
| 34 | #[cfg(not(any(stm32h745, stm32h747, stm32h755, stm32h757)))] | ||
| 35 | /// Cortex-M4, core 1 | ||
| 36 | Core0 = 0x4, | ||
| 37 | |||
| 38 | #[cfg(any(stm32wb, stm32wl))] | ||
| 39 | /// Cortex-M0+, core 2. | ||
| 40 | Core1 = 0x8, | ||
| 41 | } | ||
| 42 | |||
| 43 | /// Get the current core id | ||
| 44 | /// This code assume that it is only executed on a Cortex-M M0+, M4 or M7 core. | ||
| 45 | #[inline(always)] | ||
| 46 | pub fn get_current_coreid() -> CoreId { | ||
| 47 | let cpuid = unsafe { cortex_m::peripheral::CPUID::PTR.read_volatile().base.read() }; | ||
| 48 | match cpuid & 0x000000F0 { | ||
| 49 | #[cfg(any(stm32wb, stm32wl))] | ||
| 50 | 0x0 => CoreId::Core1, | ||
| 51 | |||
| 52 | #[cfg(not(any(stm32h745, stm32h747, stm32h755, stm32h757)))] | ||
| 53 | 0x4 => CoreId::Core0, | ||
| 54 | |||
| 55 | #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))] | ||
| 56 | 0x4 => CoreId::Core1, | ||
| 57 | |||
| 58 | #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))] | ||
| 59 | 0x7 => CoreId::Core0, | ||
| 60 | _ => panic!("Unknown Cortex-M core"), | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | /// Translates the core ID to an index into the interrupt registers. | ||
| 65 | #[inline(always)] | ||
| 66 | fn core_id_to_index(core: CoreId) -> usize { | ||
| 67 | match core { | ||
| 68 | CoreId::Core0 => 0, | ||
| 69 | #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757, stm32wb, stm32wl))] | ||
| 70 | CoreId::Core1 => 1, | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | /// HSEM driver | ||
| 75 | pub struct HardwareSemaphore<'d, T: Instance> { | ||
| 76 | _peri: PeripheralRef<'d, T>, | ||
| 77 | } | ||
| 78 | |||
| 79 | impl<'d, T: Instance> HardwareSemaphore<'d, T> { | ||
| 80 | /// Creates a new HardwareSemaphore instance. | ||
| 81 | pub fn new(peripheral: impl Peripheral<P = T> + 'd) -> Self { | ||
| 82 | into_ref!(peripheral); | ||
| 83 | HardwareSemaphore { _peri: peripheral } | ||
| 84 | } | ||
| 85 | |||
| 86 | /// Locks the semaphore. | ||
| 87 | /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to | ||
| 88 | /// check if the lock has been successful, carried out from the HSEM_Rx register. | ||
| 89 | pub fn two_step_lock(&mut self, sem_id: u8, process_id: u8) -> Result<(), HsemError> { | ||
| 90 | T::regs().r(sem_id as usize).write(|w| { | ||
| 91 | w.set_procid(process_id); | ||
| 92 | w.set_coreid(get_current_coreid() as u8); | ||
| 93 | w.set_lock(true); | ||
| 94 | }); | ||
| 95 | let reg = T::regs().r(sem_id as usize).read(); | ||
| 96 | match ( | ||
| 97 | reg.lock(), | ||
| 98 | reg.coreid() == get_current_coreid() as u8, | ||
| 99 | reg.procid() == process_id, | ||
| 100 | ) { | ||
| 101 | (true, true, true) => Ok(()), | ||
| 102 | _ => Err(HsemError::LockFailed), | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | /// Locks the semaphore. | ||
| 107 | /// The 1-step procedure consists in a read to lock and check the semaphore in a single step, | ||
| 108 | /// carried out from the HSEM_RLRx register. | ||
| 109 | pub fn one_step_lock(&mut self, sem_id: u8) -> Result<(), HsemError> { | ||
| 110 | let reg = T::regs().rlr(sem_id as usize).read(); | ||
| 111 | match (reg.lock(), reg.coreid() == get_current_coreid() as u8, reg.procid()) { | ||
| 112 | (false, true, 0) => Ok(()), | ||
| 113 | _ => Err(HsemError::LockFailed), | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | /// Unlocks the semaphore. | ||
| 118 | /// Unlocking a semaphore is a protected process, to prevent accidental clearing by a AHB bus | ||
| 119 | /// core ID or by a process not having the semaphore lock right. | ||
| 120 | pub fn unlock(&mut self, sem_id: u8, process_id: u8) { | ||
| 121 | T::regs().r(sem_id as usize).write(|w| { | ||
| 122 | w.set_procid(process_id); | ||
| 123 | w.set_coreid(get_current_coreid() as u8); | ||
| 124 | w.set_lock(false); | ||
| 125 | }); | ||
| 126 | } | ||
| 127 | |||
| 128 | /// Unlocks all semaphores. | ||
| 129 | /// All semaphores locked by a COREID can be unlocked at once by using the HSEM_CR | ||
| 130 | /// register. Write COREID and correct KEY value in HSEM_CR. All locked semaphores with a | ||
| 131 | /// matching COREID are unlocked, and may generate an interrupt when enabled. | ||
| 132 | pub fn unlock_all(&mut self, key: u16, core_id: u8) { | ||
| 133 | T::regs().cr().write(|w| { | ||
| 134 | w.set_key(key); | ||
| 135 | w.set_coreid(core_id); | ||
| 136 | }); | ||
| 137 | } | ||
| 138 | |||
| 139 | /// Checks if the semaphore is locked. | ||
| 140 | pub fn is_semaphore_locked(&self, sem_id: u8) -> bool { | ||
| 141 | T::regs().r(sem_id as usize).read().lock() | ||
| 142 | } | ||
| 143 | |||
| 144 | /// Sets the clear (unlock) key | ||
| 145 | pub fn set_clear_key(&mut self, key: u16) { | ||
| 146 | T::regs().keyr().modify(|w| w.set_key(key)); | ||
| 147 | } | ||
| 148 | |||
| 149 | /// Gets the clear (unlock) key | ||
| 150 | pub fn get_clear_key(&mut self) -> u16 { | ||
| 151 | T::regs().keyr().read().key() | ||
| 152 | } | ||
| 153 | |||
| 154 | /// Sets the interrupt enable bit for the semaphore. | ||
| 155 | pub fn enable_interrupt(&mut self, core_id: CoreId, sem_x: usize, enable: bool) { | ||
| 156 | T::regs() | ||
| 157 | .ier(core_id_to_index(core_id)) | ||
| 158 | .modify(|w| w.set_ise(sem_x, enable)); | ||
| 159 | } | ||
| 160 | |||
| 161 | /// Clears the interrupt flag for the semaphore. | ||
| 162 | pub fn clear_interrupt(&mut self, core_id: CoreId, sem_x: usize) { | ||
| 163 | T::regs() | ||
| 164 | .icr(core_id_to_index(core_id)) | ||
| 165 | .write(|w| w.set_isc(sem_x, false)); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | trait SealedInstance { | ||
| 170 | fn regs() -> pac::hsem::Hsem; | ||
| 171 | } | ||
| 172 | |||
| 173 | /// HSEM instance trait. | ||
| 174 | #[allow(private_bounds)] | ||
| 175 | pub trait Instance: SealedInstance + RccPeripheral + Send + 'static {} | ||
| 176 | |||
| 177 | impl SealedInstance for crate::peripherals::HSEM { | ||
| 178 | fn regs() -> crate::pac::hsem::Hsem { | ||
| 179 | crate::pac::HSEM | ||
| 180 | } | ||
| 181 | } | ||
| 182 | impl Instance for crate::peripherals::HSEM {} | ||
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index b4b9d5d12..81ee60c1c 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -79,6 +79,8 @@ pub mod fmc; | |||
| 79 | pub mod hash; | 79 | pub mod hash; |
| 80 | #[cfg(hrtim)] | 80 | #[cfg(hrtim)] |
| 81 | pub mod hrtim; | 81 | pub mod hrtim; |
| 82 | #[cfg(hsem)] | ||
| 83 | pub mod hsem; | ||
| 82 | #[cfg(i2c)] | 84 | #[cfg(i2c)] |
| 83 | pub mod i2c; | 85 | pub mod i2c; |
| 84 | #[cfg(all(spi_v1, rcc_f4))] | 86 | #[cfg(all(spi_v1, rcc_f4))] |
