Skip to content

Conversation

@ericseppanen
Copy link

The current implementation of calculate_pio_clock_divider only computes an integer divider, which is a missed opportunity since the return type explicitly represents an 8-bit fractional part.

This implementation ensures that the fractional part of the clock divider is accurately calculated. It uses additional u32 division/mod operations; I think this is preferable to one u64 division, but that would work as well. I don't have a great understanding of how division works on rp2040, so any advice is welcome.

Other changes:

  • Add additional asserts to catch out-of-bounds results.
  • Make the version that accepts the system clock as a parameter const and public, so if anyone wants to hardcode the system frequency they can avoid any runtime computation.
  • Remove the inline attributes because the function has grown quite a bit.
  • Add unit tests to verify that the math works.

Fixes #5048.

The test will fail, because the current implementation doesn't calculate
the fractional part.
Ensure that the fractional part of the clock divider is accurately
calculated. This does additional u32 division/mod operations, which I
think is better than using u64 for its extra precision.

Also:
- Add additional asserts to catch out-of-bounds results.
- Make the version that accepts the system clock as a parameter
const and public, so if anyone wants to hardcode the system
frequency they can avoid any runtime computation.
- Remove the `inline` attributes because the function has grown quite a
bit.
defmt::assert gives a compile error in const context.
@ericseppanen
Copy link
Author

ericseppanen commented Dec 13, 2025

I hit compile errors with defmt::assert! in the const fn. Result by using core::assert without a string literal instead; not sure if that's the right approach. I could add an error enum, or split this into three functions (runtime-with-defmt, const-without-defmt, and math-inner), but maybe that would be overkill?

Or I could just drop the public const fn idea entirely, and this will always be calculated at runtime.

@katazina0
Copy link

I hit compile errors with defmt::assert! in the const fn. Result by using core::assert without a string literal instead; not sure if that's the right approach. I could add an error enum, or split this into three functions (runtime-with-defmt, const-without-defmt, and math-inner), but maybe that would be overkill?

Or I could just drop the public const fn idea entirely, and this will always be calculated at runtime.

Could two functions work, one const and one not? That way things could be asserted at compile time and if needed, at runtime too. Would probably be a good idea to gate defmt asserts behind the "defmt" feature flag as well.

@ericseppanen
Copy link
Author

Could two functions work, one const and one not?

Perhaps, with some code repetition. There are many possible permutations, so I'm hoping to hear what style the maintainers prefer.

Would probably be a good idea to gate defmt asserts behind the "defmt" feature flag as well.

This is already handled by embassy_rp's assert macro:

macro_rules! assert {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::assert!($($x)*);
#[cfg(feature = "defmt")]
::defmt::assert!($($x)*);
}
};
}

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-rp: calculate_pio_clock_divider returns invalid clock_divider

2 participants