Skip to content

Commit 3162172

Browse files
committed
fix HardwareSemaphore (HSEM) implementation
1 parent 42ce44c commit 3162172

File tree

3 files changed

+161
-1
lines changed

3 files changed

+161
-1
lines changed

embassy-stm32/src/hsem.rs

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
//! Hardware Semaphore (HSEM)
2+
const HSEM: crate::pac::hsem::Hsem = crate::pac::HSEM;
3+
4+
/// Locking the HardwareSemaphore failed.
5+
#[derive(Debug)]
6+
pub struct HsemLockFailed;
7+
8+
/// CPU Core.
9+
///
10+
/// The enum values are identical to the bus master IDs defined for each chip family.
11+
///
12+
/// On some chips, the Reference Manual calls this value MASTERID instead of COREID.
13+
#[repr(u8)]
14+
pub enum CoreId {
15+
#[cfg(any(stm32h7a3, stm32h7b3, stm32h7b0))]
16+
/// Cortex-M7, core 1. MASTERID = 1
17+
Core0 = 1,
18+
19+
#[cfg(any(
20+
stm32h723, stm32h725, stm32h730, stm32h733, stm32h735, stm32h742, stm32h743, stm32h745, stm32h747, stm32h750,
21+
stm32h753, stm32h755, stm32h757,
22+
))]
23+
/// Cortex-M7, core 1. MASTERID = 3
24+
Core0 = 3,
25+
26+
#[cfg(any(stm32wb, stm32wl))]
27+
/// Cortex-M4, core 1
28+
Core0 = 4,
29+
30+
#[cfg(not(any(stm32wb, stm32wl, stm32h7a3, stm32h7b3, stm32h7b0)))]
31+
/// Cortex-M4, core 2
32+
Core1 = 1,
33+
34+
#[cfg(any(stm32wb, stm32wl))]
35+
/// Cortex M0+, core 2
36+
Core1 = 8,
37+
}
38+
39+
impl CoreId {
40+
#[cfg(any(feature = "_core-cm7", not(feature = "_core-cm4")))]
41+
const fn current() -> CoreId {
42+
CoreId::Core0
43+
}
44+
45+
#[cfg(feature = "_core-cm4")]
46+
const fn current() -> CoreId {
47+
CoreId::Core1
48+
}
49+
50+
fn as_index(&self) -> usize {
51+
match self {
52+
CoreId::Core0 => 0,
53+
#[cfg(not(any(stm32h7a3, stm32h7b3, stm32h7b0)))]
54+
CoreId::Core1 => 1,
55+
}
56+
}
57+
}
58+
59+
/// TODO
60+
pub struct HardwareSemaphore<'d> {
61+
_peri: crate::Peri<'d, crate::peripherals::HSEM>,
62+
}
63+
64+
impl<'d> HardwareSemaphore<'d> {
65+
/// Create a new HardwareSemaphore instance.
66+
pub fn new(peri: crate::Peri<'d, crate::peripherals::HSEM>) -> Self {
67+
HardwareSemaphore { _peri: peri }
68+
}
69+
70+
/// Locks the semaphore via the 2-step (write) lock procedure
71+
///
72+
/// The two-step procedure consists of a write to lock the semaphore, followed by a read
73+
/// to check if the lock has been successful, carried out from the HSEM_Rx retgister.
74+
pub fn two_step_lock(&mut self, sem_id: u8, process_id: u8) -> Result<(), HsemLockFailed> {
75+
HSEM.r(sem_id as usize).write(|w| {
76+
w.set_procid(process_id);
77+
w.set_coreid(CoreId::current() as u8);
78+
w.set_lock(true);
79+
});
80+
81+
let reg = HSEM.r(sem_id as usize).read();
82+
83+
match (
84+
reg.lock(),
85+
reg.coreid() == CoreId::current() as u8,
86+
reg.procid() == process_id,
87+
) {
88+
(true, true, true) => Ok(()),
89+
_ => Err(HsemLockFailed),
90+
}
91+
}
92+
93+
/// Locks the semaphore via the 1-step (read) lock procedure
94+
///
95+
/// The one-step procedure consists of a read to lock and check the semaphore in a single
96+
/// step, carried out from the HSEM_RLRx register.
97+
pub fn one_step_lock(&mut self, sem_id: u8) -> Result<(), HsemLockFailed> {
98+
let reg = HSEM.rlr(sem_id as usize).read();
99+
100+
match (reg.lock(), reg.coreid() == CoreId::current() as u8, reg.procid()) {
101+
(_, true, 0) => Ok(()),
102+
_ => Err(HsemLockFailed),
103+
}
104+
}
105+
106+
/// Unlocks the semaphore
107+
///
108+
/// Unlocking a semaphore is a protected process, to prevent accidental clearing by an AHB
109+
/// bus core ID or by a process not having the semaphore lock right.
110+
pub fn unlock(&mut self, sem_id: u8, process_id: u8) {
111+
HSEM.r(sem_id as usize).write(|w| {
112+
w.set_procid(process_id);
113+
w.set_coreid(CoreId::current() as u8);
114+
w.set_lock(false);
115+
});
116+
}
117+
118+
/// Unlocks all semahpores.
119+
///
120+
/// All semaphores locked by a COREID can be unlocked at once by using the HSEM_CR register.
121+
/// Write COREID and correct KEY value in HSEM_CR. All locked semaphores with a matching
122+
/// COREID are unlocked, and may generate an interrupt if enabled.
123+
pub fn unlock_all(&mut self, key: u16, core_id: u8) {
124+
HSEM.cr().write(|w| {
125+
w.set_key(key);
126+
w.set_coreid(core_id);
127+
})
128+
}
129+
130+
/// Checks if the semaphore is locked.
131+
pub fn is_semaphore_locked(&self, sem_id: u8) -> bool {
132+
HSEM.r(sem_id as usize).read().lock()
133+
}
134+
135+
/// Sets the clear (unlock) key
136+
pub fn set_clear_key(&mut self, key: u16) {
137+
HSEM.keyr().modify(|w| w.set_key(key));
138+
}
139+
140+
/// Gets the clear (unlock) key
141+
pub fn get_clear_key(&mut self) -> u16 {
142+
HSEM.keyr().read().key()
143+
}
144+
145+
/// Sets the interrupt enable bit for the semaphore.
146+
pub fn enable_interrupt(&mut self, core_id: CoreId, sem_x: usize, enable: bool) {
147+
HSEM.ier(core_id.as_index()).modify(|w| w.set_ise(sem_x, enable));
148+
}
149+
150+
/// Clears the interrupt flag for the semaphore.
151+
pub fn clear_interrupt(&mut self, core_id: CoreId, sem_x: usize) {
152+
HSEM.icr(core_id.as_index()).write(|w| w.set_isc(sem_x, false));
153+
}
154+
155+
/// Gets the interrupt flag for the semaphore.
156+
pub fn is_interrupt_active(&mut self, core_id: CoreId, sem_x: usize) -> bool {
157+
HSEM.isr(core_id.as_index()).read().isf(sem_x)
158+
}
159+
}
File renamed without changes.

tests/stm32/src/bin/hsem.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ async fn main(_spawner: Spawner) {
1414
let p: embassy_stm32::Peripherals = init();
1515

1616
let mut hsem = HardwareSemaphore::new(p.HSEM);
17-
hsem.one_step_lock(5).unwrap();
17+
hsem.one_step_lock(1).unwrap();
18+
hsem.two_step_lock(1, 0).unwrap();
1819

1920
info!("Test OK");
2021
cortex_m::asm::bkpt();

0 commit comments

Comments
 (0)