2023-03-02 01:11 PM
Hi, I am trying to use an external frequency to drive my STM32F303RE, using a nucleo board (NUCLEO-F303RE). There is a lot of confusion going on right now.
First of all, I was provided a nucleo board with an external oscillator that was already soldered on there. But to use the oscillator, I DISABLE the HSEBYP bit in my code. The reference manual states for this bit:
0: HSE crystal oscillator not bypassed
1: HSE crystal oscillator bypassed with external clock
I would think I need to set the bit to 1 to see the external oscillator frequency (24 MHz) and not the HSE frequency (8 MHz). But when I set the bit to 1 (RCC->CR |= RCC_CR_HSEBYP;) I see the HSE is not bypassed and the microcontroller uses the provided 8 MHz clock. If I set the bit to 0 (RCC->CR &=~ RCC_CR_HSEBYP; ) is see the 24 MHz user external oscillator as a result.
Also I noticed that the bit has no impact on a microcontroller on a nucleo board, where no external oscillator is soldered. According the the Nucleo Datasheet, there are a few solder bridges to remove, in order to use the external oscillator. Even with those solder bridges adjusted in the way the datasheet states, playing around with the HSEBYP bit is giving me weird results.
I would expect that on a Nucleo with no external oscillator and with the solder bridges set up for an external oscillator, I would not get a working code when I try to bypass the HSE (since there is just no clock provided). But in this case, the HSEBYP bit just changes the "frequency stability". If the bit is set, I have my 8 MHz. If the bit is deleted, I see 7.57 Mhz. This indicates, that in the HSEBYP=1 case I use the HSE but when I set it to 0, the microcontroller tries to find an external oscillator, does not find one and uses HSI or something, which is not exactly 8 MHz. And if this is the case, it would endorse the fact that I have to set the HSEBYP to 0 to bypass the HSE, as described above.
Then there is the whole HSERDY story. The HSERDY bit description from the reference manual states:
0: HSE oscillator not ready
1: HSE oscillator ready
After choosing the HSEBYP bit, I enable the HSE (RCC->CR |= RCC_CR_HSEON;) and then I wait for the HSERDY bit to become 1 (while !(RCC->CR & RCC_CR_HSERDY);). If I am not using an external oscillator and all solder bridges are default (brand new nucleo board), the code has no problems at this point, regardless of the HSEBYP bit (which doesn’t do anything). If I use my provided nucleo board with an external oscillator on there, the code only works if I choose the external oscillator (24 MHz, HSEBYP = 0). Waiting for the HSERDY bit does not work, if I want to use the HSE. Weirdly enough, I can still use the HSE (even though I soldered an external oscillator and the HSERDY bit is not set) if I just don’t wait for the HSERDY bit.
Last case: If I have the solder bridges set up for an external oscillator but there is none, the HSERDY flag is never set, regardless of the HSEBYP bit. So kinda what I was expecting but I am still able to use the HSE if I just ignore the HSE flag?!
This brings us to my actual problem. I am trying to use the system clock of one microcontroller via the MCO output on pin PA8 as an OSC_IN input at the next microcontroller on pin PF0 to synchronize the microcontrollers. My idea was to use the OSC_IN pin while the OSC_OUT pin is not used and left in HIGH-Z state, just as the data sheet describes. But when I try to read the input frequency on the OSC_IN pin by setting the HSE up to bypass mode, nothing really happens. I see 8 MHz and not the 4 MHz, I put on OSC_IN for testing purposes.
I gave my best to make this as little confusing as possible, I'd be grateful for answers!
Solved! Go to Solution.
2023-03-06 07:25 AM
Okay i figured it out.
I was confused by what HSE actually is. It is either an external oscillator or an external clock. I had the solder bridges configured for an HSE oscillator instead of HSE clock.
Here is my code that works just fine:
Code for nucleo 1 which is giving out its HSI clock on PA8 as MCO:
RCC->AHBENR |= RCC_AHBENR_GPIOAEN; //activate peripheral clock
GPIOA->MODER |= GPIO_MODER_MODER8_1; //PA8 in alternate function mode
GPIOA->PUPDR |= GPIO_PUPDR_PUPDR8_1; //pull down resistor
GPIOA->OSPEEDR |= 0b11<<16; //GPIO speed
GPIOA->AFR[1] &= ~0xF<<0; //select alternate function
RCC->CFGR |= RCC_CFGR_MCOPRE_DIV1; //MCO predivider
RCC->CFGR |= RCC_CFGR_MCO_HSI; //choose clock used as MCO
Code for nucleo 2 which is receiving the clock input and giving it to the PLL to achieve 72 MHz system frequency:
RCC->CR &= ~RCC_CR_HSEON; //turn off HSE clock (8MHz)
while (RCC->CR & RCC_CR_HSERDY); //wait until HSE is off
RCC->CR |= RCC_CR_HSEBYP; //HSE bypassed (external clock)
//RCC->CR &= (~1U << 18); //HSE not bypassed (external oscillator)
RCC->CR |= RCC_CR_HSEON; //turn on HSE clock (8MHz)
while (!(RCC->CR & RCC_CR_HSERDY)); //wait until HSE is ready
FLASH->ACR &= ~0b111; //clear latency bits
FLASH->ACR |= 0b1<<1; //set latency, this is important if operating the microcontroller with higher frequencies then 24 MHz!
RCC->CR &=~ RCC_CR_PLLON; //disable PLL
while(wait < 2000){ //wait until PLLRDY bit is cleared
wait ++;
}
wait = 0;
RCC->CFGR &= ~0b11<<15; //clear PLL source bits
RCC->CFGR |= RCC_CFGR_PLLSRC_HSE_PREDIV; //HSE as PLL source, not predivided
RCC->CFGR |= RCC_CFGR_PLLXTPRE_HSE_PREDIV_DIV1; //HSE not predivided before PLL
RCC->CFGR |= RCC_CFGR_PLLMUL9; //PLL multiplier, PLL must not exceed 72MHz
RCC->CR |= RCC_CR_PLLON; //enable PLL
while(!(RCC->CR && RCC_CR_PLLRDY)); //wait until PLLRDY bit is set
RCC->CFGR |= RCC_CFGR_SW_PLL; //switch the system clock to PLL
while (!(RCC->CFGR & RCC_CFGR_SWS_PLL)); //wait until sys clk = PLL
2023-03-02 01:50 PM
The board has a external crystal oscillator (XO, TCXO) soldered down, or a crystal and capacitors were placed/populated in the board locations provided?
Normally an 8 MHz singled end feed comes from the ST-LINK MCU to the OSC_IN of the Target STM32F3xx
The HSEBYP primarily determines whether the internal inverter that outputs to OSC_OUT is enabled, or not.
>>I would think I need to set the bit to 1 to see the external oscillator frequency (24 MHz) and not the HSE frequency (8 MHz).
Where would the 8 MHz be coming from in this scenario? There should only be this 24 MHz CMOS clock.
If you change the frequency on the input the HSE_VALUE define and the PLL settings would need to change to reflect that.
>> I see 8 MHz and not the 4 MHz, I put on OSC_IN for testing purposes.
Where would this come from? Unless you've got other circuits connected?
2023-03-03 08:29 AM
Thanks for your response! I realized that I have been looking at it all wrong the whole time. HSE means EITHER to solder an oscillator on the board OR to provide a clock on OSC_IN (right?). My code was using HSE and fed it into the PLL to create a 72 MHz frequency. It also worked on boards without an external oscillator. Also I used the HSE as a system clock before and got my 8 MHz. But now I have no idea where those 8 MHz are coming from. I would asume those 8 MHz were then coming from the HSI? Anyway, I was initializing a HSE that was not existing so I was getting unexpected results.
Yes, I have other circuits connected. I connected a cable from one board to the other, where the first is giving me 4 MHz and the second is receiving it on OSC_IN. The jumpers of the second board are configured for HSE. My code is doing what the reference manual tells me to:
"External source (HSE bypass)
[...] Select this mode by setting the HSEBYP and HSEON bits in the Clock control
register (RCC_CR). The external clock signal [...] has to drive the OSC_IN pin while
the OSC_OUT pin can be used a GPIO. "
I set both bits and connected a 4 MHz 50% duty cycle timer to the OSC_IN pin, PF0. When I try to run the code, it gets stuck where it waits for the HSE to get ready (while (!(RCC->CR & RCC_CR_HSERDY));).
Do you maybe also know what the problem here could be?
2023-03-06 07:25 AM
Okay i figured it out.
I was confused by what HSE actually is. It is either an external oscillator or an external clock. I had the solder bridges configured for an HSE oscillator instead of HSE clock.
Here is my code that works just fine:
Code for nucleo 1 which is giving out its HSI clock on PA8 as MCO:
RCC->AHBENR |= RCC_AHBENR_GPIOAEN; //activate peripheral clock
GPIOA->MODER |= GPIO_MODER_MODER8_1; //PA8 in alternate function mode
GPIOA->PUPDR |= GPIO_PUPDR_PUPDR8_1; //pull down resistor
GPIOA->OSPEEDR |= 0b11<<16; //GPIO speed
GPIOA->AFR[1] &= ~0xF<<0; //select alternate function
RCC->CFGR |= RCC_CFGR_MCOPRE_DIV1; //MCO predivider
RCC->CFGR |= RCC_CFGR_MCO_HSI; //choose clock used as MCO
Code for nucleo 2 which is receiving the clock input and giving it to the PLL to achieve 72 MHz system frequency:
RCC->CR &= ~RCC_CR_HSEON; //turn off HSE clock (8MHz)
while (RCC->CR & RCC_CR_HSERDY); //wait until HSE is off
RCC->CR |= RCC_CR_HSEBYP; //HSE bypassed (external clock)
//RCC->CR &= (~1U << 18); //HSE not bypassed (external oscillator)
RCC->CR |= RCC_CR_HSEON; //turn on HSE clock (8MHz)
while (!(RCC->CR & RCC_CR_HSERDY)); //wait until HSE is ready
FLASH->ACR &= ~0b111; //clear latency bits
FLASH->ACR |= 0b1<<1; //set latency, this is important if operating the microcontroller with higher frequencies then 24 MHz!
RCC->CR &=~ RCC_CR_PLLON; //disable PLL
while(wait < 2000){ //wait until PLLRDY bit is cleared
wait ++;
}
wait = 0;
RCC->CFGR &= ~0b11<<15; //clear PLL source bits
RCC->CFGR |= RCC_CFGR_PLLSRC_HSE_PREDIV; //HSE as PLL source, not predivided
RCC->CFGR |= RCC_CFGR_PLLXTPRE_HSE_PREDIV_DIV1; //HSE not predivided before PLL
RCC->CFGR |= RCC_CFGR_PLLMUL9; //PLL multiplier, PLL must not exceed 72MHz
RCC->CR |= RCC_CR_PLLON; //enable PLL
while(!(RCC->CR && RCC_CR_PLLRDY)); //wait until PLLRDY bit is set
RCC->CFGR |= RCC_CFGR_SW_PLL; //switch the system clock to PLL
while (!(RCC->CFGR & RCC_CFGR_SWS_PLL)); //wait until sys clk = PLL