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!