Skip to content

stm32l1/stmclk: refactor clck init to use stmclk.h, add msi option#8402

Closed
fjmolinas wants to merge 8 commits intoRIOT-OS:masterfrom
fjmolinas:stm32l1_clk
Closed

stm32l1/stmclk: refactor clck init to use stmclk.h, add msi option#8402
fjmolinas wants to merge 8 commits intoRIOT-OS:masterfrom
fjmolinas:stm32l1_clk

Conversation

@fjmolinas
Copy link
Copy Markdown
Contributor

@fjmolinas fjmolinas commented Jan 22, 2018

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

@kYc0o
Copy link
Copy Markdown
Contributor

kYc0o commented Jan 22, 2018

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!

Copy link
Copy Markdown
Contributor

@kYc0o kYc0o left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

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)) {}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Contributor Author

@fjmolinas fjmolinas Jan 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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;
        }
    }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

@fjmolinas fjmolinas Jan 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • 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?

Copy link
Copy Markdown
Contributor Author

@fjmolinas fjmolinas Feb 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@olegart you are right, I understood that part wrong.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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) ??

tmpreg &= ~(RCC_CR_HSEBYP | RCC_CR_CSSON | RCC_CR_PLLON);
RCC->CR = tmpreg;

cpu_clock_global = 65536 * (1 << (msi_range >> 13));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use defines instead of only numbers here? And also add some comments about the usage of such constants.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

@kYc0o kYc0o self-assigned this Jan 22, 2018
@kYc0o kYc0o added Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation Platform: ARM Platform: This PR/issue effects ARM-based platforms Type: cleanup The issue proposes a clean-up / The PR cleans-up parts of the codebase / documentation labels Jan 22, 2018
Copy link
Copy Markdown
Contributor

@kYc0o kYc0o left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

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)) {}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

printf("This board features a(n) %s MCU.\n", RIOT_MCU);

pm_set(1);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this got in a commit without being noticed...

@@ -0,0 +1,293 @@
/*
* Copyright (C) 2014 Freie Universität Berlin
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add your, or your institute/company copyright.

* @{
*
* @file
* @brief Implementation of the kernel cpu functions
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think here something like Implemetation of CPU clock functions might be more suitable.

/* 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)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

@kYc0o kYc0o left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some other questions regarding the code...

#else
#define CORE_VOLTAGE (PWR_CR_VOS_1 | PWR_CR_VOS_0)
#endif

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

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)) {}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@fjmolinas
Copy link
Copy Markdown
Contributor Author

@kYc0o are some of the issues you mentioned in #8401 related to (or could affect) this PR or #8403??

@kYc0o
Copy link
Copy Markdown
Contributor

kYc0o commented Jan 26, 2018

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.

@kYc0o
Copy link
Copy Markdown
Contributor

kYc0o commented Feb 2, 2018

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.

@fjmolinas
Copy link
Copy Markdown
Contributor Author

@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 :).

@fjmolinas
Copy link
Copy Markdown
Contributor Author

@kYc0o reposting this since the older comment thread isn't visible anymore.

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.

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.

@kYc0o
Copy link
Copy Markdown
Contributor

kYc0o commented Feb 2, 2018

Why would this delay start-up?

Because of the timeout needed to know if HSE is present.

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.

Agree, let's see if MSI can be added in the future.

Copy link
Copy Markdown
Contributor

@kYc0o kYc0o left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A small comment yet...

* @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);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if MSI is not present anymore this is not needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needed for #8403 to switch to low-power sleep mode

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this whole initialisation can follow a bit the one from L4, which takes into account the previous state of the interrupts.

Copy link
Copy Markdown
Contributor Author

@fjmolinas fjmolinas Feb 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown
Contributor Author

@fjmolinas fjmolinas Feb 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK!, will add then. Will wait for #8518 though :), awesome to see nucleo-l1 problems are getting fixed.

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)) {}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here stmclk_disable_hsi(); instead.

Copy link
Copy Markdown
Contributor Author

@fjmolinas fjmolinas Feb 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@fjmolinas
Copy link
Copy Markdown
Contributor Author

Why would this delay start-up?
Because of the timeout needed to know if HSE is present.

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.

irq_restore(state);
}

void stmclk_switch_msi(uint32_t msi_range, uint32_t ahb_divider)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I said above, this function belongs to an upcoming PR.

@kYc0o
Copy link
Copy Markdown
Contributor

kYc0o commented Feb 21, 2018

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...

@fjmolinas
Copy link
Copy Markdown
Contributor Author

fjmolinas commented Mar 5, 2018

@kYc0o removed switch_msi_clk, postpone to another PR

@fjmolinas
Copy link
Copy Markdown
Contributor Author

@kYc0o how are things going on your side? any new info?

@fjmolinas
Copy link
Copy Markdown
Contributor Author

fjmolinas commented Mar 19, 2018

@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

@fjmolinas fjmolinas closed this Mar 20, 2018
@fjmolinas
Copy link
Copy Markdown
Contributor Author

Closed this PR, kind of duplicate of #8735.

@fjmolinas fjmolinas deleted the stm32l1_clk branch July 30, 2021 13:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Platform: ARM Platform: This PR/issue effects ARM-based platforms Type: cleanup The issue proposes a clean-up / The PR cleans-up parts of the codebase / documentation Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants