-
Notifications
You must be signed in to change notification settings - Fork 69
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
Use fixed-point u64 math to divide the PLL values #212
Conversation
This avoids the need for almost 1K of code to implement division for u64 values (which the Cortex-M7 can't do in hardware). It can multiply u64 values in hardware, so instead of dividing by (integer) x, we find 1/x in fixed-point, multiply, and shift the fixed-point offset back out. Finding 1/x can be done in a u32 since our shift is small enough, and that division *can* be done in hardware on this CPU. Fixes stm32-rs#211
Hmm, I seem to be failing a bunch of rcc tests. Let's fix that up... |
This requires shifting the input frequencies down by 4 bits in order to fit both the max base_clk*n value, and the 30-bit fractional part, into a u64. (base_clk*n is up to 38 bits wide.) This is OK as long as all input frequencies are a multiple of 250kHz, which has the bottom 4 bits clear.
"cargo fmt" does not work because it requires both test mode and the #![no_std] attribute, which the crate lib.rs doesn't enable in test mode. But manually running rustfmt does.
For people not looking at #211, the issue with the tests was that we lost too much precision using only 26 bits for the fractional part of the fixed-point math. It needed at least 30 bits. But the numerator in the division operation needed up to 38 bits, so it would overflow a u64. Fortunately, we could shift the frequency right by 4 bits at the start to make everything fit, as long as the input frequencies are a multiple of 250kHz (they all are in the tests, at least, and I think they are likely to be in people's designs as well). So now we shift the frequency right by 4 bits and use 30 bits for the fractional part. Tests are all accurate enough to pass. |
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.
This looks good to me in principle, but I do not know exactly how it works. If nobody raises any issues, I would merge this.
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.
Alright, let's merge this. Thank you for your work!
This avoids the need for almost 1K of code to implement division for u64 values (which the Cortex-M7 can't do in hardware). It can multiply u64 values in hardware, so instead of dividing by (integer) x, we find 1/x in fixed-point, multiply, and shift the fixed-point offset back out. It can also divide u32 values, and finding 1/x can be done in a u32 since our shift is small enough.
Fixes #211