cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L073RZT6: Incorrect Systick Frequency?

Mahmoud Sherrah
Associate II
Posted on April 21, 2018 at 21:46

Hello all. I am new to STM paradigm. I have a Nucleo 64 STM32L073RZT6 64 PINS board.

I was trying to configure the Systick timer, however it seems that the input Systick frequency is always divided by 2.

I am using the on-board 8MHz external crystal (which is originally used by the ST-Link interface) but the board marking that I have is MB1136 C-04. According to the hardware pdf, it means that the HSE input of the microcontroller is actually the 8MHz crystal of ST-Link.

Here is my PLL configuration (please read the comment maybe I missed something obvious):

RCC->CR |= (1 << 16); //HSE on 8mhz

RCC->CFGR |= (1 << 22); //PLL out div by 2

RCC->CFGR |= (1 << 0) | (1 << 1); //Select Sysclck as PLL

RCC->CFGR &= (~(1 << 7)); //clear bit 7 for AHB prescaler = 1

RCC->CFGR &= (~(1 << 10)); //clear bit 10 for APB1 prescaler = 1

RCC->CFGR &= (~(1 << 13)); //clear bit 13 for APB2 prescaler = 1

RCC->CFGR |= (1 << 16); //PLL source is HSE

RCC->CFGR |= (1 << 18) | (1 << 19); //PLL multuplier = 8 (i.e 8mhz hse * 8 = 64 div by 2 = 32 Sysclck maximum)

RCC->CR |= (1 << 24); //PLL on

while((RCC->CR & (1 << 25)) == 0); //wait for PLL ready

SystemCoreClockUpdate(); //SystemCoreClock variable is 32Mhz (confirmed by debugger)

And then here is my Systick configuration:

SysTick->CTRL = 0;

SysTick->LOAD = 31999; //Systick clock/1000 - 1 for 1ms systicks interrupt

NVIC_SetPriority(SysTick_IRQn, (1<<__NVIC_PRIO_BITS) -1);

SysTick->VAL = 0;

SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk; //choose full AHB as source clock (no div by 8)

SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;  //enable interrupt

SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //Enable systick

I am getting a 2ms interrupt instead of 1ms. I checked the PLL clock divider in RCC-CFGR and it was indeed 0 (i.e. no division). There has to be a division by 2 somewhere that I am missing. My reference is the STM32CubeMX Clock Configuration and of course the datasheet.

0690X0000060AiCQAU.png

I don't really know where else the problem could be. Any help would be appreciated!

#stm32l073rz #nucleo-l073 #systick-config #systick-timer #systick #stm32-systick
1 ACCEPTED SOLUTION

Accepted Solutions
Mahmoud Sherrah
Associate II
Posted on April 22, 2018 at 19:37

Success! It seems that Option B was the closest to what I wanted, so I randomly added 4 __NOP() before calling

SystemCoreClockUpdate() and this did the trick! (3 nops didnt work. I started from 1000 nops and went down to 4, binary search style xD)

I tried to do this with Option A (32MHz with Bypass) but it didn't work.

I guess I reached a point where my application is running as expected (4 nops is worth it). But I will investigate more once I have an oscilloscope handy.

View solution in original post

9 REPLIES 9
Posted on April 22, 2018 at 12:32

Try using HSE BYPASS mode

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
henry.dick
Senior II
Posted on April 22, 2018 at 15:57

'

There has to be a division by 2 somewhere that I am missing. '

check to see what value SystemCoreClock takes, and go from there.

'My reference is the STM32CubeMX'

with CubeMX, anything is possible,

take out the PLL register values and see if anything is unexpected.

Mahmoud Sherrah
Associate II
Posted on April 22, 2018 at 19:18

Ok guys, really weird things happening right now...

A- Using Bypass mode and PLL multiplier 8 to get 32MHz: SystemCoreClock = 8191 Hz!! (NOK)

Running the program directly (i.e. without any breakpoints), program goes to infinite loop! Stepping into 

SystemCoreClockUpdate(), the multiplier and divider local variables are read as zeros, even though the registers are correctly set (viewed by the debugger). This results in a division by zero and program goes into infinite loop.

B- Using Bypass mode and PLL multiplier 6 to get 24MHz: SystemCoreClock = 24 MHz (OK)

Running the program directly (i.e. without any breakpoints), program also goes to infinite loop! 

However, stepping into 

SystemCoreClockUpdate() gives valid values and continuing the program after calculation of SystemCoreClock = 24MHz, the program runs fine and a correct Systick Reload value of 23999 gives a correct 1ms interrupt!

C- Without Bypass mode and PLL multiplier 8 to get 32MHz: SystemCoreClock = 32 MHz (OK)

Running the program directly (i.e. without any breakpoints), no infinite loop happens but the original problems stays (2ms interrupt instead of 1ms using Systick Reload value of 31999)

D- Without Bypass mode and PLL multiplier 6 to get 24MHz: SystemCoreClock = 24 MHz (OK)

Same as point C! Running the program directly (i.e. without any breakpoints), no

infinite loop happens but the original problems stays (2ms interrupt instead of 1ms 

using Systick Reload value of 23999

)
Mahmoud Sherrah
Associate II
Posted on April 22, 2018 at 19:37

Success! It seems that Option B was the closest to what I wanted, so I randomly added 4 __NOP() before calling

SystemCoreClockUpdate() and this did the trick! (3 nops didnt work. I started from 1000 nops and went down to 4, binary search style xD)

I tried to do this with Option A (32MHz with Bypass) but it didn't work.

I guess I reached a point where my application is running as expected (4 nops is worth it). But I will investigate more once I have an oscilloscope handy.

Posted on April 22, 2018 at 17:48

I tried to used HSE bypass mode and result is absolutely random. For example, if I flash and run continuously, it crashes. If I step over the code, it crashes on calling of SystemCoreClockUpdate(). If I step into 

SystemCoreClockUpdate, it finished fine but if I run application after it, it crashes.

I'm not really sure about the function of HSE bypass anyway. There is an on-board XTAL which drives ST-Link and it also is the HSE of the microcontroller in case of my hardware version of the board. Is your suggestion mandatory or like a workaround?

If you can provide more info about HSE and bypass mode would be much appreciated!

Posted on April 22, 2018 at 17:54

Well the usual configuration is that the ST-LINK outputs 8 MHz via it's MCO pin and that feeds the HSE-IN of target. BYPASS is supposed to be used in these cases, so it doesn't generate an HSE-OUT signal. Different STM32 behave differently the L152 seems to expect BYPASS mode where as F407 doesn't seem to care, and the L07x has issues with clocks >= 32 MHz

If you're going to use register level programming you're going to want to pull the settings back out and decode them, and confirm they produce the PLL multiplication/division you expect.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on April 22, 2018 at 17:57

SystemCoreClock

 is 32MHz, confirmed by the debugger. 

RCC registers read by debugger also confirm that

SystemCoreClock

 is

 32MHz.

I am only using STM32CubeMX as reference for the 'clock tree'. (everything is barebones, no generated code used).

Do you think the constant CALIB register has something to do with this? Quote from datasheet:

12.2 SysTick calibration value register

The SysTick calibration value is fixed to 4000, which gives a reference time base of 1 ms

with the SysTick clock set to 4 MHz (max HCLK/8).

Does this mean that CALIB overrides the value in LOAD in Systick module?

Posted on April 22, 2018 at 18:04

Aha, so I think that Bypass is mandatory in this case. Also I am running my STM32L073RZT6 on its maximum frequency which is 32MHz, maybe it's pushing it too much and the hardware divides the clock by least possible divider which is 2. Hence the 2ms interrupt instead of 1ms.

I'll try to decrease my system clock speed (with and without bypass) and report back.

Posted on April 22, 2018 at 18:10

No, it means CALIB holds an implementation specific value that might be equivalent to 1ms, not sure ST defines a helpful value here, but if it did you could read CALIB constant and write to LOAD to achieve 1ms. Likely more valuable on an SoC implementation where speeds are known and fixed by the design.

Right now you likely want to export internal clocks via MCO to confirm HSE, PLL, etc are at expected rates.

The value in SystemCoreClock in many cases a constant, and not recomputed unless SystemCoreClockUpdate() or equivalent function is called to do so. The behaviour you report suggests SystemCoreClock does not reflect reality.

You'll need to dump register settings here for others to be able to tell if they seem correct.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..