Skip to main content
Len_Heske
Associate II
March 3, 2026
Solved

Manual Clock Configuration Issue

  • March 3, 2026
  • 8 replies
  • 543 views

Hello,

first let me start this post by mentioning that I'm still very much a beginner.

I'm writing my own abstraction layer functions for the N657X0.

While running my clock_config() function, I ran into an issue that I don't know how to fix. The function works as follows:

- reset RCC->CR, CRGR1, CFGR2

- enable MSI and wait for MSI ready bit

- set CPU & SYS clock source to MSI and wait for clock source confirmation bits

- disable all other oscillators and all PLL

- reset RCC->HSICFGR

- configure HSI

- enable HSI and wait for HSI ready bit

- set CPU & SYS clock source to HSI and wait for clock source confirmation bits

- disable MSI

- reset RCC->MSICFGR

- configure MSI

- enable/disable oscillators (if HSIEN=0 then MSIEN=1 and vice-versa)

- reset RCC->ICxCFGR

- configure ICx

- reset RCC->PLLxCFGRx

- configure PLLx

- enable PLLx and wait for PLLx lock ready bit

- check CPU and SYS clock source selection

- check if source is actually active by checking the corresponding ready bit again

- select CPU and SYS clock sources (IC1 for CPU and IC2 for SYS)

- wait for clock source confirmation bits <- endless wait loop fault here!

 

The fault occurs at the very last link in the chain. I checked the clock source ready bit before when setting the sources to MSI/HSI and it worked then but not at the end. Is my clock_config() logic sound at all?

 

Best answer by Len_Heske

Solved!

Had to enable PLLxPDIV, set PLLxMODSSDIS and PLLxMODSSRST high and PLLxMODDSEN low, as well as enabling ICx - which I had no idea was something you had to enable - through a register somewhere far far into the register list.

For anyone who ever finds themselves in a similar situation, consider the following checklist:

(Whenever I talk about "resetting" a register, do NOT just set it to 0x00000000, but rather the specific default value as stated for each register in RM0486!)

  • reset RCC_CR, leave MSI on (you need two clock sources - HSI & MSI - for clock configuration)
  • wait for ready bits on/off in RCC_SR
  • reset RCC_CFGR1
  • wait for source confirmation bits in RCC_CFGR1
  • configure overdrive pin for higher clock speeds (optional - won't go into detail)
  • switch to MSI inside RCC_CFGR1
  • wait for source confirmation bits in RCC_CFGR1
  • disable HSI
  • wait for ready bits on/off in RCC_SR
  • configure HSI
  • enable HSI
  • wait for ready bits on/off in RCC_SR
  • switch to HSI inside RCC_CFGR1
  • wait for source confirmation bits in RCC_CFGR1
  • disable MSI
  • wait for ready bits on/off in RCC_SR
  • configure MSI
  • enable MSI (optional. we are done using it to configure HSI)
  • (wait for ready bits on/off in RCC_SR)
  • disable all ICx through RCC_DIVENCR
  • configure PLLx (stick to integer mode if you don't know much about the other modes!)
    • reset RCC_PLLxCFGRx (1,2,3)
    • select oscillator (f_osc >= 5MHz so you can't use MSI in 4MHz mode!)
    • set DIVM (f_DIVMout <= 50MHz)
    • set DIVN (f_DIVNout <= 3200MHz)
    • clear RCC_PLLxCFGR2 (has to be empty for integer mode)
    • enable PLLxPDIV
    • set PLLxPDIV1 & PLLxPDIV2 to 1
    • set PLLxMODSSDIS high
    • set PLLxMODSSRST high
    • set PLLxMODDSEN low (as well as other unused bits)
    • either enable or bypass PLLx with PLLxON in RCC_CR or PLLxBYP in RCC_PLLxCFGR1
    • wait for ready bits on/off in RCC_SR
  • configure ICx through RCC_ICxCFGR
    • reset RCC_ICxCFGR
    • select PLLx
    • select division factor
    • enable ICx through RCC_DIVENSR
  • reset RCC_CFGR2
  • configure TIMPRE, HPRE and PPREx (1,2,4,5)
  • select final clock source in RCC_CFGR1
  • wait for source confirmation bits in RCC_CFGR1

Hope this helps!

Kind regards

Len

8 replies

mƎALLEm
Technical Moderator
March 3, 2026

Hello,

As you are a beginner, I suggest you to use the HAL + CubeMx at the first time at least to inspire from the implementation.

PS: I'm not forcing you to use the HAL. I'm just suggesting you to accelerate the process, to understand the register configuration sequence and do some debug from your side.

"To give better visibility on the answered topics, please click on ""Accept as Solution"" on the reply which solved your issue or answered your question."
Len_Heske
Len_HeskeAuthor
Associate II
March 3, 2026

Hello @mƎALLEm,

thank you for your answer :)

Are you suggesting I should look at the HAL function code for inspiration? I should do that. Otherwise, I don't want to use HAL for my projects. I'm writing my own abstraction layer as a way to learn and as a hobby.

I'm using CubeMX only by looking at its clock config UI. The UI helps me understand how the oscillators and clock sources work. But I don't use CubeMX to setup my projects. I started with a bare bone main.c with nothing but the main function.

I'm wondering though, if you are seeing any glaring issue with my config logic? I'm not asking for help in regards to code fixing, just whether the overall logic is sound or not.

Thank you and kind regards,

Len

mƎALLEm
Technical Moderator
March 3, 2026

I was anticipating that reply from you and that's why I said:

"PS: I'm not forcing you to use the HAL. I'm just suggesting you to accelerate the process, to understand the register configuration sequence and do some debug from your side. "

I know you need to do it yourself but N6 is a complex product especially for beginners.  So what I suggest is to start with HAL and inspire from it. May be you find the answers there..

"To give better visibility on the answered topics, please click on ""Accept as Solution"" on the reply which solved your issue or answered your question."
Danish1
Lead III
March 3, 2026

What values do you actually get in the clock source confirmation bits? And in other RCC registers?

Could you share your code? You describe yourself as a beginner. It is possible you've made a mistake e.g. in your bitwise operations looking for the confirmation bits

Len_Heske
Len_HeskeAuthor
Associate II
March 3, 2026

Hello @Danish1 and @TDK ,

thank you very much for your answers!

Should I send the entire code, i.e. my main.c and my library? Or just the function in question? I work with a lot of structs, so I'm concerned about the readability of it.

I attached a file with the function in question and some comments. I have no idea what a good code should look like so I'm sorry if it's ugly :D

 

Btw, this is the definition of the clear() function if you think it could be the culprit:

void clear(volatile uint32_t*reg, unsigned bit, unsigned pos)
{

    *reg &= ~(((high<<bit)-high)<<pos);
}

 

Kind regards,

Len

TDK
Super User
March 3, 2026

> The function works as follows: 

Why not show the function itself?

Only translation errors can be introduced by paraphrasing what it's doing.

"If you feel a post has answered your question, please click ""Accept as Solution""."
waclawek.jan
Super User
March 3, 2026

I am not familiar with the 'Nx.

Are you running from FLASH? Do you set FLASH waitstates according to the system frequency?

Also, while others call for showing code, I'd recommend to read out and check/post content of relevant registers.

JW

Len_Heske
Len_HeskeAuthor
Associate II
March 10, 2026

Hello @waclawek.jan ,

I took some time to read up on what you said.

In development mode, I load my FSBL program from my debug PC straight into the internal SRAM of the microcontroller. The N657 does not have internal flash memory like other µc. Instead, the programs are loaded into the internal SRAM either from external Octo-SPI flash memory in flash mode or from a debug PC in development mode through an ST-Link connection. The latter making the program not persistent, as I already noticed myself.

So in conclusion, it is never the goal to run a program from flash memory but to always load it into the SRAM before execution. Which is either done through ST-Link or the BootROM, but - as far as I know - not by the user.

Since the program is always loaded into SRAM before execution, memory bus configuration and flash wait states are not relevant, I think...

Kind regards

Len

TDK
Super User
March 3, 2026

You should be more deliberate when changing RCC register values to avoid invalid intermediate states. For example:

reset(&rcc.CR);

This cannot clear the CR register as that would stop all clocks. The CPU needs a clock to run. The hardware is smart enough to avoid letting you do this, but you shouldn't rely on that. The state of CR after this operation is (a) definitely not 0 and (b) dependent upon the current clock configuration.

> RCC_SR_PLL1RDY_Msk

Are these the bits not being set? If so, there's probably a misconfiguration issue. Looking at the RCC register values as @waclawek.jan suggests at the time the issue occurs is probably the best approach to debugging.

I don't see wait states being set anywhere in here. Could have missed it.

The checks done in HAL_RCC_OscConfig are done deliberately to ensure the system transitions smoothly to the target state. Your code will need to do the same, or need to ensure the starting state is always the same.

"If you feel a post has answered your question, please click ""Accept as Solution""."
Len_Heske
Len_HeskeAuthor
Associate II
March 5, 2026

Hello @TDK ,

sorry for the very late reply. I couldn't look into it very much the last few day as I didn't have much time.

First of all thank you very much for your reply! :)

Just so you know, the reset() function doesn't clear the register. It only writes the default reset condition word - as specified in the manuals - into that register. Every register has a reset word and the structs "[REFERENCE].[REGISTER_NAME]" (like "rcc.CR" or "a.MODER" for GPIOA) contain a register pointer and the specific reset word like 0x00000008. These writes should not violate any rules as they essentially don't change anything and just make sure the register is in its default state.

RCC_SR_PLL1RDY_Msk

^This is a ST specific mask that I didn't create but is instead a standard constant in the ST libraries. Same goes for any constant names similar to this. There are three types: (1) no ending for single bits or bit position "_0", "_1", "_[n]" to indicate a high bit in that position, (2) "_Msk" ending to indicate a mask for that bit segment (relevant if mask is more than one bit) and (3) "_Pos" ending to indicate the starting position of the segment. As these are ST constants, I'm very confident that they are not a problem or could cause any issues.

HAL_RCC_OscConfig

Thank you for suggesting this HAL function. I'll look into it and see if I can check its source code for more information.

I generally cleaned up my code a bit and improved and expanded the error information on return for better troubleshooting. I'll keep you updated and post a fix if I can find it so that I may close this case. I'm always open and glad for more feedback and suggestions. I'm still a beginner after all and need to learn a lot.

Kind regards,

Len

waclawek.jan
Super User
March 10, 2026

> The N657 does not have internal flash memory like other µc.

Oh. OK, learned that, thanks.

JW

LCE
Principal II
March 11, 2026

I recently checked the N6, and oh my - what a beast, especially the clock configuration.

I'm also a big fan of NOT using STM's HAL, but as said before: at least use it for "inspiration" how this is set up.

Len_Heske
Len_HeskeAuthorBest answer
Associate II
March 12, 2026

Solved!

Had to enable PLLxPDIV, set PLLxMODSSDIS and PLLxMODSSRST high and PLLxMODDSEN low, as well as enabling ICx - which I had no idea was something you had to enable - through a register somewhere far far into the register list.

For anyone who ever finds themselves in a similar situation, consider the following checklist:

(Whenever I talk about "resetting" a register, do NOT just set it to 0x00000000, but rather the specific default value as stated for each register in RM0486!)

  • reset RCC_CR, leave MSI on (you need two clock sources - HSI & MSI - for clock configuration)
  • wait for ready bits on/off in RCC_SR
  • reset RCC_CFGR1
  • wait for source confirmation bits in RCC_CFGR1
  • configure overdrive pin for higher clock speeds (optional - won't go into detail)
  • switch to MSI inside RCC_CFGR1
  • wait for source confirmation bits in RCC_CFGR1
  • disable HSI
  • wait for ready bits on/off in RCC_SR
  • configure HSI
  • enable HSI
  • wait for ready bits on/off in RCC_SR
  • switch to HSI inside RCC_CFGR1
  • wait for source confirmation bits in RCC_CFGR1
  • disable MSI
  • wait for ready bits on/off in RCC_SR
  • configure MSI
  • enable MSI (optional. we are done using it to configure HSI)
  • (wait for ready bits on/off in RCC_SR)
  • disable all ICx through RCC_DIVENCR
  • configure PLLx (stick to integer mode if you don't know much about the other modes!)
    • reset RCC_PLLxCFGRx (1,2,3)
    • select oscillator (f_osc >= 5MHz so you can't use MSI in 4MHz mode!)
    • set DIVM (f_DIVMout <= 50MHz)
    • set DIVN (f_DIVNout <= 3200MHz)
    • clear RCC_PLLxCFGR2 (has to be empty for integer mode)
    • enable PLLxPDIV
    • set PLLxPDIV1 & PLLxPDIV2 to 1
    • set PLLxMODSSDIS high
    • set PLLxMODSSRST high
    • set PLLxMODDSEN low (as well as other unused bits)
    • either enable or bypass PLLx with PLLxON in RCC_CR or PLLxBYP in RCC_PLLxCFGR1
    • wait for ready bits on/off in RCC_SR
  • configure ICx through RCC_ICxCFGR
    • reset RCC_ICxCFGR
    • select PLLx
    • select division factor
    • enable ICx through RCC_DIVENSR
  • reset RCC_CFGR2
  • configure TIMPRE, HPRE and PPREx (1,2,4,5)
  • select final clock source in RCC_CFGR1
  • wait for source confirmation bits in RCC_CFGR1

Hope this helps!

Kind regards

Len