Skip to content

Commit 05d63b5

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

File tree

3 files changed

+159
-1
lines changed

3 files changed

+159
-1
lines changed

embassy-stm32/src/hsem.rs

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