-
Notifications
You must be signed in to change notification settings - Fork 1k
Fix HSEM Implementation #4092
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Fix HSEM Implementation #4092
Conversation
thanks for working on this! :) With the |
3028382
to
bcc3463
Compare
Enable HSEM test on more MCUs
3a3a0c0
to
2c81928
Compare
ffaf79f
to
a580e27
Compare
Have you seen #4106 ? seems you guys are working on the same thing. |
@Dirbaio ha, no, I hadn't, though looking now, that PR will only fix the WB55 where as this one aims to fix the implementation for all of the MCUs supported. |
I did not see it, sorry. I am fine with any implementation :-) |
6f59f1e
to
df06cd4
Compare
Is there a reason why you moved your hsem code out into a separate file and rename the |
This was not my intention. I kept the values for the This is out of inspiration of the |
HSEM doesn't need multiple files, therefore |
I'd like input regarding the H7 variants for HSEM @Dirbaio and @ckrenslehner. I cannot seem to get them working, no matter what I try the results do not match what the datasheets say they should. I've even checked against STM's official HAL & my implementation semantically matches. As such, which do you think is the better option:
|
Can you explain more about the datasheet mismatch or what exactly is not working? I probably have no access to a H7 so unfortunately I cannot test myself |
Looking through the manual of the h7 and your code, it should work. Have you tested running some cube code on a h7 target? Unfortunately, I do not have a h7 to test with |
Apologies for the delay on response.
Yes, see the latest
To which comment are you referring? |
let reg = HSEM.rlr(sem_id as usize).read(); | ||
|
||
match (reg.lock(), reg.coreid() == CoreId::current() as u8, reg.procid()) { | ||
(_, true, 0) => Ok(()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the match condition really be (_, true, 0)
?
reg.lock()
returns true
if locked and false
if not locked, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the wb55 hal drivers there is the following code:
/**
* @brief Get the lock with 1-step lock.
* @rmtoll RLR LOCK LL_HSEM_1StepLock
* @rmtoll RLR COREID LL_HSEM_1StepLock
* @rmtoll RLR PROCID LL_HSEM_1StepLock
* @param HSEMx HSEM Instance.
* @param Semaphore Semaphore number. Value between Min_Data=0 and Max_Data=31
* @retval 1 lock fail, 0 lock successful or already locked by same core
*/
__STATIC_INLINE uint32_t LL_HSEM_1StepLock(HSEM_TypeDef *HSEMx, uint32_t Semaphore)
{
return ((HSEMx->RLR[Semaphore] != (HSEM_R_LOCK | LL_HSEM_COREID)) ? 1UL : 0UL);
}
HSEM_R_LOCK
= (0x1UL << (31U))
LL_HSEM_COREID
= (0x4U << (8U))
So the top 1
is checked which corresponds to reg.lock()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the match condition really be
(_, true, 0)
?reg.lock()
returnstrue
if locked andfalse
if not locked, right?
You would think that, however the datasheet itself doesn't mention it, and my WB55 board returns reg.lock() == false
even though the lock is successful - I know this because I need to lock HSEM 5 in order for Wireless & USB stacks to not fight over clocks, and they both function perfectly.
The same issue appeared to occur when I ran it through CI too, on one of the early runs. Feel free to see if you get different behaviour on your WB55.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay.. thats odd, because I can report the opposite.
I was making my HSEM PR only, because I want to fully add the low-power feature for the stm32wb55. Unfortunately I did not see your PR (sorry again).
See #4116.
This code does successfully lock and unlock Sem3 and Sem4. And the match expression required lock
to be true
.
I actually had to change the original match (from the code ours PRs are based on) because there was false
which did not work for me.
You can test it yourself using the low-power executor if you want to. If it helps I can provide you a little example project.
Further looking at the lock algorithm for entering the low power mode of this document page 23. There is clearly a "check if locked" step. So there needs to be an indication in the RLR which actually signals a successful lock..
How would you know if sem is granted otherwise?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By manually checking if it's locked, I guess. Which wb55 are you using, exactly? All my tests have been on wb55rg, maybe there's a difference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wb55rg too. as mentioned, I could provide you a small sample application where it enters stop mode via locking/unlocking the semaphores
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a low_power
example to the stm32wb55 showing the behavior of the hsem with trace output.
See this commit
You can run it on your own by executing cargo r --bin low_power --features low-power
in the stm32wb examples dir
My output shows this:
29.429840 TRACE Polling Sem3 until granted
└─ embassy_stm32::rcc::low_power::stm32wb_configure_clocks_enter_stop_mode::{closure#0} @ C:\Users\ChristianKrenslehner\Software\fork\embassy\embassy-stm32\src\rcc\low_power.rs:15
29.429840 TRACE RLR (bits: 0x80000400) - lock: true, coreid: 4, procid: 0
└─ embassy_stm32::hsem::{impl#4}::one_step_lock @ C:\Users\ChristianKrenslehner\Software\fork\embassy\embassy-stm32\src\hsem\mod.rs:206
29.429840 TRACE Locked successfully (coreid: 4, procid: 0)
└─ embassy_stm32::hsem::{impl#4}::one_step_lock @ C:\Users\ChristianKrenslehner\Software\fork\embassy\embassy-stm32\src\hsem\mod.rs:220
29.429840 TRACE Sem3 granted
└─ embassy_stm32::rcc::low_power::stm32wb_configure_clocks_enter_stop_mode::{closure#0} @ C:\Users\ChristianKrenslehner\Software\fork\embassy\embassy-stm32\src\rcc\low_power.rs:17
As you can see, the topmost bit is set when the semaphore is locked successfully :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Legorooj if I can provide further help, ping me :-)
You mentioned your successful use of USB. I wonder if you implemented the algorithm of page 26. Inside this flow chart you are also supposed to poll Sem5 until granted.
/// | ||
/// Unlocking a semaphore is a protected process, to prevent accidental clearing by an AHB | ||
/// bus core ID or by a process not having the semaphore lock right. | ||
pub fn unlock(&mut self, sem_id: u8, process_id: u8) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not part of your PR, but shoud be make process_id
and Option? It feels a little awkward to just pass 0 if you locked it with one_step_lock
before. Maybe we could pass None
instead and set it to 0 inside in such a case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While I understand & would normally agree with this, considering it is an embedded context I wonder whether it would not be better to simply specify in the doc comment that "if you are not sure which process_id
to enter - e.g. if you used one_step_lock
- the default should be 0
".
I say this because someone learning to program these devices in Rust will either be coming from a C/C++ background, or be a beginner having to heavily rely on C/C++ resources, which would specify that 0
is the correct value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah thats true
/// | ||
/// The one-step procedure consists of a read to lock and check the semaphore in a single | ||
/// step, carried out from the HSEM_RLRx register. | ||
pub fn one_step_lock(&mut self, sem_id: u8) -> Result<(), HsemLockFailed> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to introduce a semaphore ID enum for MCUs as here in my PR?
Maybe it saves others some time when looking for possible ID values
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did think about this, and I really like what you did with your PR, and meant to bring it up as a discussion point, because I feel if we could find a reference of different SEMIDs and their meanings for all the chips, it would be a good idea, however if not, it might be better to just link to the relevant documentation for each chip we can find docs for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the stm32wb is can be found in this page 21.
I suppose there are similar documents for the other MCUs. I can look if I find something
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Legorooj if you find the time, you could try adding true
in the match (to check for the uppermust lock bit) and a full RLR content log to your code and push it.
If I understand correctly, you can run your code on the test-cluster this way?
So maybe we gain further evidence why this PR might not work.
Sorry, I thought I submitted the review. My bad, sorry again. |
Ok, so the actual core ID value is 0 even though it should be 3. That's odd. I just wonder if there is anything non zero inside |
impl<'d> HardwareSemaphore<'d> { | ||
/// Create a new HardwareSemaphore instance. | ||
pub fn new(peri: crate::Peri<'d, crate::peripherals::HSEM>) -> Self { | ||
HardwareSemaphore { _peri: peri } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we need to call rcc::enable_and_reset::<T>();
here as well to make sure, that the AHB clock is enabled?
In this case for the HSEM of course.
At least there is some hsem related code in _generated.rs
.
Here for the stm32wb55
impl crate::rcc::SealedRccPeripheral for peripherals::HSEM {
fn frequency() -> crate::time::Hertz {
unsafe {
unwrap ! (crate :: rcc :: get_freqs () . hclk3 . to_hertz () , "peripheral '{}' is configured to use the '{}' clock, which is not running. \
Either enable it in 'config.rcc' or change 'config.rcc.mux' to use another clock" , "HSEM" , "HCLK3")
}
}
const RCC_INFO: crate::rcc::RccInfo = unsafe {
crate::rcc::RccInfo::new(
Some((12u8, 19u8)),
(20u8, 19u8),
None,
#[cfg(feature = "low-power")]
crate::rcc::StopMode::Stop1,
)
};
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good thought, I'll explore this tomorrow if I have time.
This PR fixes the HSEM implementation for STM32 MCUs. The current implementation does not appear to work on wb55 boards at minimum, and as such needs testing where possible.
List of chips that the current implementation is confirmed to not function correctly on:
Chips that the new implementation is confirmed to work on:
This implementation should provide full functionality on all STM MCUs which have a Hardware Semaphore feature.