Skip to content

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

Fix HSEM Implementation #4092

wants to merge 3 commits into from

Conversation

Legorooj
Copy link

@Legorooj Legorooj commented Apr 14, 2025

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:

  • WB55
  • WL5x
  • WLEx
  • h723,h725,h730,h733,h735
  • h742,h743,h753,h750
  • h745,h755,h747,h757
  • h7a3,h7b3,h7b0

Chips that the new implementation is confirmed to work on:

  • WB55
  • WL5x
  • WLEx
  • h723,h725,h730,h733,h735
  • h742,h743,h753,h750
  • h745,h755,h747,h757
  • h7a3,h7b3,h7b0

This implementation should provide full functionality on all STM MCUs which have a Hardware Semaphore feature.

@Dirbaio
Copy link
Member

Dirbaio commented Apr 14, 2025

thanks for working on this! :)

With the trusted label CI will run HIL tests. I can also give you a token so you can cargo run in the HIL test farm locally so you don't have to wait for CI to build stuff. Ping me on Matrix if you want it.

@Legorooj Legorooj force-pushed the hsem-fix branch 5 times, most recently from 3028382 to bcc3463 Compare April 15, 2025 00:34
Enable HSEM test on more MCUs
@Legorooj Legorooj marked this pull request as ready for review April 17, 2025 14:45
@Legorooj Legorooj force-pushed the hsem-fix branch 3 times, most recently from 3a3a0c0 to 2c81928 Compare April 17, 2025 15:00
@Dirbaio
Copy link
Member

Dirbaio commented Apr 17, 2025

Have you seen #4106 ? seems you guys are working on the same thing.

@Legorooj
Copy link
Author

@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.

@ckrenslehner
Copy link
Contributor

I did not see it, sorry. I am fine with any implementation :-)

@Legorooj Legorooj force-pushed the hsem-fix branch 6 times, most recently from 6f59f1e to df06cd4 Compare April 17, 2025 17:24
@ckrenslehner
Copy link
Contributor

Is there a reason why you moved your hsem code out into a separate file and rename the mod.rs into old.rs?

@ckrenslehner
Copy link
Contributor

@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.

This was not my intention. I kept the values for the h7 mcus as they were, but I moved the RLR values into a separate enum. Looking at your code, you added more h7 variants, though. :-)
e3034a7#diff-e2b9c0e56c77ee17673e3aa131d3a98e608d3fd12a0c57eed4108b3a86107bcbR73

This is out of inspiration of the stm32-data crate, but I am not sure if this is worth the hassle to really move such things into the data crate and add mcu specific hsem yaml files

@Legorooj
Copy link
Author

Is there a reason why you moved your hsem code out into a separate file and rename the mod.rs into old.rs?

HSEM doesn't need multiple files, therefore hsem/mod.rs is slightly more confusing than hsem.rs in my opinion. Additionally, there's no consistency within Embassy for one or the other of these, as there are multiple modules in both patterns. If @Dirbaio has a preference, I am happy to make it match, but if not, then a single hsem.rs file is clearer imo.

@Legorooj
Copy link
Author

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:

  1. Commit current implementation (a little housekeeping is needed before this happens). H7 MCUs with HSEM should just fail, I could also maybe add a note in the docs for h7 that it is known to have issues.
  2. Remove support for H7 CPUs entirely, via features.
  3. If you have suggestions?

@ckrenslehner
Copy link
Contributor

ckrenslehner commented Apr 21, 2025

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

@ckrenslehner
Copy link
Contributor

Looking through the manual of the h7 and your code, it should work.
As commented, the onestep should IMO check the uppermost bit for the lock status.

Have you tested running some cube code on a h7 target? Unfortunately, I do not have a h7 to test with

@Legorooj
Copy link
Author

Apologies for the delay on response.

Have you tested running some cube code on a h7 target? Unfortunately, I do not have a h7 to test with

Yes, see the latest ci/build. I've got a bunch of debug statements in there, you should be able to read those and track my confusion!

Looking through the manual of the h7 and your code, it should work. As commented, the onestep should IMO check the uppermost bit for the lock status.

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(()),
Copy link
Contributor

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?

Copy link
Contributor

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()

Copy link
Author

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?

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.

Copy link
Contributor

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.

See
https://github.com/embassy-rs/embassy/pull/4106/files#diff-e2b9c0e56c77ee17673e3aa131d3a98e608d3fd12a0c57eed4108b3a86107bcbL109-L112

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..

{C8C00FE4-98A9-477B-91ED-64F557EAA898}

How would you know if sem is granted otherwise?

Copy link
Author

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?

Copy link
Contributor

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

Copy link
Contributor

@ckrenslehner ckrenslehner Apr 25, 2025

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 :-)

Copy link
Contributor

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.

{A025C871-7FC4-44E8-9355-984A76DB503A}

///
/// 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) {
Copy link
Contributor

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

Copy link
Author

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.

Copy link
Contributor

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> {
Copy link
Contributor

@ckrenslehner ckrenslehner Apr 18, 2025

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

Copy link
Author

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{00BC702E-5571-4327-AA92-71F49C6D73D5}

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

Copy link
Contributor

@ckrenslehner ckrenslehner Apr 30, 2025

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.

@ckrenslehner
Copy link
Contributor

ckrenslehner commented Apr 23, 2025

To which comment are you referring?

Sorry, I thought I submitted the review.
To this comment: #4092 (comment)

My bad, sorry again.

@ckrenslehner
Copy link
Contributor

Yes, see the latest ci/build. I've got a bunch of debug statements in there, you should be able to read those and track my confusion!

Ok, so the actual core ID value is 0 even though it should be 3. That's odd.
Can you print the whole RLR and R register?

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 }
Copy link
Contributor

@ckrenslehner ckrenslehner Apr 23, 2025

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,
        )
    };
}

Copy link
Author

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.

ckrenslehner added a commit to ckrenslehner/embassy that referenced this pull request Apr 25, 2025
ckrenslehner added a commit to ckrenslehner/embassy that referenced this pull request Apr 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants