In this tutorial, I will walk you step by step to blink the LED on the STM32 Value line discovery board (STM32F1_VL). 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/STM32F1_VL_DISC_LIB.git

Alternatively, you can download directly from ST website. However, in subsequent parts, you might be required to modify your Makefile accordingly to satisfy the requirements of STM32F1_VL, your own 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 "stm32f10x.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 STM32F1_VL, according to the Reference Manua, there are two user LEDs that are connected to I/O pins PC8 and PC9. This means that we need to enable bits 8 and 9 of Port C. So we have to configure these pins before running into the forever loop. To do that, we first allow the clock to access Port C by setting the 4th bits of clock register RCC_APB2ENR to 1. We can also use a predefined constant RCC_APB2ENR_IOPCEN for our convenience.

RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
__asm("dsb");

2.3.2. Pin configuration

Next, within port C, we want to set the I/O mode of the pins to "output mode". To do so, within register GPIOC_CHR, we set either 01 (10 MHz), 10 (2 MHz) or 11 (50 MHz) to each pair of configuration bits corresponding to these pins. According to Reference Manual, in order to set mode for pins PC8 and PC9, we will need to set bits 0, 1, 5, 6 of GPIOC_CHR acorrdingly. I personally choose 10 MHz, so I will set 010001 to bits 0 to 5. And since 010001 is 51 in decimal, we do

GPIOC->CRH = 51;

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 GPIOC->ODR. To turn on, we set value 1 to bits 8 and 9, and vice versa. In order to toggle the pin values, I use XOR operation (^=). Again, since 11 is 3 in decimal, I use the bit shift trick as following.

GPIOD->ODR ^= (3 << 8);
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 "stm32f10x.h"

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

int main(void)
{
    RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;  // enable the clock to GPIOC
    __asm("dsb");                         // wait till finished setup
    GPIOC->CRH = 51;

    for (;;) {
        GPIOC->ODR ^= 3 << 8;
        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
STM32F1_LIB_DIR = ../STM32F1_VL_DISC_LIB

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

# Config file and startup script
SRCS += $(STM32F1_LIB_DIR)/system_stm32f10x.c
SRCS += $(STM32F1_LIB_DIR)/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/startup/TrueSTUDIO/startup_stm32f10x_hd_vl.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 $(STM32F1_LIB_DIR)/stm32f10x_flash.ld
CFLAGS += -I $(STM32F1_LIB_DIR)/.

# Include libraries
CFLAGS += -I $(STM32F1_LIB_DIR)/Utilities/STM32_EVAL
# CFLAGS += -I $(STM32F1_LIB_DIR)/Libraries/CMSIS/Include
CFLAGS += -I $(STM32F1_LIB_DIR)/Libraries/CMSIS/CM3/CoreSupport
CFLAGS += -I $(STM32F1_LIB_DIR)/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x
CFLAGS += -I $(STM32F1_LIB_DIR)/Libraries/STM32F4xx_StdPeriph_Driver/inc

# Default make target
all: build_fw

# Build firmware
.PHONY: build_fw
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 ""