STM32 LEDBlinken AtollicTrueStudio
Version: 07 Oktober 2010
Authoren: Lukas Simma (Inexess Technology Simma KG)
Norbert Kleber (Sensing Solutions)
Info: Bitte Artikel verbessern und erweitern wenn gewünscht
IDE: IDE Atollic Truestudio Lite 1.4 (Free)
Editor Atollic - Eclipse 3.5
Toolchain arm-atollic-eabi-gcc
Debugger ST-LINK via Atollic gdbproxy für JTAG
Hardware: Ein Test/Demoboard mit einem STM32F10x
(und mindestens eine schaltbare LED)
hier STM3210C Demoboard mit STM32F107
sowie ein Kundenboard mit STM32F103
Um den Einstieg zu erleichtern wird hier ein minimales Beispiel, eine blinkende LED, mithilfe der STM32 Std. Peripherial Library vorgestellt.
In diesem Beispiel möchte ich so gut wie das Minimum zeigen was nötig ist um mit der Std. Peripherie Library eine LED zum Blinken bringen.
(Für mich war auch lange nicht klar was als Minimum benötigt wird). Dass das Blinken (der delay) mit dem Systick vom Cortex-M3 schöner lösbar ist,
kommt dann in einem nächsten Intro incl. dem DeInit().
Hier also erst mal das Minimumbeispiel...
Verwendete Komponenten
- IDE Atollic Truestudio Lite 1.4 (Free)
- JTAG Debugger ST-LINK (ca. 25€)
- Ein Test/Demoboard mit einem STM32F10x (und mindestens eine schaltbare LED)
Kompontenten herunterladen und installieren
Downloaden von Atollic TrueSTUDIO®/STM32 Lite (1.4)
und installieren.
Den ST-LINK updaten damit er neuere Controller kennt. Downloaden des "ST-Link firmware upgrade" von der ST Seite
http://www.st.com/mcu/familiesdocs-110.html. ST-Link am USB anstecken, ZIP-File Entpacken, ST-LinkUpgrade.exe ausführen, Button "Device Connect"
und "YES" anklicken um das update auszuführen.
Dokumentationen herunterladen
Von der ST Seite http://www.st.com/mcu/familiesdocs-110.html herunterladen von
- RM0008 Reference Manual
- Das zum Controller auf dem Board passende Datasheet
(zb. "STM32F105/107xx" für den STM32F107)
- PM0056 STM32F10xxx Cortex-M3 programming manual
C-Code Projekt für den Controller einrichten
TrueStudio starten und einen (neuen) Workspace Ordner wählen. Im Workspace Ordner wird pro Projekt dann ein Projektordner abgelegt.
Die Introseite beenden mit "Start using TrueSTUDIO" und ein neues C-Projekt erstellen mit File -> New -> C-Projekt.... wähle STM32 C Projekt ... Atollic ARM Tools
Nachfolgender Dialog definier welche Projekteinstellungen vorgenommen werden und welches Linkerscript und Startupfile in das Projekt kopiert wird.
Evaluation board: None Ausser der Std. Peripherial Library wollen wir keinen zusätzlichen Code hinzufügen
Microcontroller family und Microcontroller: Wähle hier den Controller der auf DEINEM EIGENEN Board bestückt ist.
Code location: FLASH -- das Programm wird dauerhaft in in internen Flash des STM32 abgelegt. RAM -- das Programm wird in den internen RAM geschrieben und
ist nach dem Abschalten des Stromes wieder futsch.
Nun den Finish Button drücken, das Projekt wird erstellt, die notwendigen Dateien erzeugt.
Main Code für Blinking LED
Die Codefiles finden sich im Order src. Der vom Wizard erstellte Code im main.c wird durch folgenden Code ersetzt.
main.c:
#include "stm32f10x.h"
// Die Std. Peripherie arbeitet viel über Strukturen
// Struktur um PortPins zu initialisieren
GPIO_InitTypeDef GPIO_InitStructure;
void delayLoop() {
volatile uint32_t delayCount = 1000000; // volatile, um "Wegoptimieren" zu vermeinden
//(http://en.wikipedia.org/wiki/Volatile_variable)
while (delayCount > 0) {
delayCount--;
}
}
int main(void)
{
// Die Std. Peripherie nun Clocks, PLLs usw. einrichten
SystemInit();
// PORT D Peripherie aktivieren
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
// PortPin als Ausgang configurieren
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
while(1) {
GPIOD->BSRR = GPIO_Pin_7; // LED On
delayLoop();
GPIOD->BRR = GPIO_Pin_7; // LED Off
delayLoop();
}
}
Projekt Builden
Das Projekt nun Builden mit dem Eintrag "Debug" beim Hammersymbol. Am unteren Rand gibt es die Problems view, hier dürfen keine Fehler aufscheinen.
In der Console View wird der Compile und Linkerablauf und das Ergebnis ausgegeben.
Wenn es klappt liegt nun das fertige File als LEDBlinken.elf im Ordner "Debug".
Configuration zum Flashen und Debuggen
Das File nun mit dem ST-Link über JTAG auf das Board flashen. Dazu muss erstmalig eine Debug Configuration eingerichtet werden. Klicke auf das Icon des
"Grünen Käfer" und selektiere "Debug As" --> "Embedded C/C++ Application". Der Wizard für eine neue Debug Configuration wird geöffnet, die Einstellungen für den ST-LINK sich korrekt eingetragen.
Mit Apply und OK wird die neuen Debug Configuration angelegt (elf File in den Controller flashen, debug starten, brakepoint ist erste zeile in main) Diese Debug Config ist nun direkt über
das Debug Icon "Grüner Käfer" erreichbar.
Workspace mit Projekt zum download
Falls es nicht klappt hier der Workspace mit dem Blinking LED Projekt drin.
TrueStudio/STM32 Workspace mit Blinking LED Projekt
Erklärungen zum Code
Notwendiger Include
#include "stm32f10x.h"
Um mit der STM32 Standard Peripheral Library (STM32StdPerLib) zu arbeiten ist in den Code Files jeweils obiger Include einzubinden. Die gesamte Library liegt im Projekt im Ordner "firmware" und wird vom Compiler mitkompiliert.
- Ordner: firmware/CMSIS
Coretx-M3 spezifische Codes
- Ordner: firmware/STM32F10x_StdPeriph_Driver
STM32 Peripherie Codes
Die Code Files im Ordner "firmware" sollen -wenn möglich- nicht geändert werden. Von der STM32StdPerLib wird ein Configfile (stm32f10x_conf.h) eingebunden welches vom User geändert werden soll, das Headerfile ist nicht unter "firmware" zu finden sondern unter "src" bei den Userfiles.
- File src/stm32f10x_conf.h
Bindet die im Projekt verwendeten Peripherie Module ein. Es können alle Module aktiviert bleiben jedoch ist bei einem "Build all" dann die Compilezeit etwas länger. Durch die Optimierung dass unbenutzte Funktionen vom Linker entfernt werden hat es keine Auswirkungen auf die Codesize.
Alternative kann für dieses Beispiel der Include Block im stm32f10x_conf.h wie folgt auf zwei Module reduziert werden.
/* Uncomment the line below to enable peripheral header file inclusion */
// #include "stm32f10x_adc.h"
// #include "stm32f10x_bkp.h"
// #include "stm32f10x_can.h"
// #include "stm32f10x_cec.h"
// #include "stm32f10x_crc.h"
// #include "stm32f10x_dac.h"
// #include "stm32f10x_dbgmcu.h"
// #include "stm32f10x_dma.h"
// #include "stm32f10x_exti.h"
// #include "stm32f10x_flash.h"
// #include "stm32f10x_fsmc.h"
#include "stm32f10x_gpio.h"
// #include "stm32f10x_i2c.h"
// #include "stm32f10x_iwdg.h"
// #include "stm32f10x_pwr.h"
#include "stm32f10x_rcc.h"
// #include "stm32f10x_rtc.h"
// #include "stm32f10x_sdio.h"
// #include "stm32f10x_spi.h"
// #include "stm32f10x_tim.h"
// #include "stm32f10x_usart.h"
// #include "stm32f10x_wwdg.h"
// #include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
Hier ein Bild wie die Library aufgebaut ist
STM32 Initialisieren lassen
Einen STM32 (ARM Cortex-M3) zu initialisieren ist etwas aufwändiger da er mehrere interne Bussysteme hat und auch mehrere Clocks für die unterschiedlichen Peripheriebausteine erzeugen muss. Desweiteren wird der interne oder externe (Quartz) Takt mittels PLL multipliziert so dass der Core und die Peripherie auf einer höheren Frequenz arbeitet.
Siehe RM0008 Reference manual
für Connection Linie (CL): Seite 115 (Figure 11. Clock tree) für die anderen Linien: Seite 84 (Figure 8. Clock tree)
Diese Initialisierung wird am besten der STM32StdPerLib überlassen. Dazu wird die Funtion SystemInit(); am Anfange der Main aufgerufen.
SystemInit();
Da jedoch die Clocksettings für die verschiedenen Linie voneinander abweichen sind im Compiler Environment zwei Symbole zu definieren.
- STM32F10X_CL
Definiert dass eine Controller aus der Connectin Line (STM32F107 oder STM32F105) verwendet wird.
- USE_STDPERIPH_DRIVER
Definiert dass die Module für die STM32 Peripherie aus der STM32StdPerLib verwendet werden können.
Siehe dazu im "stm32f10x.h" auf Zeile 48
Folgende Controller Settings sind möglich
#define STM32F10X_LD STM32F10X_LD: STM32 Low density devices
#define STM32F10X_LD_VL STM32F10X_LD_VL: STM32 Low density Value Line devices
#define STM32F10X_MD STM32F10X_MD: STM32 Medium density devices
#define STM32F10X_MD_VL STM32F10X_MD_VL: STM32 Medium density Value Line devices
#define STM32F10X_HD STM32F10X_HD: STM32 High density devices
#define STM32F10X_XL STM32F10X_XL: STM32 XL-density devices
#define STM32F10X_CL STM32F10X_CL: STM32 Connectivity line devices
Stolperfalle Quartzfrequenz auf eigenen Boards
ACHTUNG: Um die STM32StdPerLib ohne Änderungen am Code zu nutzen darf nur jene Quarzfrequenz bei externen Quarzen (HSE) verwendet werden für welche die Lib auch ausgelegt wurde.
- bei STM32F10X_CL: NUR 25MHz Quartz verwenden
- bei allen anderen: NUR 8MHz Quartz verwenden
Siehe dazu im "stm32f10x.h" auf Zeile 92 und system_stm32f10x.c auf Zeile 977 hier ist ersichtlich dass die Configuration auf die obigen HSE Quartzfrequenzen geschrieben ist. Falls es kein Politikum gibt am besten die beiden Quartze verwenden, das erspart viele (sinnlose) Stunden.
Für CL compiliert jedoch anderen STM32 auf dem Board (und umgekehrt)
ACHTUNG: Die Connection Line hat einen andere internen Aufbau für PLL und Clocks. Ein Code der für die CL Line compiliert wurde und auf eine andere Linie geflasht wird (oder umgekehrt) hängt dann bei der Initialisierung der Clocks.
Siehe RM0008 Reference manual, beachte dass es ZWEI RCC Kapitel gibt
Kapitel 6: Low-, medium-, high- and XL-density reset and clock control (RCC) Kapitel 7: Connectivity line devices: reset and clock control (RCC)
Initialisierung eines Peripheriebausteins
Der Ablauf einer Initialisierung einer Peripherie ist grundsätzlich immer derselbe. Bevor irgend ein Register der Peripherie configuriert werden kann muss der Clock der Peripherie aktiviert werden.
Wie aus der System Architecture des STM32 ersichtlich ist sind die Peripherie Bausteine auf zwei Peripherie Busse aufgeteilt: APB1 und APB2 oder sitzen am AHB.
Siehe RM0008 Reference manual, Seite 41 und 42
Je nachdem an welchem Bus die Peripherie angeschlossen ist muss die Funktion RCC_APB1PeriphClockCmd(...), RCC_APB2PeriphClockCmd(...) oder RCC_AHBPeriphClockCmd(...) verwendet werden.
In diesem Intro wird der GPIO Port D aktiviert, alle Ports hängen am APB2.
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
Zum herausfinden welche Peripherie an welchem Bus hängt, die Codedoku konsultieren (stm32f10x_stdperiph_lib_um.chm) oder den Code von APB2PeriphClockCmd (bzw. APB1PeriphClockCmd oder RCC_AHBPeriphClockCmd) in stm32f10x_rcc.c ansehen.
Tipp: Strg Taste drücken und zugleich mit der linken Mousetaste eine Funktion anklicken öffnet das File und den zugehörigen Code im Editor.
Startupcode und Linkerscript
Wird mit dem TrueStudio Projektwizard ein Projekt erstellt dann kopiert TrueStudio die notwendigen Files in das Projekt. Soll das Projekt für eine andere Controller Linie configuriert werden oder soll der Code in den RAM so sind die Files zu ersetzen.
- Linkerscript:
<Projet>\stm32_flash.ld
In diesem Intro ist der Code so gelinkt dass er in den Flash des Controllers geladen wird
Weitere Linkerscripts sind zu finden in
<TrueStudio Installationsverzeichnis>\scripts\ld
- Startupcode:
<Projet>\firmware\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\TrueSTUDIO\startup_stm32f10x_cl.s
In diesem Intro ist der StartupCode für einen Conection Line Controller in verwendung.
Startupcodes für andere STM32 Controller Lines sind zu finden in
<TrueStudio Installationsverzeichnis>\Library\STM32F10x_StdPeriph_Lib_V3.3.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\TrueSTUDIO
Wo gibt es weitere Beispiele
Die STM32 Std. Periph. Library enthält viele Beispiele, da ist für jeden Peripheriebaustein was mit dabei.
TrueStudio hat die komplette Library bei der Installation mit auf die Platte kopiert. Diese ist zu finden in
<TrueStudio Installationsverzeichnis>\Library\STM32F10x_StdPeriph_Lib_V3.3.0
Die Beispiele finde sich in
..\Library\STM32F10x_StdPeriph_Lib_V3.3.0\Project\STM32F10x_StdPeriph_Examples
Um das Beispiel zu testen wie in diesem Intro ein Projekt, dann den Code aus dem Beispiel in den Ordner src des Projektes kopieren. Die Ports anpassen, dann kann das Beispiel compiliert und getestet werden.