In this tutorial, I will walk you step by step to blink the LED on the Discovery board. Firstly, let's create a directory for our code. I prefer to put it in my home directory /~

cd ~ && mkdir ~/blink
cd ~/blink

1. Obtain the library

You can get it quickly from my Github repositories:

cd ~/blink
git clone https://github.com/hmchung/STM32F4_DISC_LIB.git

Alternatively, you can download directly from ST website. However, in subsequent parts, you might be required to modify your Makefile according to your library name and directory.

2. Source code

cd ~/blink
mkdir src && cd src

Create the code for LED blinking as main.c

2.1. Include libraries

Firstly, include the neccessary header files so that we can use libraries to access the I/O pins.

#define USE_STDPERIPH_DRIVER
#include "stm32f4xx.h"

2.2. Delay function

Secondly, in order to blink, we have to turn on and off the LED between some waiting intervals. We shall call that a delay function. Here I will borrow the trick from .... This function utilizes the assembly code command 'NOP', which stands for "NO-OP", or "No Operations".

void ms_delay(int ms){
    while (ms-- > 0) {
        volatile int x=5971;
        while (x-- > 0) ("nop");
    }
}

2.3. Main function

Thirdly, we shall write our main program, which runs "forever".

int main(void){
    for (;;) {
        // Do something here
    }
}

2.3.1. Port configuration

But before blinking, we have to let the board knows which LED we are using. For the STM32F4 Discovery board, there are four user LEDs that are connected to I/O pins PD12, PD13, PD14 and PD15. So we shall now configure the pins before running into the forever loop. To do that, we have to allow the clock to access these pins, by setting the 8th bit of clock register RCC_AHB1ENR to 1. We can also use a predefined constant RCC_AHB1ENR_GPIODEN for our convenience.

RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
__asm("dsb");

2.3.2. Pin configuration

Next, within port D, we want to set the I/O mode of the pins to "general purpose output mode". This requires setting a 01 to each pair of configuration bits corresponding to the pins. According to documentation, in order to set mode for pins PD12 to PD15, we will need to set 01010101 for bits 24 to 31 of GPIO->MODER. Since 01010101 is 85 in decimal, we can just use a bit shift operation, as following

GPIOD->MODER = 85 << 24;

2.3.3. Write value to pins

Let's say we want our LEDS to blink on and off every second. That requires a toggle every (delay of) 1000 ms. Firstly, in order to set the value to a pin, we set the corresponding bit in the register GPIOD->ODR. To turn on, we set value 1 to bits 12 to 15 and vice versa. In order to toggle the pin values, I use XOR operation (^=). Again, since 1111 is 15 in decimal, I use the bit shift trick as following.

GPIOD->ODR ^= (15 << 12);
ms_delay(1000);

2.4. Wrap up

If you follow correctly, your whole piece of code should now look like this

#define USE_STDPERIPH_DRIVER
#include "stm32f4xx.h"

// 1ms second delay
void ms_delay(int ms){
    while (ms-- > 0) {
        volatile int x=5971;
        while (x-- > 0) ("nop");
    }
}

int main(void)
{
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;  // enable the clock to GPIOD
    __asm("dsb");                         // wait till finished setup
    GPIOD->MODER = 85 << 24;
    for (;;) {
        GPIOD->ODR ^= 15 << 12;     // toggle the pins
        ms_delay(1000);
    }
}

3. Makefile

Create a Makefile in our working directory

cd ~/blinky
nano Makefile

I will not bore you further with explanations, since the comments in the Makefile already make it self-explanatory.

# Binary firmware name
FW_NAME = blinky

# Source code file
SRCS = main.c

# Libraries
STM32F4_LIB_DIR = ./STM32F4_DISC_LIB

# Compilers
CC = arm-none-eabi-gcc
OBJCOPY = arm-none-eabi-objcopy

# Config file and startup script
SRCS += $(STM32F4_LIB_DIR)/system_stm32f4xx.c
SRCS += $(STM32F4_LIB_DIR)/Libraries/CMSIS/ST/STM32F4xx/Source/Templates/TrueSTUDIO/startup_stm32f4xx.s

# Compiler flags
CFLAGS = -g -O2 -Wall
CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
CFLAGS += -T $(STM32F4_LIB_DIR)/stm32_flash.ld
CFLAGS += -I $(STM32F4_LIB_DIR)/.

# Include libraries
CFLAGS += -I $(STM32F4_LIB_DIR)/Utilities/STM32F4-Discovery
CFLAGS += -I $(STM32F4_LIB_DIR)/Libraries/CMSIS/Include
CFLAGS += -I $(STM32F4_LIB_DIR)/Libraries/CMSIS/ST/STM32F4xx/Include
CFLAGS += -I $(STM32F4_LIB_DIR)/Libraries/STM32F4xx_StdPeriph_Driver/inc

# Default make target
all: build_fw

# Build firmware
.PHONY: firmware
build_fw: $(SRCS)
    $(CC) $(CFLAGS) $^ -o $(FW_NAME).elf
    $(OBJCOPY) -O ihex $(FW_NAME).elf $(FW_NAME).hex
    $(OBJCOPY) -O binary $(FW_NAME).elf $(FW_NAME).bin

# Upload firmware
.PHONY: upload
upload: build_fw
    st-flash write $(FW_NAME).bin 0x8000000

# Clean
.PHONY: clean
clean:
    rm -f *.o $(FW_NAME).elf $(FW_NAME).hex $(FW_NAME).bin

4. Build

To build the code, just go to our working directory and type make

cd ~/blinky
make

5. Flash

Because the Makefile already includes a rule for flashing using ST-Link, we only have to

cd ~/blinky
make flash

6. Wrap-up

In this tutorial, I have walked you through all the necessary steps to get your LED blinking. At this point, I strongly encourage you to modify my source code or makefile to blink the LED in your own ways. Good luck! :)

7. Reference

results matching ""

    No results matching ""