stm32l1/stmclk: refactor clck init to use stmclk.h, add msi option#8402
stm32l1/stmclk: refactor clck init to use stmclk.h, add msi option#8402fjmolinas wants to merge 8 commits intoRIOT-OS:masterfrom
Conversation
|
Wow, I just have started to work on this but this have already a good shape. I'll make a quick review and a test with all the associated PRs. Thanks a lot for tackling this! |
kYc0o
left a comment
There was a problem hiding this comment.
Some changes to do especially on the format of #if statements. Please align all of them to the left and add some comments where needed.
cpu/stm32l1/stmclk.c
Outdated
| RCC->CR |= CLOCK_CR_SOURCE; | ||
| /* Wait till the clock source is ready | ||
| * NOTE: the MCU will stay here forever if you use an external clock source and it's not connected */ | ||
| while (!(RCC->CR & CLOCK_CR_SOURCE_RDY)) {} |
There was a problem hiding this comment.
I was about to introduce a timeout here to know if the HSE is ready, otherwise we enable the HSI. Would you mind to introduce something like that?
There was a problem hiding this comment.
@kYc0o isn't what you are refering introduced at line 129-136
while (!(RCC->CR & clock_source_rdy)) {
timeout++;
if (timeout > 10000) {
clock_source_rdy = RCC_CR_HSIRDY;
timeout = 0;
}
}
There was a problem hiding this comment.
Oh yeah, didn't see that code in depth. However I should ask, why only when defined(CLOCK_HS_MULTI)? IMHO this should be present whenever any external clock source is being used. So, in your case, are you assuming that HSI can't be used standalone? Otherwise, I think it's worth to show explicitly in the code when only HSI is being used.
There's also a consensus, especially with nucleo boards on which some revisions don't have any HSE or LSE, that we try systematically to use HSE, if it's not present, we switch to internal.
There was a problem hiding this comment.
Well because when defined(CLOCK_HS_MULTI) is not defined CLOCK_CR_SOURCE would be HSI or HSE, and if CLOCK_HSI is not defined and HSE is not responding for some reason than the only option would be MSI which as far as I know isn't supported as base clock in RIOT, I'm not sure if it could interfere with other drivers (ADC at least wouldn't work); and PLL can't be configured from MSI.
There was a problem hiding this comment.
What you mean is that only HSI == MSI? As far as I can see in the code for CLOCK_HS_MULTI you need both HSI and HSE, and above you're forcing CLOCK_HS_MULTI when HSI and HSE are defined. Thus, I need some clarification on how this works and which are the possibilities with boards without HSE and LSE.
There was a problem hiding this comment.
- If HSE try to configure it, if timeout go to HSI
Discussing offline with @haukepetersen convinced me that this might not be necessary, since it's also somehow delaying the startup, so you can just assume the configuration is given by the user who knows if HSE is available.
- If HSI use it directly, no timeout needed
Agree.
- MSI not yet an option as a run clock since there aren't function to properly handle the lower core clock speed this would have.
Looking at the implementatin for L4, it seems it's also fallbacking to MSI under certain conditions, though L4 can actually go to 48MHz... Can you just take a look and if needed try to adapt it to this PR?
There was a problem hiding this comment.
convinced me that this might not be necessary, since it's also somehow delaying the startup
Why would this delay start-up?
Looking at the implementation for L4, it seems it's also fall-backing to MSI under certain conditions, though L4 can actually go to 48MHz... Can you just take a look and if needed try to adapt it to this PR?
There are two problems and difference I see here related to L4.
- L1 MSI goes up to 4 MHz on L1, and usually targeted CORE_CLOCK on nucleo boards is 32MHz, and CORE_CLOCK is used by other driver to configure their clock speed, which wouldn't be accurate in this case.
*L4 MSI can be used to run the PLL and also ADC threw the SYSCLK, which is not the case for L1.
IMHO, for this to work there should first be support for changing CORE_CLOCK speed for this to work properly since drivers (spi, uart) should be able to adjust to this. And also somehow adc should be disabled when running on MSI in L1. And I think these would be bigger changes since the current clock speed would have to be exposed, and that would start a hole different discussion.
There was a problem hiding this comment.
adc should be disabled when running on MSI in L1
Why? ADC on L1 needs HSI to be enabled, but it doesn't care about system clock. On L0 and L4, both HSI and APB clock can be selected as ADC clock source.
There was a problem hiding this comment.
@olegart you are right, I understood that part wrong.
There was a problem hiding this comment.
@olegart do you see a problem with leaving the use of MSI as a sysclk source and all it's config for a later PR (this would come with functions to recalculate uart baudrate, xtimer and others) ??
cpu/stm32l1/stmclk.c
Outdated
| tmpreg &= ~(RCC_CR_HSEBYP | RCC_CR_CSSON | RCC_CR_PLLON); | ||
| RCC->CR = tmpreg; | ||
|
|
||
| cpu_clock_global = 65536 * (1 << (msi_range >> 13)); |
There was a problem hiding this comment.
Can you use defines instead of only numbers here? And also add some comments about the usage of such constants.
There was a problem hiding this comment.
Thinking I should remove this. It isn't really needed unless runing MCU on MSI clock in run-mode. In that case CORE_CLOCK isn't the mcu actual speed and might need to recalculate timer, uart and other setting accordingly to this. But that would mean exposing a global variable and stuff like that. What do you think?
8eddc69 to
b3f1827
Compare
kYc0o
left a comment
There was a problem hiding this comment.
Found some other issues.
In our current supported boards there's no definition of HSI for stm32l1 based boards, though I can imagine a custom board or custom application using and defining both of them, but I wonder, what's the behaviour when only HSI is being used?
cpu/stm32l1/stmclk.c
Outdated
| RCC->CR |= CLOCK_CR_SOURCE; | ||
| /* Wait till the clock source is ready | ||
| * NOTE: the MCU will stay here forever if you use an external clock source and it's not connected */ | ||
| while (!(RCC->CR & CLOCK_CR_SOURCE_RDY)) {} |
There was a problem hiding this comment.
Oh yeah, didn't see that code in depth. However I should ask, why only when defined(CLOCK_HS_MULTI)? IMHO this should be present whenever any external clock source is being used. So, in your case, are you assuming that HSI can't be used standalone? Otherwise, I think it's worth to show explicitly in the code when only HSI is being used.
There's also a consensus, especially with nucleo boards on which some revisions don't have any HSE or LSE, that we try systematically to use HSE, if it's not present, we switch to internal.
examples/hello-world/main.c
Outdated
| printf("This board features a(n) %s MCU.\n", RIOT_MCU); | ||
|
|
||
| pm_set(1); | ||
|
|
There was a problem hiding this comment.
I think this got in a commit without being noticed...
| @@ -0,0 +1,293 @@ | |||
| /* | |||
| * Copyright (C) 2014 Freie Universität Berlin | |||
There was a problem hiding this comment.
Please add your, or your institute/company copyright.
cpu/stm32l1/stmclk.c
Outdated
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Implementation of the kernel cpu functions |
There was a problem hiding this comment.
I think here something like Implemetation of CPU clock functions might be more suitable.
cpu/stm32l1/stmclk.c
Outdated
| /* See if we want to use the PLL */ | ||
| #if defined(CLOCK_PLL_DIV) || defined(CLOCK_PLL_MUL) || \ | ||
| defined(CLOCK_PLL_DIV_HSE) || defined(CLOCK_PLL_MUL_HSE) || \ | ||
| defined(CLOCK_PLL_DIV_HSI) || defined(CLOCK_PLL_MUL_HSI) |
There was a problem hiding this comment.
You aligned the #if statement, but the subsequent defines which belong to the same statement are also aligned between them, thus:
#if defined(CLOCK_PLL_DIV) || defined(CLOCK_PLL_MUL) || \
defined(CLOCK_PLL_DIV_HSE) || defined(CLOCK_PLL_MUL_HSE) || \
defined(CLOCK_PLL_DIV_HSI) || defined(CLOCK_PLL_MUL_HSI)
is the result we want.
db10652 to
30c57db
Compare
kYc0o
left a comment
There was a problem hiding this comment.
I have some other questions regarding the code...
| #else | ||
| #define CORE_VOLTAGE (PWR_CR_VOS_1 | PWR_CR_VOS_0) | ||
| #endif | ||
|
|
There was a problem hiding this comment.
Well now that the #ifdef's got aligned is difficult to follow each statement. Can you add some doc (preferably doxygen, otherwise normal comments would be ok) to the statements?
cpu/stm32l1/stmclk.c
Outdated
| RCC->CR |= CLOCK_CR_SOURCE; | ||
| /* Wait till the clock source is ready | ||
| * NOTE: the MCU will stay here forever if you use an external clock source and it's not connected */ | ||
| while (!(RCC->CR & CLOCK_CR_SOURCE_RDY)) {} |
There was a problem hiding this comment.
What you mean is that only HSI == MSI? As far as I can see in the code for CLOCK_HS_MULTI you need both HSI and HSE, and above you're forcing CLOCK_HS_MULTI when HSI and HSE are defined. Thus, I need some clarification on how this works and which are the possibilities with boards without HSE and LSE.
6376fff to
30c57db
Compare
|
AFAIK no, this is IMHO a separated issue which will (should) be included further when we repair the state of stm32l1xx devices, but I'm testing separately as much as I can. |
|
I was looking more closer to the Lxx clock implementations to see if we can migrate them together but they look quite different. Thus I like this approach of stmclk and with the needed adjustments it can be merged IMHO. @haukepetersen if you can detail your concerns about this PR it would be awesome, so we can focus the efforts on something which can be merged and benefit a better support for the currently broken L1 platform. Though this won't solve the current problems (mostly related to PM), it's a step forward. |
|
@kYc0o simplified some of th the clock intialization (assumed HSI allways enabled). Some functionality was removed sutch as using MSI as core clock since there isn't support for this to happen in other RIOT modules or function, might address this on another PR since some code is there already. .Please tell me what you think :). |
1abbe8b to
593141d
Compare
|
@kYc0o reposting this since the older comment thread isn't visible anymore.
Why would this delay start-up?
There are two problems and difference I see here related to L4.
IMHO, for this to work there should first be support for changing CORE_CLOCK speed for this to work properly since drivers (spi, uart) should be able to adjust to this. And also somehow adc should be disabled when running on MSI in L1. And I think these would be bigger changes since the current clock speed would have to be exposed, and that would start a hole different discussion. |
Because of the timeout needed to know if HSE is present.
Agree, let's see if MSI can be added in the future. |
cpu/stm32_common/include/stmclk.h
Outdated
| * @param[in] msi_range MSI frequency range | ||
| * @param[in] ahb_divider AHB bus divider | ||
| */ | ||
| void stmclk_switch_msi(uint32_t msi_range, uint32_t ahb_divider); |
There was a problem hiding this comment.
if MSI is not present anymore this is not needed.
There was a problem hiding this comment.
needed for #8403 to switch to low-power sleep mode
There was a problem hiding this comment.
Hmmm yeah but that's independent of this PR, so it should be included either in a separated (upcoming) PR or in #8493, but I'd say in a different PR enhancing this one.
| /* Reset HSION, HSEON, CSSON and PLLON bits */ | ||
| RCC->CR &= ~(RCC_CR_HSION | RCC_CR_HSEON | RCC_CR_HSEBYP | RCC_CR_CSSON | RCC_CR_PLLON); | ||
| /* Clear all interrupts */ | ||
| RCC->CIR = 0x0; |
There was a problem hiding this comment.
Maybe this whole initialisation can follow a bit the one from L4, which takes into account the previous state of the interrupts.
There was a problem hiding this comment.
There's something I don't like about this approach. One ends up having multiple useless calls to irq_disable; irq_restore. This function in only used in cpu_init (are there any isr that should be restored here?), and in pm. And in pm ir_restore, irq_disable already has to be called around this function. Anyway, I saw this comment in th l4 code: /* disable any interrupts. Global interrupts could be enabled if this is * called from some kind of bootloader... */ . I don't now much about that case so if that is a concern I will include it, I leave it up to you @kYc0o, just feels weird having so many nested calls to irq_disable/restore.
There was a problem hiding this comment.
Well actually I'm working on this platform because I want to support the RIOT bootlaoder I'm working on, towards OTA updates. Thus, the case of a bootlaoder is very important since I had several problems with clocking when it was already initialised by the bootloader. I can actually test it soon, as I'm approaching an end to the support of this platform (if #8518 gets merged soon)
There was a problem hiding this comment.
OK!, will add then. Will wait for #8518 though :), awesome to see nucleo-l1 problems are getting fixed.
cpu/stm32l1/stmclk.c
Outdated
| RCC->CR |= RCC_CR_HSION; | ||
| /* Wait till the clock source is ready | ||
| * NOTE: no timeout for HSI, should allways be available*/ | ||
| while (!(RCC->CR & RCC_CR_HSIRDY)) {} |
There was a problem hiding this comment.
Here I think you can make use of stmclk_enable_hsi();
|
|
||
| /* Wait for sysyem clock to be ready before desabling other clocks*/ | ||
| while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != clock_cfgr_sw_rdy) {} | ||
| RCC->CR &= ~(clock_disable_clocks); |
There was a problem hiding this comment.
And here stmclk_disable_hsi(); instead.
There was a problem hiding this comment.
it's not always HSI, can be HSI+MSI or HSE+MSI. MSI is not enabled (software wise) as a core clock but still used on start-up and reset and needes to be disabled afterwards.
If HSE is ready (RCC->CR & clock_source_rdy) will be valid and it would exit the loop, it doesn't wait for the whole timeout, I really can't see any delay, if HSE isn't configured on the board it doesn't even get into the timeout part of the code. I don't actually mind assuming user now id HSE is or isn't present, just can't see how this would delay start_up, more thatn the time it takes the cpu to add 1 to the timeout variable. |
cef1bb7 to
e181afa
Compare
e181afa to
20dbd2e
Compare
cpu/stm32l1/stmclk.c
Outdated
| irq_restore(state); | ||
| } | ||
|
|
||
| void stmclk_switch_msi(uint32_t msi_range, uint32_t ahb_divider) |
There was a problem hiding this comment.
As I said above, this function belongs to an upcoming PR.
|
I'll need a bit more time to test this PR but I think it's already in a good shape. I'd like to have @haukepetersen or @kaspar030 ACK here... |
|
@kYc0o removed switch_msi_clk, postpone to another PR |
|
@kYc0o how are things going on your side? any new info? |
|
@kYc0o @kaspar030 @haukepetersen just saw that #8735 got merged 14 days ago. I get it implements the same thing in a different way, I also agree its cleaner/better. I just find it really annoying that you have me adapting the PR making changes for 3 month's, and apparently just wasting time just to open a different PR and have it closed the same day or the day after, at least since you are tagged in this PR letting me know you will work on a different solution would be cool. I think kaspar's solution is cleaner, better; and does a lot of tiding up. It's just really annoying how the contribution process works in RIOT, it really dissuades anyone that isn't a maintainer or in direct contact with a maintainer to spend time adapting code to fit RIOT or making PR's. I don't really care about where ever one solution or another gets merged, the better, cleaner, smaller one should get merged, but I do care about wasting my time. A "contested" tag or don't like the solution from the start would have saved my time and also @kYc0o. Cheers, Francisco. PS: we can close this one too |
|
Closed this PR, kind of duplicate of #8735. |
Contribution description
This PR is based on work by @olegart, refactors to use stmclk.h structure and adds MSI clock use.
Issues/PRs references
#8403 depends on this PR