prof. dr. otto parzhuber labor d204 stm32 einführung...
TRANSCRIPT
Prof. Dr. Otto Parzhuber
Labor D204
STM32 Einführung D204
Version: 16.10.2018 Seite 1 - 15
File: STM32_Prakt_Einfuehrung_I.docx
Einführung in die C-Programmierung mit STM32
Cortex Mikrocontroller
Aufgabenstellung:
Blinklicht und Taster mit dem stm32Nucleo und der
OpenSTM32 Programmierumgebung
Das Gerüst eines Blinklichts sieht folgendermaßen aus:
/**
\brief einfaches Blinklicht
\author max muster
*/
int main(void)
{
Portbit auf Ausgang stellen; while(1){ Portbit setzen; Portbit löschen; }
return 0;
}
Wenn an das entsprechende Portbit eine LED angeschlossen ist wird diese abwechselnd ein-
und ausgeschaltet.
Vorbereitungsfragen
Weshalb muss Ihr Programm in einer Endlosschleife innerhalb von main()
ablaufen?
Wie viele Bits besitzen die Register des MikroControllers?
Wie viele Bits besitzen die Ports des MikroControllers?
Wie können Sie mit der Sprache C einzelne Bits in den Registern des
Mikrocontrollers setzen und löschen?
Sind die Portbits als Default Ein- oder Ausgänge? Begründung!
Suchen Sie im Referenzmanual des Prozessors (stm32F072) die Bezeichnungen
MODER, ODR und IDR. Was bedeuten sie?
Welcher Datentyp verbirgt sich hinter dem Bezeichner GPIOA?
Was bedeutet CMSIS und Cube-HAL?
Für alle Verzeichnisse, Datei- und Projektnamen sind Umlaute,
Sonderzeichen und Freizeichen tabu.
Anstelle von \1. Versuch\Blödsinn.c können Sie z.B. \1_Versuch\Bloedsinn.c
schreiben
Prof. Dr. Otto Parzhuber
Labor D204
STM32 Einführung D204
Version: 16.10.2018 Seite 2 - 15
File: STM32_Prakt_Einfuehrung_I.docx
Kurzeinführung in die OpenStm32 IDE
Starten Sie die OpenStm32 IDE, falls bereits ein Projekt geöffnet ist, schließen Sie es mit
File->Close.
Da mit Sicherheit bereits Studierende anderer Praktikumsgruppen mit der
Programmierumgebung vor Ihnen gearbeitet haben ist es wichtig den Workspace
umzuschalten:
Unter Other… geben Sie nun ein Verzeichnis für Ihre Praktikumsgruppe ein, z.B.
Z:\mfb5g_pa1\workspace.
Zuvor müssen Sie sich natürlich mit dem Netzlaufwerk verbinden, in dem obigen Beispiel mit
dem Netzlaufwerk \\192.168.10.113\homes\mfb5g_pa1
Für ein lokales Laufwerk ist das Vorgehen natürlich identisch, aber in jedem Fall müssen Sie
zu jedem Beginn des Praktikums den Vorgang Switch Workspace durchführen.
Prof. Dr. Otto Parzhuber
Labor D204
STM32 Einführung D204
Version: 16.10.2018 Seite 3 - 15
File: STM32_Prakt_Einfuehrung_I.docx
Erstellen Sie ein neues Projekt mit File->New-> C Project. Der Name des Projekts bleibt
Ihnen überlassen, z.B. blinken wie im Beispiel:
Dieser Schritt ist sehr wichtig. Es muss als Board das NUCLEO-F072RB eingestellt sein.
Mit den Drop-Down Menüs finden sie es sicher problemlos.
Prof. Dr. Otto Parzhuber
Labor D204
STM32 Einführung D204
Version: 16.10.2018 Seite 4 - 15
File: STM32_Prakt_Einfuehrung_I.docx
Mit diesen wenigen Schritten haben Sie ein lauffähiges Gerüst für ein C-Programm für den
gewählten Prozessor und dem Nucleo-Board:
Prof. Dr. Otto Parzhuber
Labor D204
STM32 Einführung D204
Version: 16.10.2018 Seite 5 - 15
File: STM32_Prakt_Einfuehrung_I.docx
Unter dem Ordner src ist das Gerüst für die main-Funktion abgelegt. Für das Projekt wurden
mehrere weitere Verzeichnisse angelegt. Wichtig ist aber für unser erstes Projekt nur der
Ordner CMSIS.
CMSIS: CMSIS bedeutet Cortex Mikrocontroller Software Interface Standard und ermöglicht den
Zugriff auf die Peripheriemodule der unterschiedlichen Cortex Derivate von NXP, Atmel, TI
etc. mit einheitlichen Funktionen.
Mit dem Modul CMSIS core wird der für das Booten des Mikrocontrollers benötigte Code in
das Projekt eingefügt. Dazu gehören:
die Definition der Datentypen für den Zugriff auf die Peripherie,
der sogenannte Startup Code und die
vollständige (typspezifische) Interrupt Vektor Tabelle.
Programmieraufgabe I :
Erweitern Sie Datei main.c für die Erzeugung
eines Blinklichts. Verwenden Sie die Struktur
GPIOA und die Register MODER und ODR.
An welchem Port und welchem Pin ist die
LED angeschlossen?
Stellen Sie mit einer einfachen Wartefunktion
(for Schleife…) eine für das Auge sichtbare
Blinkfrequenz ein.
Sie müssen in der main-Funktion einmalig
den Takt für den GPIO-Port einschalten. Dies
geschieht mit der folgenden Anweisung: /* GPIOA Takt einschalten */ RCC->AHBENR |= (1<<17);
Das Referenzmanual liefert die Erklärung für diese ominösen 17 Bits um die Sie die „1“
verschieben müssen:
Prof. Dr. Otto Parzhuber
Labor D204
STM32 Einführung D204
Version: 16.10.2018 Seite 6 - 15
File: STM32_Prakt_Einfuehrung_I.docx
Alle GPIOs sind nach dem Reset als Eingang konfiguriert (warum?) und müssen zunächst
einmalig auf Ausgang gestellt werden. Vervollständigen Sie dazu die folgende Codezeile:
GPIOA->MODER |= (0b01 << . . . ); // Pin auf Ausgang
Die Antwort finden Sie im Referenzmanual auf Seite 157.
In einer Endlosschleife können Sie nun die LED abwechselnd ein- und ausschalten:
GPIOA->ODR ^= (1 << . . .); /* oder */ GPIOA->ODR |= (1 << . . .); GPIOA->ODR &= ~(1 << . . .);
Um welche Bitoperation handelt es sich bei der ersten Anweisung?
Um das Blinklicht für das Auge sichtbar zu machen benutzen Sie am einfachsten eine for-
Schleife, die einfach durch inkrementieren einer Variable Zeit „verbrät“.
Interessant ist es auch ohne Verwendung einer Warteschleife mit einem Logicanalyser die
Zeit zwischen ein- und ausschalten der LED zu betrachten. Ist die Zeit für das Einschalten
gleich lang wie die fürs ausschalten? Begründung.
Prof. Dr. Otto Parzhuber
Labor D204
STM32 Einführung D204
Version: 16.10.2018 Seite 7 - 15
File: STM32_Prakt_Einfuehrung_I.docx
Programmieraufgabe II :
Achtung: Kein neues Verzeichnis anlegen,
sondern das bereits bestehende Projekt
kopieren
Am Ende nicht vergessen das (alte) kopierte Projekt wieder zu schließen.
Erweitern Sie das
Programm aus der ersten
Programmieraufgabe. Das
Blinklicht soll nur bei
Betätigen des blauen
Tasters auf der Platine
aktiviert sein.
Verwenden Sie die
Struktur GPIOC und das
Register IDR.
Wie in der Programmieraufgabe I müssen Sie zuerst den Takt für den betreffenden GPIO-
Port einschalten. Welcher Port ist das und an welchen Pin ist der Taster angeschlossen?
Ein Gerüst für die Lösung zeigt der folgende Codeschnippsel:
taster = GPIO. . . ->IDR & (1 << . . . . );
if ( taster == . . . . ){ . . . blinke mit einer sichtbaren Frequenz . . . }
Welche zwei Werte kann die Variable taster annehmen? Welchen Datentyp können Sie
verwenden?
Prof. Dr. Otto Parzhuber
Labor D204
STM32 Einführung D204
Version: 16.10.2018 Seite 8 - 15
File: STM32_Prakt_Einfuehrung_I.docx
Programmieraufgabe III : ---- externe Interrupts und Einstieg in die Cube-HAL----
Achtung: Wie bei Aufgabe II ist es am einfachsten wenn Sie das bestehende Projekt
kopieren
Das Blinklicht soll nun
durch Betätigen des blauen
Tasters ein- und wieder
ausgeschaltet werden
können.
Der Pin soll als externer
Interrupteingang verwendet
werden
Bei der Projekterstellung
muss die Bibliothek Cube-HAL eingebunden sein.
Der prinzipielle Aufbau für die Verwendung der Cube-HAL ist immer gleich.
Vervollständigen Sie den folgenden Code:
. . . . . . int main(void) {
GPIO_InitTypeDef G; //Variablen deklarieren, meist Datentyp struct HAL_Init(); //Initialisierung für die Cube-HAL Library __HAL_RCC_GPIOA_CLK_ENABLE(); //Takt einschalten hier Beispiel GPIOA /* ---- LED PA5 einstellen ---- */ G.Pin = . . . . . . . . ; G.Mode = GPIO_MODE_OUTPUT_PP; G.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOA, &G); /* ---- Taster PC13 einstellen ---- */ . . . . . . . . . . . . . . ; // Takt einschalten /* ---- Taster PC13 einstellen ---- */ G.Pin = . . . . . . . . ; G.Mode = GPIO_MODE_IT_FALLING; //1) G.Pull = GPIO_PULLUP; HAL_GPIO_Init( . . . . . , . . . .); /* ---- Interrupt einschalten ---- */ HAL_NVIC_EnableIRQ(. . . . . . . . ); //2)
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, . . . . . . ); //3)
Prof. Dr. Otto Parzhuber
Labor D204
STM32 Einführung D204
Version: 16.10.2018 Seite 9 - 15
File: STM32_Prakt_Einfuehrung_I.docx
while (1) { if (blinken_flag == true) { HAL_GPIO_TogglePin(. . . . . . ., . . . . . . ); HAL_Delay(50); //4) }
}
1) Ein Interrupt soll bei einer fallenden Flanke ausgelöst werden, was müssen Sie hier
einstellen? Welchen der folgenden Bezeichner verwenden Sie? GPIO_MODE_INPUT /*!< Input Floating Mode */ GPIO_MODE_OUTPUT_PP /*!< Output Push Pull Mode */ GPIO_MODE_OUTPUT_OD /*!< Output Open Drain Mode */ GPIO_MODE_AF_PP /*!< Alternate Function Push Pull Mode */ GPIO_MODE_AF_OD /*!< Alternate Function Open Drain Mode*/ GPIO_MODE_ANALOG /*!< Analog Mode */ GPIO_MODE_IT_RISING /*!< ExtInterrupt Mode with Rising edge trigger detection */ GPIO_MODE_IT_FALLING /*!< Ext Interrupt Mode with Falling edge trigger detection*/ GPIO_MODE_IT_RISING_FALLING /*!< External Interrupt Mode with Rising/Falling edge trigger detection */
2) Welchen Interruptvektor müssen Sie hier einsetzen? Die Lösung finden Sie in der Datei
startup_stm32f072xb.s. Die folgenden drei Möglichkeiten stehen zur Auswahl: EXTI0_1_IRQHandler /* EXTI Line 0 and 1 */ EXTI2_3_IRQHandler /* EXTI Line 2 and 3 */ EXTI4_15_IRQHandler /* EXTI Line 4 to 15 */
3) PA5 soll nun zuerst gelöscht werden. Tragen Sie den nötigen Bezeichner ein.
4) Die Funktion HAL_Delay wartet x Millisekunden.
Eine Möglichkeit für die Interruptfunktion sieht so aus:
//Interrupt Serviceroutine void EXTI4_15_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(. . . . . . .); //1) if (blinken_flag == true) blinken_flag = . . . . ; //2) else blinken_flag = . . . .; }
1)
Hier müssen Sie den passenden Pin eintragen
2)
Vervollständigen Sie den Code.
Hinweis: für den Datentyp Boolean gibt es den Header stdbool.h.
Prof. Dr. Otto Parzhuber
Labor D204
STM32 Einführung D204
Version: 16.10.2018 Seite 10 - 15
File: STM32_Prakt_Einfuehrung_I.docx
Programmieraufgabe IV : Textausgabe über das LCD-Keypad
Achtung: Wie bei Aufgabe II ist es am einfachsten wenn Sie das bestehende Projekt
kopieren
Wir benützen eine Bibliothek bestehend aus den
beiden Dateien1 lcd.c und lcd.h
Diese beiden Dateien müssen Sie wie im
nebenstehenden Bild gezeigt in ihr Projekt
einfügen.
Um die gewohnte Funktion printf(….)
verwenden zu können muss nur noch in der Datei
syscalls.c (siehe rechts) ein Funktionsaufruf aus der lcd.c hinzugefügt
werden. Suchen Sie die (leere) Funktionsdefinition __io_putchar(int ch)
und fügen den unten gezeigten Funktionsaufruf hinzu:
/* * für die lcdbibliothek und printf */ int __io_putchar(int ch){ lcd_putchar(ch); }
Mit diesen kleinen Anpassungen können Sie nun beliebige Texte und
formatierte Zahlen auf dem LCD-Keypad ausgeben:
printf("Hallo %3d %3x \r\n", i, i);
Sie können die üblichen
Formatierungsparameter
verwenden, z.B. :
%s für Strings
%d für Dezimalzahlen
%x für Hexadezimalzahlen
%f für Gleitkommazahlen ist nicht
implementiert
1 Basiert auf der avr lib von Fleury
Prof. Dr. Otto Parzhuber
Labor D204
STM32 Einführung D204
Version: 16.10.2018 Seite 11 - 15
File: STM32_Prakt_Einfuehrung_I.docx
Anschluss des Boards:
Das Bild zeigt den Anschluss des Boards. Der linke Teil der Platine ist der Debugger und
rechts mit den Stiftleisten das Target-Board. Das Board wird über die USB-Schnittstelle des
Debuggers mit Strom versorgt, es wird also kein extra Stromanschluss benötigt.
Prof. Dr. Otto Parzhuber
Labor D204
STM32 Einführung D204
Version: 16.10.2018 Seite 12 - 15
File: STM32_Prakt_Einfuehrung_I.docx
Schaltplan des LCD-Keypad-Shield
Prof. Dr. Otto Parzhuber
Labor D204
STM32 Einführung D204
Version: 16.10.2018 Seite 13 - 15
File: STM32_Prakt_Einfuehrung_I.docx
GNU ARM Toolchain:
Im Praktikum wird die frei verfügbare GNU ARM Toolchain verwendet. Für eine genauere
Beschreibung des Compilers steht eine sehr lesenswerte Website zur Verfügung:
http://www.bravegnu.org/gnu-eprog/
Einfaches Beispiel:
Die Größe der Text und Datensegmente interessiert Sie spätestens bei einer Meldung des
Linkers wie memory overflow. Die Bezeichnung der Segmente lautet:
bss: in dieses Segment werden static und globale Variablen abgespeichert
data: hier werden initialisierte Daten abgespeichert
text: hier kommt der Code rein
Für die detaillierte Speicheraufteilung ist es interessant die map- Datei in dem
Unterverzeichnis (Projektverzeichnis)/debug/bin anzusehen!
Prof. Dr. Otto Parzhuber
Labor D204
STM32 Einführung D204
Version: 16.10.2018 Seite 14 - 15
File: STM32_Prakt_Einfuehrung_I.docx
Die folgende Tabelle zeigt die Speicheraufteilung für den Mikrocontroller.
Load and Runtime Location
Load Location
Runtime Location
Der Heap wächst von der ersten freien Adresse im Datenspeicher aufwärts.
Der StackPointer wächst von der höchsten Adresse abwärts. Der C Programmierer
muss sich nicht darum kümmern.
Aber:
Je größer der Stack eingestellt wird, umso kleiner wird der Heap.
Diese Eigenschaft ist für den C Programmierer bei größeren Programmen mit vielen
Variablen äußerst wichtig!!!!!
Flash
vectors
.text
.rodata
0x0000 0000
(512 KB)
Im Segment .data
werden lokale Variablen
abgelegt
.data
0x0007 FFFF
Nix, kein Speicher implementiert
RAM
Im Segment .bss werden
static und globale
Variablen abgelegt
.data
.bss
0x1000 0000
Initialer StackPointer ->
Heap
Stack
(32 KB)
0x1000 7FFF
Prof. Dr. Otto Parzhuber
Labor D204
STM32 Einführung D204
Version: 16.10.2018 Seite 15 - 15
File: STM32_Prakt_Einfuehrung_I.docx
Musterlösung:
// Musterlösung 1. Termin #include "stm32f0xx.h" #include "stm32f0xx_nucleo.h" int main(void) { uint32_t i; RCC->AHBENR |= (1<<17); // GPIOA Takt einschalten GPIOA->MODER |= (0b01 <<10); // Ausgang GPIOA.5 for(;;) // oder while(1) { GPIOA->ODR |= (1<<5); // logisch 1 for (i=0;i<1E5;i++); // Strichpunkt nicht vergessen!! GPIOA->ODR &= ~(1<<5); // logisch 0 for (i=0;i<1E5;i++); // Strichpunkt nicht vergessen!! } }
Oder kürzer mit der Exclusiv-Oder (XOR oder Antivalenz) Verknüpfung:
for(;;) // oder while(1) { GPIOA->ODR ^= (1<<5); // abwechselnd logisch 1 und 0 for (i=0;i<1E5;i++); // Strichpunkt nicht vergessen!! }
Mit dem Taster:
uint32_t taster; RCC->AHBENR |= (1<<17); // GPIOA Takt einschalten RCC->AHBENR |= (1<<19); // GPIOC Takt einschalten RCC->APB1ENR |= (1<<4); // Timer 6 GPIOA->MODER |= (0b01 <<10); // Ausgang GPIOA.5 for(;;){ taster = GPIOC->IDR & (1<<13); if ( taster == 0){ GPIOA->ODR ^= (1<<5); //delay_ms(500); delay(); } }