‎2021-09-17 02:57 PM
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
Solved! Go to Solution.
‎2021-09-17 03:09 PM
Don't you need to unlock the low power domain before you can change RCC->BDCR ?
‎2021-09-17 03:09 PM
Don't you need to unlock the low power domain before you can change RCC->BDCR ?
‎2021-09-17 03:15 PM
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 :)
‎2021-09-17 03:22 PM
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
‎2021-09-17 03:29 PM
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​ .
‎2021-09-17 03:47 PM
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 (;;);
}
‎2021-09-18 12:22 AM
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
‎2021-09-18 09:34 AM
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!