aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Zill <[email protected]>2024-04-05 16:12:58 +0200
committerDario Nieuwenhuis <[email protected]>2024-05-21 23:08:44 +0200
commit7d350fb4c8133d7569f3b0873a7120e3a7832dcd (patch)
treefa79488eedc3442b7c9184b4d9b2ba7d20b87fdc
parente85242af2c638b41772029a28be4a64bf43922dc (diff)
HSEM support for embassy-stm32
-rw-r--r--embassy-stm32/src/hsem/mod.rs181
-rw-r--r--embassy-stm32/src/lib.rs2
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.
7use embassy_hal_internal::{into_ref, PeripheralRef};
8
9use crate::rcc::RccPeripheral;
10use crate::{pac, Peripheral};
11
12/// HSEM error.
13#[derive(Debug)]
14pub 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)]
25pub 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)]
46pub 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)]
66fn core_id_to_index(core: CoreId) -> usize {
67 match core {
68 CoreId::Core0 => 0,
69 CoreId::Core1 => 1,
70 }
71}
72
73/// HSEM driver
74pub struct HardwareSemaphore<'d, T: Instance> {
75 _peri: PeripheralRef<'d, T>,
76}
77
78impl<'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
168trait SealedInstance {
169 fn regs() -> pac::hsem::Hsem;
170}
171
172/// HSEM instance trait.
173#[allow(private_bounds)]
174pub trait Instance: SealedInstance + RccPeripheral + Send + 'static {}
175
176impl SealedInstance for crate::peripherals::HSEM {
177 fn regs() -> crate::pac::hsem::Hsem {
178 crate::pac::HSEM
179 }
180}
181impl 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;
79pub mod hash; 79pub mod hash;
80#[cfg(hrtim)] 80#[cfg(hrtim)]
81pub mod hrtim; 81pub mod hrtim;
82#[cfg(hsem)]
83pub mod hsem;
82#[cfg(i2c)] 84#[cfg(i2c)]
83pub mod i2c; 85pub mod i2c;
84#[cfg(all(spi_v1, rcc_f4))] 86#[cfg(all(spi_v1, rcc_f4))]