diff options
| author | Michael Zill <[email protected]> | 2024-04-05 16:12:58 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2024-05-21 23:08:44 +0200 |
| commit | 7d350fb4c8133d7569f3b0873a7120e3a7832dcd (patch) | |
| tree | fa79488eedc3442b7c9184b4d9b2ba7d20b87fdc | |
| parent | e85242af2c638b41772029a28be4a64bf43922dc (diff) | |
HSEM support for embassy-stm32
| -rw-r--r-- | embassy-stm32/src/hsem/mod.rs | 181 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 2 |
2 files changed, 183 insertions, 0 deletions
diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs new file mode 100644 index 000000000..cc30302b9 --- /dev/null +++ b/embassy-stm32/src/hsem/mod.rs | |||
| @@ -0,0 +1,181 @@ | |||
| 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 | #[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 | CoreId::Core1 => 1, | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | /// HSEM driver | ||
| 74 | pub struct HardwareSemaphore<'d, T: Instance> { | ||
| 75 | _peri: PeripheralRef<'d, T>, | ||
| 76 | } | ||
| 77 | |||
| 78 | impl<'d, T: Instance> HardwareSemaphore<'d, T> { | ||
| 79 | /// Creates a new HardwareSemaphore instance. | ||
| 80 | pub fn new(peripheral: impl Peripheral<P = T> + 'd) -> Self { | ||
| 81 | into_ref!(peripheral); | ||
| 82 | HardwareSemaphore { _peri: peripheral } | ||
| 83 | } | ||
| 84 | |||
| 85 | /// Locks the semaphore. | ||
| 86 | /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to | ||
| 87 | /// check if the lock has been successful, carried out from the HSEM_Rx register. | ||
| 88 | pub fn two_step_lock(&mut self, sem_id: u8, process_id: u8) -> Result<(), HsemError> { | ||
| 89 | T::regs().r(sem_id as usize).write(|w| { | ||
| 90 | w.set_procid(process_id); | ||
| 91 | w.set_coreid(get_current_coreid() as u8); | ||
| 92 | w.set_lock(true); | ||
| 93 | }); | ||
| 94 | let reg = T::regs().r(sem_id as usize).read(); | ||
| 95 | match ( | ||
| 96 | reg.lock(), | ||
| 97 | reg.coreid() == get_current_coreid() as u8, | ||
| 98 | reg.procid() == process_id, | ||
| 99 | ) { | ||
| 100 | (true, true, true) => Ok(()), | ||
| 101 | _ => Err(HsemError::LockFailed), | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | /// Locks the semaphore. | ||
| 106 | /// The 1-step procedure consists in a read to lock and check the semaphore in a single step, | ||
| 107 | /// carried out from the HSEM_RLRx register. | ||
| 108 | pub fn one_step_lock(&mut self, sem_id: u8) -> Result<(), HsemError> { | ||
| 109 | let reg = T::regs().rlr(sem_id as usize).read(); | ||
| 110 | match (reg.lock(), reg.coreid() == get_current_coreid() as u8, reg.procid()) { | ||
| 111 | (false, true, 0) => Ok(()), | ||
| 112 | _ => Err(HsemError::LockFailed), | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | /// Unlocks the semaphore. | ||
| 117 | /// Unlocking a semaphore is a protected process, to prevent accidental clearing by a AHB bus | ||
| 118 | /// core ID or by a process not having the semaphore lock right. | ||
| 119 | pub fn unlock(&mut self, sem_id: u8, process_id: u8) { | ||
| 120 | T::regs().r(sem_id as usize).write(|w| { | ||
| 121 | w.set_procid(process_id); | ||
| 122 | w.set_coreid(get_current_coreid() as u8); | ||
| 123 | w.set_lock(false); | ||
| 124 | }); | ||
| 125 | } | ||
| 126 | |||
| 127 | /// Unlocks all semaphores. | ||
| 128 | /// All semaphores locked by a COREID can be unlocked at once by using the HSEM_CR | ||
| 129 | /// register. Write COREID and correct KEY value in HSEM_CR. All locked semaphores with a | ||
| 130 | /// matching COREID are unlocked, and may generate an interrupt when enabled. | ||
| 131 | pub fn unlock_all(&mut self, key: u16, core_id: u8) { | ||
| 132 | T::regs().cr().write(|w| { | ||
| 133 | w.set_key(key); | ||
| 134 | w.set_coreid(core_id); | ||
| 135 | }); | ||
| 136 | } | ||
| 137 | |||
| 138 | /// Checks if the semaphore is locked. | ||
| 139 | pub fn is_semaphore_locked(&self, sem_id: u8) -> bool { | ||
| 140 | T::regs().r(sem_id as usize).read().lock() | ||
| 141 | } | ||
| 142 | |||
| 143 | /// Sets the clear (unlock) key | ||
| 144 | pub fn set_clear_key(&mut self, key: u16) { | ||
| 145 | T::regs().keyr().modify(|w| w.set_key(key)); | ||
| 146 | } | ||
| 147 | |||
| 148 | /// Gets the clear (unlock) key | ||
| 149 | pub fn get_clear_key(&mut self) -> u16 { | ||
| 150 | T::regs().keyr().read().key() | ||
| 151 | } | ||
| 152 | |||
| 153 | /// Sets the interrupt enable bit for the semaphore. | ||
| 154 | pub fn enable_interrupt(&mut self, core_id: CoreId, sem_x: usize, enable: bool) { | ||
| 155 | T::regs() | ||
| 156 | .ier(core_id_to_index(core_id)) | ||
| 157 | .modify(|w| w.set_ise(sem_x, enable)); | ||
| 158 | } | ||
| 159 | |||
| 160 | /// Clears the interrupt flag for the semaphore. | ||
| 161 | pub fn clear_interrupt(&mut self, core_id: CoreId, sem_x: usize) { | ||
| 162 | T::regs() | ||
| 163 | .icr(core_id_to_index(core_id)) | ||
| 164 | .write(|w| w.set_isc(sem_x, false)); | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 168 | trait SealedInstance { | ||
| 169 | fn regs() -> pac::hsem::Hsem; | ||
| 170 | } | ||
| 171 | |||
| 172 | /// HSEM instance trait. | ||
| 173 | #[allow(private_bounds)] | ||
| 174 | pub trait Instance: SealedInstance + RccPeripheral + Send + 'static {} | ||
| 175 | |||
| 176 | impl SealedInstance for crate::peripherals::HSEM { | ||
| 177 | fn regs() -> crate::pac::hsem::Hsem { | ||
| 178 | crate::pac::HSEM | ||
| 179 | } | ||
| 180 | } | ||
| 181 | impl Instance for crate::peripherals::HSEM {} | ||
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 029e01480..e0b3cbe37 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))] |
