Introduction
I wanted to start playing around with an ARM microcontroller. After some research I decided to buy the STM32F103RBT6 from STMicroelectronics. It is fast and has lots of peripherals, but is still small enough to be put an adapter PCB for use on a bread board. A popular first step in using a new microcontroller is to get a blinking LED. I'll show the essential steps to achieve this on a STM32F103RBT6 with a free and simple Linux toolchain. It is also important to me to program a bare chip (with no bootloader).A lot of information about the device is available on the STMicroelectronics web page. I'll refer here to the Reference Manual and the application note AN2586 on that page.
In addition I got valuable information and hints from the following sources:
- http://siwawi.bauing.uni-kl.de/avr_projects/arm_projects/index_cortex.html#stm32_blink
- http://regalis.com.pl/en/arm-cortex-stm32-gnulinux/
- https://www.youtube.com/playlist?list=PL6PplMTH29SHgRPDufZhfMRoFwRAIrzOp
- http://pandafruits.com/stm32_primer/stm32_primer_toolchain.php
I'm thankful to all people, providing all that helpful content. In this post, I try to summarize the most useful information (based on my personal judgement).
Toolchain Installation
The toolchain is the set of programs that is needed to compile the program code into an executable file that can be copied on the target chip. On my Arch Linux I installed the following packages in order to get the gcc compiler for ARM processors:
- arm-none-eabi-binutils
- arm-none-eabi-gcc
- arm-none-eabi-gdb
- arm-none-eabi-newlib
That gives me a compiler and all related tools. But I need more. A chip like the STM32F103RBT6 is rather complex. It needs some startup code before the main() function is entered. And in order to control the peripherals (ADC, GPIO, ...), one needs all the addresses of the registers to control them. In addition a linker script is needed to put the code together into a program that will run on the target device. All these things are provided on the STMicroelectronics website. The package is called STM32Cube. It is available for different STM32 devices (F1, F2, F3,...). I need the package STM32Cube F1 (link to .zip file is on the bottom of that page), because I use STM32F103RBT6.
I also need a device that can be plugged into the USB-port of my PC and copies the program on the chip. I bought a ST-Link V2 (a cheap, ebay clone from China) for that purpose. That device can be controlled with a program called Open On-Chip Debugger. On Arch Linux, I got this program after installing the package
- openocd
The PCB
Because I bought a bare chip, I need a PCB to put it on.
A thing of beauty |
I want a PCB that can be plugged onto a bread board (as I saw here), but I wanted to add the decoupling capacitors on the PCB, a programming socket and a mini-USB connector in case I later want to play with the USB interface of the controller.
During the board design I followed the application note AN2586. I used KiCAD to draw schematic and board layout, and produced it with the toner transfer method.
Front side of the board with a blinking LED. It is not fully populated yet (missing quarz and USB) but works already |
Back side of the board with all the decoupling capacitors. |
Blinking LED Program
I created a project directory and copied the following files from the STM32Cube package:
and page 170 of the Reference Manual:
The program code is using the names for the registers and the numbers, such as GPIO_CRL_MODE4 instead of the corresponding hex number 0x00030000. They are provided after including the fille stm32f1xx.h
Finally, a makefile is needed to compile everything. The CFLAGS contain include paths to the STM32Cube package. In case you have put it somewhere else, that path has to be changed accordingly. The rest of the CFLAGS variable specifies the processor core (cortex-m3) and the device type (STM32F103x6). With -mthumb the compiler uses a reduced ARM instruction set to save memory space, more info here.
- STM32Cube_FW_F1_V1.3.0/Drivers/CMSIS/Device/ST/STM32F1xx/Source/Templates/gcc/startup_stm32f103x6.s (startup code written in assembly language. I need that file, because I have STM32F103RBT6)
- STM32Cube_FW_F1_V1.3.0/Middlewares/Third_Party/FreeRTOS/Source/include/stdint.readme -> stdint.h (rename the file to stdint.h)
- STM32Cube_FW_F1_V1.3.0/Drivers/CMSIS/Device/ST/STM32F1xx/Source/Templates/gcc/linker/STM32F103X6_FLASH.ld (the linker script, There are '0' characters in some lines that I needed to remove)
- STM32Cube_FW_F1_V1.3.0/Drivers/CMSIS/Device/ST/STM32F1xx/Source/Templates/system_stm32f1xx.c (more startup code written in C, which is called from the assembly startup code)
- STM32Cube_FW_F1_V1.3.0/Drivers/CMSIS/Device/ST/STM32F1xx/Include/system_stm32f1xx.h (header file for the startup code)
and page 170 of the Reference Manual:
The program code is using the names for the registers and the numbers, such as GPIO_CRL_MODE4 instead of the corresponding hex number 0x00030000. They are provided after including the fille stm32f1xx.h
#include "stm32f1xx.h" void wait(int delta) { volatile int i; for (i = delta; i; --i); } int main() { // Enbale GPIOC RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; // Configure GPIOC pin 4 by setting bits in the lower half // of the port configuration register CRL // (reset value of GPIOC->CRL = 0x44444444) GPIOC->CRL |= GPIO_CRL_MODE4; // MODE4 = 11 (50 MHz = fast mode) GPIOC->CRL &= ~(GPIO_CRL_CNF4); // CNF4 = 00 (Push-Pull mode) for (;;) { GPIOC->BSRR |= GPIO_BSRR_BS4; // set pin4 (LED on) wait(200000); GPIOC->BRR |= GPIO_BRR_BR4; // reset pin4 (LED off) wait(200000); } }
Finally, a makefile is needed to compile everything. The CFLAGS contain include paths to the STM32Cube package. In case you have put it somewhere else, that path has to be changed accordingly. The rest of the CFLAGS variable specifies the processor core (cortex-m3) and the device type (STM32F103x6). With -mthumb the compiler uses a reduced ARM instruction set to save memory space, more info here.
Note, that this makefile is written in a simple way in order to make it easy to see the individual commands (no use of default rules). It compiles the main program and the startup (C code and assembly code), then combines everything into main.elf using the linker script provided in the STM32Cube package. Finally, it converts the program to Intel hex format.
CFLAGS = -I ../STM32Cube_FW_F1_V1.3.0/Drivers/CMSIS/Device/ST/STM32F1xx/Include \ -I ../STM32Cube_FW_F1_V1.3.0/Drivers/CMSIS/Include \ -Wall -mcpu=cortex-m3 -mlittle-endian -mthumb -DSTM32F103x6 -Os main.hex: main.elf arm-none-eabi-objcopy -Oihex main.elf main.hex main.elf: system.o main.o startup.o arm-none-eabi-gcc $(CFLAGS) -T STM32F103X6_FLASH.ld \ -Wl,--gc-sections system.o main.o startup.o -o main.elf startup.o: startup_stm32f103x6.s arm-none-eabi-gcc $(CFLAGS) -c startup_stm32f103x6.s -o startup.o system.o: system_stm32f1xx.c arm-none-eabi-gcc $(CFLAGS) -c system_stm32f1xx.c -o system.o main.o: main.c arm-none-eabi-gcc $(CFLAGS) -Os -c main.c -o main.o flash: main.hex openocd -f /usr/share/openocd/scripts/interface/stlink-v2.cfg \ -f /usr/share/openocd/scripts/target/stm32f1x.cfg \ -c "program main.hex verify reset exit" clean: rm *.o main.elf
Writing to Flash
In order to copy the program (main.hex) to the flash memory on the chip, I use the ST-Link V2 mentioned above. The ST-Link is controlled by the openocd program called with the correct command line arguments. These arguments are two configuration file for the programmer and for the target device, and a list of commands to execute: program verify reset exit. The correct call can be seen in the makefile under the flash: target. Note that you might change the path to the interface and target configuration files. These files are installed together with the openocd program. The paths I've used here work for my Linux distribution.
The ST-Link device has to be connected with 5 cables to the chip
pin_on_STLink -> pin_on_STM32:
After typing make flash in the terminal, the LED (connected to pin PC4 and through a resistor to GND) starts blinking.
The ST-Link device has to be connected with 5 cables to the chip
pin_on_STLink -> pin_on_STM32:
- 2 cables with supply voltage: GND -> GND and 3.3V -> VDD
- 2 cables for data transfer: SWDIO -> PA13 and SWCLK -> PA14
- 1 cable for reset: RST ->NRST
After typing make flash in the terminal, the LED (connected to pin PC4 and through a resistor to GND) starts blinking.
Keine Kommentare:
Kommentar veröffentlichen