2024-01-04 01:04 AM - edited 2024-01-04 02:59 AM
Hi.
I am learning how to turn on LED2 of a NUCLEO-G474RE board by using registers (without HAL).
I have created a small project which contains:
// This first block works and updates the registers
// Start GPIOA Clock
(*(uint32_t*)0x4002104C) &= ~(1 << 0); /* AHB2ENR clear */
(*(uint32_t*)0x4002104C) |= (1 << 0); /* AHB2ENR set */
(*(uint32_t*)0x4002102C) &= ~(1 << 0); /* AHB2STR clear */
(*(uint32_t*)0x4002102C) |= (1 << 0); /* AHB2STR set */
// This block doesn't work
// Set mode 10 for GPIOA PIN 5
(*(uint32_t*)0x48000000) &= ~(0x3 << 5 * 2); /* GPIOA MODER clear */
(*(uint32_t*)0x48000000) |= (0x2 << 5 * 2); /* GPIOA MODER set */
// This block doesn't work
// Set GPIOA PIN 5 as HIGH/SET state
(*(uint32_t*)0x48000014) &= ~(1 << 5); /* GPIOA ODR clear */
(*(uint32_t*)0x48000014) |= (1 << 5); /* GPIOA ODR set */
The RCC register to enable clock for AHB2ENR seems to work. I can see the register change. But MODER and ODR registers doesn't seem to change. Could somebody tell me what I am doing wrong?
When I connect to the board with STM32CubeProg I can access the registers and change also AHB2ENR register but not MODER and ODR.
Thanks in advance.
Raúl Pérez
Solved! Go to Solution.
2024-01-04 03:28 AM
Ah, ok.
// (*(uint32_t*)0x4002104C) &= ~(1 << 0); /* AHB2ENR clear - here not necessary */
(*(uint32_t*)0x4002104C) |= (1 << 0); /* AHB2ENR set */
At least the first command is not required because you set the bit afterwards anyway. The same applies to 0x4002102C (which is correctly called AHB2RSTR). Clearing this bit has no effect here either, as you can read in RM0440, section 7.4.9.
I would have to check your settings on my board and compare them with the assembler programme I wrote some time ago using the same approach. I had also realised the clock settings (PLL etc) in assembler, but did not control the pin via ODR, but atomically via GPIOA_BSRR.
I also just realised that you set the alternate function mode (0x02) in MODER and not the general purpose output mode (0x01)?
2024-01-04 01:18 AM - edited 2024-01-04 01:27 AM
Generally, magic numbers do not work. Rewrite your code so that is uses register names and bit names defined in standard vendor-supplied header, then you will see what's wrong.
It looks like you are trying to configure PA5 as output, then to toggle PA10 instead of PA5. Also, you probably keep GPIOA peripheral in reset state so that id doesn't work There is no need to reset it at all.
2024-01-04 01:26 AM - edited 2024-01-04 01:29 AM
I have included the addresses so that anybody can check if the registers of the comments are right. The code should be pretty straight forward. I have checked the addresses multiple times and they seem ok. Even compared them with SFRs register viewer of STM32CubeIDE.
I can see AHB2ENR gets updated by the first part of the code but neither MODER or ODR get updated.
I can actually manually update AHB2ENR by using SFRs registers viewer of STM32CubeIDE. But MODER and ODE registers seem locked...
It is possible there are any other registers on the MCU that prevents these two register get updated?
2024-01-04 01:30 AM
Have you previously enabled the clock for the GPIO?
2024-01-04 01:43 AM - edited 2024-01-04 01:44 AM
I have used this code to enable the clock of GPIOA:
(*(uint32_t*)0x4002104C) &= ~(1 << 0); /* AHB2ENR clear */
(*(uint32_t*)0x4002104C) |= (1 << 0); /* AHB2ENR set */
According to the reference manual RCC register has address 0x40021000 and AHB2ENR register offset: 0x4C that makes 0x4002104C the address to enable the clock for GPIOA which is hanging at AHB2 bus. Is that right?
Sorry I am newbie by using registers. I have been using HAL so far on my projects.
2024-01-04 03:22 AM
I have found out these lines are preventing enabling the clock. After removing them LCK register gets value of 0x00000000 and MODER can be modified. So, I removed the lines:
(*(uint32_t*)0x4002102C) &= ~(1 << 0); /* AHB2STR clear */ (*(uint32_t*)0x4002102C) |= (1 << 0); /* AHB2STR set */
But still cannot see the LD2 working. At least on step ahead...
2024-01-04 03:28 AM
Ah, ok.
// (*(uint32_t*)0x4002104C) &= ~(1 << 0); /* AHB2ENR clear - here not necessary */
(*(uint32_t*)0x4002104C) |= (1 << 0); /* AHB2ENR set */
At least the first command is not required because you set the bit afterwards anyway. The same applies to 0x4002102C (which is correctly called AHB2RSTR). Clearing this bit has no effect here either, as you can read in RM0440, section 7.4.9.
I would have to check your settings on my board and compare them with the assembler programme I wrote some time ago using the same approach. I had also realised the clock settings (PLL etc) in assembler, but did not control the pin via ODR, but atomically via GPIOA_BSRR.
I also just realised that you set the alternate function mode (0x02) in MODER and not the general purpose output mode (0x01)?
2024-01-04 03:37 AM
Oh yes, Correct. It should be MODER5 should have the value 0x01.
The working code looks now like this:
(*(uint32_t*)0x4002104C) &= ~(0x1UL << 0U); /* AHB2ENR clear */
(*(uint32_t*)0x4002104C) |= (0x1UL << 0U); /* AHB2ENR set */
(*(uint32_t*)0x48000000) &= ~(0x3UL << 2U * 5U); /* GPIOA MODER clear */
(*(uint32_t*)0x48000000) |= (0x1UL << 2U * 5U); /* GPIOA MODER set */
(*(uint32_t*)0x48000014) &= ~(0x1UL << 5U); /* GPIOA ODR clear */
(*(uint32_t*)0x48000014) |= (0x1UL << 5U); /* GPIOA ODR set */
Thank you for the help @Peter BENSCH . As a newbie there are still many things to remember and to set correctly :)
2024-01-04 03:40 AM
Always happy to help.
However, you still have line 1 in the code, which you should also remove if you want to optimise as much as possible.
Good luck!
/Peter
2024-01-04 03:44 AM
Oh yes that is right thanks! The next line if forcing the bit to be high anyway. :)