Reputation: 41
I am trying to turn the led (LD2 in schematic) inside the nucleo board on using only registers with the STM32CubeIDE.
The user manual states the following addresses for the clock, mode and data registers:
Led pin: PA5
Address of the Clock control register: RCC_AHBENR
[base address] + [offset] ===> [Result]
0x4002 1000 + 0x14 ===> 0x40021014
Address of the GPIOA mode register
0x4800 0000 + 0x00 ===> 0x48000000
Address of the GPIOA output data register
0x4800 0000 + 0x14 ===> 0x48000014
I am using the following code to set/clear the registers in the board:
#include <stdint.h>
int main(void)
{
uint32_t *pClkCtrlReg = (uint32_t*)0x40021014;
uint32_t *pPortAModeReg = (uint32_t*)0x48000000;
uint32_t *pPortAOutReg = (uint32_t*)0x48000014;
//1. enable the clock for GPIOA peripheral in the AHBENR
*pClkCtrlReg |= 0x00020000;
//2. configure the mode of the IO pin as output
//a. clear the 24th and 25th bit positions
*pPortAModeReg &= 0xFCFFFFFF;
//b set 24th bit position as 1
*pPortAModeReg |= 0x01000000;
//3. SET 12th bit of the output data register to make I/O pin-12 as HIGH
*pPortAOutReg |= 0x20;
while(1);
}
Using the register viewer from the IDE, I can see that the PA5 is set as output, but physically, my led is not turning on.
I do not know what I am doing wrong. I am suspecting that the pin PA5 is wrong, but i tried PA12 too and it does not work. Can someone please help me out here?
Upvotes: 3
Views: 1886
Reputation: 66
A few comments on your code:
volatile
keyword when accessing peripheral registers. Otherwise the compiler may end up optimizing out your code. I usually make a typedef for something like a reg32_t type in order not to forget.(1 << b)
to make it obvious which bit(s) you are referencing. Your compiler will optimize this, so the end result in the compiled code will be the same. You could even consider making this into a couple of macros or inline functions.Here's your code with these changes:
#include <stdint.h>
typedef volatile uint32_t reg32_t;
int main(void)
{
reg32_t *pClkCtrlReg = (reg32_t*)0x40021014;
reg32_t *pPortAModeReg = (reg32_t*)0x48000000;
reg32_t *pPortABsrReg = (reg32_t*)0x48000018;
//1. enable the clock for GPIOA peripheral in the AHBENR
*pClkCtrlReg |= (1<<17);
//2. configure the mode of the IO pin as output
uint32_t modereg = *pPortAModeReg & ~(3<<(2*5));
modereg |= (1<<(2*5));
*pPortAModeReg = modereg;
//3. SET 5th bit of the bit set/reset register to make I/O pin 5 HIGH
*pPortABsrReg = (1<<5);
// If you want to turn the LED back off at a later time, do this:
// *pPortABsrReg = (1<<(5+16));
for (;;) ;
}
Good luck with your blinky!
Upvotes: 3
Reputation: 1525
I ran through your code with reference manual in hand. RM0316 STM32F303 Reference manual.
You activate clock to GPIO Port A correctly (also, GPIOA registers would also read all 0x00 is it hadn't been activated).
Then you set GPIO mode as, quoting you:
//2. configure the mode of the IO pin as output
//a. clear the 24th and 25th bit positions
*pPortAModeReg &= 0xFCFFFFFF;
//b set 24th bit position as 1
*pPortAModeReg |= 0x01000000;
You work with bits 24 and 25. Which are these:
So you set the mode for pin A12, not A5. For GPIOA Pin 5 you need to manipulate bits 10 and 11.
//clear pin5 bits
*pPortAModeReg &= ~(0x03 << 10); //take 0b11, shift it to position 10, flip all bits, AND with original state of register
And follow it with setting those bits to "General purpose output mode" 01, which you also do for wrong bits:
//b set 10th bit position as 1
*pPortAModeReg |= (0x01 << 10);
I checked all the registers GPIO has, there shouldn't be anything else you need to set. If things still don't work, please post the contents of all GPIOA registers.
EDIT: also, try using bit set/reset registers. Note that they are read only, so no "|=" for them, only "=". Writing 0 to them doesn't do anything. So you need to write only (0x01<<5) straight to the GPIOA BSRR register.
GPIOA->BSRR = (1U<<5); //or however you want to address that register
Upvotes: 3
Reputation: 189
//3. SET 12th bit of the output data register to make I/O pin-12 as HIGH
*pPortAOutReg |= 0x20;
for PIN 12, the value should be *pPortAOutReg |= 0x1000;
Or you could do as following:*pPortAOutReg |= (1 << 12);
With this you don't need to know excactly value.
Upvotes: 0