cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with outputting LSE clock on PA8 pin as MCO

eidetech
Associate II

Hi!

I'm trying to output the LSE clock on the PA8 pin on my Nucleo64 STM32L476 board.

The code I have written is the following:

#include<stdint.h>
 
#define RCC_BASE_ADDR              0x40021000UL
 
#define RCC_CFGR_REG_OFFSET        0x08UL
 
#define RCC_CFGR_REG_ADDR          (RCC_BASE_ADDR + RCC_CFGR_REG_OFFSET )
 
#define GPIOA_BASE_ADDR            0x48000000UL
 
int main(void)
{
	uint32_t *pRccCfgrReg =  (uint32_t*) RCC_CFGR_REG_ADDR;
 
 
	//1. Configure the RCC_CFGR MCOSEL bit fields to select LSE as clock source: 0111: LSE clock selected
	*pRccCfgrReg &=~(0U << 27);
	*pRccCfgrReg |= (1U << 26);
	*pRccCfgrReg |= (1U << 25);
	*pRccCfgrReg |= (1U << 24);
 
	//2. Configure PA8 to AF0 mode to behave as MCO signal
 
	//a ) Enable the peripheral clock for GPIOA peripheral
	// RCC_AHB2ENR
	 uint32_t *pRCCAhb2Enr = (uint32_t*)(RCC_BASE_ADDR + 0x4C);
	*pRCCAhb2Enr |= (1U << 0); //Enable GPIOA peripheral clock
 
	//b ) Configure the mode of GPIOA pin 8 as alternate function mode
// GPIOx_MODER
	uint32_t *pGPIOAModeReg = (uint32_t*)(GPIOA_BASE_ADDR + 0x00UL);
	*pGPIOAModeReg &=~(1U << 16); 	// clear bit 16
	*pGPIOAModeReg |= (1U << 17);  // set bit 17
 
	//c ) Configure the alternation function register to set the mode 0 for PA8
	// GPIOx_AFRH
	uint32_t *pGPIOAAltFunHighReg = (uint32_t*)(GPIOA_BASE_ADDR + 0x24);
	*pGPIOAAltFunHighReg &=~(1U << 0);
	*pGPIOAAltFunHighReg &=~(1U << 1);
	*pGPIOAAltFunHighReg &=~(1U << 2);
	*pGPIOAAltFunHighReg &=~(1U << 3);
 
	uint32_t *pRCC_BDCR = (uint32_t*)(RCC_BASE_ADDR + 0x90);
 
	// Turn on LSE clock (LSEON)
	*pRCC_BDCR |= (1U << 0);
	for (;;);
}

Can anyone see an obvious mistake? Is there something I have forgotten? I have read that the LSE clock might take some time to start, how can I improve my code to get around this?

An observation I have made is that the LSERDY bit is never set to 1, and I suspect this to be the issue. What can cause this bit to always stay 0?

Sincerely,

Marcus

1 ACCEPTED SOLUTION

Accepted Solutions

Don't you need to unlock the low power domain before you can change RCC->BDCR ?

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

View solution in original post

7 REPLIES 7

Don't you need to unlock the low power domain before you can change RCC->BDCR ?

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

That could be, although I have not read anything about it in the RM. How do I unlock the low power domain? I'm new to STM32 :)

Read the description of RCC_BDCR register - it directs you to PWR_CR1.DBP.

Don't forget to enable PWR's clock in RCC.

JW

Ah! Found it, thanks a lot @Community member​ , now I get what you referred to @Community member​ .

What do you mean by "Don't forget to enable PWR's clock in RCC." @Community member​ ?

EDIT:

Nvm, I got it @Community member​ .

eidetech
Associate II

Fantastic! I got it working now that you guys told me how it's done. Thanks a lot for the help both of you.

Here is the final code for anyone stumbling across this post at a later date:

#include<stdint.h>
 
#define RCC_BASE_ADDR              0x40021000UL
#define PWR_BASE_ADDR              0x40007000UL
 
#define RCC_CFGR_REG_OFFSET        0x08UL
 
#define RCC_CFGR_REG_ADDR          (RCC_BASE_ADDR + RCC_CFGR_REG_OFFSET )
 
#define GPIOA_BASE_ADDR            0x48000000UL
 
int main(void)
{
	uint32_t *pRccCfgrReg =  (uint32_t*) RCC_CFGR_REG_ADDR;
 
 
	// 1. Configure the RCC_CFGR MCOSEL bit fields to select LSE as clock source: 0111: LSE clock selected
	*pRccCfgrReg &=~(0U << 27);
	*pRccCfgrReg |= (1U << 26);
	*pRccCfgrReg |= (1U << 25);
	*pRccCfgrReg |= (1U << 24);
 
	// 2. Configure PA8 to AF0 mode to behave as MCO signal
	// 2.1 Enable the peripheral clock for GPIOA peripheral - RCC_AHB2ENR
	uint32_t *pRCCAhb2Enr = (uint32_t*)(RCC_BASE_ADDR + 0x4C);
	*pRCCAhb2Enr |= (1U << 0); //Enable GPIOA peripheral clock
 
	// 2.2 Configure the mode of GPIOA pin 8 as alternate function mode - GPIOx_MODER
	uint32_t *pGPIOAModeReg = (uint32_t*)(GPIOA_BASE_ADDR + 0x00UL);
	*pGPIOAModeReg &=~(1U << 16); 	// clear bit 16
	*pGPIOAModeReg |= (1U << 17);   // set bit 17
 
	// 2.3 Configure the alternation function register to set the mode 0 for PA8 - GPIOx_AFRH
	uint32_t *pGPIOAAltFunHighReg = (uint32_t*)(GPIOA_BASE_ADDR + 0x24);
	*pGPIOAAltFunHighReg &=~(1U << 0); // clear bit 0
	*pGPIOAAltFunHighReg &=~(1U << 1); // clear bit 1
	*pGPIOAAltFunHighReg &=~(1U << 2); // clear bit 2
	*pGPIOAAltFunHighReg &=~(1U << 3); // clear bit 3
 
	// 3. Turn on PWR peripheral clock
	uint32_t *pRCC_APB1ENR1 = (uint32_t*)(RCC_BASE_ADDR + 0x58);
	*pRCC_APB1ENR1 |= (1U << 28);
 
	// 4. Disable backup domain write protection
	uint32_t *pPWR_CR1 = (uint32_t*)(PWR_BASE_ADDR + 0x00);
	*pPWR_CR1 |= (1U << 8);
 
	// 5. Turn on LSE clock (LSEON)
	uint32_t *pRCC_BDCR = (uint32_t*)(RCC_BASE_ADDR + 0x90);
	*pRCC_BDCR |= (1U << 0);
	for (;;);
}

Glad you got it working.

Please select Clive's (Tesla's) post as Best so that thread is marked as solved.

[stylistics]

You may want to change registers' content in one operation rather than bit by bit. Here it does not matter but I'm runtime code it would be rather inefficient.

JW

Good, I have done that now.

In regards to the bit by bit style of programming: I am quite new to bare metal programming, and therefore I find it easier to understand all the operations by splitting them up, and I know that it is not the most efficient way of doing things. I guess I'll combine operations and write more efficient code as I get more familiar with the concepts. But thanks for the heads up anyways!