diff options
| author | xoviat <[email protected]> | 2025-11-19 19:24:43 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-11-19 19:24:43 +0000 |
| commit | a68b5d5d29514dcaf0a6ed08207d3a1f1fa9b464 (patch) | |
| tree | c1bcc573f050b5353db6f4561f2957cac288f3f4 | |
| parent | 0ee68ed648ef96f001247409a9bacd2dc5cfbb30 (diff) | |
| parent | 141685f6f7ff5e78fb08d3aefb67be5d16485ceb (diff) | |
Merge pull request #4918 from xoviat/hsem-fix
rework hsem and add to tests
| -rw-r--r-- | embassy-stm32/CHANGELOG.md | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/hsem/mod.rs | 252 | ||||
| -rw-r--r-- | tests/stm32/Cargo.toml | 10 | ||||
| -rw-r--r-- | tests/stm32/src/bin/hsem.rs | 47 |
4 files changed, 245 insertions, 65 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index b6caf8f65..597cbb192 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md | |||
| @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 7 | 7 | ||
| 8 | ## Unreleased - ReleaseDate | 8 | ## Unreleased - ReleaseDate |
| 9 | 9 | ||
| 10 | - change: rework hsem and add HIL test for some chips. | ||
| 10 | - change: stm32/eth: ethernet no longer has a hard dependency on station management, and station management can be used independently ([#4871](https://github.com/embassy-rs/embassy/pull/4871)) | 11 | - change: stm32/eth: ethernet no longer has a hard dependency on station management, and station management can be used independently ([#4871](https://github.com/embassy-rs/embassy/pull/4871)) |
| 11 | - feat: allow embassy_executor::main for low power | 12 | - feat: allow embassy_executor::main for low power |
| 12 | - feat: Add waveform methods to ComplementaryPwm | 13 | - feat: Add waveform methods to ComplementaryPwm |
diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs index 4d3a5d68d..a6b910a53 100644 --- a/embassy-stm32/src/hsem/mod.rs +++ b/embassy-stm32/src/hsem/mod.rs | |||
| @@ -1,14 +1,20 @@ | |||
| 1 | //! Hardware Semaphore (HSEM) | 1 | //! Hardware Semaphore (HSEM) |
| 2 | 2 | ||
| 3 | use core::future::poll_fn; | ||
| 4 | use core::marker::PhantomData; | ||
| 5 | use core::sync::atomic::{Ordering, compiler_fence}; | ||
| 6 | use core::task::Poll; | ||
| 7 | |||
| 3 | use embassy_hal_internal::PeripheralType; | 8 | use embassy_hal_internal::PeripheralType; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 4 | 10 | ||
| 5 | // TODO: This code works for all HSEM implemenations except for the STM32WBA52/4/5xx MCUs. | 11 | // TODO: This code works for all HSEM implemenations except for the STM32WBA52/4/5xx MCUs. |
| 6 | // Those MCUs have a different HSEM implementation (Secure semaphore lock support, | 12 | // Those MCUs have a different HSEM implementation (Secure semaphore lock support, |
| 7 | // Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute), | 13 | // Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute), |
| 8 | // which is not yet supported by this code. | 14 | // which is not yet supported by this code. |
| 9 | use crate::Peri; | 15 | use crate::Peri; |
| 10 | use crate::pac; | ||
| 11 | use crate::rcc::{self, RccPeripheral}; | 16 | use crate::rcc::{self, RccPeripheral}; |
| 17 | use crate::{interrupt, pac}; | ||
| 12 | 18 | ||
| 13 | /// HSEM error. | 19 | /// HSEM error. |
| 14 | #[derive(Debug)] | 20 | #[derive(Debug)] |
| @@ -41,63 +47,136 @@ pub enum CoreId { | |||
| 41 | Core1 = 0x8, | 47 | Core1 = 0x8, |
| 42 | } | 48 | } |
| 43 | 49 | ||
| 44 | /// Get the current core id | 50 | impl CoreId { |
| 45 | /// This code assume that it is only executed on a Cortex-M M0+, M4 or M7 core. | 51 | /// Get the current core id |
| 46 | #[inline(always)] | 52 | /// This code assume that it is only executed on a Cortex-M M0+, M4 or M7 core. |
| 47 | pub fn get_current_coreid() -> CoreId { | 53 | pub fn current() -> Self { |
| 48 | let cpuid = unsafe { cortex_m::peripheral::CPUID::PTR.read_volatile().base.read() }; | 54 | let cpuid = unsafe { cortex_m::peripheral::CPUID::PTR.read_volatile().base.read() }; |
| 49 | match (cpuid & 0x000000F0) >> 4 { | 55 | match (cpuid & 0x000000F0) >> 4 { |
| 50 | #[cfg(any(stm32wb, stm32wl))] | 56 | #[cfg(any(stm32wb, stm32wl))] |
| 51 | 0x0 => CoreId::Core1, | 57 | 0x0 => CoreId::Core1, |
| 58 | |||
| 59 | #[cfg(not(any(stm32h745, stm32h747, stm32h755, stm32h757)))] | ||
| 60 | 0x4 => CoreId::Core0, | ||
| 52 | 61 | ||
| 53 | #[cfg(not(any(stm32h745, stm32h747, stm32h755, stm32h757)))] | 62 | #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))] |
| 54 | 0x4 => CoreId::Core0, | 63 | 0x4 => CoreId::Core1, |
| 55 | 64 | ||
| 56 | #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))] | 65 | #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))] |
| 57 | 0x4 => CoreId::Core1, | 66 | 0x7 => CoreId::Core0, |
| 67 | _ => panic!("Unknown Cortex-M core"), | ||
| 68 | } | ||
| 69 | } | ||
| 58 | 70 | ||
| 59 | #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))] | 71 | /// Translates the core ID to an index into the interrupt registers. |
| 60 | 0x7 => CoreId::Core0, | 72 | pub fn to_index(&self) -> usize { |
| 61 | _ => panic!("Unknown Cortex-M core"), | 73 | match &self { |
| 74 | CoreId::Core0 => 0, | ||
| 75 | #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757, stm32wb, stm32wl))] | ||
| 76 | CoreId::Core1 => 1, | ||
| 77 | } | ||
| 62 | } | 78 | } |
| 63 | } | 79 | } |
| 64 | 80 | ||
| 65 | /// Translates the core ID to an index into the interrupt registers. | 81 | /// TX interrupt handler. |
| 66 | #[inline(always)] | 82 | pub struct HardwareSemaphoreInterruptHandler<T: Instance> { |
| 67 | fn core_id_to_index(core: CoreId) -> usize { | 83 | _phantom: PhantomData<T>, |
| 68 | match core { | 84 | } |
| 69 | CoreId::Core0 => 0, | 85 | |
| 70 | #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757, stm32wb, stm32wl))] | 86 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for HardwareSemaphoreInterruptHandler<T> { |
| 71 | CoreId::Core1 => 1, | 87 | unsafe fn on_interrupt() { |
| 88 | let core_id = CoreId::current(); | ||
| 89 | |||
| 90 | for number in 0..5 { | ||
| 91 | if T::regs().isr(core_id.to_index()).read().isf(number as usize) { | ||
| 92 | T::regs() | ||
| 93 | .icr(core_id.to_index()) | ||
| 94 | .write(|w| w.set_isc(number as usize, true)); | ||
| 95 | |||
| 96 | T::regs() | ||
| 97 | .ier(core_id.to_index()) | ||
| 98 | .modify(|w| w.set_ise(number as usize, false)); | ||
| 99 | |||
| 100 | T::state().waker_for(number).wake(); | ||
| 101 | } | ||
| 102 | } | ||
| 72 | } | 103 | } |
| 73 | } | 104 | } |
| 74 | 105 | ||
| 75 | /// HSEM driver | 106 | /// Hardware semaphore mutex |
| 76 | pub struct HardwareSemaphore<'d, T: Instance> { | 107 | pub struct HardwareSemaphoreMutex<'a, T: Instance> { |
| 77 | _peri: Peri<'d, T>, | 108 | index: u8, |
| 109 | process_id: u8, | ||
| 110 | _lifetime: PhantomData<&'a mut T>, | ||
| 78 | } | 111 | } |
| 79 | 112 | ||
| 80 | impl<'d, T: Instance> HardwareSemaphore<'d, T> { | 113 | impl<'a, T: Instance> Drop for HardwareSemaphoreMutex<'a, T> { |
| 81 | /// Creates a new HardwareSemaphore instance. | 114 | fn drop(&mut self) { |
| 82 | pub fn new(peripheral: Peri<'d, T>) -> Self { | 115 | HardwareSemaphoreChannel::<'a, T> { |
| 83 | rcc::enable_and_reset::<T>(); | 116 | index: self.index, |
| 117 | _lifetime: PhantomData, | ||
| 118 | } | ||
| 119 | .unlock(self.process_id); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | /// Hardware semaphore channel | ||
| 124 | pub struct HardwareSemaphoreChannel<'a, T: Instance> { | ||
| 125 | index: u8, | ||
| 126 | _lifetime: PhantomData<&'a mut T>, | ||
| 127 | } | ||
| 128 | |||
| 129 | impl<'a, T: Instance> HardwareSemaphoreChannel<'a, T> { | ||
| 130 | pub(self) const fn new(number: u8) -> Self { | ||
| 131 | core::assert!(number > 0 && number <= 6); | ||
| 132 | |||
| 133 | Self { | ||
| 134 | index: number - 1, | ||
| 135 | _lifetime: PhantomData, | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | /// Locks the semaphore. | ||
| 140 | /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to | ||
| 141 | /// check if the lock has been successful, carried out from the HSEM_Rx register. | ||
| 142 | pub async fn lock(&mut self, process_id: u8) -> HardwareSemaphoreMutex<'a, T> { | ||
| 143 | let core_id = CoreId::current(); | ||
| 144 | |||
| 145 | poll_fn(|cx| { | ||
| 146 | T::state().waker_for(self.index).register(cx.waker()); | ||
| 147 | |||
| 148 | compiler_fence(Ordering::SeqCst); | ||
| 84 | 149 | ||
| 85 | HardwareSemaphore { _peri: peripheral } | 150 | T::regs() |
| 151 | .ier(core_id.to_index()) | ||
| 152 | .modify(|w| w.set_ise(self.index as usize, true)); | ||
| 153 | |||
| 154 | if self.two_step_lock(process_id).is_ok() { | ||
| 155 | Poll::Ready(HardwareSemaphoreMutex { | ||
| 156 | index: self.index, | ||
| 157 | process_id: process_id, | ||
| 158 | _lifetime: PhantomData, | ||
| 159 | }) | ||
| 160 | } else { | ||
| 161 | Poll::Pending | ||
| 162 | } | ||
| 163 | }) | ||
| 164 | .await | ||
| 86 | } | 165 | } |
| 87 | 166 | ||
| 88 | /// Locks the semaphore. | 167 | /// Locks the semaphore. |
| 89 | /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to | 168 | /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to |
| 90 | /// check if the lock has been successful, carried out from the HSEM_Rx register. | 169 | /// check if the lock has been successful, carried out from the HSEM_Rx register. |
| 91 | pub fn two_step_lock(&mut self, sem_id: u8, process_id: u8) -> Result<(), HsemError> { | 170 | pub fn two_step_lock(&mut self, process_id: u8) -> Result<(), HsemError> { |
| 92 | T::regs().r(sem_id as usize).write(|w| { | 171 | T::regs().r(self.index as usize).write(|w| { |
| 93 | w.set_procid(process_id); | 172 | w.set_procid(process_id); |
| 94 | w.set_coreid(get_current_coreid() as u8); | 173 | w.set_coreid(CoreId::current() as u8); |
| 95 | w.set_lock(true); | 174 | w.set_lock(true); |
| 96 | }); | 175 | }); |
| 97 | let reg = T::regs().r(sem_id as usize).read(); | 176 | let reg = T::regs().r(self.index as usize).read(); |
| 98 | match ( | 177 | match ( |
| 99 | reg.lock(), | 178 | reg.lock(), |
| 100 | reg.coreid() == get_current_coreid() as u8, | 179 | reg.coreid() == CoreId::current() as u8, |
| 101 | reg.procid() == process_id, | 180 | reg.procid() == process_id, |
| 102 | ) { | 181 | ) { |
| 103 | (true, true, true) => Ok(()), | 182 | (true, true, true) => Ok(()), |
| @@ -108,9 +187,9 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> { | |||
| 108 | /// Locks the semaphore. | 187 | /// Locks the semaphore. |
| 109 | /// The 1-step procedure consists in a read to lock and check the semaphore in a single step, | 188 | /// The 1-step procedure consists in a read to lock and check the semaphore in a single step, |
| 110 | /// carried out from the HSEM_RLRx register. | 189 | /// carried out from the HSEM_RLRx register. |
| 111 | pub fn one_step_lock(&mut self, sem_id: u8) -> Result<(), HsemError> { | 190 | pub fn one_step_lock(&mut self) -> Result<(), HsemError> { |
| 112 | let reg = T::regs().rlr(sem_id as usize).read(); | 191 | let reg = T::regs().rlr(self.index as usize).read(); |
| 113 | match (reg.lock(), reg.coreid() == get_current_coreid() as u8, reg.procid()) { | 192 | match (reg.lock(), reg.coreid() == CoreId::current() as u8, reg.procid()) { |
| 114 | (false, true, 0) => Ok(()), | 193 | (false, true, 0) => Ok(()), |
| 115 | _ => Err(HsemError::LockFailed), | 194 | _ => Err(HsemError::LockFailed), |
| 116 | } | 195 | } |
| @@ -119,14 +198,53 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> { | |||
| 119 | /// Unlocks the semaphore. | 198 | /// Unlocks the semaphore. |
| 120 | /// Unlocking a semaphore is a protected process, to prevent accidental clearing by a AHB bus | 199 | /// Unlocking a semaphore is a protected process, to prevent accidental clearing by a AHB bus |
| 121 | /// core ID or by a process not having the semaphore lock right. | 200 | /// core ID or by a process not having the semaphore lock right. |
| 122 | pub fn unlock(&mut self, sem_id: u8, process_id: u8) { | 201 | pub fn unlock(&mut self, process_id: u8) { |
| 123 | T::regs().r(sem_id as usize).write(|w| { | 202 | T::regs().r(self.index as usize).write(|w| { |
| 124 | w.set_procid(process_id); | 203 | w.set_procid(process_id); |
| 125 | w.set_coreid(get_current_coreid() as u8); | 204 | w.set_coreid(CoreId::current() as u8); |
| 126 | w.set_lock(false); | 205 | w.set_lock(false); |
| 127 | }); | 206 | }); |
| 128 | } | 207 | } |
| 129 | 208 | ||
| 209 | /// Checks if the semaphore is locked. | ||
| 210 | pub fn is_semaphore_locked(&self) -> bool { | ||
| 211 | T::regs().r(self.index as usize).read().lock() | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | /// HSEM driver | ||
| 216 | pub struct HardwareSemaphore<T: Instance> { | ||
| 217 | _type: PhantomData<T>, | ||
| 218 | } | ||
| 219 | |||
| 220 | impl<T: Instance> HardwareSemaphore<T> { | ||
| 221 | /// Creates a new HardwareSemaphore instance. | ||
| 222 | pub fn new<'d>( | ||
| 223 | _peripheral: Peri<'d, T>, | ||
| 224 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, HardwareSemaphoreInterruptHandler<T>> + 'd, | ||
| 225 | ) -> Self { | ||
| 226 | rcc::enable_and_reset::<T>(); | ||
| 227 | |||
| 228 | HardwareSemaphore { _type: PhantomData } | ||
| 229 | } | ||
| 230 | |||
| 231 | /// Get a single channel, and keep the global struct | ||
| 232 | pub const fn channel_for<'a>(&'a mut self, number: u8) -> HardwareSemaphoreChannel<'a, T> { | ||
| 233 | HardwareSemaphoreChannel::new(number) | ||
| 234 | } | ||
| 235 | |||
| 236 | /// Split the global struct into channels | ||
| 237 | pub const fn split<'a>(self) -> [HardwareSemaphoreChannel<'a, T>; 6] { | ||
| 238 | [ | ||
| 239 | HardwareSemaphoreChannel::new(1), | ||
| 240 | HardwareSemaphoreChannel::new(2), | ||
| 241 | HardwareSemaphoreChannel::new(3), | ||
| 242 | HardwareSemaphoreChannel::new(4), | ||
| 243 | HardwareSemaphoreChannel::new(5), | ||
| 244 | HardwareSemaphoreChannel::new(6), | ||
| 245 | ] | ||
| 246 | } | ||
| 247 | |||
| 130 | /// Unlocks all semaphores. | 248 | /// Unlocks all semaphores. |
| 131 | /// All semaphores locked by a COREID can be unlocked at once by using the HSEM_CR | 249 | /// All semaphores locked by a COREID can be unlocked at once by using the HSEM_CR |
| 132 | /// register. Write COREID and correct KEY value in HSEM_CR. All locked semaphores with a | 250 | /// register. Write COREID and correct KEY value in HSEM_CR. All locked semaphores with a |
| @@ -138,11 +256,6 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> { | |||
| 138 | }); | 256 | }); |
| 139 | } | 257 | } |
| 140 | 258 | ||
| 141 | /// Checks if the semaphore is locked. | ||
| 142 | pub fn is_semaphore_locked(&self, sem_id: u8) -> bool { | ||
| 143 | T::regs().r(sem_id as usize).read().lock() | ||
| 144 | } | ||
| 145 | |||
| 146 | /// Sets the clear (unlock) key | 259 | /// Sets the clear (unlock) key |
| 147 | pub fn set_clear_key(&mut self, key: u16) { | 260 | pub fn set_clear_key(&mut self, key: u16) { |
| 148 | T::regs().keyr().modify(|w| w.set_key(key)); | 261 | T::regs().keyr().modify(|w| w.set_key(key)); |
| @@ -152,38 +265,51 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> { | |||
| 152 | pub fn get_clear_key(&mut self) -> u16 { | 265 | pub fn get_clear_key(&mut self) -> u16 { |
| 153 | T::regs().keyr().read().key() | 266 | T::regs().keyr().read().key() |
| 154 | } | 267 | } |
| 268 | } | ||
| 155 | 269 | ||
| 156 | /// Sets the interrupt enable bit for the semaphore. | 270 | struct State { |
| 157 | pub fn enable_interrupt(&mut self, core_id: CoreId, sem_x: usize, enable: bool) { | 271 | wakers: [AtomicWaker; 6], |
| 158 | T::regs() | 272 | } |
| 159 | .ier(core_id_to_index(core_id)) | ||
| 160 | .modify(|w| w.set_ise(sem_x, enable)); | ||
| 161 | } | ||
| 162 | 273 | ||
| 163 | /// Gets the interrupt flag for the semaphore. | 274 | impl State { |
| 164 | pub fn is_interrupt_active(&mut self, core_id: CoreId, sem_x: usize) -> bool { | 275 | const fn new() -> Self { |
| 165 | T::regs().isr(core_id_to_index(core_id)).read().isf(sem_x) | 276 | Self { |
| 277 | wakers: [const { AtomicWaker::new() }; 6], | ||
| 278 | } | ||
| 166 | } | 279 | } |
| 167 | 280 | ||
| 168 | /// Clears the interrupt flag for the semaphore. | 281 | const fn waker_for(&self, number: u8) -> &AtomicWaker { |
| 169 | pub fn clear_interrupt(&mut self, core_id: CoreId, sem_x: usize) { | 282 | &self.wakers[number as usize] |
| 170 | T::regs() | ||
| 171 | .icr(core_id_to_index(core_id)) | ||
| 172 | .write(|w| w.set_isc(sem_x, false)); | ||
| 173 | } | 283 | } |
| 174 | } | 284 | } |
| 175 | 285 | ||
| 176 | trait SealedInstance { | 286 | trait SealedInstance { |
| 177 | fn regs() -> pac::hsem::Hsem; | 287 | fn regs() -> pac::hsem::Hsem; |
| 288 | fn state() -> &'static State; | ||
| 178 | } | 289 | } |
| 179 | 290 | ||
| 180 | /// HSEM instance trait. | 291 | /// HSEM instance trait. |
| 181 | #[allow(private_bounds)] | 292 | #[allow(private_bounds)] |
| 182 | pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + Send + 'static {} | 293 | pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + Send + 'static { |
| 294 | /// Interrupt for this peripheral. | ||
| 295 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 296 | } | ||
| 183 | 297 | ||
| 184 | impl SealedInstance for crate::peripherals::HSEM { | 298 | impl SealedInstance for crate::peripherals::HSEM { |
| 185 | fn regs() -> crate::pac::hsem::Hsem { | 299 | fn regs() -> crate::pac::hsem::Hsem { |
| 186 | crate::pac::HSEM | 300 | crate::pac::HSEM |
| 187 | } | 301 | } |
| 302 | |||
| 303 | fn state() -> &'static State { | ||
| 304 | static STATE: State = State::new(); | ||
| 305 | &STATE | ||
| 306 | } | ||
| 188 | } | 307 | } |
| 189 | impl Instance for crate::peripherals::HSEM {} | 308 | |
| 309 | foreach_interrupt!( | ||
| 310 | ($inst:ident, hsem, $block:ident, $signal_name:ident, $irq:ident) => { | ||
| 311 | impl Instance for crate::peripherals::$inst { | ||
| 312 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 313 | } | ||
| 314 | }; | ||
| 315 | ); | ||
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index b92b47be2..f5684d4df 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml | |||
| @@ -31,9 +31,9 @@ stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng", "dual- | |||
| 31 | stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash", "dual-bank"] | 31 | stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash", "dual-bank"] |
| 32 | stm32u585ai = ["embassy-stm32/stm32u585ai", "spi-v345", "chrono", "rng", "hash", "cordic"] | 32 | stm32u585ai = ["embassy-stm32/stm32u585ai", "spi-v345", "chrono", "rng", "hash", "cordic"] |
| 33 | stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "spi-v345", "chrono", "rng", "hash"] # FIXME: cordic test cause it crash | 33 | stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "spi-v345", "chrono", "rng", "hash"] # FIXME: cordic test cause it crash |
| 34 | stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] | 34 | stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng", "hsem"] |
| 35 | stm32wba52cg = ["embassy-stm32/stm32wba52cg", "spi-v345", "chrono", "rng", "hash"] | 35 | stm32wba52cg = ["embassy-stm32/stm32wba52cg", "spi-v345", "chrono", "rng", "hash"] |
| 36 | stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] | 36 | stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono", "hsem"] |
| 37 | stm32f091rc = ["embassy-stm32/stm32f091rc", "cm0", "not-gpdma", "chrono"] | 37 | stm32f091rc = ["embassy-stm32/stm32f091rc", "cm0", "not-gpdma", "chrono"] |
| 38 | stm32h503rb = ["embassy-stm32/stm32h503rb", "spi-v345", "rng", "stop"] | 38 | stm32h503rb = ["embassy-stm32/stm32h503rb", "spi-v345", "rng", "stop"] |
| 39 | stm32h7s3l8 = ["embassy-stm32/stm32h7s3l8", "spi-v345", "rng", "cordic", "hash-v34"] # TODO: fdcan crashes, cryp dma hangs. | 39 | stm32h7s3l8 = ["embassy-stm32/stm32h7s3l8", "spi-v345", "rng", "cordic", "hash-v34"] # TODO: fdcan crashes, cryp dma hangs. |
| @@ -58,6 +58,7 @@ not-gpdma = [] | |||
| 58 | dac = [] | 58 | dac = [] |
| 59 | ucpd = [] | 59 | ucpd = [] |
| 60 | cordic = ["dep:num-traits"] | 60 | cordic = ["dep:num-traits"] |
| 61 | hsem = [] | ||
| 61 | dual-bank = ["embassy-stm32/dual-bank"] | 62 | dual-bank = ["embassy-stm32/dual-bank"] |
| 62 | single-bank = ["embassy-stm32/single-bank"] | 63 | single-bank = ["embassy-stm32/single-bank"] |
| 63 | eeprom = [] | 64 | eeprom = [] |
| @@ -224,6 +225,11 @@ name = "wpan_mac" | |||
| 224 | path = "src/bin/wpan_mac.rs" | 225 | path = "src/bin/wpan_mac.rs" |
| 225 | required-features = [ "mac",] | 226 | required-features = [ "mac",] |
| 226 | 227 | ||
| 228 | [[bin]] | ||
| 229 | name = "hsem" | ||
| 230 | path = "src/bin/hsem.rs" | ||
| 231 | required-features = [ "hsem",] | ||
| 232 | |||
| 227 | # END TESTS | 233 | # END TESTS |
| 228 | 234 | ||
| 229 | [profile.dev] | 235 | [profile.dev] |
diff --git a/tests/stm32/src/bin/hsem.rs b/tests/stm32/src/bin/hsem.rs new file mode 100644 index 000000000..19648997c --- /dev/null +++ b/tests/stm32/src/bin/hsem.rs | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | // required-features: hsem | ||
| 2 | #![no_std] | ||
| 3 | #![no_main] | ||
| 4 | |||
| 5 | #[path = "../common.rs"] | ||
| 6 | mod common; | ||
| 7 | |||
| 8 | use common::*; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_stm32::bind_interrupts; | ||
| 11 | use embassy_stm32::hsem::{HardwareSemaphore, HardwareSemaphoreInterruptHandler}; | ||
| 12 | use embassy_stm32::peripherals::HSEM; | ||
| 13 | |||
| 14 | bind_interrupts!(struct Irqs{ | ||
| 15 | HSEM => HardwareSemaphoreInterruptHandler<HSEM>; | ||
| 16 | }); | ||
| 17 | |||
| 18 | #[embassy_executor::main] | ||
| 19 | async fn main(_spawner: Spawner) { | ||
| 20 | let p: embassy_stm32::Peripherals = init(); | ||
| 21 | |||
| 22 | let hsem = HardwareSemaphore::new(p.HSEM, Irqs); | ||
| 23 | |||
| 24 | // if hsem.channel_for(SemaphoreNumber::Channel5).is_semaphore_locked() { | ||
| 25 | // defmt::panic!("Semaphore 5 already locked!") | ||
| 26 | // } | ||
| 27 | // | ||
| 28 | // hsem.channel_for(SemaphoreNumber::Channel5).one_step_lock().unwrap(); | ||
| 29 | // hsem.channel_for(SemaphoreNumber::Channel1).two_step_lock(0).unwrap(); | ||
| 30 | // | ||
| 31 | // hsem.channel_for(SemaphoreNumber::Channel5).unlock(0); | ||
| 32 | |||
| 33 | let [_channel1, _channel2, _channel3, _channel4, mut channel5, _channel6] = hsem.split(); | ||
| 34 | |||
| 35 | info!("Locking channel 5"); | ||
| 36 | |||
| 37 | let mutex = channel5.lock(0).await; | ||
| 38 | |||
| 39 | info!("Locked channel 5"); | ||
| 40 | |||
| 41 | drop(mutex); | ||
| 42 | |||
| 43 | info!("Unlocked channel 5"); | ||
| 44 | |||
| 45 | info!("Test OK"); | ||
| 46 | cortex_m::asm::bkpt(); | ||
| 47 | } | ||
