+ All Categories
Home > Documents > Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1...

Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1...

Date post: 05-May-2018
Category:
Upload: vucong
View: 221 times
Download: 1 times
Share this document with a friend
45
Laborpraktikum Embedded Systems Sommersemester 2018 Stand: 15.04.2018 Technische Hochschule Mittelhessen (THM) Campus Friedberg Fachbereich IEM Wilhelm-Leuschner-Straße 13 61169 Friedberg
Transcript
Page 1: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

LaborpraktikumEmbedded Systems

Sommersemester 2018

Stand: 15.04.2018

Technische Hochschule Mittelhessen (THM)

Campus FriedbergFachbereich IEMWilhelm-Leuschner-Straße 1361169 Friedberg

Page 2: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

Vorwort

Zu den Lernzielen des Laborpraktikums "Embedded Systems":

a) Praktische Umsetzung

Praktische Umsetzung und Vertiefung der in der Vorlesung Embedded Systems theoretisch vermittelten Kenntnisse mit Hilfe der bereitgestellten Lernumgebung.

b) Programmtests

Die entwickelten Programme zur Ansteuerung von Peripheriekomponenten sollen mit Hilfe ei-nes Hochsprachen-Debuggers selbstständig getestet und bei Auftreten von logischen Pro-grammfehlern eigenständig korrigiert werden.

c) Ingenieurmäßiges Arbeiten

Durch die Teilnahme am Laborpraktikum soll ingenieurmäßiges Arbeiten geübt werden. Ähnlich der Arbeit in einer Entwicklungsabteilung der Industrie sollen gestellte technische Aufgaben in anforderungsgemäß arbeitende, klar strukturierte und kommentierte Programme umgesetzt werden.

d) Teamarbeit

Die Aufgaben des Laborpraktikums „Embedded Systems“ sollen durch die Studierenden größ-tenteils alleine gelöst werden. Dies bedeutet jedoch nicht, dass Teamarbeit generell uner-wünscht wäre. Eine gegenseitige Unterstützung bei der Lösung der Aufgaben ist also durchaus erwünscht.

Weitere Hinweise:Unterlassen Sie bitte das Kopieren von Programmen anderer Gruppen, denn ein Lernerfolg ist nur durch eigenständige Arbeit möglich.

Zur Organisation des Laborpraktikums:Für das Programmieren der Mikrocontroller-Boards (STM32 PerformanceStick) wird die Entwick-lungsumgebung „HiTOP“ der Firma Hitex benötigt. Die Version 5.3 ist auf einem virtuellen Desktop-System der THM vorinstalliert; außerdem steht die Version 5.4 als kostenloses Down-load in Moodle zur Verfügung. Für das Laborpraktikum wird ein modifiziertes Project-Template verwendet, das auf dem virtuellen Desktop vorinstalliert und ebenfalls als Download in Moodle hin-terlegt ist.

Virtueller Desktop ClientAuf den PCs in den Rechnerräumen ist die Software „VMware Horizon Client“(kurz: „View-Client“) installiert, die den Desktop eines virtuellen PCs mit Win-dows 7 (32 Bit) und vorinstallierter HiTOP Entwicklungsumgebung (Version 5.3) zur Verfügung stellt. Starten Sie den virtuellen Desktop über das Desktop-Icon!

Page 3: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

Nach dem Start des View-Clients klicken Sie auf den Server „view-int.thm.de“!Nach erfolgreichem Verbindungsaufbau erscheint das Anmeldefenster, in dem Sie sich mit Ihren THM-Zugangsdaten anmelden müssen. Achten Sie darauf, dass als Domäne „THM“ eingestellt ist!

Wählen Sie anschließend den virtuellen Desktop „Embedded Systems“ aus:Je nach Konfiguration des Desktop-Clients haben Sie anschließend noch dieMöglichkeit, einen Zugriff von dem virtuellen Desktop auf die lokalen Dateien zuzulassen.

Hardware mit dem virtuellen Desktop verbindenBevor Sie die HiTOP Entwicklungsumgebung auf dem virtuellen Desktop starten, muss zunächst der STM32 PerformanceStick in einen freien USB-Port des lokalen PCs eingesteckt und mit dem virtuellen Desktop verbunden werden. Bewegen Sie dazu den Mauszeiger an den oberen Rand des Bildschirms, um das Menü des Desktop-Clients einzublenden. Dort wählen Sie dann „USB-Gerät verbinden“ und in dem Pull-down-Menü das Gerät „Hitex...STM32-PerformanceStick“ aus:

Achtung: Wenn Sie die virtuelle Maschine am Ende der Übung herunterfahren, wird diese wieder in den ursprünglichen Zustand versetzt, d. h. alle Dateien, die Sie neu erstellt haben, werden ge-löscht! Sichern Sie Ihre Dateien daher auf einem eigenen USB-Stick oder über Moodle!

HiTop Entwicklungsumgebung auf einem eigenen PC installieren Um auch zu Hause arbeiten zu können besteht alternativ die Möglichkeit, die Entwicklungsumge-bung HiTop (Version 5.4) lokal auf Ihrem eigenen PC zu installieren. Die Setup-Datei ist in dem Moodle-Kurs verfügbar, allerdings musste sie aufgrund der Größe als Multi-Volume-Zip-File auf zwei Dateien aufgeteilt werden. Zum Entpacken des Multi-Volume-Archivs können Sie beispiels-weise das kostenlose Programm „7Zip“ (http://www.7-zip.de/) verwenden.Zusätzlich zu der HiTop Entwicklungsumgebung benötigen Sie noch das angepasste Projekt-Tem-plate, das Sie ebenfalls in Moodle finden.Die Installation der Entwicklungsumgebung auf einem eigenen PC soll nicht während der Laborübung erfolgen! Die Präsenzzeit während der Laborübung ist ausschließlich für die Bearbeitung der Laboraufgaben gedacht!

Page 4: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

Inhaltsverzeichnis1 Entwicklungssystem.....................................................................................................................1

1.1 Hardware..............................................................................................................................11.2 Software................................................................................................................................3

2 Motivation.....................................................................................................................................43 Nutzung der STM32-Peripherie....................................................................................................5

3.1 Einführung............................................................................................................................53.1.1 Interne Busse und Peripherie........................................................................................53.1.2 Manuelle Konfiguration..................................................................................................7

3.2 Laboraufgabe 1: LED manuell einschalten...........................................................................83.2.1 Manuelles Einschalten der LED mit Hilfe der Special Function Register.......................8

4 Programmierung des STM32......................................................................................................104.1 Programmiervorbereitung...................................................................................................10

4.1.1 Grundeinstellungen......................................................................................................114.1.2 Projekt erstellen...........................................................................................................114.1.3 Quellcode bearbeiten, kompilieren und testen.............................................................114.1.4 Debugging-Grundlagen...............................................................................................124.1.5 Design-Diagramme erstellen.......................................................................................14

4.2 Laboraufgabe 2: Addition (Debug-Übung)...........................................................................154.2.1 Aufgabenstellung.........................................................................................................154.2.2 Erläuterungen..............................................................................................................16

4.3 Laboraufgabe 3: Einschalten der LED mit einem C-Programm...........................................174.3.1 Vorgehensweise..........................................................................................................174.3.2 Optionale Erweiterung.................................................................................................17

5 Nutzung der STM32-Funktionsbibliothek....................................................................................185.1 Konfiguration durch die Firmware-Bibliothek.......................................................................185.2 Laboraufgabe 4a: Blinklicht.................................................................................................20

5.2.1 Vorgehensweise..........................................................................................................205.2.2 Erläuterungen..............................................................................................................20

5.3 Timer...................................................................................................................................205.4 Laboraufgabe 4b: Blinklicht mit Timer.................................................................................21

5.4.1 Vorgehensweise..........................................................................................................216 Interrupt-Handler........................................................................................................................22

6.1.1 Funktionsweise eines Timer-Interrupts........................................................................226.2 Laboraufgabe 5: Lauflicht mit Timer-ISR.............................................................................23

6.2.1 Aufgabenstellung.........................................................................................................236.2.2 Hinweise......................................................................................................................236.2.3 Vorgehensweise..........................................................................................................23

7 Tasten......................................................................................................................................... 247.1 Laboraufgabe 6: Entprellung...............................................................................................25

7.1.1 Aufgabenstellung.........................................................................................................267.1.2 Vorgehensweise..........................................................................................................267.1.3 Schnittstelle von pushbuttons.h...................................................................................26

8 Assembler..................................................................................................................................278.1 Laboraufgabe 7a: ggT.........................................................................................................27

8.1.1 Vorgehensweise..........................................................................................................278.2 Laboraufgabe 7b: Bubblesort..............................................................................................27

8.2.1 Vorgehensweise..........................................................................................................289 Pulsweitenmodulation.................................................................................................................29

9.1 Laboraufgabe 8: LED-Helligkeit mit PWM...........................................................................299.1.1 Augabenstellung..........................................................................................................299.1.2 Vorgehensweise..........................................................................................................29

10 LCD-Einführung........................................................................................................................3010.1 SPI....................................................................................................................................3010.2 Laboraufgabe 9a: SPI-Bus-Modul.....................................................................................32

10.2.1 Aufgabenstellung.......................................................................................................32

Page 5: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

10.2.2 Schnittstelle von spi.h................................................................................................3210.3 LCD-Ansteuerung.............................................................................................................3310.4 Laboraufgabe 9b: LCD-Ansteuerung................................................................................35

10.4.1 Aufgabenstellung.......................................................................................................3510.4.2 Schnittstelle von lcd.h................................................................................................3510.4.3 Schnittstelle von lcd_drawing.h.................................................................................3610.4.4 Wichtige Befehle des LCD-Controllers......................................................................3710.4.5 Schriftarten................................................................................................................38

Page 6: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

1 - Entwicklungssystem 1

1 EntwicklungssystemEin Entwicklungssystem, das der Anwendungsprogrammerstellung für einen Mikrocontroller dient, besteht aus spezifischen Hardware- und Software-Komponenten:

Als Hardware stehen für die einzelnen Mikrocontroller-Familien sowohl die meist teureren herstel-lerspezifischen Entwicklungsplatinen als auch einfachere, preiswertere Entwicklungsplatinen von Drittanbietern zur Verfügung.Als Software kommen diverse Editoren, hardwarespezifische Systembibliotheken sowie Compiler, Linker und Debugger zum Einsatz.

1.1 HardwareDie im Laborpraktikum eingesetzte Entwicklungshardware besteht aus einem industriell gefertigten Development Kit und einer Zusatzplatine, die speziell für das Embedded Systems-Labor an der FH Gießen-Friedberg entwickelt worden ist. Das Development Kit hat einen STM32F103RBT6 der Fir-ma ST Microelectronics als Kern, der auf dem ARM Cortex M3 basiert. Das Kit wurde als USB-Dongle konzipiert und kann mit einer ansteckbaren Zusatzplatine erweitert werden.

1 Steckverbinder für IO-Board2 Grüne LED / Fototransistor3 Rote LED4 Grüne LED für USB-Status5 USB-Steckverbinder6A Pin PC0 (für Voltmeter, Zähler, Frequenzmesser)6B Analog Ground (GNDA)6C Pin PC13 (bspw. als Trigger für 6A)6D Ground (GND)

1 Steckverbinder für PerformanceStick2 Taster3 LEDs, grün4 Grafik-LCD mit Hintergrundbeleuchtung,

128x64 Pixel5 Beschleunigungssensor (unter dem LCD)6 A/D-Wandler-Erweiterung7 SPI-Bus-Erweiterung

Die Erweiterungsplatine stellt einige Peripheriekomponenten zur Verfügung, die wir in diesem La-bor nutzen werden. Sie muss an den PerformanceStick angesteckt werden, bevor dieser mit dem PC verbunden wird.

Üblicherweise findet man auf Entwicklungsplatinen eine erheblich höhere Anzahl von ICs, die Peri-pherie darstellen oder den Anschluss von eben solcher ermöglichen. Da Cortex M3-basierte Chip-designs jedoch bereits viele Schnittstellen integrieren und folglich wesentlich mehr als nur die CPU beinhalten, werden derartige Mikrocontroller auch als System-on-Chip (SoC) bezeichnet:

Abbildung 1.1: STM32-PerformanceStick

Abbildung 1.2: Zusatzplatine mit LCD

Page 7: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

1.1 - Hardware 2

Wie im Diagramm ersichtlich, arbeitet die CPU mit einem maximalen Takt von 72MHz, den wir auf dem PerformanceStick auch verwenden. Die dort verbaute SoC-Variante STM32F103RBT6 besitzt 20KB SRAM, 128KB internen Flash-Speicher und besitzt außer dem FSMC-Interface, dem SDIO-Interface, dem I²S-Bus, der ETC und den DACs alle der dargestellten Komponenten.

Der PerformanceStick alleine beinhaltet also bereits alle nötigen Funktionen, die von einer moder-nen Entwicklungshardware erwartet werden: On-Chip Debugger, JTAG-Interface zum Übertragen des Programmes auf den Chip, USB-Interface-Chip für besagtes JTAG-Interface sowie einige LEDs als Beispielperipherie. Weitergehende Hardware kann üblicherweise direkt ange-schlossen werden, was besonders für platzsparende Designs von Bedeutung ist.

Die CPU selbst ist eine 32-Bit-CPU, die mit ARMs Thumb-2-Befehlssatz arbeitet. Sie besitzt 16 Register, von denen 13 frei verwendet werden können, und einen Adressraum von 4GB. Da so viel Speicher nicht vorhanden ist, werden bestimmte Bereiche dieses Adressraums für die Implemen-tierung diverser Funktionen (bspw. Bit Banding) und über Memory Mapped I/O für die Ansteuerung der Peripherie genutzt.

Bit Banding beschreibt dabei ein Verfahren, bei dem jedem Bit eines wählbaren Speicherbereiches eine eigene Speicheradresse zugewiesen wird. Auf diese Weise kann man effizient einzelne Bits eines Wertes setzen und löschen, was durch den Thumb-2-Befehlssatz weniger elegant möglich ist. Besonders attraktiv ist das Verfahren, wenn man berücksichtigt, dass die gesamte Peripherie

Abbildung 1.3: Blockdiagramm des STM32

Page 8: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

1.1 - Hardware 3

durch Memory Mapped I/O im Speicher abgebildet wird und man sehr oft nur einzelne Bits setzen oder löschen möchte.

Zum Debuggen von Programmen ist es äußerst hilfreich, den Thumb-2-Befehlssatz zu kennen. Da dieser sehr umfangreich ist, sei auf die offizielle ARM-Dokumentation verwiesen, die unter [Thum-b2] zu finden ist.Desweiteren sind unter [STM32DS] die Datenblätter von ST zu finden, die den Funktionsumfang sowie die mechanischen und elektrischen Eigenschaften des verwendeten Chips ausführlich doku-mentieren.

1.2 SoftwareAls Entwicklungsumgebung wird die zum STM32 PerformanceStick gehörende Anwendung HiTOP Verwendung. Die IDE selbst besitzt keinen Compiler, weshalb ihr die GNU Compiler Collection (GCC) zur Seite gestellt wird. Auf den virtuellen Desktops (s. o.) ist die Version 5.3 (mit Anpassun-gen für diese Lehrveranstaltung) installiert. Darüber hinaus steht im Downloadbereich der Lehrver-anstaltung die Version 5.40 zur Verfügung, die auch auf 64 Bit-Windows lauffähig ist.

Die IDE enthält alles, was für das Erstellen und Debuggen von Programmen auf dem STM32 not-wendig ist:

• Ein Assembler, der aus hardwarespezifischem Assemblercode linkbare Objekte generiert.• Ein Cross-Compiler für C/C++, der aus Quellcode ebenso linkbare Objekte generiert.• Ein Linker, der nach entsprechenden Vorgaben mittels der linkbaren Objekte und einer hardwa-

respezifischen Bibliothek eine Binärdatei erzeugt, die der Zielprozessor ausführen kann.• Ein Debugger, der mittels der vom Compiler/Linker erzeugten Debug-Informationen den Pro-

grammverlauf auf dem Prozessor mit Verweisen auf den C/C++-Quellcode nachvollziehbar macht. Darüber hinaus erlaubt er einen direkten Eingriff in den Programmverlauf sowie die In-spektion/Überwachung von Speicher-, Register- und Variableninhalten.

Zum besseren Verständnis der Zusammenhänge folgt nun eine Übersicht über die in der Entwick-lungsumgebung verwendeten Dateiarten, deren Beziehungen untereinander und die verwendeten Werkzeuge:

C-Quelldatei .c Header-Datei .h Assemblercode .s ↓ ↓ ↓

C-Cross-Compiler (gcc) Cross-Assembler (as) ↓ ↓ ↓

Relocatable Object .o Quellverweis .d Relocatable Object .o ↓ ↓ ↓ Linker-Skript .ld ↓ ↓ ↓ ↓

Linker (ld) ↓ ↓

Ausführbare Datei .elf Quellverweis .d Debug-Symboltabelle .map ↓ ↓ ↓

Debugger (in HiTOP integriert)

Page 9: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

2 - Motivation 4

2 MotivationDas Ziel dieses Labors ist es, die Besonderheiten und Anforderungen von eingebetteten Systemen zu vermitteln. Um auch Studenten anzusprechen, die eher wenig Interesse an dieser Thematik ha-ben, werden die gestellten Einzelaufgaben in den Rahmen einer konkreten Anwendung gestellt. Jede dieser Aufgaben stellt somit einen notwendigen Baustein auf dem Weg zum Endprodukt dar.

Das Ergebnis der letzten Aufgabe des Labors wird somit eine Uhr sein, die sich sehen lassen kann. Die Hardware, auf der sie basiert, besteht aus den folgenden Komponenten:

• Grafikdisplay mit 128x64 Pixeln, monochrom• Hintergrundbeleuchtung für das Display• 2 Taster• 3D-Beschleunigungssensor• 8 LEDs, grün

Die Liste mag zwar kurz erscheinen, diese Komponenten bieten jedoch zusammen mit den Fähig-keiten des STM32 derart viele Möglichkeiten, dass man den Umfang des Labors leicht verdoppeln könnte. Eine Stoppuhr passt allerdings gut in den Zeitrahmen von einem Semester und erlaubt es, die wichtigsten Komponenten unseres eingebetten Systems kennen zu lernen:

Die folgenden Abschnitte beschäftigen sich jeweils mit bestimmten Teilen des Systems. Zu einigen der Komponenten werden im Rahmen der Laboraufgaben Module entwickelt, die in späteren Ab-schnitten Verwendung finden. Die Aufgaben bauen somit aufeinander auf und gegen Ende des La-bors werden alle Komponenten integriert und die Stoppuhr fertiggestellt.

Abbildung 2.1: Im Labor verwendete Hardware-Komponenten

Page 10: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

3 - Nutzung der STM32-Peripherie 5

3 Nutzung der STM32-Peripherie

3.1 EinführungVor noch nicht allzu langer Zeit wurden Mikroprozessoren ausschließlich mittels Assembler pro-grammiert. Zu dieser Zeit war der Funktionsumfang eines solchen Prozessors nicht so umfang-reich wie heute. Peripherie wurde also oft als externes Bauteil über einen allgemein verwendbaren Bus angebunden. Durch diese allgemeine Verwendbarkeit der Mikroprozessoren war zwar einer-seits eine hohe Flexibilität möglich, andererseits verstand der Prozessor aber nicht die Protokolle, die notwendig sind, um mit der Peripherie zu kommunizieren.

Diese Situation machte es oft unumgänglich, sogenanntes „bit banging“ zu betreiben, also das ver-langte Protokoll softwaretechnisch zu emulieren, indem mit Hilfe von Timern und Warteschleifen zu möglichst gut definierten Zeitpunkten bestimmte Werte auf den Peripheriebus geschrieben wurden. Man kann sich gut vorstellen, dass diese Vorgehensweise nicht nur komplex, sondern in gewissem Sinne auch gefährlich ist, da beispielsweise durch Interrupts die durch das Protokoll vorgeschrie-benen Zeiten überschritten werden können.

Mit dem Fortschreiten der Entwicklung auf Hardwareebene wurde es möglich, mehr und mehr Komponenten auf dem Chip zu vereinen. Die Anzahl der Komponenten wurde mit der Zeit so hoch, dass man für diese Architekturen mittlerweile den Begriff „System on Chip“ (SoC) bevorzugt, um die Unterscheidung zu reinen Mikroprozessoren zu ermöglichen.Viele SoCs bieten nun also Komponenten, die der Kommunikation mit Peripherie dienen. Sie im-plementieren die benötigten Protokolle in Hardware, was zum einen die Ansteuerung einfacher und zum anderen das bit banging überflüssig macht.

Gleichzeitig vollzog sich auf Softwareseite ein ähnlicher Paradigmenwechsel, indem Assembler abgelöst und durch Hochsprachen ersetzt wurde. Für zeitkritische oder sehr spezifische Algorith-men findet Assembler zwar auch heute noch Verwendung, derzeit trifft man allerdings hauptsäch-lich die Sprachen C oder C++ an.Wie bereits im vorigen Abschnitt gesehen, werden wir den STM32 in diesem Labor ebenfalls in C programmieren, was uns durch den Hersteller des SoC besonders einfach gemacht wird. Dazu je-doch später mehr.

3.1.1 Interne Busse und Peripherie

Die Komponenten, die sich auf einem SoC befinden, müssen in der Lage sein, Daten auszutau-schen. Im Falle des STM32 geschieht dies über die folgenden Busse:

Abbildung 3.1: Die Busse im STM32

Page 11: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

3.1 - Einführung 6

Dabei bedeutet... und ermöglicht...

I-Bus Instruction Bus ...Lesezugriff auf das im Prozessor ablaufende Programm

D-Bus Data Bus ...Lese-/Schreibzugriff auf RAM und Peripherie

System System Bus ...Kontrolle über Systeminterne Komponenten

GP-DMA General Purpose DMA ...schnelle Datentransfers zwischen RAM und Peripherie, bei denen die CPU selbst nicht aktiv werden muss und somit entlastet wird

AHB Advanced High Speed Bus ...die Schnelle Anbindung von Peripherieeinhei-ten an die Bus-Matrix

APB1 Advanced Peripheral Bus 1 ...Zugriff auf die etwas langsameren Teile der Peripherie

APB2 Advanced Peripheral Bus 2 ...Zugriff auf die schnellen Teile der Peripherie

Des Weiteren gibt es noch den Arbiter und die Bridges, deren Aufgaben und Funktionsweisen je-doch sehr spezifisch sind und den Rahmen dieses Abschnittes sprengen würden.

Möchte man beispielsweise Daten von der Cortex-M3-CPU an den Controller USART1 schicken, so müssen diese Daten über den D-Bus, die Bus-Matrix, den AHB und APB2 geschickt werden, bevor sie das Zeil erreichen. Dabei kommt bei eingebetteten Systemen auch die Notwendigkeit des Energiesparens ins Spiel.

Der STM32 besitzt daher vielfältige Möglichkeiten, den Stromverbrauch zu senken. Eine dieser Möglichkeiten besteht darin, ungenutzte Komponenten effektiv in einen Ruhezustand zu versetzen, indem diese vom Systemtakt getrennt werden. Um standardmäßig so energiesparend wie möglich zu sein, sind nach einem Reset des STM32 alle nicht unbedingt nötigen Zusatzkomponenten ohne Takt. Es ist also wichtig zu wissen, dass die Peripherie und diverse interne Komponenten nur dann ansprechbar sind, wenn sie auch mit dem Systemtakt versorgt werden.

Bevor wir im folgenden Abschnitt lernen, wie wir die auf dem STM32 vorhandene Peripherie mittels HiTOP direkt konfigurieren können, erfolgt eine Übersicht über die am weitest verbreiteten Peri-pherieeinheiten und deren Bezeichnungen im STM32:

Üblicher Name Bezeichnung STM32 Zweck

Port Port A..E Gruppierung von I/O-Leitungen

GPIO (General Purpose I/O) Px0..15 (x = Port A..E) Frei verfügbare I/O-Leitung

ADC (A/D Converter) ADC Messwertaufnahme, Digitalisierung

DAC (D/A Converter) Signalerzeugung

Watchdog IWDG / WWDG Zustandsüberwachung,Schutz bei Fehlfunktion

Page 12: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

3.1 - Einführung 7

Timer TIM1..4 Verzögerung, Taktung, PWM

RTC (Real Time Clock) RTC Bereitstellung einer Uhr

SPI (Serial Peripheral Interface) SPI1..2 Kommunikation mit externer Peripherie über den SPI-Bus

I²C (Inter-Integrated Cicruit) I2C1..2 Kommunikation mit externer Peripherie über den I²C-Bus

I²S (Integrated Interchip Sound) Übermittlung von Sound-Samples

USART (Universal sync / async receiver transmitter)

USART1..2 Konvertierung serieller Daten zu parallelen Daten und umgekehrt

USB (Universal Serial Bus) USB Breitbandige Kommunikation mit externen Komponenten

CAN (Controller area Network) CAN Kommunikation mit externen Komponenten, insbesondere in Fahrzeugen

JTAG (Joint Test Action Group) JTAG Schnittstelle zur Programmierung und Fehlerbehebung

DMA (Direct Memory Access) DMA Durchführung von Datentransfers innerhalb des SoC ohne Mitwirkung der CPU

SDIO (Secure Digital I/O) Anschluss von Komponenten mit hohem Datendurchsatz, z.B. WLAN, Bluetooth oder SD-Karten

NOR / NAND Schnittstelle für externen NOR- oder NAND-Speicher

Flash Flash Zugriff auf internen oder externen Flash-Speicher

Es gibt noch weitere Peripherieeinheiten, diese sind aber weniger stark verbreitet und somit auf spezielle Anforderungen zugeschnitten. Im Verlauf dieses Labors werden Sie von den oben gelis-teten Peripherieeinheiten mit den GPIOs, den Timern, einer der beiden SPI-Schnittstellen und eventuell der RTC arbeiten. Sollten Sie aus Interesse weitere Komponenten in Ihre Lösungen ein-bauen, kann diese freiwillige Erweiterung zu Bonuspunkten führen (vgl. Abschnitt Fehler: Referenznicht gefunden).

3.1.2 Manuelle Konfiguration

In der folgenden Aufgabe soll die rote LED (Nummer 3 in Abbildung 1.1) von Ihnen zum Leuchten gebracht werden. Die LED ist mit einem digitalen Ein-/Ausgang (GPIO) des STM32 Mikrocontrol-lers verbunden.Man könnte nun ein Programm schreiben, das die LED ansteuert. Im Folgenden wird jedoch eine einfachere Möglichkeit beschrieben.

Page 13: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

3.1 - Einführung 8

In HiTOP gibt es ein Fenster, das Sie eventuell bereits entdeckt haben. Es trägt den wenig aussa-gekräftigen Titel „SFR Window“, der für „Special Function Register Window“ steht. Das Fenster er-möglicht die komfortable Beobachtung und Manipulation derjenigen Speicherinhalte, die die Peri-pherie kontrollieren. Wählen Sie den Menüpunkt „View → SFR window“, um es zu öffnen. Auf der linken Seite des Fensters ist eine Baumstruktur zu sehen, die die einzelnen Komponenten auflistet. Rechts davon kann man die in der gewählten Komponente verfügbaren Parameter auswerten und modifizieren. Es ist dabei egal, ob der STM32 mitten in der Programmausführung ist oder gerade über ein Reset zurückgesetzt worden ist - alle Einstellungen, die im SFR-Fenster vorgenommen werden, treten sofort in Kraft.

3.2 Laboraufgabe 1: LED manuell einschaltenBevor Sie die rote LED auf dem STM32 PerformanceStick einschalten können, müssen Sie her-ausfinden, an welchem GPIO-Port und welchem Pin dieses Ports die LED angeschlossen ist. Au-ßerdem benötigt man die Information, ob Anode oder Kathode der LED mit dem Port-Pin verbun-den ist. Diese Informationen können Sie dem Schaltbild des STM32 PerformanceStick entnehmen:

Auf Seite 3 des Schaltbilds finden Sie die rote LED (Abkürzung „rt“ für „rot“). Sie sehen dort, dass die LED mit der Anode an PB5 angeschlos-sen ist. „PB5“ steht hier für Port B (also GPIO B), Pin 5 (Bit 5). Dadurch, dass diese I/O-Leitung mit der Anode der LED verbunden ist und die Katho-de der LED auf „GND“ (0V) liegt, ergibt sich, dass die LED über eine positive Spannung (lo-gisch „1“) an der I/O-Leitung eingeschaltet wird.

3.2.1 Manuelles Einschalten der LED mit Hilfe der Special Function Register

Wählen Sie GPIOB im Baum. Sie werden feststellen, dass die meisten GPIOs des Ports als Typ „Floating Input / General purpose Open-drain“ im Modus „Input mode“ konfiguriert sind:

Dies bedeutet , dass die GPIOs als unbeschaltete Eingänge konfiguriert sind und keine Funktion besitzen. Somit können eventuell angeschlossene externe Komponenten auf keinen Fall Schaden nehmen.Die Konfiguration sorgt gleichzeitig aber auch dafür, dass unsere LED nicht mit Strom versorgt werden kann. Um dies zu ändern, setzen Sie den Typ von Leitung 5 auf „Analog input mode / General purpose output push-pull“.

Schaltbild-Auszug vom STM32 Performance Stick (Seite 3)

Page 14: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

3.2 - Laboraufgabe 1: LED manuell einschalten 9

Sie werden feststellen, dass ihre Wahl zunächst ignoriert wird. Dies liegt daran, dass GPIOB eine Peripherieeinheit ist, die explizit mit dem Systemtakt versorgt werden muss, damit sie arbeiten kann. Um dies zu erledigen, müssen wir uns kurz um die zentrale Steuerung für System- und Bu-stakte kümmern. Sie befindet sich in der Komponente „Reset and Clock Control“, kurz RCC.

Setzen Sie dort den Parameter „I/O port B clock“ auf „Enabled“, wodurch Port B Systemtakt be-kommt:

Gehen Sie nun zurück zu den Parametern von Port B und versuchen Sie erneut, Leitung 5 auf „Analog input mode / General purpose output push-pull“ zu setzen. Wie erwartet gelingt es jetzt, weshalb wir nun auch den Modus auf „Output mode“ setzen können - die Frequenz ist erst einmal egal. Ausgang B5 ist nun konfiguriert und einsatzbereit.

Scrollt man nach unten, schreibt eine 1 in das Feld neben „Port output data 5“ und drückt Enter, so leuchtet die LED. Wird eine 0 eingetragen, verlischt sie wieder.

Auf diese Weise kann man sämtliche Parameter der gesamten STM32-Hardware einstellen, wäh-rend der Fehlersuche inspizieren oder im Betrieb eventuell auftretende Fehlersituationen simulie-ren. Es ist allerdings sinnvoll, diese Konfigurationen im Programm selbst vorzunehmen, so dass sie dauerhaft gespeichert und automatisch nach dem Systemstart wiederhergestellt werden.

Page 15: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

4 - Programmierung des STM32 10

4 Programmierung des STM32

4.1 ProgrammiervorbereitungObwohl die von Ihnen im Laborpraktikum zu erstellenden Programme relativ kurz sein werden, sollten bei der Programmerstellung immer folgende Punkte beachtet werden:

a) Erstellen Sie für jede Aufgabe ein eigenes Projekt.b) Machen Sie sich gut mit der Aufgabenstellung vertraut, damit Sie genau wissen, was durch Ihr

Programm erreicht werden soll. Verschaffen Sie sich ausreichende Informationen über techni-sche Daten, Verfahren, Programmierbibliotheken, etc.

c) Die Aufgabe, die das Programm lösen soll, ist so in Teilaufgaben zu splitten, dass diese Teilauf-gaben unabhängig voneinander erstellt werden können. Dies erfordert eine saubere Schnittstel-lenklärung.

d) Bereiten Sie Ihr Programm durch die Erstellung von Struktogrammen (gemäß DIN 66261; auch „Nassi-Shneiderman-Diagramme“ genannt), von Programmablaufplänen oder von geeigneten UML-Diagrammen vor.

e) Das Programm ist zu modularisieren, sodass nach schrittweiser Verfeinerung der Problemstel-lung überschaubare, kurze Programmteile (z.B. C-Funktionen) entstehen. Programm-Module sollen nur einen Eingang und einen Ausgang haben. Jedes Modul soll eine abgeschlossene Funktionseinheit bilden, d.h. ein anderes Modul ist entweder vollständig darin gekapselt (ge-schachteltes Programm) oder es ist davon komplett unabhängig.

f) Änderungen, Anpassungen und Erweiterungen müssen jederzeit schnell und sicher ohne Be-einflussung anderer Programmteile durchgeführt werden können. Module sollen einzeln testbar sein.

g) Aus der Gliederung des Programms muss dessen dynamischer Ablauf klar erkennbar sein, so-dass auch eine andere Person, die nicht an der Programmentwicklung beteiligt war, den Pro-grammablauf ohne großen Aufwand nachvollziehen kann.

h) Für eine ausreichende und aktuelle Dokumentation durch ausführliche Kommentierung des Pro-gramms ist stets zu sorgen, damit ein lesbares und wartungsfreundliches Programm entsteht. Dies beinhaltet die Erstellung von Dateiköpfen, die den Namen des Programms, den Inhalt der Datei (z.B. Kurzbeschreibung eines Moduls), die Autoren und das Erstellungsdatum beinhalten. Ein solcher Dateikopf könnte etwa wie folgt aussehen:

123456789

101112131415161718

/******************************************************************** * Project: Laboraufgabe 1 * File: main.c * * System: STM32-PerformanceStick (Cortex M3 ) * Compiler: GNU GCC 4.3.0 * * Date: 2008-10-06 * Authors: Olli Dittrich * Ester Schweins * Mirko Nontschew * * Rights: All rights reserved * License: n/a ******************************************************************** * Description: * Contains the main program and implements the core functionality ********************************************************************/

Listing 1: Beispiel-Dateikopf

Page 16: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

4.1 - Programmiervorbereitung 11

Der Dateikopf kann natürlich wahlweise auch in Deutsch verfasst werden. In größeren Unterneh-men wird jedoch üblicherweise die englische Sprache vorgezogen.

4.1.1 Grundeinstellungen

Nach dem Hochfahren des Hostrechners (Benutzername „Student“, Passwort „student“) wird durch Anklicken des Icons „HiTOP52“ die Entwicklungsumgebung gestartet. Stecken Sie nun den STM32-PerformanceStick in eine freie USB-Buchse.

Da HiTOP zur Arbeit an einem Projekt mit dem STM32-PerformanceStick in Verbindung stehen muss und Sie diese Voraussetzung gerade erfüllt haben, kann nun ein Projekt erzeugt oder gela-den werden.

4.1.2 Projekt erstellen

Um ein neues Projekt zu erstellen, gehen Sie bitte wie folgt vor:

1) Wählen Sie den Menüpunkt „Project → New“ und wählen Sie den GNU C Compiler.2) Klicken Sie auf „Next“ und wählen Sie den PerformanceStick aus der Liste.3) Nach einem erneuten Klick auf „Next“ können Sie den Namen Ihres Projekts eingeben. Stellen

Sie sicher, dass für „Project location“ das Verzeichnis C:\STM32 eingetragen ist, sofern Sie die Projekte nicht auf einem mitgebrachten USB-Stick speichern möchten. Wird dies gewünscht, müssen Sie den Pfad natürlich entsprechend anpassen.

4) Wählen Sie im nächsten Schirm den STM32-PerformanceStick als Zielplattform.5) Nach Bestätigung der Wahl mit „Next“ müssen Sie evtl. die Seriennummer ihres Performance-

Sticks eingeben. Diese finden Sie auf der Unterseite des Sticks.6) Klicken Sie dann auf „Connect“, so wird HiTOP die Verbindung zum PerformanceStick aufbau-

en, das Projekt erzeugen, auf den STM32 flashen, das Programm bis zum Eintritt in die Reset()-Funktion ausführen und es dann stoppen.

4.1.3 Quellcode bearbeiten, kompilieren und testen

Die HiTOP-Entwicklungsumgebung kennt zwei Betriebsmodi, zwischen denen unterschieden wer-den muss. Zum einen gibt es den Debugmodus, in dem sich das Programm standardmäßig be-findet. Ist er aktiv, lässt sich das kompilierte Programm ausführen und der Programmablauf im STM32 verfolgen. Man kann den Quelltext jedoch nicht verändern. Hat man die Arbeit im Debug-ger abgeschlossen und möchte am Programm weiterarbeiten, muss man in den Editiermodus wechseln. Dies geschieht, indem man im Quelltextfenster rechts klickt und die Option „Switch to Edit Mode“ wählt oder die Tastenkombination STRG-T drückt.

Auf die selbe Art und Weise kann man auch wieder in den Debugmodus wechseln. Üblicherweise wird man jedoch nach Änderung des Programms dessen Funktion testen wollen, wozu das Pro-gramm kompiliert und geflasht werden muss. Durch das Flashen schaltet HiTOP allerdings auto-matisch in den Debugmodus, was die Benutzung des Editors ein wenig angenehmer gestaltet.

Hinweis : Wenn Sie manuell vom Editor-Modus in den Debugmodus umschalten, dann sollten Sie sich darüber im Klaren sein, dass das sich im STM32 befindliche Programm nicht automatisch ge-ändert worden ist und Ihre Änderungen am Quellcode nicht nur unberücksichtigt sind, sondern so-gar zu ungewollten Fehlinterpretationen des Debuggers führen können.

Haben Sie an Ihrem Programm Änderungen vorgenommen, die Sie testen möchten, so müssen Sie das Projekt kompilieren, linken und flashen. Dies geschieht durch den Menüpunkt „Project → Build“. Sie können alternativ dazu aber auch einfach F7 drücken.

Page 17: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

4.1 - Programmiervorbereitung 12

Schlägt die Kompilierung ein-mal fehl, können Sie über das Fenster „Output → Build“ nachvollziehen, wo Fehler aufgetreten sind. Über einen Doppelklick auf die Fehlermeldung gelangen Sie zur entsprechenden Zeile im Quelltext.

Gelingt die Kompilierung und wurde das Programm im STM32-Flash somit auf den neuesten Stand gebracht, können Sie es ausführen. Im Regelfall werden jedoch die Register noch alte Werte haben, weshalb Sie den Menüpunkt „Debug → Reset&Go“ verwenden sollten. Er sorgt dafür, dass der STM32 zurückgesetzt und danach das Programm im Flash neu gestartet wird. Analog zum Kompiliervorgang kann auch hier ein entspre-chendes Tastaturkürzels (STRG-R) verwendet werden.

4.1.4 Debugging-Grundlagen

Abbildung 4.1: Das Build Log in HiTOP

Abbildung 4.2: HiTOP im Debugmodus

Page 18: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

4.1 - Programmiervorbereitung 13

Läuft ein Programm auf dem STM32, können Sie es mit dem in HiTOP integrierten Debugger be-obachten und analysieren. Sehr wertvoll dabei ist die Möglichkeit des Setzens von Breakpoints bei unterbrochener Programmausführung, wobei zwischen permanenten und temporären Breakpoints unterschieden wird:

• Temporäre Breakpoints sorgen dafür, dass die CPU das Programm sofort weiter ausführt und erst dann unterbricht, wenn die Stelle erreicht worden ist, die der Breakpoint markiert. Danach wird der Breakpoint automatisch gelöscht.

• Permanente Breakpoints werden erst dann aktiv, wenn der Benutzer dem Debugger sagt, dass das Programm weiter ausgeführt werden soll. Dann jedoch unterbrechen sie das Programm im-mer dann, wenn die betroffene Programmzeile als nächstes ausgeführt werden würde.

Das Setzen von Breakpoints kann bspw. mit einem Rechtsklick im Quelltext-Editor über die Menü-punkte „Run to Cursor Line“ und „Set Breakpoint“ erfolgen. Vorzugsweise wird der Programmfluss jedoch über ein etwas intuitiveres Interface beeinflusst: die graue Spalte auf der linken Seite des Quelltext-Editors.

Einen temporären Breakpoint setzen Sie, indem Sie auf den blauen Balken derjenigen Zeile Ihres Quelltextes klicken, bis zu welcher Anweisung das Pro-gramm ausgeführt werden soll.

Daraufhin wird diese Zeile grün hinterlegt, was auf einen Break-point hinweist. Auch steht nun der gelbe Pfeil auf der Zeile - er zeigt an, welche Anweisung als nächstes ausgeführt wird.

Permanente Breakpoints halten das Programm immer dann an, bevor die Anweisung ausgeführt wird, auf der ein Breakpoint ge-setzt worden ist.

Sie werden durch einen Klick links neben den blauen Balken erzeugt und hinterlegen die Zeile im Editor rot.

Hinweis: Beachten Sie, dass das Setzen eines temporären Breakpoints die sofortige Ausführung des Programms zur Folge hat.

Neben den Breakpoints stehen auch die nachfolgend beschriebenen Debug-Funktionen zur Verfü-gung. Ob Sie die Befehle über die Icons, mit Hilfe der Tastaturkürzel oder über das Pull-Down-Me-nü ausführen, bleibt der Gewohnheit überlassen.

Page 19: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

4.1 - Programmiervorbereitung 14

Icon Tastaturkürzel Menüeintrag Bedeutung

F5 Go Startet das Programm oder setzt die Ausführung fort.

Wird ein Breakpoint angetroffen, hält das Programm an.

STRG-F5 Go (disable) Startet das Programm oder setzt die Ausführung fort.

Alle gesetzten Breakpoints werden ignoriert.

F11 Step Into Führt den nächsten Befehl aus. Ist dies ein Funktionsaufruf, stoppt das Programm in der ersten Zeile der Funktion.

F9 Step Instruction Führt den nächsten Befehl aus und hält danach an.

F10 Step Over Führt den nächsten Befehl aus. Ist dies ein Funktionsaufruf, wird die Funktion abgearbeitet und danach angehalten.

STRG-F11 Step Out Setzt die Ausführung fort, bis die aktuelle Funktion verlassen wird.

SHIFT-F10 Go until... Führt das Programm bis zum Eintritt in eine Funktion aus, deren Namen Sie im Dialogfenster angeben müssen.

STRG-F10 Go to Cursor Führt das Programm bis zur aktuellen Cursorposition aus.

SHIFT-F5 Stop Hält den Programmablauf an.

ALT-R Reset Versetzt die CPU in den Ursprungszustand, es werden also alle Register- und Speicherinhalte gelöscht.

STRG-R Reset&Go Versetzt die CPU in den Ursprungszustand und beginnt danach mit der Ausführung des im Flash gespeicherten Programms.

Breakpoints... Ermöglicht die übersichtliche Verwaltung von gesetzten Break-points. Diese können hier auch an- und abgeschaltet werden.

STRG-B Set/Remove Breakp. Erzeugt bzw. löscht einen Breakpoint in der Zeile, in dem sich der Cursor befindet.

Show PC Location Macht diejenige Zeile im Quelltext-Editor sichtbar, die als nächstes ausgeführt wird, wenn das Programm weiterläuft.

Die in diesem Abschnitt besprochenen Möglichkeiten stellen die Basis dar, die von den allermeis-ten Debuggern zur Verfügung gestellt werden. Der HiTOP-Debugger bietet darüberhinaus noch mehr Funktionen, von denen einige im Rahmen der Übungen näher erläutert werden.

4.1.5 Design-Diagramme erstellen

Wie Sie der Liste der Programmiervorbereitungen entnehmen konnten, müssen für die einzelnen Versuche Diagramme erstellt werden, die das Design des von Ihnen entwickelten Programms ver-deutlichen. Daher bietet es sich an, noch einmal kurz auf diese Thematik einzugehen. Zuerst müs-sen Sie entscheiden, welchen der nachfolgend angegebenen Diagrammtypen Sie einsetzen möch-ten:

• Struktogramm• Progammablaufplan• UML-Diagramme (Aktivitätsdiagramm, Sequenzdiagramm, Zustandsdiagramm)

Wie Sie wissen umfasst der UML-Standard zwar 13 Diagrammtypen, allerdings sind nur die hier

Page 20: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

4.1 - Programmiervorbereitung 15

erwähnten zur Abbildung der in diesem Labor auftretenden Problemstellungen geeignet. Sollten Sie weitergehende Informationen zu diesen Diagrammtypen wünschen, finden Sie diese auf Wiki-pedia unter [UMLDiag]. Ebenso auf Wikipedia finden Sie unter [UMLTools] eine Liste von UM-L-Werkzeugen, die Sie zur Erstellung der Diagramme verwenden können.

Besonders empfohlen werden die folgenden Programme:• ArgoUML (UML, http://argouml.tigris.org)• BOUML (UML, http://bouml.free.fr/)• Vips (Struktogramm, http://partheil.com/vips/)• Structorizer (Struktogramm, http://structorizer.fisch.lu/)• PapDesigner (PAP, http://www.gso-koeln.de/papdesigner/)

4.2 Laboraufgabe 2: Addition (Debug-Übung)

4.2.1 Aufgabenstellung

1) Folgen Sie den Anweisungen des Abschnitts 4.1 auf Seite 10ff..2) Erzeugen Sie ein neues Projekt in HiTOP.3) Fügen Sie Listing 2 (Seite 16) an passender Stelle in die Datei main.c ein.4) Erstellen Sie das Programm und beheben eventuell vorhandene Fehler, bis es fehlerfrei ist und

somit automatisch geflasht wird.5) Wenden Sie den „Go to Cursor“-Befehl auf Zeile 11 in Listing 2 an.6) Am unteren Bildschirmrand sehen Sie eine Reiterleiste. Wechseln Sie zum Fenster „Locals“,

falls es nicht schon aktiv ist. Sie merken, dass dort alle lokalen Variablen der Funktion main() aufgelistet werden. In jeder Zeile findet sich auch der jeweilige Wert der Variablen. Da diese je-doch noch undefiniert sind, steht überall ein Fragezeichen als Wert.

7) Führen Sie das Programm schrittweise aus (bspw. mittels „Step Into“), während Sie die Fenster „Locals“ und „Disassembly“ beobachten.

8) Haben Sie die Endlosschleife erreicht, setzen Sie das Programm zurück und führen Sie es bis zum Anfang von main() aus.

9) Setzen Sie auf Zeile 17 des Listings einen Breakpoint.10) Auf der linken Seite der Entwicklungsumgebung finden Sie einen Reiter namens „Callstack“.

Klicken Sie ihn an und führen Sie das Programm aus.11) Wird das Programm am Breakpoint gestoppt, beobachten Sie das „Callstack“-Fenster und füh-

ren das Programm schrittweise fort, bis Sie wieder in main() angekommen sind.

Page 21: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

4.2 - Laboraufgabe 2: Addition (Debug-Übung) 16

123456789

1011121314151617181920212223242526

int add(int a, int b) { int result; result = a + b; return result; }

int main(void) { int a, i, x, y, z; x = 3; y = 4;

z = add(x, y);

a = 0; for (i=0; i<z; i++) { a += z; } while (1); }

Listing 2: Programm zu Laboraufgabe 2

4.2.2 Erläuterungen

Im Programmlisting wird Ihnen aufgefallen sein, dass sich am Ende eine Endlosschleife befindet. Diese ist nicht etwa problematisch, sondern ist sogar zwingend erforderlich. Der Grund dafür be-steht darin, daß nach dem Durchlaufen von main() das Programm schlicht aufhört, die CPU jedoch fleissig weiter Instruktionen aus dem Speicher liest und ab-arbeitet. Im Normalfall werden diese In-struktionen Funktionen des Programms sein, die dann in komplett ungültige Zustände geraten (da kein Stack initialisiert, keine Parameter übergeben, etc.), es könnten aber auch Daten sein, die gar keine Instruktionen sind. Sie sehen also, dass main() unter keinen Umständen verlassen werden darf!

Abschließend noch ein paar Bemerkungen zu den benutzten Fenstern:

Das „Locals“-Fenster, mit dem Sie Bekanntschaft gemacht haben, ist eine spezielle Variante des benachbarten Fensters „Watch1“ - die Einträge in diesen Listen werden in der Regel als Watches bezeichnet. Der Begriff stammt daher, daß man auf diese Weise diese Variablen überwacht, quasi also „anschaut“. Der Unterschied zwischen den beiden Fenstern besteht darin, daß in „Locals“ nur die lokalen Variablen der aktuellen Funktion angezeigt werden, während das reguläre Watch-Fens-ter nur diejenigen Watches anzeigt, die man selbst definiert hat.

Hinweis: Ist der Programmablauf angehalten, können die Werte der Watches in den Fenstern auch beliebig geändert werden, um bestimmte Situationen hervorzurufen bzw. zu testen.

Das mit „Callstack“ bezeichnete Fenster beinhaltet wie Sie festgestellt haben die aktuelle Hierar-chie der aufgerufenen Funktionen. Es lässt sich insbesondere dazu nutzen, um festzustellen, wel-che Funktionen eine andere Funktion aufrufen. Dies erreicht man dadurch, indem man in der auf-gerufenen Funktion einen Breakpoint setzt.

Page 22: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

4.2 - Laboraufgabe 2: Addition (Debug-Übung) 17

Zusammen mit den Einzelschrittbefehlen bilden Breakpoints, Watches und der Call Stack das Grundgerüst, mit dem alle modernen Debugger ausgerüstet sind. Sie werden davon im Laufe ihrer beruflichen Karriere noch oft Gebrauch machen, wenn Sie Software entwickeln möchten. Nutzen Sie also die Gelegenheit und sammeln Sie Erfahrungen im Umgang mit dem Debugger.

4.3 Laboraufgabe 3: Einschalten der LED mit einem C-Programm

4.3.1 Vorgehensweise

1) Legen Sie ein neues Projekt in HiTOP an. Beachten Sie dabei die Hinweise aus Abschnitt 4.1!2) Öffnen Sie das „Reference Manual“ zum STM32-Mikrocontroller und suchen Sie in der Memory

Map die Basisadresse der RCC Register (Reset and Clock Control). Definieren Sie ein Makro (#define) in dem Quelltext Ihres Projekts (main.c) mit dieser Basisadresse.

3) Suchen Sie in der Memory Map die Basisadresse für die Register des GPIO B und halten diese ebenfalls als Makro in Ihrem Quelltext fest.

4) Gehen Sie in dem Reference Manual zum Abschnitt mit der Beschreibung der RCC-Register. Suchen Sie dort den Offset für das „APB2 peripheral clock enable register“ und definieren Sie in Ihrem Quelltext wiederum ein Makro für diesen Wert.

5) Lesen Sie aus der Beschreibung des Registers ab, welches Bit für GPIOB zuständig ist. Auch diesen Wert sollten Sie als Makro festhalten.

6) Gehen Sie in dem Reference Manual zum Abschnitt mit der Beschreibung der GPIO-Register und lesen Sie den Offset für das „Port configuration register low“ ab. Notieren Sie sich, welche Bits in diesem Register für die I/O-Leitung Nr. 5 zuständig sind. (MODE5 und CNF5).

7) Bestimmen Sie anhand der Beschreibung der MODE- und CNF-Bits, welchen Wert diese Bits haben müssen, um die I/O-Leitung in den Modus „General purpose output push-pull“ und „Out-put mode 2 MHz“.

8) Weiter unten in dem Reference Manual finden Sie den Offset für das „Port output data register“ und das „Port bit set/reset register“. Auch für diese beiden Offsets sollten Sie jeweils ein Makro in Ihrem Quelltext definieren.

9) Ergänzen Sie in der Funktion main() Ihres Quelltextes zwischen der NVIC-Configuration und der Endlosschleife die erforderlichen Code-Zeilen, um GPIOB mit Takt zu versorgen und an-schließend I/O-Pin 5 zu konfigurieren und die LED einzuschalten. Verwenden Sie dafür zu-nächst das „Port output data register“. Nach erfolgreichem Test des Programms sollten Sie den Code so ändern, dass die LED mit Hilfe des „Port bit set/reset register“ eingeschaltet wird.

4.3.2 Optionale Erweiterung

Lassen Sie die LED blinken, indem Sie sie in der Endlosschleife abwechselnd ein- und ausschal-ten. Rufen Sie zwischen dem Ein- und Ausschalten jeweils die Funktion busy_wait(Wartezeit) auf. Probieren Sie aus, wie groß der Wert für die Wartezeit gewählt werden muss, damit die LED mit etwa 2 Hz blinkt.

Page 23: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

5 - Nutzung der STM32-Funktionsbibliothek 18

5 Nutzung der STM32-Funktionsbibliothek

5.1 Konfiguration durch die Firmware-BibliothekVor noch nicht allzu langer Zeit war es üblich, dass Hardwarehersteller ihren Kunden lediglich aus-führliche Datenblätter und Beschreibungen über die Steuerung und das Verhalten der einzelnen in-ternen Komponenten übergaben. Diese wurden dann mittels Assembler angesprochen. Mittlerwei-le fand durch den Wechsel von Assembler zu C jedoch auch hier eine Veränderung statt. Haupt-sächlich aus Gründen der Entwicklungsgeschwindigkeit bieten die Hersteller nun zusätzliche Firm-ware-Bibliotheken an, mit denen sich die Funktionen der vorhandenen Hardware deutlich beque-mer ausnutzen lassen.

Der von uns verwendete STM32 wird von STMicroelectronics produziert. Man findet die Firmware-bibliothek daher unter [STM32Files]. Das Paket dort beinhaltet nicht nur den Quellcode der Biblio-thek in C, sondern auch einige Beispiele, um den Einstieg zu erleichtern. (Für das Praktikum ist es allerdings nicht notwendig, das Paket herunterzuladen.)Wichtig ist jedoch die Dokumentation der Bibliothek, die als Dokument UM0427 verfügbar war (neue Versionen sind nur als minderwertige CHM-Dateien vorhanden). Sie erläutert alle vorhande-nen Befehle und dient Ihnen somit während der Softwareentwicklung als erster Anlaufpunkt bei Problemen und Unklarheiten.

Es ist nun das Ziel, die Konfiguration der STM32-Peripherie über ein Programm durchzuführen, so dass die LED an PB5 aufleuchtet. Erstellen Sie dazu ein neues Projekt nach Abschnitt 4.1.2 auf Seite 11. Ist das Projekt erstellt, findet man auf der linken Seite von HiTOP einen Dateibaum, der die Dateien anzeigt, die zum aktuell geladenen Projekt gehören. Standardmäßig sind dort einige Basisdateien eingetragen, die die Grundinitialisierung der Hardware durchführen und die Firmwa-re-Bibliothek einbinden.

Klicken Sie auf das „+“-Zeichen neben der Kategorie „Library Sources“. Die nun angezeigte Liste beinhaltet diejenigen C-Dateien, die für die Steuerung der im Projekt verwendeten Komponenten verantwortlich sind.

In dem von Ihnen neu erzeugten Projekt sind nun die Dateien, die die Komponenten RCC, Flash und NVIC verfügbar machen, sichtbar. Außerdem findet sich in der Liste die Datei stm32f10x_lib.c, die ebenso wie ihr Pendant stm32f10x_lib.h selbst keine Funktionalität bereitstellt, jedoch zentrale Konstan-ten und Variablen für die anderen Teile der Bibliothek vorhält.

Um also die GPIOs ansteuern zu können, muss man die Datei stm32f10x_gpio.c zu den „Library Sources“ hinzufügen. Dies gelingt, indem man mit der rechten Maustaste auf den Katego-rienamen klickt und „Add Files To Folder“ wählt.In dem Verzeichnes des Projektes befindet sich ein Verzeichnis namens „Library“, das die Header und Quellcodes der Biblio-

thek beinhaltet. Navigieren Sie dorthin und fügen Sie die Datei stm32f10x_gpio.c in das Projekt ein.

Dadurch werden zwar rein formell alle Voraussetzungen erfüllt, um die in stm32f10x_gpio.c vor-handenen Funktionen zu nutzen, der Inhalt wird jedoch nur dann vom Compiler beachtet, wenn eine passende Compilerdirektive definiert ist. Diese befindet sich zusammen mit den restlichen Di-rektiven der Bibliothek in der Datei stm32f10x_conf.h, die bereits in das Projekt eingebunden ist.

Abbildung 5.1: Datei hinzufügen

Page 24: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

5.1 - Konfiguration durch die Firmware-Bibliothek 19

Öffnen Sie diese Datei mit einem Doppelklick auf den Dateinamen im Projektdateibaum und führen Sie die folgenden Änderungen durch:

Damit werden die GPIO-bezogenen Funktionen nicht länger ignoriert und sind verwendbar. Diese werden in Kapitel 10 (Seite 166) in der Referenz zur Firmware-Bibliothek (UM0427) beschrieben - schauen Sie es sich dort einmal an.Sollten Ihnen dabei die Typen der Variablen Schwierigkeiten bereiten, finden Sie die entsprechen-den Definitionen in Kapitel 1.3.1 (Seite 38). Dort sind auch weitere wichtige Typen und Konstanten gelistet, die man für die Programmierung der Bibliothek kennen sollte. Ein Blick lohnt also!

Durch Studium und Anwendung der Kapitel über die RCC und die GPIOs könnte nun beispielswei-se das folgende Programm entstehen, um PB5 anzusteuern:

123456789

101112131415161718192021222324

int main(void) { GPIO_InitTypeDef GPIO_InitStructure; // required by GPIO_Init()

/* System Clocks Configuration **************************************/ RCC_Configuration();

/* NVIC Configuration ***********************************************/ NVIC_Configuration();

/* Enable GPIO clock for port B */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

/* Set output mode for pin 5 of port B */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOB, &GPIO_InitStructure);

/* PB5 = 1 */ GPIO_SetBits(GPIOB, GPIO_Pin_5); while (1); }

Listing 3: Verwendung der STM32-Library zum Setzen von PB5

Welche Bedeutungen RCC_Configuration() und NVIC_Configuration() im Detail haben ist hier zu-nächst noch nicht wichtig. Es sei jedoch kurz erwähnt, dass die erste Funktion die Takte hochsetzt (CPU: 72MHz, Busse: 36/72MHz) und die zweite Funktion den „Nested vectored interrupt control-ler“ (NVIC) an das laufende Programm anpasst.

Page 25: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

5.2 - Laboraufgabe 4a: Blinklicht 20

5.2 Laboraufgabe 4a: Blinklicht

5.2.1 Vorgehensweise

1) Folgen Sie den Anweisungen des Abschnitts 4.1 auf Seite 10.2) Erzeugen Sie ein neues Projekt in HiTOP.3) Fügen Sie den Quellcode aus Listing 3 in Ihr Programm ein.4) Erweitern Sie das Programm so, dass die LED an PB5 zum Blinken gebracht wird. Erstellen

Sie dazu ein Struktogramm, einen PAP oder ein passendes UML-Diagramm, bevor Sie mit der Codierung beginnen.

5) Verwenden Sie die in main.c vorhandene Funktion busy_wait(Wartezeit) und probieren Sie aus, bei welchem Wert für die Wartezeit die LED etwa im Sekundentakt (1 Hz) blinkt.

6) Ziehen Sie die Firmware-Referenz unter [STM32LibDoc] zu Rate!

5.2.2 Erläuterungen

In main.c befindet sich die Funktion busy_wait(), die nichts anderes macht, als die CPU eine be-stimmte Anzahl von leeren Schleifen durchlaufen zu lassen. Diese Art von Ausführungsverzöge-rung nennt man „busy loop“, „busy waiting“ oder „spinning“. Sie ist zwar schell geschrieben, hat je-doch erhebliche Nachteile:

• die Verzögerungszeit ist nur umständlich berechenbar;• die Verzögerungszeit hängt vom Compiler ab;• die Verzögerungszeit wird durch auftretende Interrupts beeinflusst;• die Verzögerungszeit ist direkt vom Takt abhängig, also auch vom Energiesparmodus des SoCs.

Das schwerwiegendste Problem ist jedoch, dass ein optimierender Compiler feststellen wird, dass in der Schleife keine Arbeit erfolgt und somit durch Optimierung keinen Code erzeugen wird. Entwi-ckelt und testet man also ein Programm mit abgeschalteter Optimierung und schaltet diese nach erfolgter Arbeit ein, um ein möglichst gutes Endergebnis zu erzielen, wird das Programm plötzlich nicht mehr funktionieren, da sämtliche Verzögerungsschleifen wegfallen!

Hinweis: Der Vollständigkeit halber sei erwähnt, dass man auch optimierende Compiler dazu brin-gen kann, busy loops nicht zu verwerfen. Eine Möglichkeit dazu bietet das C-Schlüsselwort „volati-le“, das an dieser Stelle aber nicht weiter behandelt werden soll.

5.3 TimerDie Nachteile von busy waiting können durch den Ein-satz von Timern vermieden werden. Sie sind üblicher-weise fester Bestandteil der Hardware und benötigen zur Verrichtung der Arbeit keine CPU-Ressourcen. Aus diesem Grund sind sie nicht nur unabhängig von dem, was die CPU macht, sondern bieten darüberhinaus viel-fältige Funktionen und hohe Präzision.

Der hier verwendete STM32 hat insgesamt 4 Timer. Da-bei ist TIM1 ein Timer mit erweiterten Funktionen, wäh-rend TIM2, TIM3 und TIM4 für allgemeine Zwecke ge-dacht sind. Das bedeutet jedoch nicht, dass die Timer 2..4 nicht viel zu bieten haben. Auch sie besitzen bereits viele verschiedene Betriebsmodi.

Abbildung 5.2: Aufbau eines Timers

Page 26: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

5.3 - Timer 21

Alle Timer haben im Grunde den gleichen Aufbau, der vereinfacht dargestellt aus Controller, Pres-caler (Vorteiler) und Counter (Binärzähler) besteht.

Die äußere Taktgenerierung ist komplex. Es reicht daher zu wissen, dass die Timer in unserem Fall mit 36 MHz getaktet werden. Für Details sei auf [STM32DS], Seite 17, und die Funktion RCC_Configuration() in main.c verwiesen.1

Der 36 MHz-Takt wird nun durch einen Prescaler um einen frei wählbaren Faktor von 1 bis 65536 heruntergesetzt und dem Zähler zugeführt. Dieser wiederum erhöht oder erniedrigt den internen Zählerstand um 1, wenn der Prescaler einen Takt generiert. Hat der Zähler einen Unter- oder Über-lauf der 16 bit breiten Zählstufe erkannt, signalisiert er dies dem durch Setzen des „Update“-Flags. Zum Abfragen des Update-Flags stellt die STM32-Funktionsbibliothek eine entsprechende Funk-tion zur Verfügung:

1 if (TIM_GetFlagStatus(TIM2, TIM_FLAG_Update) == SET) { ... }

Listing 4: Abfrage des Update-Flags von Timer 2

Das Update-Flag muss anschließend durch das Programm gelöscht werden, um den nächsten Zählerüberlauf wieder erkennen zu können. Für den Timer TIM2 geschieht das Löschen des Flags mit dem folgenden Befehl:

1 TIM_ClearFlag(TIM2, TIM_FLAG_Update);

Listing 5: Löschen des Update-Flags von Timer 2

Benutzt man einen Timer, möchte man natürlich genau festlegen, mit welcher Frequenz der Zäh-lerüberlauf stattfindet. Um dies zu erledigen, muss man dem Vorteiler und dem Zähler passende Werte zuweisen. Hierzu ein Rechenbeispiel:

TIM2CLK = 36MHz = 36000000 HzPrescaler = 2250 36000000 Hz / 2250 = 16000 HzPeriod = 80 16000 Hz / 80 = 200 Hz

In diesem Beispiel wird also 200 mal pro Sekunde (200 Hz) das Update-Flag gesetzt.

5.4 Laboraufgabe 4b: Blinklicht mit TimerIm Gegensatz zu Augabe 4a soll nun der Timer 2 für die Zeitverzögerung zwischen dem Ein- und Ausschalten der LED verwendet werden, um ein präzises Timing zu erzielen. Ziel ist es, dass die LED exakt mit 1 Hz und einem Tastverhältnis von 50% blinkt, also 1x pro Sekunde für 0,5 Sekun-den ein- und 0,5 Sekunden ausgeschaltet wird.

5.4.1 Vorgehensweise

1) Verwenden Sie das Projekt aus Laboraufgabe 4a.2) Aktivieren Sie in der Datei „stm3210x_conf.h“ zusätzlich die Makros _TIM und _TIM2.3) Fügen Sie bei den Library-Sources die Datei „stm32f10x_tim.c“ hinzu.4) Ergänzen Sie in Ihrem Programm den Funktionsaufruf, um Timer 2 mit Takt zu versorgen.

1 Hinweis: HCLK = AHB clock; PCLK1 = Low Speed APB = APB1; PCLK2 = High Speed APB = APB2

Page 27: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

5.4 - Laboraufgabe 4b: Blinklicht mit Timer 22

5) Definieren Sie eine strukturierte Variable für die Konfiguration der Timers mit Hilfe der Funktion TIM_TimeBaseInit() und initialisieren Sie diese Struktur mittels TIM_TimeBaseStructInit().

6) Stellen Sie die Elemente TIM_Period und TIM_Prescaler der strukturierten Variable so ein, dass alle 0,5 Sekunden ein Zählerüberlauf stattfindet. Zusätzlich können Sie noch die Zählrich-tung über TIM_CouterMode auf TIM_CounterMode_Up2 einstellen, wobei die Zählrichtung für diese Laboraufgabe unbedeutend ist, da wir den Zählerstand nicht auslesen. Konfigurieren Sie den Timer 2 mit Hilfe dieser strukturierten Variable und der Funktion TIM_TimeBaseInit().

7) Aktivieren Sie den Timer 2 mittels TIM_Cmd() (→ ENABLE).8) Fragen Sie in der Endlosschleife das Update-Flag ab (siehe Listing 4) und wechseln Sie den

Zustand der LED bei jedem Zählerüberlauf. (Die Abfrage des aktuellen Zustands kann über die Funktion GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_5) erfolgen.) Denken Sie daran, nach jedem Zählerüberlauf das Update-Flag wieder gemäß Listing 5 zu löschen!

6 Interrupt-HandlerEs gibt eine Vielzahl von Interrupts, denen auf dem STM32 ein Handler bzw. eine ISR zugewiesen werden kann. Sie alle sind bereits in der Datei interrupt.c vorhanden, jedoch leer. Soll ein Handler nun eine bestimmte Aufgabe verrichten, schreiben Sie den entsprechenden Code einfach hinein.

Beachten Sie jedoch, dass es nicht ausreichend ist, eine ISR mit Code zu füllen und den Interrupt in der entsprechenden Komponente (bspw. TIM2) zu aktivieren. Der Interrupt würde in diesem Fall zwar den Interrupt Controller erreichen, dieser würde ihn jedoch ignorieren und der Handler würde nie aufgerufen werden.

Um dies zu ändern, muss der gewünschte Interrupt auch beim NVIC aktiviert werden, was sich zum Beispiel mit NVIC_Init()3 bewerkstelligen lässt. Um die Konfiguration des NVIC zu vereinfa-chen, benutzen Sie bitte die Funktion NVIC_StructInit() zur Initialisierung der strukturierten Varia-blen mit Default-Werten für die Preemption Priority und die Sub Priority. Weitere Details dazu ent-nehmen Sie bitte der Bibliotheks-Referenz.

6.1.1 Funktionsweise eines Timer-Interrupts

Hat ein Timer einen Unter- oder Überlauf erkannt, sendet er ein Signal an eine Leitung des Inter-rupt Controllers (NVIC), der die CPU unterbricht und die für diese Leitung konfigurierte Interrupt Service Routine (ISR) aufruft. Das Update-Flag signalisiert in diesem Fall der ISR, dass der Zäh-lerstand die Ursache für die Auslösung des Interrupts war. Das Update-Flag muss von der ISR ge-löscht werden, um die erfolgreiche Bearbeitung zu signalisieren. Geschieht dies nicht, wird der In-terrupt unabhängig vom Zählerstand so lange ausgelöst, bis die Bearbeitung erfolgt ist.

Sie sollten darauf achten, Ihre Interrupt-Handler so kurz wie möglich zu halten. Der Hauptgrund dafür ist der, dass der Interrupt-Handler eventuell gerade andere wichtige Programmteile unter-bricht und Sie somit zeitkritische Arbeiten verzögern könnten. Das Resultat davon wären dann Fehler, beispielsweise in der Einhaltung von Protokoll-Timings (Stichwort: bit banging).

Desweiteren könnte der Handler des Timers wiederum von noch wichtigeren Interrupts unterbro-chen werden, was am Ende dazu führen kann, dass der Timer einen Interrupt auslöst, während der entsprechende Handler den vorigen Interrupt noch bearbeitet.

2 Hier ist ein Fehler auf Seite 343 des UM0427: Es muss TIM_CounterMode_Up heißen.3 In dem Programmbeispiel auf Seite 228 des UM0427 steht fälschlicher Weise NVIC_InitStructure()

Page 28: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

6.2 - Laboraufgabe 5: Lauflicht mit Timer-ISR 23

6.2 Laboraufgabe 5: Lauflicht mit Timer-ISR

6.2.1 Aufgabenstellung

Die Zusatzplatine mit dem LCD verfügt über 8 grüne LEDs, siehe Abbildung 1.2. Diese LEDs sol-len als „Lauflicht“ angesteuert werden, d. h. es soll immer nur eine der acht LEDs leuchten, ange-fangen mit LED1, dann LED2, bis LED8. Anschließend soll das Ganze wieder von vorn beginnen. Ein „Durchlauf“ soll dabei genau 1 Sekunde dauern. Das Timing soll dabei mit Hilfe einer Interrupt-Service-Routine (ISR) erfolgen.

6.2.2 Hinweise

Die LEDs auf der Zusatzplatine sind mit dem GPIO-Port C verbunden. Dabei muss beachtet wer-den, dass die erste LED an PC5 und die achte LED an PC12 angeschlossen ist:

PC15 PC14 PC13 PC12 PC11 PC10 PC9 PC8 PC7 PC6 PC5 PC4 PC3 PC2 PC1 PC0

32768 16384 8192 4096 2048 1024 512 256 128 64 32 16 8 4 2 1

Bisher wurden die Zustände von GPIO-Ausgängen mittels GPIO_SetBits() und GPIO_ResetBits() gesetzt. Da GPIOs aber in 16er-Gruppen zu Ports zusammengefasst sind, ist es möglich, die Wer-te aller 16 Pins eines Ports gleichzeitig auszulesen oder zu setzen:

12 current_value = GPIO_ReadOutputData(GPIOC); GPIO_Write(GPIOC, new_value);

Listing 6: Lesen und Setzen des gesamten GPIO-Ports CBeim Schreiben eines neuen Wertes in das Port-Register sollen jedoch nur die Ausgänge für die 8 LEDs (PC5...12) verändert werden. Die restlichen Portleitungen sollen ihren alten Wert behalten! Verwenden Sie dazu das Read-Modify-Write -Prinzip !

Für die Lauflichtfunktion ist der Operator „<<“ in „C“ sehr hilfreich!

6.2.3 Vorgehensweise

1) Legen Sie ein neues Projekt an, schalten Sie den Timer 2 und den GPIOC in der Datei stm32f10x_conf.h frei. Binden Sie die Library-Sources für Timer und GPIO in das Projekt ein!

2) Konfigurieren Sie die Leitungen 5 bis 12 des GPIO-Ports C auf Output Push-Pull 2MHz. Den-ken Sie auch an die Taktversorgung des GPIOC!

3) Konfigurieren Sie den Timer 2 analog zur Laboraufgabe 4b. Dabei soll die Update-Frequenz je-doch auf 8 Hz eingestellt werden.

4) Der Interrupt-Ausgang eines verwendeten Timers muss durch Aufruf von TIM_ITConfig() expli-zit aktiviert werden, bevor der jeweilige Clock Controller ein Signal an den NVIC abschickt. Als Interrupt-Quelle ist lediglich TIM_IT_Update zu aktivieren.

5) Denken Sie daran, den Timer mittels TIM_Cmd() zu aktivieren!6) Der Interrupt Controller muss über den Befehl NVIC_Init() initialisiert werden, sodass er die

vom gewählten Timer verursachten Interrupts bearbeitet. Verwenden Sie dafür zunächst die Funktion NVIC_StructInit(), um die nicht benötigten Elemente der Struktur NVIC_InitTypeDef zu initialisieren (z. B. NVIC_IRQChannelPreemptionPriority)!

7) Fügen Sie Ihre ISR in der Datei interrupt.c in der Funktion TIM2_IRQHandler() ein! 8) In der ISR muss mit Hilfe von TIM_ClearFlag() das Update-Flag zurückgesetzt werden!

Page 29: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

7 - Tasten 24

7 TastenEingebettete Systeme verrichten ihre Arbeit zwar oft autonom, ein sehr großer Anteil benötigt für die Arbeit jedoch Benutzereingaben. Dies trifft auch auf die in diesem Laborpraktikum zu entwi-ckelnde Uhr zu, deren Platine mit zwei Tastern ausgestattet ist. Ziel dieses Abschnittes ist es, ein Modul für die beiden Taster zu entwickeln, das für die Uhr später wiederverwendet werden kann.

Wie aus dem Schaltplan ersichtlich ist, sind die Taster direkt mit den GPIOs PB8 und PB9 verbun-den. In Abschnitt 3.1.2 konnte bereits beobachtet werden, dass die GPIOs sich nach einem Reset in einem Zwischenzustand befinden, der im Englischen als „floating“ bezeichnet wird. Das bedeu-tet, dass der entsprechende Pin keinen definierten Pegel hat und er sich so verhält, als wäre er nicht verbunden und hinge frei in der Luft. Es muss also auch für die GPIOs der Taster eine Konfi-guration erfolgen, bevor diese genutzt werden können - diesmal jedoch nicht als Ausgang, sondern als Eingang:

1234567

GPIO_InitTypeDef Pin_Config;

Pin_Config.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; Pin_Config.GPIO_Mode = GPIO_Mode_IPD; Pin_Config.GPIO_Speed = GPIO_Speed_2MHz; // doesn't matter!

GPIO_Init(GPIOB, &Pin_Config);

Listing 7: Konfiguration der GPIOs 8 und 9 als Eingänge mit Pull-down-Widerstand

Die Konstante GPIO_Mode_IPD steht dabei für die Konfiguration als Eingang (Input) mit pull down-Wi-derstand (PD). Analog dazu wird der interne pull up-Widerstand benutzt, wenn GPIO_Mode_IPU ver-wendet wird.

Im Bild rechts ist leicht zu erkennen, dass durch Schließen von SPU (pull up) bzw. SPD (pull down) festgelegt wird, welcher Pegel am Eingang anliegt, wenn kein externes Bauteil einen anderen Pegel vorgibt. Die Widerstände sind dabei so gewählt, dass selbst bei Kurzschluss nur ein minimaler Strom über sie fließt.

Auf der Zusatzplatine sind die Taster gegen die Be-triebsspannung VCC geschaltet, was beim Durch-schalten eine logische Eins darstellen soll. Da der linke Schaltkontakt im unbetätigten Fall in der Luft hängt, sorgt der durch die Konfiguration des GPIOs gewählte pull down-Widerstand dafür, dass der Pegel am Eingang eine stabile logische Null ergibt.

Wenn die beiden GPIOs einsatzbereit sind, kann man deren Zustand beispielsweise über die Funktion GPIO_ReadInputDataBit() erfahren. Sie liefert entweder Bit_SET oder Bit_RESET:

1234

if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_8) == Bit_SET) { ... }

Listing 8: Abfrage eines GPIO-Eingangs

Abbildung 7.1: GPIO-Eingangsbeschaltung

Page 30: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

7.1 - Laboraufgabe 6: Entprellung 25

7.1 Laboraufgabe 6: EntprellungWährend des Tests der vorhergehenden Aufgabe haben Sie sicherlich beobachtet, dass das Lauf-licht nicht immer wie gewünscht auf die Eingaben reagiert. Der Grund dafür ist kein Fehler im Pro-gramm, sondern eine Erscheinung, die als „Prellen“ bezeichnet wird. Dabei prallen die beiden Schaltkontakte einers Tasters oder Schalters durch die mechanische Krafteinwirkung derart aufein-ander, dass der Kontakt während einer kurzen Zeitspanne weder stabil als „offen“, noch stabil als „geschlossen“ angesehen werden kann. Beispielhaft ist dies im folgenden Bild zu sehen, auf dem der Prellvorgang eines sich öffnenden Tasters dargestellt ist:

Es lässt sich leicht erkennen, dass durch solche Prell-vorgänge ein angeschlossenes digitales Bauteil mehre-re Wechel zwischen Eins und Null registriert. Da der Taster jedoch nur einen einzelnen Wechsel von Eins nach Null verursachen soll, ist der Effekt äußerst uner-wünscht.

Abhilfe schaffen kann man auf mehrere Arten, bei-spielsweise mit Hilfe von Schmitt-Triggern oder RS- Flip-Flops. Bauteile kosten jedoch Geld, weshalb man heute im Allgemeinen eine Softwarelösung vorzieht.

Die für dieses Laborpraktikum verwendete Lösung be-ruht auf einem Algorithmus, der sich in festen Interval-len den Eingangszustand merkt. Ist dieser Zustand

über mehrere Intervalle konstant, wird dieser Zustand als stabil angenommen und an andere Pro-grammteile weitergereicht. Da es nach Betätigung des Tasters einige Intervalle dauert, bis sich ein stabiler Zustand eingestellt hat, wird das Signal um eine gewisse Zeit verzögert. Diese Zeit hängt auch davon ab, wie viele Zustände identisch sein müssen, bis der Algorithmus den Zustand als stabil ansieht.

Ist die Verzögerung zu kurz, so ist die Entprellung unzuverlässig. Ist sie hingegen zu lang, empfin-den Benutzer das System als langsam und träge. Es gilt also, einen Mittelweg zu finden.

Der gewählte Algorithmus benutzt eine Variable vom Typ „unsigned char“, die somit 8 Bit besitzt. Folglich lassen sich in dieser Variablen 8 einzelne binäre Zustände speichern. Diese sollen in je-dem Zeitintervall um eine Bit-Stelle verschoben werden, so dass sich eine zeitliche Abfolge der Zu-stände abbilden lässt:

Operation 27 26 25 24 23 22 21 20

Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0

<< 1 ∕ ∕ ∕ ∕ ∕ ∕ ∕

Z6 Z5 Z4 Z3 Z2 Z1 Z0 0

| Zx | | | | | | |

Z6 Z5 Z4 Z3 Z2 Z1 Z0 Zx

Der zeitlich gesehen neueste Zustand wird dabei durch das niederwertigste Bit abgebildet, wäh-rend der älteste Zustand durch das höchstwertigste Bit dargestellt wird. Beim Verschieben der Bits um eine Stelle nach links fällt der älteste Zustand weg und Bit 0 wird auf Null gesetzt. Durch die

Abbildung 7.2: Prellvorgang

Page 31: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

7.1 - Laboraufgabe 6: Entprellung 26

anschließende Oder-Operation wird dieses Bit dann mit dem Wert des aktuellen Zustands Zx be-legt.

Hat die 8-Bit-Variable also den Wert 0 angenommen, so hat der Eingang über einen Zeitraum von 8 Intervallen keine Signaländerung vollzogen - er ist also stabil. Das selbe gilt, wenn der Wert 255 angenommen wird.

Verzögerungszeiten von 100ms werden von Menschen gerade noch nicht wahrgenommen. Um diese Grenze nicht zu überschreiten, ist es daher zweckmäßig, den Algorithmus alle 80 ms / 8 = 10 ms aufzurufen. Der Timer, der dies erledigt, muss also auf eine Frequenz von 100 Hz eingestellt werden.

7.1.1 Aufgabenstellung

Das Programm aus Laboraufgabe 5 („Lauflicht“) soll so erweitert werden, dass durch Drücken der Taste S1 die Richtung des Lauflichts gewechselt werden kann.

7.1.2 Vorgehensweise

1) Fügen Sie zum Projekt aus Laboraufgabe 5 die Dateien pushbuttons.c und pushbuttons.h in die Dateikategorien „Source Files“ bzw. „Header Files“ des Projekts hinzu.

2) Versehen Sie die Funktionen in pushbuttons.c mit Inhalt, der die in Abschnitt 7.1.3 erläuterten Aufgaben erfüllt. Die Prototypen in pushbuttons.h dürfen dabei nicht verändert werden.

3) Verwenden Sie TIM2 für das Lauflicht und TIM4 für den periodischen Aufruf des Entprellalgo-rithmus. Timer TIM4 wird von nun an für diese Aufgabe reserviert sein.

4) Verwenden Sie eine globale Variable in main.c für die die Laufrichtung. Deklarieren Sie diese Variable in main.h mit Hilfe der Speicherklasse „extern“. Dadurch können Sie den Wert der Variablen auch innerhalb der ISR in der Datei interrupt.c abfragen.

5) Das Abfragen der Taste und das Umschalten der Laufrichtung soll innerhalb der Endlosschleife in main() erfolgen. Erstellen Sie für diesen Code-Teil zunächst ein Struktogramm oder Fluss-diagramm!

7.1.3 Schnittstelle von pushbuttons.h

void BTN_Init(void)

Diese Funktion initialisiert die Schnittstelle zum Abfragen der Tasten S1 und S2, indem sie Timer TIM4, die GPIOs PB8/9 und den NVIC entsprechend konfiguriert.

void BTN_UpdateButtonStates(void)

Der Interrupt-Handler von TIM4 soll diese Funktion aufrufen. Sie muss die Tasten abfragen und den Entprell-Algorithmus implementieren. Tritt dabei eine Zustandsänderung einer der beiden Tas-ten auf, muss die entsprechende Variable (BTN_State1 bzw. BTN_State2) aktualisiert werden.

BTN_State BTN_GetButtonState(BTN_Identifier ButtonID)

Über diese Funktion kann ein anderer Programmteil den aktuellen Zustand eines bestimmten Tas-ters erfahren. Die Funktion nimmt dabei die Werte BTN_ID_S1 und BTN_ID_S2 entgegen. Als Er-gebnis liefert sie entweder BTN_State_Pressed oder BTN_State_Released zurück.Beachten Sie, dass in dieser Funktion keine andere Funktion aufgerufen werden muss. Sie arbei-tet lediglich mit den Werten der Variablen BTN_State1 und BTN_State2.

Page 32: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

8 - Assembler 27

8 Assembler

8.1 Laboraufgabe 7a: ggTEs soll eine Funktion in Assembler geschrieben werden, die den größten gemeinsamen Teiler (ggT) von zwei Zahlen (Datentyp int) berechnet. Diese Funktion soll aus dem C-Programm heraus aufgerufen werden.

1234567891011

int ggT(int a, int b) { while (a != b) { if (a > b) a -= b; else b -= a; } return a; }

Listing 9: Berechnung des größten gemeinsamen Teilers in „C“ (Euklidischer Algorithmus)

8.1.1 Vorgehensweise

1) Erstellen Sie ein Assembler-geeignetes Flussdiagramm aus dem C-Code in Listing 9!2) Legen Sie ein neues Projekt an. Fügen Sie den Quelltext asm_functions.s in das Projekt ein!3) Fügen Sie die notwendigen Assembler-Befehle gemäß Ihres Flussdiagramms an der vorgese-

henen Stelle in den Quelltext asm_functions.s ein. Beachten Sie, dass die Funktionsparameter in den Registern R0 und R1 übergeben werden und der Rückgabewert in R0 stehen muss.

4) Fügen Sie in den Quelltext main.c die Funktionsdeklaration ein: int ggT(int a, int b);

5) Fügen Sie in der Funktion main() einen Funktionsaufruf von ggT() ein und prüfen Sie mit Hilfe des Debuggers, ob die Funktion korrekt arbeitet (→ Breakpoints, lokale Variablen prüfen)!

8.2 Laboraufgabe 7b: BubblesortSchreiben Sie eine Funktion in Assembler, die ein Feld von Zahlen (Datentyp int) sortiert. Die Funktion soll als ersten Parameter die Feldvariable (Adresse des ersten Feldelements) und als zweiten Parameter die Feldgröße erwarten:

123456789101112

void bubblesort(int array[], int count) { int i, tmp1, tmp2; for (count--; count>0; count--) for (i=0; i<count; i++) { tmp1 = array[i]; tmp2 = array[i+1]; if (tmp1 > tmp2) { array[i+1] = tmp1; array[i] = tmp2; } } }

Listing 10: Bubblesort in „C“

Page 33: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

8.2 - Laboraufgabe 7b: Bubblesort 28

8.2.1 Vorgehensweise

1) Erstellen Sie ein Assembler-geeignetes Flussdiagramm aus dem C-Code in Listing 10!2) Fügen Sie die notwendigen Assembler-Befehle gemäß Ihres Flussdiagramms an der vorgese-

henen Stelle in den Quelltext asm_functions.s ein.3) Fügen Sie in den Quelltext main.c die Funktionsdeklaration ein:

void bubblesort(int array[], int count);

4) Fügen Sie in der Funktion main() einen Funktionsaufruf von bubblesort() ein und prüfen Sie mit Hilfe des Debuggers, ob die Funktion korrekt arbeitet (→ Breakpoints, lokale Variablen prüfen)!

1234567891011121314151617181920212223

@ --------------------------------------------- @ mode of assembly @ --------------------------------------------- .syntax unified .thumb .arch armv7m

@ --------------------------------------------- @ allocation @ --------------------------------------------- .text

@ --------------------------------------------- @ function definition @ --------------------------------------------- .global my_function @ make 'my_function' visible .thumb_func my_function: @ <- your code goes here! bx lr @ return from subroutine

@ --------------------------------------------- .end

Listing 11: Datei „asm_functions.s“

Page 34: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

9 - Pulsweitenmodulation 29

9 PulsweitenmodulationEine sehr einfache Möglichkeit, analoge Signale zu erzeugen, bietet die Pulsweitenmodulation. Zwar besitzt der STM32 Mikrocontroller bereits einen Digital-Analog-Wandler, aber bei der folgen-den Laboraufgabe soll die Helligkeit einer LED an einem Digitalausgang gesteuert werden.

9.1 Laboraufgabe 8: LED-Helligkeit mit PWM

9.1.1 Augabenstellung

Es soll ein Programm für den erstellt werden, das die Helligkeit der roten LED (PB5) mit Hilfe einer Pulsweitenmodulation mit einer Frequenz von 1kHz steuert. Dabei soll die Helligkeit durch Drücken (und Halten) der Taste S1 (PB8) an der Zusatzplatine erhöht und mit der Taste S2 (PB9) verringert werden können.

9.1.2 Vorgehensweise

1) Erstellen Sie in der HiTOP IDE ein neues Projekt und fügen Sie in dem „Workspace - FileView“ zu den Library Sources die Datei „stm32f10x_gpio.c“ und „stm32f10x_tim.c“ hinzu.

2) Öffnen Sie das STM32 Reference Manual und schlagen Sie dort im Abschnitt „9.3.7 Timer al-ternate function remapping“ nach, welcher der Timer 2 bis 7 so konfiguriert werden kann, dass er die rote LED (PB5) ansteuert. (Timer Nummer? Timer Channel? Remapping?)

3) Öffnen Sie die Datei „stm32f10x_conf.h“ und aktivieren Sie dort die Makros _GPIO, _GPIOB, _AFIO, _TIM und _TIMx (x = Nummer des unter Punkt 2 gewählten Timers).

4) Öffnen Sie die Datei „main.c“ und ergänzen Sie dort den Funktionsaufruf zum Einschalten der Taktversorgung des GPIOB und des unter Punkt 2 gewählten Timers, sowie den Takt für die „alternate function“ der GPIOs.

5) Konfigurieren Sie GPIOB Pin 8 und 9 als Input mit Pull-Down-Widerstand. Verwenden Sie dazu die Funktion GPIO_Init() gemäß der Dokumentation (Bandbreite: 2 MHz).

6) Berechnen Sie den erforderlichen Wert für den Vorteiler (Prescaler) mit dem eine Zählerober-grenze (Period) von 100 insgesamt eine Frequenz von 1 kHz ergibt.

7) Verwenden Sie die Funktionen TIM_TimeBaseStructInit() und TIM_TimeBaseInit(), um den Timer zu konfigurieren (1 kHz, Modus: count up), und schalten Sie den Timer mit der Funktion TIM_Cmd() ein.

8) Verwenden Sie die Funktionen TIM_OCStructInit() und TIM_OCxInit(), wobei Sie das 'x' durch die Kanalnummer (Channel) ersetzen müssen, die Sie unter Punkt 2 ausgewählt haben. Mo-dus: PWM1, Output State: Enable, Pulse: 50 (= halbe Helligkeit), Polarity: high.

9) Stellen Sie das GPIO-Remapping mit Hilfe der Funktion GPIO_PinRemapConfig() gemäß Punkt 2 ein, so dass die rote LED (Port B, Pin 5) von dem Timer angesteuert wird.

10) Konfiguration für GPIOB, Pin 5 als „Alternate Function Push-Pull“, damit die LED von dem Timerausgang angesteuert wird.

11) Fügen Sie in die Endlosschleife am Ende von main() die Abfrage der Tasten mit Hilfe von GPIO_ReadInputDataBit() ein. 10. Ergänzen Sie dort den erforderlichen Code, mit dem bei gedrückter Taste S1 mit Hilfe der Funktion TIM_SetComparex() (x = Nr. des Kanals gemäß Punkt 2) das PWM-Tastverhältnis um 1 (bis max. 100) erhöht wird und bei gedrückter Taste S2 um 1 verringert wird (solange > 0). In beiden Fällen soll anschließend mit busy_wait(50000) eine kurze Zeit gewartet werden.

Page 35: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

10 - LCD-Einführung 30

10 LCD-EinführungFlüssigkristallanzeigen (LCDs) sind aus unserer heutigen Welt nicht mehr wegzudenken. Sie die-nen als Anzeigen in vielfältigen Anwendungsbereichen und sind durch ihre niedrigen Produktions-kosten interessante Alternativen zu LED-Anzeigen. Die Erweiterungsplatine zum STM32-Perfor-manceStick, mit der die Uhr erstellt wird, besitzt ebenfalls ein LCD. In diesem Abschnitt wird nun gezeigt, wie man es anspricht und welche Besonderheiten zu beachten sind.

Die Displays selbst benötigen mehrere Betriebsspannungen und eine präzise Ansteuerung, damit sie keinen Schaden nehmen. Aus diesem Grund muss man zwischen reinen LCDs und LCD-Mo-dulen unterscheiden. Letztere sind bereits mit einem passenden Controller ausgestattet, wodurch die Anbindung an den Rest der Schaltung enorm vereinfacht wird. Die Controller erzeugen die be-nötigten Spannungen/Impulse, stellen aber auch Schnittstellen für die Ansteuerung bereit. Am häu-figsten anzutreffen sind dabei Schnittstellen mit 4- und 8-Bit-Bussen, I²C und SPI. Das im Labor eingesetzte LCD-Modul wird im SPI-Modus betrieben, weshalb dessen Grundlagen erarbeitet wer-den müssen, bevor das LCD-Modul besprochen werden kann.

10.1 SPIDer SPI-Bus wird primär zum Anschluss von Peripheriekomponenten an eine CPU/ein SoC be-nutzt. Das Kürzel SPI steht dabei für „Serial Peripheral Interface“, was bereits erkennen lässt, dass die Datenübertragung seriell erfolgt. Die Anbindung erfolgt in Sterntopologie, wodurch relativ hohe Geschwindigkeiten ermöglicht werden. Da alle am Bus angeschlossenen Komponenten die gleiche Taktleitung benutzen, kann immer nur ein Busteilnehmer den Takt vorgeben. Aus diesem Grund muss jeder Komponente eine Rolle als Master (stellt Takt bereit) oder Slave (benutzt Takt) zugeteilt werden.

Der SPI-Bus hat üblicherweise drei Leitungen:

• SCK - Serial Clock• MISO - Master in, Slave out• MOSI - Master out, Slave in

Diese Leitungen werden von allen Komponenten glei-chermaßen verwendet - es ist somit einleuchtend, dass zu jedem Zeitpunkt immer nur eine als Slave arbeitende Peripherieeinheit mit dem Master kommunizieren kann. Um zu bestimmen, welche Komponente den Bus benut-zen darf, gibt es daher noch zusätzliche „Chip Select“-Leitungen, die vom Master verwaltet werden.

Auf der Zusatzplatine befinden sich zwei Slave-Kompo-nenten, die fast genau so an den STM32 angeschlos-sen sind, wie auf dem Bild rechts zu sehen ist: das LCD und der Beschleunigungssensor. Das LCD sendet je-doch keine Daten aus, sodass die MISO-Leitung hier keine Verwendung findet. Auf der Platine gibt es somit eine Chip Select-Leitung für das LCD (SPI1_CS_LCD), eine für den Sensor (SPI1_CS_Accel) und eine weitere für Erweiterungen (SPI1_CS_Plug), die momentan unbenutzt ist.

Zuerst soll das LCD angesteuert werden. Damit es Daten empfangen kann, müssen aufgrund der Funktionsweise des Busses die folgenden Bedingungen erfüllt sein:• Der STM32 muss als Master konfiguriert sein;• Die Chip Select-Leitungen müssen so geschaltet sein, dass nur das Display angesprochen wird.

Abbildung 10.1: Beispiel SPI-Bus

Page 36: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

10.1 - SPI 31

Um diese zu erfüllen, muss der STM32 entsprechend konfiguriert werden. Dies geschieht auf die gleiche Weise wie bei allen Hardwarekomponenten des SoCs. Hinzu kommt jedoch die Besonder-heit, dass die SPI-Schnittstelle mit GPIO-Pins verbunden ist, die nicht frei wählbar sind. Die Pins PA5..7 müssen also ebenfalls aktiviert und konfiguriert werden, damit sie für die Schnittstelle arbei-ten können. Da die Funktion als SPI-Schnittstelle eine Sonderfunktion darstellt, muss den betroffe-nen GPIOs mitgeteilt werden, dass eben diese Sonderfunktion genutzt werden soll. Dies ge-schieht, indem ihr Modus auf GPIO_Mode_AF_PP gesetzt wird (AF = alternate function):

123456789

10

GPIO_InitTypeDef Pin_Config;

Pin_Config.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7; // SPI1_SCK und SPI1_MOSI Pin_Config.GPIO_Mode = GPIO_Mode_AF_PP; // lt. Reference Manual S. 162 Pin_Config.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &Pin_Config);

Pin_Config.GPIO_Pin = GPIO_Pin_6; // SPI_MISO auf Input Pin_Config.GPIO_Mode = GPIO_Mode_IPU; // lt. Reference Manual S. 162 GPIO_Init(GPIOA, &Pin_Config);

Listing 12: Konfiguration der GPIOs PA5..7 für SPI1

Die Reihenfolge zur Initialisierung von SPI1 sieht demnach wie folgt aus:

1) Takt für GPIOA und SPI1 über RCC_APB2PeriphClockCmd() bereitstellen2) Die als Chip Select-Leitungen verwendeten GPIOs SPI1_CS_LCD, SPI1_CS_Accel und

SPI1_CS_Plug im Modus GPIO_Mode_Out_PP initialisieren (GPIO Port A)3) Alle drei Chip Select-Leitungen auf „low“ in negativer Logik setzen (= Ausgangsbit gesetzt)4) Von SPI1 verwendete GPIOs PA5..7 mittels GPIO_Init() initialisieren5) Konfiguration von SPI1 durch SPI_Init()6) SPI_Cmd() verwenden, um SPI1 zu aktivieren

Der Aufruf von SPI_Init() zur Konfiguration von SPI1 soll von Ihnen mit Hilfe der Firmware-Biblio-theks-Referenz erarbeitet werden. Schlagen Sie die benötigten Parameter dort nach und realisie-ren Sie die folgenden Einstellungen:

• Vollduplex-Modus mit 2 Datenleitungen (Senden/Empfangen)• STM32 ist Busmaster• Pro Datenpaket werden 8 Bit übertragen• Wenn keine Daten auf dem SPI-Bus übertragen werden, ist die SCK-Leitung „low“• Die erste Flanke des Takts wird zur Auswertung eintreffender Daten verwendet• Das (im Labor unbenutzte) NSS-Signal wird softwareseitig gesteuert• Die Baudrate ergibt sich aus 72 MHz / 8 = 9 MHz 4

• Das höchstwertigste Bit wird zuerst übertragen 5

Damit wäre SPI1 selbst einsatzbereit, jedoch ist noch keine am Bus angeschlossene Peripherie-einheit als Empfänger gewählt. Dies lässt sich ändern, indem die zur entsprechenden Einheit ge-hörende GPIO-Leitung den Wert „high“ in negativer Logik annimmt, ihr zum GPIO-Port gehörendes Bit also gelöscht wird. Die drei Chip Select-Leitungen sollten dabei durch die drei Konstanten

4 Achtung: Im UM0427, Seite 309, Tabelle 420 ist ein Tippfehler: statt SPI_FisrtBit_MSB muss es natürlich SPI_FirstBit_MSB heißen.

5 Achtung: Im UM0427 Seite 308, Tabelle 419 ist ein Tippfehler: statt SPI_BaudRatePrescaler8 muss es SPI_BaudRatePrescaler_8 heißen.

Page 37: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

10.1 - SPI 32

SPI1_CS_LCD, SPI1_CS_Accel und SPI1_CS_Plug ausgedrückt werden, damit eine gewisse Ab-strahierung ermöglicht wird. Beispielhaft soll die Wahl der CS-Leitung für das LCD geschehen:

12 GPIO_SetBits(GPIOA, SPI1_CS_LCD | SPI1_CS_Accel | SPI1_CS_Plug); GPIO_ResetBits(GPIOA, SPI1_CS_LCD);

Listing 13: Aktivierung der Chip Select-Leitung des LCDsDie erste Zeile des Listings stellt dabei sicher, dass alle anderen Slaves deaktiviert sind, bevor die gewünschte Peripherieeinheit aktiviert wird.

Jetzt ist auch das LCD empfangsbereit und wird die vom STM32 über den SPI-Bus gesendeten Daten entgegennehmen. Da der STM32 jedoch über keinen Sende-/Empfangspuffer verfügt, muss vor dem Senden jedes Bytes gewartet werden, bis die SPI-Schnittstelle zum Senden bereit ist. Da-nach kann dann mittels SPI_I2S_SendData() ein weiteres Byte auf den Bus geschickt werden. Auf Empfängerseite müssen die Daten jedoch auch verarbeitet werden können, weshalb nach Versand der Daten eine kleine Verzögerung angemessen sein kann. Dieses Vorgehen sei auch hier kurz exemplarisch dargestellt:

12345

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

SPI_I2S_SendData(SPI1, Data);

for (i=0; i<10; i++);

Listing 14: Senden eines Bytes via SPI

Die Verwendung eines busy loops ist in diesem Fall übrigens gerechtfertigt. Würde man für diese Aufgabe einen Timer verwenden wollen, würde der Code um einiges komplexer und es könnte so-gar möglich sein, dass die Abarbeitung des Codes zur Verwaltung des Timers länger dauert als eine solch kleine Schleife. Im Einzelfall muss man also abwägen.

10.2 Laboraufgabe 9a: SPI-Bus-Modul

10.2.1 Aufgabenstellung

1) Folgen Sie den Anweisungen des Abschnitts 4 auf Seite 10.2) Erzeugen Sie ein neues Projekt in HiTOP.3) Kopieren Sie die Dateien spi.c und spi.h in Ihr Projekt und fügen Sie diese in die Dateikatego-

rien „Source Files“ bzw. „Header Files“ des Projekts hinzu.4) Versehen Sie die Funktionen in spi.c mit Inhalt, der die in Abschnitt 10.2.2 erläuterten Aufgaben

erfüllt. Die Prototypen in spi.h dürfen dabei nicht verändert werden. Orientieren Sie sich bei der Codierung der Funktionen an den Beispielen des vorangegangenen Abschnittes.

5) Für diese Aufgabe ist keinerlei Diagramm erforderlich.

10.2.2 Schnittstelle von spi.h

void SPI1_Init()

Diese Funktion initialisiert die SPI-Schnittstelle, indem sie die in Abschnitt 10.1 erläuterte Initialisie-rungsliste umsetzt.

Page 38: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

10.2 - Laboraufgabe 9a: SPI-Bus-Modul 33

void SPI1_SendData(u8 Data)

Unter Verwendung dieser Funktion sollen andere Programmteile Daten über den SPI-Bus schicken können. In Listing 14 wurde das notwendige Vorgehen bereits beschrieben.

bool SPI1_SelectDevice(SPI1_Device Device)

Die Funktion SelectDevice() dient dazu, eine der am Bus angeschlossenen Komponenten zu akti-vieren. Bevor dies erledigt werden kann, müssen jedoch unbedingt alle anderen Komponenten de-aktiviert werden, da sie sonst Daten auswerten würden, die gar nicht für sie bestimmt sind. Die Wahl der Komponente erfolgt über den Parameter „Device“, der nur die in spi.h definierten Werte annehmen kann. Verwenden Sie in Ihrem Code die benannten Konstanten der dortigen Aufzäh-lung, nicht deren numerische Entsprechungen.Die Funktion soll vorerst immer TRUE zurückliefern.

10.3 LCD-AnsteuerungDer SPI-Bus ist jetzt einsatzbereit. Es bedarf jedoch noch weiterer Schritte, bis das LCD tatsäch-lich angesprochen werden kann, denn der Controller auf dem LCD-Modul befindet sich nach dem Einschalten in einem unbekannten Zustand. Er muss zunächst durch ein Reset in einen definierten Zustand gebracht werden.

Die Reset-Leitung ist an Pin PA10 angeschlossen und arbeitet mit negativer Logik. Da ein GPIO-Pin nach der Konfiguration im Modus GPIO_Mode_Out_PP standardmäßig einen Pegel von 0V aufweist, wird das Display demnach fortwährend zurückgesetzt. Also muss der Ausgangspegel an-gehoben werden, um den Reset zu beenden.

Abbildung 10.2: Verbindungen zwischen dem Mikrocontroller und dem LCD-Modul

Danach nimmt der Controller die über den SPI-Bus übertragenen Daten entgegen und wertet sie aus. Der Controller ist jedoch sehr flexibel gestaltet, um mit möglichst vielen LCDs arbeiten zu kön-nen. Die Anpassung an unsere Umgebung geschieht über eine einmalige Initialisierung, die in der folgenden Tabelle beschrieben wird:

Page 39: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

10.3 - LCD-Ansteuerung 34

Die Tabelle ist fast unverändert aus dem Datenblatt entnommen. Sie gibt an, welche Einstellungen vorzunehmen sind und mit welchen Befehlen diese umgesetzt werden können. Die Bits D0..7 sind dabei nicht als Datenleitungen ausgeführt, sondern geben die einzelnen Bits eines Bytes an, das über den Bus an das LCD geschickt wird. Zusammengefasst ergeben sie den hexadezimalen Wert, der in der Spalte „Hex“ eingetragen ist. Diese Werte müssen also lediglich in der angegebe-nen Reihenfolge übertragen werden.

Das Kürzel „C/D“ in der Tabelle steht für die „Command / Data“-Leitung. Ihr Pegel bestimmt, ob das übertragene Byte ein Befehl an den Controller ist, oder ob es Daten sind, die in den internen Speicher geschrieben werden sollen. Wie in der Tabelle ersichtlich, bedeutet ein „low“-Pegel, dass die Daten als Befehl zu interpretieren sind.

Zu welchem Zeitpunkt der Datenübertragung das C/D-Signal vom Controller ausgewertet wird, ist aus dem im Datenblatt vorhandenen Zeitdiagramm ersichtlich:

Der Pegel wird also vor Übertragung eines Bytes ausgewertet und ist zu allen anderen Zeitpunkten beliebig. Daraus folgt für die Ansteuerung, dass die C/D-Leitung auf den gewünschten Pegel ge-setzt werden muss, bevor das Daten- oder Befehlsbyte an die SPI-Schnittstelle des STM32 über-geben wird. Danach sollte die C/D-Leitung auf low gesetzt werden, um einen definierten Standard-zustand herzustellen.

Ist die Initialisierung erfolgt, so ist das LCD-Modul vollständig einsatzbereit. Zum Verständnis der Ansteuerung des Moduls wird nachfolgend sein interner Aufbau besprochen:

Abbildung 10.3: Initialisierung des LCD-Moduls

Abbildung 10.4: Zeitdiagramm der Datenübertragung zum LCD-Controller

Page 40: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

10.3 - LCD-Ansteuerung 35

Das Modul ist mit einem Display ausgestattet, das 128x64 Pixel besitzt. Der Controller des Moduls verfügt über einen kleinen Speicher, um den Displayinhalt verwalten zu können. Dieser ist jedoch nicht pixelweise ansprechbar. Vielmehr lassen sich nur Gruppen zu acht Pixeln ansprechen:

Die Pixel sind dabei in der Horizontalen auf 128 Spal-ten (columns) verteilt, während die Pixel auf der verti-kalen Achse in 8 Speicherseiten (pages) mit jeweils 8 Pixeln aufgeteilt sind.Die Werte der acht vertikalen Pixel einer Seite werden dabei in einem Byte abgelegt - jede Seite beansprucht also 128*1 Byte = 128 Bytes an Speicher.

Diese Aufteilung bereitet dann Probleme, wenn Dis-playinhalte erst nach und nach erzeugt werden: Weiß das Programm von der Struktur des Displayspeichers nichts, so werden mit der Übertragung eines Bytes möglicherweise sieben Pixel gelöscht, um ein einzel-nes zu setzen. Dem kann mit Hilfe eines Framebuffers begegnet werden, was aber nicht Thema dieses Ab-schnittes ist.

Zur Verdeutlichung des Aufbaus einer einzelnen Seite dient Abbildung 10.6, die die Spalten 0 bis 8 einer Zeichenkette illustriert, die in einer Speicherseite dargestellt ist. Man erkennt, wie sich die Werte eines Bytes zusammensetzen: Das Byte in Spalte 0 hat beispielsweise den Wert 38 (2+4+32), das in Spalte 1 den Wert 73 (1+8+64). Würden also die Werte 38 und 73 in den Spei-cher des LCD-Controllers übertragen, würden die ersten beiden Spalten dargestellt.

Damit die Werte im Speicher auch an die richtige Stelle geschrieben werden, muss im Normalfall die Seite und Spalte gesetzt werden, in der sich das zu schreibende Byte befindet. Hierzu dienen zwei Befehle, die in Abschnitt 10.4.4 gelistet sind. Schreibt man eine Funktion, die die Spalte setzt, die Seite setzt und dann das Datenbyte überträgt, so lässt sich darauf aufbauend eine Funktion schreiben, die Text auf dem Display ausgeben kann.

Eine Funktion zur Textausgabe ist aufgrund der Komplexität des Schrift-Datenformats bereits vor-handen, es ist nun jedoch Ihre Aufgabe, die noch fehlenden Funktionen zu codieren, auf denen der bereits geschriebene Code aufbaut.

Abbildung 10.5: LCD-Speicherorganisation

Abbildung 10.6: Aufbau einer einzelnen Speicherseite des LCD-Moduls

Page 41: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

10.4 - Laboraufgabe 9b: LCD-Ansteuerung 36

10.4 Laboraufgabe 9b: LCD-Ansteuerung

10.4.1 Aufgabenstellung

1) Folgen Sie den Anweisungen des Abschnitts 4 auf Seite 10.2) Erzeugen Sie ein neues Projekt in HiTOP.3) Übernehmen Sie die Dateien spi.c und spi.h aus Ihrer Lösung zu Laborübung 4a in das neue

Projekt und fügen Sie sie zum Projekt hinzu.4) Kopieren Sie die Dateien lcd.c, lcd.h, lcd_drawing.c, lcd_drawing.h und lcd_fonts.c in Ihr

Projekt und fügen Sie diese zu den Dateikategorien „Source Files“ bzw. „Header Files“ des Projekts hinzu.

5) Versehen Sie die Funktionen in lcd.c mit Inhalt, der die in Abschnitt 10.4.2 erläuterten Aufgaben erfüllt. Die Prototypen in lcd.h dürfen dabei nicht verändert werden. Erstellen Sie für jede zu er-stellende Funktion ein Struktogramm, einen PAP oder ein passendes UML-Diagramm, bevor Sie mit der Codierung beginnen.

6) Lassen Sie in der Funktion main() Text auf dem LCD ausgeben. Denken Sie daran, dass vor der Ansteuerung des LCDs SPI1 zu initialisieren ist.

10.4.2 Schnittstelle von lcd.h

void LCD_Init()

Diese Funktion initialisiert zuerst die für das LCD verwendeten GPIOs als Ausgänge. Es sind hier-für die drei Konstanten LCD_Backlight, LCD_NRST und LCD_CD zu benutzen (siehe Tabelle). Anschließend wird, wie weiter oben beschrieben, der kontinuierliche Reset des LCD-Controllers beendet und mittels SPI1_SelectDevice() das LCD auf dem Bus aktiviert. Ist dies erfolgt, so wird die in Abbildung 10.3 dargestellte Initialisierungssequenz übertragen. Schließlich wird mittels LCD_Clear() der Speicherinhalt des Controllers gelöscht.

Konstante Port Aufgabe LogikLCD_NRST GPIOA Reset LCD-Controller negativ

LCD_CD GPIOA Command/Data-Signal positiv

LCD_Backlight GPIOC LCD-Hintergrundbel. positiv

void LCD_SetBacklightState(bool State)

Aufgabe dieser Funktion ist es, die Hintergrundbeleuchtung des LCDs an- bzw. auszuschalten, je nach Wert des Parameters.

void LCD_SetPageData(u8 X, u8 Page, u8 Data)

Die Übertragung eines Bytes in den Displayspeicher des Moduls erfolgt mit dieser Funktion. Sie wählt die Spalte und Seite, in die das Byte geschrieben werden soll, setzt die C/D-Leitung auf 1, überträgt das Byte an den LCD-Controller und setzt dann die C/D-Leitung wieder auf 0 zurück.

void LCD_Clear()

In dieser Funktion wird der gesamte Speicherinhalt des LCD-Controllers mit Nullen gefüllt. Es wer-den somit alle Pixel des Displays ausgeschaltet. Dazu müssen in jede der 8 Seiten des Controllers 128 Nullbytes geschrieben werden. Sie können dazu die Funktion LCD_SetPageData() verwen-den, wenn Sie möchten.

Page 42: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

10.4 - Laboraufgabe 9b: LCD-Ansteuerung 37

Sie können allerdings auch von der Eigenschaft des Controllers Gebrauch machen, die gewählte Spalte nach jedem erfolgten Schreibzugriff auf den Speicher um eins zu erhöhen. Dadurch entfällt die Notwendigkeit, die Spalte vor jedem Nullbyte neu zu setzen. Es reicht somit aus, nach der Wahl der Speicherseite die Spalte auf Null zu setzen und 128 Nullbytes zu übertragen, um die Sei-te zu füllen. Vergessen Sie jedoch nicht, dass bei dieser Variante die C/D-Leitung entsprechend zu setzen ist.

10.4.3 Schnittstelle von lcd_drawing.h

void LCD_Print(u8 X, u8 Page, char* String, const u8 Font[])

Diese Funktion ermöglicht die Ausgabe von Strings auf dem LCD. Es stehen dabei vier verschie-dene Schriftarten zur Verfügung, die in Abschnitt 10.4.5 dargestellt sind.

void LCD_DrawLine(u8 XStart, u8 YStart, u8 XEnd, u8 YEnd)

Mit Hilfe von LCD_DrawLine() kann man Linien auf dem LCD ausgeben lassen. Der Anfangspunkt wird dabei durch die Koordinaten (XStart,YStart) bestimmt, während der Endpunkt durch (XEnd,YEnd) beschrieben wird.

void LCD_DrawCircle(u8 X, u8 Y, u8 Radius)

Analog zur vorhergehenden Funktion lassen sich mit LCD_DrawCircle() Kreise darstellen. Die Pa-rameter X und Y geben dabei den Mittelpunkt an.

10.4.4 Wichtige Befehle des LCD-Controllers

Befehl C/DBefehlscode

FunktionD7 D6 D5 D4 D3 D2 D1 D0

Display on/off 01 0 1 0 1 1 1 0 LCD aus

1 LCD an

Page address set 0 1 0 1 1 0 A2 A1 A0 Speicherseite A wählen (0..7)

Column address set 00 0 0 1 A7 A6 A5 A4 Spalte A wählen (0..127), obere 4 Bits

0 A3 A2 A1 A0 Spalte A wählen (0..127), untere 4 Bits

Display data write 1 A7 A6 A5 A4 A3 A2 A1 A0 Schreibt A in die gewählte Speicherstelle

Display normal/reverse 01 0 1 0 0 1 1 0 Alle Pixel werden normal dargestellt

1 Alle Pixel werden invertiert dargestellt

Display all points on/off 01 0 1 0 0 1 0 0 Normaldarstellung

1 Alle Pixel werden eingeschaltet

Page 43: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

10.4 - Laboraufgabe 9b: LCD-Ansteuerung 38

10.4.5 Schriftarten

Abbildung 10.8: Schriftart LCD_Font_11x14

Abbildung 10.7: Schriftart LCD_Font_6x7int

Page 44: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

10.4 - Laboraufgabe 9b: LCD-Ansteuerung 39

Abbildung 10.9: Schriftart LCD_Font_6x7lcd

Abbildung 10.10: Schriftart LCD_Font_21x28

Page 45: Laborpraktikum Embedded Systems - thm.de Laboraufgabe 9a: SPI-Bus-Modul.....32 10.2.1 Aufgabenstellung ... • Ein Assembler, ...

10.4 - Laboraufgabe 9b: LCD-Ansteuerung 40

Verweise[Thumb2]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.subset.swdev.qrc/index.html

[STM32DS]: http://www.st.com/stonline/products/literature/ds/13587.pdf

[UMLDiag]: http://de.wikipedia.org/wiki/UML#Darstellung_in_Diagrammen

[UMLTools]: http://de.wikipedia.org/wiki/UML-Werkzeug#Programme

[STM32Files]: http://www.st.com/mcu/familiesdocs-110.html

[STM32LibDoc]: http://www.st.com/stonline/products/literature/um/13475.pdf

[PSSchem]: http://www.hitex.com/fileadmin/free/stm32-performancestick/stm32-stick-schematic.pdf


Recommended