Skip to content

Conversation

@Serhii-the-Dev
Copy link

@Serhii-the-Dev Serhii-the-Dev commented Sep 8, 2024

Resolves #49

Embassy time driver implementation is mostly a copy-pasta of the STM32 driver except it's not implementing RTC functionality required for low-power/deep-sleep scenarios in order to keep it simple (AFAIK current HAL implementation also lacks of RTC support).

This PR brings a set of new features:

  • embassy - enables Embassy support in general
  • time-driver-tim<1, 2, 14> - enables Embassy time driver support for a specified general-purpose timer instance

Both features are required to use the Embassy executor, so any of the time-driver-tim<1, 2, 14> features enables the embassy feature in general.

Despite that the driver uses unsafe access to the selected timer's registry, in order to guard an access to a TIMERx peripheral, the driver initialization requires to move a timer<1, 2, 14> so it couldn't be used anywhere else causing undefined behavior, ex:

embassy::init(p.timer1, &clocks, &mut rcu.apb1);

After that the p.timer1 could not be moved, to create a Timer::timer1, for example.

Please take into account that Embassy support comes with a price, as a binary relying on the embassy feature and using the async executor would have additional ~2KiB added to it's size (also an extra memory would be required for the tasks arena):

> cargo bloat --release --features gd32f130x8,time-driver-tim1 --example embassy
...
File  .text   Size            Crate Name
0.4%  41.9% 1.4KiB embassy_executor embassy_executor::arch::thread::Executor::run
0.2%  20.2%   706B embassy_executor embassy_executor::raw::TaskStorage<F>::poll
0.1%  11.6%   406B     gd32f1x0_hal TIMER1
0.1%  10.5%   366B embassy_executor embassy_executor::raw::TaskStorage<F>::poll
0.0%   4.7%   164B        [Unknown] __aeabi_memclr8
0.0%   2.3%    80B embassy_executor embassy_executor::arch::thread::Executor::new
0.0%   1.3%    46B embassy_executor embassy_executor::raw::util::UninitCell<T>::write_in_place
0.0%   1.1%    40B      cortex_m_rt Reset
0.0%   0.7%    24B        [Unknown] HardFaultTrampoline
0.0%   0.6%    20B          embassy embassy::__cortex_m_rt_main
0.0%   0.5%    18B              std core::option::unwrap_failed
0.0%   0.5%    16B     gd32f1x0_hal gd32f1x0_hal::gpio::gpioc::<impl gd32f1x0_hal::gpio::GpioRegExt for gd32f1::gd32f130::gpioc::RegisterBlock>::is_set_low
0.0%   0.5%    16B     gd32f1x0_hal gd32f1x0_hal::gpio::gpioc::<impl gd32f1x0_hal::gpio::GpioRegExt for gd32f1::gd32f130::gpioc::RegisterBlock>::is_low
0.0%   0.4%    14B     gd32f1x0_hal gd32f1x0_hal::gpio::gpioc::<impl gd32f1x0_hal::gpio::GpioRegExt for gd32f1::gd32f130::gpioc::RegisterBlock>::set_high
0.0%   0.4%    14B     gd32f1x0_hal gd32f1x0_hal::gpio::gpioc::<impl gd32f1x0_hal::gpio::GpioRegExt for gd32f1::gd32f130::gpioc::RegisterBlock>::set_low
0.0%   0.3%    10B         cortex_m _critical_section_1_0_release
0.0%   0.2%     8B embassy_executor embassy_executor::raw::SyncExecutor::alarm_callback
0.0%   0.2%     8B              std core::panicking::panic_const::panic_const_async_fn_resumed
0.0%   0.2%     8B              std core::panicking::panic
0.0%   0.2%     8B              std core::panicking::panic_fmt
0.0%   1.1%    38B                  And 9 smaller methods. Use -n N to show more.
0.8% 100.0% 3.4KiB                  .text section size, the file size is 405.7KiB

@Serhii-the-Dev Serhii-the-Dev marked this pull request as draft September 19, 2024 18:18
@Serhii-the-Dev
Copy link
Author

Serhii-the-Dev commented Sep 19, 2024

@qwandor I must ask to wait with a merge as I've just discovered some strange issues with this PR: a couple of fresh new GD32F130C8 are starting to reboot after a few alarm cycles on any timer/channel instance. I tried to fully erase my GD32F130G8's flash, and uploaded an example, now it's reproducing on this chip as well. Moreover, openocd is not able to program the GD32F130G8 anymore, however probe-rs is working just fine. Alas, no meaningful ideas what's going on so far, I'll keep investigation.

Copy link
Collaborator

@qwandor qwandor left a comment

Choose a reason for hiding this comment

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

Weird! Good luck. I haven't finished reviewing this yet, but some comments in the meantime...

@Serhii-the-Dev
Copy link
Author

Serhii-the-Dev commented Sep 21, 2024

@qwandor Thank you for pointing those out, I've fixed the issues you mentioned. Also I realized that my MCUs are restarting due to the free watchdog timer timeout. According to the GD32F1x0 user manual, the watchdog timer is always running which makes me confused why the examples were running before without chip reset.
I've added a watchdog timer loop into the embassy example however it's still looking odd.
P.S. I've just found your old thread describing the similar issue 😄 So after the SWWDG option was set to zero, the watchdog is disabled and everything is working as expected.

@Serhii-the-Dev Serhii-the-Dev marked this pull request as ready for review September 21, 2024 17:37
#[cfg(feature = "time-driver-tim14")]
const ALARM_COUNT: usize = 1;

fn timer() -> &'static RegisterBlock {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This function shouldn't be safe, because it can allow creating aliases to timer register blocks which may already be owned by other parts of the program.

Or better, rather than constructing the reference here, use the Timer passed in to EmbassyTimeDriver::init, as that way you know you have ownership of it.

Copy link
Author

@Serhii-the-Dev Serhii-the-Dev Nov 22, 2025

Choose a reason for hiding this comment

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

I'm passing it to the driver's EmbassyTimeDriver::init without borrowing, so it owns the Timer, hence, it's safe to use internally within the driver (as far as someone else will not decide to access it in the unsafe manner of course).
If it's still a must to change this approach, I will ask your advice on how to do it properly...I could not simply add it as the driver's struct field as I need to create a static instance of it using the time_driver_impl macro before initialization...Option looks like an overkill and most likely would not be beneficial for performance, and making it global would require some mutex/atomic pointer for safety guarantees which will also affect the code performance.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I've pushed a commit to your branch to do this safely. I'm pretty sure atomics will be just as fast as non-atomics on a single-core system like this, so I think performance is unlikely to be an issue. Likewise accessing a CriticalSectionMutex is free as long as you are already in a critical section.

fn now(&self) -> u64 {
let r = timer();
let period = self.period.load(Ordering::Relaxed);
compiler_fence(Ordering::Acquire);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would using Ordering::Acquire for the period load operation on the previous line have an equivalent effect?

Copy link
Author

Choose a reason for hiding this comment

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

Yes, though Acquire usually slower AFAIK, and we are using the now method a lot as a core of our "ticker", so I've tried to follow the Embassy implementation for STMs and use the compile-time assurance counter read will not be reordered.

@Serhii-the-Dev Serhii-the-Dev force-pushed the feat/embassy branch 2 times, most recently from a63c4e6 to 87345fd Compare November 22, 2025 08:11
@Serhii-the-Dev
Copy link
Author

Serhii-the-Dev commented Nov 22, 2025

Hi @qwandor
First of all, sorry for abandoning this PR for such a long time. I've updated the entire approach following refactoring done in Embassy for STM32, hopefully it resolves some of the problems you highlighted in your review, otherwise please let me know if anything else should be updated.

@qwandor
Copy link
Collaborator

qwandor commented Dec 7, 2025

@Serhii-the-Dev Let me know if my changes work for you, if so I'll go ahead and merge this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Embassy compatibility

2 participants