Skip to content
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

Rework PLL calculation and utilize oscillator clock divison #67

Merged
merged 9 commits into from
May 6, 2020

Conversation

Sh3Rm4n
Copy link
Member

@Sh3Rm4n Sh3Rm4n commented Mar 8, 2020

Rework

This PR turned out to be rework of the PLL setup.

Now get _sysclk will choose, whether PLL is needed as the source for the system clock.

The usb_valid check should work just fine, as we need the PLL anyways to get the supported frequencies (48 MHz and 72 MHz). Both can not be directly generated from the external oscillator as the HSE OSC does only allow up to 32 MHz.

calc_pll does now calculate the optimal divisor and multiplier values to generate the system clock, which the user provides. For that the greatest common divisor calculation is used, because the range of the possible values, which the PRE_DIV and PLL_MUL can take is 16 in both cases.

calc_pll is split into 2 implementations, one for devices which only can adjust the division of the clock of the external oscillator.
The other one, where both HSI and HSE division can be adjusted.

Both can not be directly generated from the external oscillator as the HSE OSC does only allow up to 32 MHz.

Now that the divisor (PRE_DIV) is utilized, 48 MHz and 72 MHz can be generated out of a 32 MHz

48 MHz / 32 MHz can be simplified to 3 / 2 as the greatest common divisor is 16. PLL_MUL is now set to 3 and PRE_DIV is set to 2.

Similarly, 72 MHz / 32 MHz can be simplified to 9 / 4 as the greatest common divisor is 8.

Fix

Initially a fix, which removes HSI division for devices, which do not divide HSI.

Fix #57

Ref #57 (comment)

Relevant parts in the reference manual:

with /2 divisor after HSI

without /2 divisor after HSI

@Sh3Rm4n
Copy link
Member Author

Sh3Rm4n commented Mar 8, 2020

Reminder: Compare with stm32f30x-hal, as this crate does not have this bug.

@Sh3Rm4n Sh3Rm4n force-pushed the issue-57 branch 2 times, most recently from bc0e0a9 to c2a73e7 Compare March 8, 2020 01:14
@Sh3Rm4n
Copy link
Member Author

Sh3Rm4n commented Mar 11, 2020

For stm32f302 devices there is also a distinction between B/C and D/E devices.

This distinction (as features) between these devices do not exist yet.

@Sh3Rm4n
Copy link
Member Author

Sh3Rm4n commented Mar 12, 2020

Going through these quite complicated clock trees: Another reminder.

stm32f303d/e does have an extra PREDIV block, while stm32f302d/e does not.

stm32f303d/e:

img-2020-03-12-235719

stm32f302d/e:

img-2020-03-12-235731

Cargo.toml Outdated Show resolved Hide resolved
@strom-und-spiele strom-und-spiele mentioned this pull request Mar 16, 2020
@Sh3Rm4n Sh3Rm4n force-pushed the issue-57 branch 3 times, most recently from 93c9d48 to 7ad0346 Compare March 22, 2020 12:36
@Sh3Rm4n Sh3Rm4n changed the title Remove HSI division for devices, which do not devide HSI Rework PLL calculation and utilize oscillator clock divison Mar 22, 2020
@Sh3Rm4n Sh3Rm4n closed this Mar 22, 2020
@Sh3Rm4n Sh3Rm4n reopened this Mar 22, 2020
@Sh3Rm4n Sh3Rm4n force-pushed the issue-57 branch 3 times, most recently from 6afee57 to 6b2446f Compare April 11, 2020 16:56
@Sh3Rm4n Sh3Rm4n closed this Apr 11, 2020
@Sh3Rm4n Sh3Rm4n reopened this Apr 11, 2020
@Sh3Rm4n
Copy link
Member Author

Sh3Rm4n commented Apr 11, 2020

So I tested it on different clock configuration on hardware, seeing if the clock configuration is correctly initialized and most things worked as expected. Now it is possible to choose clocks like 14 MHz on an 8 MHz based Oscillator clocks.

However, with 9 MHz I had a strange problem I used itm (iprintln!) to print out the clock configuration return from freeze(). I always had to adjust the gdb config according to the system clock.

monitor tpiu config internal /tmp/itm.fifo uart off 9000000

But on 9 MHz itmdump return garbage. I don't really know why, I haven't looked into much further. But looking into the register settings and variables via gdb, everything was set up correctly.

@Sh3Rm4n
Copy link
Member Author

Sh3Rm4n commented Apr 14, 2020

I feel like this is ready to be review again.

I don't like the way that the rcc module contains so many asserts, which keeping coming up, when using a wrong configuration. A better documentation for valid clock settings or a way to propagate the error to the user is needed. But this is not scope of this PR.

@russellmcc maybe you'd like to take another look. If not I'll ask somebody else. I'm comfortable merging this code as is but would like to have it reviewed, as this is code everybody depends upon, when using this hal.

Initially this should fix the case, that the system clock calculation
assumed that HSI was always devided by 2 for any device.

As the initial state hat some problems this ended up being a rework of
the PLL calculation to resemble the clock tree setup of stm32f3xx
mitrockrollers more closely.

The difference between different devices can be divided into two
categories:

1. Devices which have the possibility to configure HSI dividend
    The clock tree of the stm32f303xd as an example:
    https://www.st.com/content/ccc/resource/technical/document/reference_manual/4a/19/6e/18/9d/92/43/32/DM00043574.pdf/files/DM00043574.pdf/jcr:content/translations/en.DM00043574.pdf#page=127
2. Devices which always divide HSI by 2
    The clock tree of the stm32f303x6 as an example:
    https://www.st.com/content/ccc/resource/technical/document/reference_manual/4a/19/6e/18/9d/92/43/32/DM00043574.pdf/files/DM00043574.pdf/jcr:content/translations/en.DM00043574.pdf#page=128

For [1] the HSI is not initially divided by 2 and both HSE and HSI can be
changed via divisor block (PRE_DVI) and multiplier block (PLL_MUL).
For [2] the HSI is **always** divided by by 2 and the divisor can only
be used for the HSE.

These differences also apply to the stm32f302x{b,c,d,e}, so these
targets get added as a feature.

With this rewrite  it is now possible to get more fine grained control
over the system clock we can choose.

To find out the optimal values for both the multiplier and the divisor,
a greatest common divisor calculation is used.

Some examples:

- If you want 72 Mhz system clock out of 32 Mhz oscillator clock
  the common divisor would be 8. Represented in a fraction this would
  look like this:

72 / 32 = (72 / 8) / (32 / 8) = 9 / 4

These values can be represented in the divisor and multiplier block, as
these can take values up to 16.

- If you want 26 Mhz system clock out of 8 Mhz oscillator clock
  the common divisor would be 2. Represented in a fraction this would
  look like this:

26 / 8 = (26 / 2) / (8 / 2) = 13 / 4
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.

stm32f3xx_hal::rcc::CFGR::freeze() gives wrong default clocks: it gives half of the real clocks
3 participants