-
Notifications
You must be signed in to change notification settings - Fork 211
rcc: I2S and SAI clocks #247
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
Conversation
Note that #212 contains a remark that I2S frequencies are difficult because configuration is spread out between I2S and RCC. I do not think this is a problem. I think we should just list a number of good intermediate frequencies in the documentation for systems where the PLL VCO output can be a multiple of 1MHz, which will be the case for most systems (for example, 86 MHz can be used for precise generation of I2S frequencies for 48KHz audio). |
Could you be more specific about what you mean with the stm32f1 remark? I do not quite understand what you mean with that. w.r.t. APB1 clock: doesn't pclk1(...) set the APB1 clock already? Edit: If the latter really answers the question, then that shows how much the existing documentation is lacking. I had to look through the implementation to see that pclk1 means "APB1 clock". |
What I mean is that the rcc module in stm32f1 has the APB1 struct that you can use as such:
It also has other such similar structs. It is similar to copy these structs from stm32f1 to stm32f4 because the layout is currently about the same. If you modify the layout, it will not be so simple. I just need APB1, but it would be good to add the other structs as well. |
Ah, I see. I think that is completely orthogonal to this PR, I'll concentrate on the PLL stuff. Although I personally do not mind the current practice to just make an unsafe access to the apb1enr/rst registers, given that the writes are atomic and that the user API is less cluttered. |
With the fixes, the code generates correct SAI frequencies both with active and inactive main PLL on the STM32F429. That should cover the SAI code path of the STM32F446 as well. The I2S code path is sufficiently similar that I'd consider this ready for review. |
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.
Missing CHANGELOG entry, other than that looks good to me on visual inspection.
@therealprof Thanks for the review! I fixed the clippy lints and added a changelog entry. |
The clock configuration code will become much more complex.
There are many different clock trees with different types of PLL clock connections, so we need different PLL optimization algorithms with different complexity.
The PLLSRC needs to be set even if the main PLL is not enabled, because the source is also used by the other PLLs. The old code also did not correctly set M, destroying all other values in the process.
dcd3787
to
9ac793f
Compare
... and I rebased to fix the merge conflict. |
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.
LGTM, thanks.
bors r+
self.freeze_internal(true) | ||
} | ||
|
||
pub fn freeze_internal(self, unchecked: bool) -> Clocks { |
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.
Was this supposed to be pub
?
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 do not see why it should be, but it was already pub before I started.
Apparently I messed up and caused some warnings about unused fields on F410/413/423. I will create a follow-up PR for those. |
Preface
Some of this code is probably pretty ugly. In parts, the code looks pretty bad, and it imposes pretty arbitrary limitations (see below) in terms of functionality. I propose merging something like this on the basis that it is strictly more powerful than the previous implementation - in cases where no I2S or SAI clocks are requested, the old code is still used providing identical performance and identical results.
Situation
The current RCC code only provides the sysclk, but no I2S and SAI clocks. Future pull requests (#212? I am currently working on support for SAI) require these clocks. Different MCUs have wildly differing clock trees, though. Some microcontrollers (e.g. STM32F411/446) have separate I2SPLLM dividers, others do not. F413/423 do not have an SAI PLL even though SAI is supported. F410 does not even have an I2S PLL and the I2S clock is generated by the main PLL. The different amount of SAIs and I2S instances causes differences in the clock selection code. See #240 for a table of all those differences. Note: The table does not include that F413/423 have a different SAI divider range compared to the other models.
Approach
This wide range of different configurations and the flexible, yet very model-specific connections (e.g., SAI clocks can usually be generated by the I2S PLL and vice versa) make writing a completely flexible solution difficult. The computational complexity of such a solution to generate the ideal results might very likely be prohibitive for any runtime implementation.
I therefore decided on an approach with some limitations to keep both implementation and computational complexity down. In particular, I2S clocks, if required, are always generated by the I2S PLL, and likewise SAI clocks are always generated by the SAI PLL, with special cases for the models where these PLLs do not exist. This means that there can be only one I2S frequency (and likewise SAI frequency) that does not match the provided I2S_CKIN external frequency. This should be enough for all applications except for applications which implement resampling between e.g. 44100 and 48000 Hz audio and have to implement an I2S master for both.
The code decouples clock selection (the bottom half of the table in #240) from PLL optimization to reduce the numbers of special cases required in each part - clock selection is implemented in the form of I2sClocks and SaiClocks types in rcc.rs.
Alternatives
I believe the restrictions described above are valid for now. If, eventually, we want a more complete and more flexible interface and do not care about API backwards compatibility, we can implement clock tree configuration in the form of an external compile-time tool - either via procedural macros or via a library that can be used within build.rs. In this case, the RCC library should probably be changed to provide two functions "RCC.apply_static_config()" or "RCC.apply_runtime_config()", where the former just applies a set of precalculated config options and the latter executes the current cheap yet limited runtime configuration algorithms.
Status/Testing
At the moment, most of the code is still completely untested and I only have a STM32F429 discovery board for testing:
Once the tests on the F429 are done, I need help with the other models - and I could use help with the F410 right away. Do not expect the code to work as-is, though.