cancel
Showing results for 
Search instead for 
Did you mean: 

stm32f103rb nucleo HSE clock output, no signal

MMatv
Associate II

Dear ST folks,

I'm trying to configure the HSE clock output over PA8 on stm32F103 from scratch.

Here is my code.

  1. #include <stdint.h>
  2. #include "stm32f10x.h" // Device header
  3.  
  4.  
  5. int main (void)
  6. {
  7.  
  8. RCC_TypeDef *pRCC;
  9. GPIO_TypeDef *pGPIOA;
  10. pGPIOA = GPIOA;
  11. pRCC = RCC;
  12. // enable external clock source
  13. pRCC->CR = pRCC->CR | (1 << 16);
  14. // wait for stable clock
  15. while( !(pRCC->CR & (1 << 17)));
  16. // HSE selected as SystemCoreClock
  17. pRCC->CFGR &= ~(0x3 << 0);
  18. pRCC->CFGR |= (0x1 << 0);
  19. // enable clock output HSE
  20. pRCC->APB2ENR |= (0x1 << 2);
  21. // Output MODE bits Maximum output speed 10 MHz
  22. pGPIOA->CRH &= ~(0x1 << 0);
  23. pGPIOA->CRH |= (0x1 << 0);
  24. // CNF8 alternate function output Push-pull
  25. pGPIOA->CRH &= ~(0x3 << 2);
  26. pGPIOA->CRH |= (0x3 << 2);
  27. // HSE clock selected
  28. pRCC->CFGR &= ~(0x3 << 24);
  29. pRCC->CFGR |= (0x6 << 24);
  30.  
  31. return 0;
  32. }

Where is the mistake.

it works with cubemx but this is not a solution for me, I'd like to understand where the problem is.

thank you very much.

regards

Mike

4 REPLIES 4

Learn what HAL/LL are doing, inspect the registers in the working vs not-working cases.

You don't look to select the AF mode for the pin

/**

 * @brief Configure MCO pin (PA8).

 * @param None

 * @retval None

 */

void MCO_ConfigGPIO(void)

{

 /* MCO Clock Enable */

 LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA);

 /* Configure the MCO pin in alternate function mode */

 LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_8, LL_GPIO_MODE_ALTERNATE);

 LL_GPIO_SetPinOutputType(GPIOA, LL_GPIO_PIN_8, LL_GPIO_OUTPUT_PUSHPULL);

 LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_8, LL_GPIO_SPEED_FREQ_HIGH);

}

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
  1. // CNF8 alternate function output Push-pull
  2. pGPIOA->CRH &= ~(0x3 << 2);
  3. pGPIOA->CRH |= (0x3 << 2);

I don't use the 'F1 but my copy of RM0008 says for CNFy[1:0]

11: Alternate function output Open-drain

Stylistics:

What's wrong with using the constants defined in the CMSIS-mandated device header?

  1. pRCC->CFGR &= ~(0x3 << 24);
  2. pRCC->CFGR |= (0x6 << 24);

Why do you clear only 2 bits of that 3-bit bitfield?

I also would recommend against going through intermediate states by first ANDing the register then ORing. Use only one read and one write, either using both AND and OR in one assignment, or use a temporary local variable.

JW

Hello everybody,

thank you for your great support.

I'm doing it without cmsis because of the learning effect.

actually, that works for me.

Alternate function output Push-pull, that was the mistake.

Thank you.

That works for me.

pGPIOA->CRH &= ~(0x3 << 2);

pGPIOA->CRH |= (0x2 << 2);

I also would recommend against going through intermediate states by first ANDing the register then ORing. Use only one read and one write, either using both AND and OR in one assignment, or use a temporary local variable.

@Community member​ 

Could you write an example please?

what is wrong with that?

regards,

Mike

> I'm doing it without cmsis because of the learning effect.

There are many things called CMSIS, some of which have nothing to do with CMSIS (e.g. often people call the older SPL library CMSIS).

I am talking about the device headers, which define values with names roughly matching those used in the RM, e.g.

[CubeF1]\Drivers\CMSIS\Device\ST\STM32F1xx\Include\stm32f103x6.h

You are probably using them already, unless you define your own RCC_TypeDef etc. So why don't you use also the symbols defined there? I know, there are not always defined well and some of them are missing, but still the resulting code is more legible than that using "magic constants", IMO.

Also I don't quite understand why do you define pointers e.g. pGPIOa of the same effective type, and being assigned the same value, as those in this mentioned header, e.g. GPIOA. In other words, what's wrong with

GPIOA->CRH = whatever_value;

?

>> I also would recommend against going through intermediate states by first ANDing the register then ORing.

> what is wrong with that?

Besides probably occupying more code space and resulting in more time spent in execution, the biggest problem is in the intermediate state. E.g. let's assume that the system clock is currently PLL, i.e. RCC_CFGR.SW = 0b10, and you want to use your above code to switch from PLL to HSE

pRCC->CFGR &= ~(0x3 << 0);

pRCC->CFGR |= (0x1 << 0);

that goes through the state where RCC_CFGR.SW = 0b00, i.e. HSI is used as system clock. But what if you've previously switched off HSI, as unused, o spare power? You'd be doomed now, core would lose clock and the execution would stop at that very moment.

And there's no real benefit doing so, or do you thing the following less legible?

pRCC->CFGR = (pRCC->CFGR

& ~(0x3 << 0))

| (0x1 << 0)

;

or

pRCC->CFGR = (pRCC->CFGR

& ~RCC_CFGR_SW_Msk))

| (0b01 << RCC_CFGR_SW_Pos)

;

(RCC is the exception where bitfield constats are defined, so we could've used RCC_CFGR_SW_HSE; but I don't like they are defined in the "already shifted" way).

Style is a personal matter, but maybe there is some merit in things said above.

JW