Journey with STM32 Nucleo Board: 1. Blinking a LED using the C program
Today I have started my journey with the STM32 Nucleo board😃. Obviously, blinking a LED is the first one. Let me share my experience with you all.
Some details about the board:
- Model: STM32F446 Nucleo-64
- Core: Arm 32-bit Cortex — M4
- Memory: 512 Kbytes of Flash memory, 128 Kbytes of SRAM
About the LEDs
There are total 3 LEDs; LD1, LD2, and LD3.
LD2 led is also called User LD2. I was going to blink this one.
LD1 gives the communication status between the STM32 board and my PC.
LD3 led is also known as LD3 PWR. Because it indicates the power status of the board.
**FYI: +5V power is passed to the board.
Dev Environment Setup
First I installed and ran STM32CubeIDE and selected board: NUCLEO-F446RE.
Then I wrote the following final piece of code (Obviously there was a lot of testing, debugging 😊)
This code is self commented and well documented.
#define PERIPH_BASE (0x40000000UL)
// base address of bus AHB1
#define AHB1_OFFSET (0x00020000UL)
#define AHB1_BASE (PERIPH_BASE + AHB1_OFFSET)
// base address of GPIOA port
#define GPIOA_OFFSET (0x00000000UL)
#define GPIOA_BASE (AHB1_BASE + GPIOA_OFFSET)
// base address of RCC module
#define RCC_OFFSET (0x00003800UL)
#define RCC_BASE (AHB1_BASE + RCC_OFFSET)
// base address of AHB1 enable register
#define AHB1EN_R_OFFSET (0x30000000UL)
#define RCCAHB1EN_R (*(volatile unsigned int*)(RCC_BASE+AHB1EN_R_OFFSET))
// base address of GPIOA mode register
#define GPIOAMODE_R_OFFSET (0x0000000UL)
#define GPIOAMODE_R (*(volatile unsigned int*)(GPIOA_BASE+GPIOAMODE_R_OFFSET))
// base address of GPIOA output data register
#define GPIOAOD_R_OFFSET (0x14000000UL)
#define GPIOAOD_R (*(volatile unsigned int*)(GPIOA_BASE+GPIOAOD_R_OFFSET))
// setting explicitly 1 to position 0 of 32 bit register
#define GPIOAEN (1U<<0)
// setting explicitly 1 to position 5 of 32 bit register
#define PIN5 (1U<<5)
#define LED_PIN PIN5
int main (void)
{
//enable clock access to GPIOA
// |(OR) operator is used to
// make specific bit to high
RCCAHB1EN_R |= GPIOAEN;
// set Port A Pin5 as output
// |(OR) operator is used to
// make specific bit to high
// &=~ operator is used to
// make specific bit to low
GPIOAMODE_R |= (1U<<10);
GPIOAMODE_R &=~ (1U<<11);
while(1)
{
// set Port A Pin 5 high
GPIOAOD_R |= LED_PIN;
for(int i=0; i < 100000; i++){}
}
}
I connected my board and downloaded the above program to my board.
Code builds and runs perfectly without any error or warning.
Bam! LED is not blinking! 😟
As you can see in the above image only two LEDs, LD1 and LD3 are ON after loading the code on the board. But, LD2 is not blinking. Which was our main objective.
So, where is the problem?
The LD3 PWR is ON which is indicating that the board is getting +5V input for power. LD1 is also ON which means the initial connection between the board and the PC is done. I tried to understand whether there is any problem with my USB cable or board. USB cable is good as the board is getting power, and board LEDs are working too.
How did I resolve the problem?
One thing still remains, maybe I didn’t define the correct address of LD2. As you know, the destination address should be errorless. I checked my code and found the error on the addresses I defined.
Lesson Learned: Always check the addresses. Typo mistakes might be hiding in plain sight.
Correct code
#define PERIPH_BASE (0x40000000UL)
// base address of bus AHB1
#define AHB1_OFFSET (0x00020000UL)
#define AHB1_BASE (PERIPH_BASE + AHB1_OFFSET)
// base address of GPIOA port
#define GPIOA_OFFSET (0x00000000UL)
#define GPIOA_BASE (AHB1_BASE + GPIOA_OFFSET)
// base address of RCC module
#define RCC_OFFSET (0x00003800UL)
#define RCC_BASE (AHB1_BASE + RCC_OFFSET)
// base address of AHB1 enable register
#define AHB1EN_R_OFFSET (0x00000030UL)
#define RCCAHB1EN_R (*(volatile unsigned int*)(RCC_BASE+AHB1EN_R_OFFSET))
// base address of GPIOA mode register
#define GPIOAMODE_R_OFFSET (0x0000000UL)
#define GPIOAMODE_R (*(volatile unsigned int*)(GPIOA_BASE+GPIOAMODE_R_OFFSET))
// base address of GPIOA output data register
#define GPIOAOD_R_OFFSET (0x00000014UL)
#define GPIOAOD_R (*(volatile unsigned int*)(GPIOA_BASE+GPIOAOD_R_OFFSET))
// setting explicitly 1 to position 0 of 32 bit register
#define GPIOAEN (1U<<0)
// setting explicitly 1 to position 5 of 32 bit register
#define PIN5 (1U<<5)
#define LED_PIN PIN5
int main (void)
{
//enable clock access to GPIOA
// |(OR) operator is used to
// make specific bit to high
RCCAHB1EN_R |= GPIOAEN;
// set Port A Pin5 as output
// |(OR) operator is used to
// make specific bit to high
// &=~ operator is used to
// make specific bit to low
GPIOAMODE_R |= (1U<<10);
GPIOAMODE_R &=~ (1U<<11);
while(1)
{
// set Port A Pin 5 high
GPIOAOD_R |= LED_PIN;
for(int i=0; i < 100000; i++){}
}
}
Voila!!! LD2 is blinking…
About code
It’s really tough to explain all the codes here. Though I have tried to comment on each instruction about their purpose. Still, you have a question? Feel free to ask in the comment.