cancel
Showing results for 
Search instead for 
Did you mean: 

Switching ''32 MHz HSI'' to ''4 MHz MSI'' and go back in runtime

ferrarofcf
Associate II
Posted on October 12, 2015 at 11:14

I use the STM32L151RBT6.

I can work well with a clock initialized with the ''Code 1''HSI 32MKz or with a clock initialized with the ''Code 2'' MSI 4MHz.

But I do not know how to change the clock in runtime.

I would like:

loop

{

configure to 32MHz HSI

switch to 4MHz MSI

configure to STOP mode with RTC clocked by LSI

wakeup and work to 4 MHz MSI

switch to 32MHz HSI

}

the ''Code 1'' and the ''Code 2'' works well only after the reset, but how do switch correctly ''32 MHz HSI'' to ''4 MHz MSI'' and go back?

some advice?

 

(I will estimate, maybe I'm just less than 4 MHz.)

�Code 1�

/*  PLL configuration */

  RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL | RCC_CFGR_PLLDIV));

  RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI | RCC_CFGR_PLLMUL6 | RCC_CFGR_PLLDIV3);

  /* Enable PLL */

  RCC->CR |= RCC_CR_PLLON;

  /* Wait till PLL is ready */

  while((RCC->CR & RCC_CR_PLLRDY) == 0);

  /* Select PLL as system clock source */

  RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));

  RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;

  /* Wait till PLL is used as system clock source */

  while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL);

  

�Code 2� 

  __IO uint32_t StartUpCounter = 0, MSIStatus = 0;  

  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    

  /* Enable MSI */    

  RCC->CR |= ((uint32_t)RCC_CR_MSION);

   /* Wait till MSI is ready and if Time out is reached exit */

  do

  {

    MSIStatus = RCC->CR & RCC_CR_MSIRDY;

    StartUpCounter++;  

  } while((MSIStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

  if ((RCC->CR & RCC_CR_MSIRDY) != RESET)

  {

    MSIStatus = (uint32_t)0x01;

  }

  else

  {

    MSIStatus = (uint32_t)0x00;

  }  

  

  if (MSIStatus == (uint32_t)0x01)

  { 

    /* Enable 64-bit access */

    FLASH->ACR |= FLASH_ACR_ACC64;  

    /* Enable Prefetch Buffer */

    FLASH->ACR |= FLASH_ACR_PRFTEN;    

    /* Flash 1 wait state */

    FLASH->ACR |= FLASH_ACR_LATENCY; 

    /* Enable the PWR APB1 Clock */

    RCC->APB1ENR |= RCC_APB1ENR_PWREN;

    /* Select the Voltage Range 3 (1.2V) */

    PWR->CR = PWR_CR_VOS;

    /* Wait Until the Voltage Regulator is ready */

    while((PWR->CSR & PWR_CSR_VOSF) != RESET);    

    /* HCLK = SYSCLK */

    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;

    /* PCLK2 = HCLK */

    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;

    /* PCLK1 = HCLK */

    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1;

    /* Set MSI clock range */

    RCC->ICSCR &= (uint32_t)((uint32_t)~(RCC_ICSCR_MSIRANGE));    

    RCC->ICSCR |= (uint32_t)RCC_ICSCR_MSIRANGE_6;

    /* Select MSI as system clock source */

    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));

    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_MSI;    

    /* Wait till MSI is used as system clock source */

    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x00);

  }

  else

  { 

    /* If MSI fails to start-up, the application will have wrong clock 

       configuration. User can add here some code to deal with this error */    

  } 

#clock-hsi-msi-lsi
6 REPLIES 6
Posted on October 12, 2015 at 19:39

There is no ''4 MHz LSI'' - in the 'L15x, there is a MSI RC oscillator, which can be used as system clock and can run at 4MHz (and other frequencies); and there is a LSI RC oscillator running at 37kHz which can be used as RTC source.

Both HSI and MSI will stop during STOP mode, so there's little reason to switch between them if the only reason would be to conserve power during STOP mode.

Please read carefully the RCC chapter in RM0038, and also the PWR chapter for the Stop mode.

JW

ferrarofcf
Associate II
Posted on October 13, 2015 at 10:18

copy and paste is bad :( yes MSI I corrected (“Code2�? is MSI)

My flow is:

status 1: Hi-performance - Hi-power -> 32MHz (about 10mA)

status 2: Low-performance - Low-power -> 4MHz or Less (about 4mA)

status 3: STOP mode in WFI with exit RTC clocked by LSI or pin EXTI

The environment determine ''Status1'' and ''Status2''.

The link by Client determine ''Status3''

Sincerely I have any consumption problems in STOP mode (about 1mA) , but that's another story ( maybe I open another thread) But now I want to fix this frequency switch.

Posted on October 13, 2015 at 19:41

Generally, you switch on the new clock source, switch system clock to the new clock source, then shut off the old clock source. If the two timings require different FLASH latency, you can switch to the lower latency AFTER you switched to lower clock (MSI), and switch back to high latency BEFORE you switch to higher clock.

You should think also about how the timing-dependent peripherals will behave (timers, UART,...)

JW

ferrarofcf
Associate II
Posted on October 16, 2015 at 11:06

Ok, I still have not solved some problems.

Now I would easier the question.

After resuming from STOP, the clock config returns to its reset state (MSI used as

system clock).

I want to go back to 32 MHz, using this code:

 

 /*  PLL configuration */

  RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL |

                                        RCC_CFGR_PLLDIV));

  RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI | RCC_CFGR_PLLMUL6 | RCC_CFGR_PLLDIV3);

  /* Enable PLL */

  RCC->CR |= RCC_CR_PLLON;

  /* Wait till PLL is ready */

  while((RCC->CR & RCC_CR_PLLRDY) == 0);

        

  /* Select PLL as system clock source */

  RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));

  RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;

  /* Wait till PLL is used as system clock source */

  while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL);  

but it stop on

  /* Wait till PLL is ready */

  while((RCC->CR & RCC_CR_PLLRDY) == 0);

can you give me some advice.

Posted on October 16, 2015 at 11:36

As you use HSI as PLL source, make sure it is running before switching on PLL (i.e. switch on HSI and wait until it is running).

JW
ferrarofcf
Associate II
Posted on October 16, 2015 at 13:57

Thank you very much, now works fine, but I have to understand why USART_IT_ORE_RX  when I restore USART .

I take this opportunity to ask you.

It is good thing stop all peripherals before the STOP MCU  and at wakeup reconfigure it ?

It seems to consumes less if not stop periperal.

My sequence is:

             Stop_User_Timer();

             Stop_Measure_Timer();

             SPI_Cmd(LSM303D_SPI, DISABLE);

             I2C_Cmd(S_EEPROM_I2C, DISABLE);

             I2C_Cmd(LPS25H_I2C, DISABLE);

             USART_IO_DeConfig();

    ATOMIC_SECTION_BEGIN(); *******************

    GPIO_LowPower_Config(); 

    SysTick->CTRL = 0; Stop the sys tick to avoid interrupts 

    SysTick_CounterCmd(SysTick_Counter_Clear);

    StartRtcWakeupIrq(RTC_WakeUpSecond);

   //////////////////////////////////////////////////////////////// 

    PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI); 

   //////////////////////////////////////////////////////////////// 

    PWR_ClearFlag(PWR_FLAG_WU);        Clear Wake Up flag

 

    StopRtcWakeupIrq();

    RestoreClock32MHzAfterStop();++++++++++++++++++++++

    Clock_Init();    // reconfigure il sysTick

   Restore_GPIO_Config();

    ATOMIC_SECTION_END();**********************

             USART_IO_Config();

             I2C_Cmd(LPS25H_I2C, ENABLE);

             I2C_Cmd(S_EEPROM_I2C, ENABLE);

             SPI_Cmd(LSM303D_SPI, ENABLE);

             Start_Measure_Timer();

             Start_User_Timer();