Einstieg: Mikrocontroller STM32F103

Veröffentlicht von Joe-C (jch) am Dec 03 2011
Mikrocontroller >>

Diese Webseite ist gerade in Überarbeitung.

Bis zum Abschluss der Arbeiten, ist auf den Unterseiten mit Darstellungsfehlern und Unvollständigkeiten zu rechnen.

Index

Zurück zur Übersicht

Einleitung

zurück zum Index


Ich wollte mich nach dem Picaxe mit leistungsstärkeren Mikrocontrollern beschäftigen. Dafür hab ich den AVR32 und den STM32 genauer betrachtet und bin letztendlich beim STM32 gelandet. Dieser stellt den Picaxe im Verhältnis Preis/Leistung meiner Ansicht nach in den Schatten, ist dafür aber auch um einiges aufwendiger zu Entwickeln.

Die Beispielbezeichnung STM32F103RBT6 (verbaut im kleineren Kameraboard weiter unten) setzt sich zusammen aus:
Familie Produkttyp Unterfamilie Pins Flash größe Gehäuseart Temperaturbereich
STM32 F1 = Mainstream
L1 = Ultra Low Power
F2 = Hi-Performance
F4 = Hi-Performance & DSP
100 = Value line
101 = Access line
102 = USB Access line
103 = Performance line
105/107 = Connectivity line
T = 36 pins
C = 48 pins
R = 64 pins
V = 100 pins
Z = 144 pins
8 = 64K Flash
B = 128K Flash
C = 256K Flash
D = 384K Flash
E = 512K Flash
H = BGA
T = LQFP
U = VFQFPN
Y = WLCSP64
6 = –40 to 85 °C
7 = –40 to 105 °C

(Hier ist nur ein Teil der ST Bezeichnungen dargestellt. Es gibt noch ein paar mehr.)

Chipbezeichnung

Auflösung: 627x644

Der STM32 hat einen Cortex M3 Kern und noch so einiges an Peripherie. Es gibt ihn in verschiedenen Ausführungen (Performance Line, Access Line, Connective Line...), welche sich in Ihrer möglichen Taktrate (max. 72Mhz bei diesem) und ihren Interfaces unterscheiden.
Die einen haben I2C und USART, die anderen CAN, wieder andere haben gleich alles. Auf der Webseite des Herstellers findet man daher eine sehr breite Auswahl (www.st.com).
Soweit möglich, haben sie eine ähnliche Struktur und Pinbelegung. Es soll in etwa so laufen, dass man ein Board für einen Mikrocontroller entwickelt, später aber diesen einfach tauschen kann, um z.B. die Funktionen des Boards zu erweitern. Alle Bisherigen Funktionen sollen erhalten bleiben (den Programmcode größtenteils mit eingeschlossen).

Cortex
Ist eine Art Mikroprozessor Standard für die Infrastruktur des Kerns. Die Pinbelegung kann zwischen den Herstellern nach außen zwar variieren, aber die innere Verarbeitung, Interruptsteuerung und Speicherverarbeitung ist gleich.
Cortex-A (applications profile) ...findet man gerne in PocketPcs, Navis und anderen Geräten, die meistens über ein Grapical User Interface (GUI) gesteuert werden
Cortex-R (real-time profile) ...wahrscheinlich vorwiegend in der Signalverarbeitung zu finden.
Cortex-M(microcontroller profile) ..um die geht es hier

Interrupt
Der Nested Vector Interrupt Controller (NVIC) ist Bestandteil des Cortex und hat, je nach Chiptyp, eine gewisse Menge an Interruptleitungen. Jede kann eine Priorität von 0 (sehr hoch) bis 15 (sehr niedrig) haben, was direkten Einfluss auf ihre Abarbeitungsreihenfolge hat. Im low power mode sind nur noch einige Aktiv. Wenn ein WFI (Wait for Interrupt) oder WFE (Wait for Event) deklariert ist, kann man damit den Mikrocontroller auch wieder starten. Entweder ist er danach wieder aktiv, oder er kehrt nach der Arbeit wieder in den low power mode... je nach Einstellung.
Es werden 3 sachen gebraucht:
-vector table für die Interruptquellen, die verwendet werden sollen
-NVIC Register bearbeiten um die Prioritäten festzulegen
-Peripherie konfigurieren und einschalten (Enable Bit bei der Peripherie)

Power
Zum Starten eines programmierten STM32 braucht man streng genommen nur 2-3.6V (wird intern auf 1.8V für den Kern reguliert). Der Chip hat einen internen RC Oszillator und einen Resetgeber. Oft wird die Peripherie mit eigenen Stromversorgungspins ausgestattet, die aber meistens auch so 2.4-3.6V brauchen. Es gibt auch ein Vbatt Anschluss, welcher zur Verwendung einer Pufferbatterie vorgesehen ist. Ein kleiner Teil des SRAMs sowie die Uhr kann damit betrieben werden, während der Rest des Chips ohne Versorgung ist.
Stromverbrauch: 36mA (alles aktiv) / 0.0024mA (low Power Mode).

Clock
Der Interne Oszillator läuft mit 8Mhz, ein externer kann von 4-16Mhz laufen. Der interne Takt wird halbiert (also 4Mhz) an die interne PLL (Phase locked Loop) angelegt, wo sie sich vervielfältigt. Der Faktor kann bis zu 16 gehen. So erreicht der STM32 Taktraten von 64Mhz. Wenn ein externer Oszillator verwendet wird, arbeitet der PLL mit einer Mischung aus beiden und kann so auf 72Mhz kommen. Mein Board hat einen 8Mhz Quarz und einen im Programm eingestellten Faktor von 9 -> 9x8=72Mhz.
Man soll außerdem ein External High Speed Clock (HSE) definieren können, welcher sogar als Sinus oder Dreieck vorliegen darf. Aber es muss ein Signal mit 50% duty cycle (Verhältnis zwischen Puls und Pause) und max. 25Mhz sein.
Es gibt auch einen internen langsamen Oszilator, der mit 32.768KHz läuft. Dieser ist für die Systemuhr und spezielle Überwachungstimer (watchdogs).

Watchdog
Ist eine selbstständige Überwachungslogik mit selbst definierbaren werten, die Interrupts generiert.
Beispiel für den AWD (Analog Watchdog): man legt einen oberen und unteren Messwert fest. Dann schließt man den Analogeingang an eine Batterie. Wenn die Batteriespannung über oder unterschritten wird, führt ein erzeugtes Interruptsignal dazu, dass der Mikrocontroller seine aktuelle Tätigkeit unterbricht und sich um den Code der Interruptsteuerung kümmert. Ist der Messwert zu hoch, könnte das Laden der Batterie jetzt abgeschaltet werden, damit sie nicht überladen wird. Ist der Messwert hingegen zu niedrig, könnte eine LED anzeigen, dass die Batterie mal wieder aufgeladen werden müsste. Somit lassen sich natürlich auch Klassiker wie Dämmerungsschalter einfach umsetzen.

IDE (Integrated Development Environment)
Für den Picaxe gibt es den Programming Editor und für C# nutze ich fast immer Sharpdevelop (3.2), aber für den STM32 wirds komplizierter. Es gibt sehr viele IDEs, welche ihre vor und Nachteile haben. Programmiert wird meistens in C, wofür es ja auch schon massig Auswahl gibt.
Eine nette Übersicht findet man im STM32 Artikel: mikrocontroller.net
Viele Boards haben ihre eigenen Beispiele, die meistens in bestimmten IDE gebundenen Projekten vorliegen. Man kann sich also mit der IDE anfreunden, oder versuchen, das Projekt Stück für Stück in eine andere umzusetzen. Mein eines Kameraboard nutzte die Keil µVision, das andere Board hatte IAR Workbench. Ich hab fast 2 Tage damit verbracht, das IAR Projekt auf Coocox umzuschreiben. Jetztendlich hatte ich es so weit bekommen, dass das Programm über Compiler und Linker zum Flash übergeben werden konnte, aber auf dem Display waren dann Querstreifen zu sehen. Eine (oder mehrere) der vielen Kern/Libary Dateien schien also ein Timingproblem zu verursachen.
Irgendwann hab ich entnervt aufgegeben und mich dazu entschlossen, beide IDEs parallel zu verwenden. Später hab ich auf die Keil IDE gewechselt und bin dabei geblieben.

  • Coocox
    Eine auf Eclipse basierende IDE. Coocox ist eine der wenigen, die Codefolding unterstützen und deshalb nehm ich sie bevorzugt (ich mag's halt übersichtlich und suche nicht gerne lange). Weitere nette Features: das Markieren einer Funktion für dazu, das sie überall in der Datei mit Markiert wird. Man findet so schnell den nächsten Aufruf. Die IDE hat auch eine sehr nette Möglichkeit neue Projekte zu erstellen, bei denen je nach Auswahl weitere Funktionen hinzugefügt werden. Und sie ist komplett Kostenlos.
    Wenn das Projekt nicht für Coocox vorliegt, kann man den gesamten Projektordner als "verlinkten Ordner" in ein eigenes Projekt hinzufügen. Von dort kann man in allen Projektdateien Entwickeln und mit STRG + S sind alle Änderungen gespeichert. Das Debuggen muss man dann aber dem Quellprojekt mit der anderen IDE überlassen.
  • Keil µVision
    Sehr umfangreich, sehr weit verbreitet, sehr viele Einstellungsmöglichkeiten und leider bis 32kB begrenzt (für den internen Compiler). Eine recht gute IDE mit vielfältigen Einstellungsmöglichkeiten und Codefolding (hier Outlining genannt). Man kann Tools (externe Anwendungen) hinzufügen und mit Tasten belegen. So kann man beispielsweise über ein Command Line Interface (CLI) das Programm erweitern. Ich nutze z.B. einen ST-Link als Debugger (http://www.watterott.com/de/ST-Link). Über das ST CLI hab ich mir ein Tool zum Programmieren und eins zum Reset erstellt. Ich brauch dann nur F10 oder F11 drücken, um die Funktion auszulösen.
  • IAR Workbench
    Für sie gilt fast das gleiche wie für die Keil IDE. Allerdings gibt es hier kein Codefolding. Ich konnte auf meinem Laborrechner die Installation erst nicht ausführen, weil sie dort wegen eines Checksumm-Fehlers nicht installiert werden konnte. Die Installation lief aber auf meinem Hauptrechner mit der gleichen Datei ein zweites mal ohne Probleme. Ich musste also eine neue Datei (mit neuem Lizenzcode, trotz Testversion) anfordern, was dann auch geklappt hat.
    Ich finde, die Entwickler hätten lieber mehr Features implementieren sollen, anstatt solche Lizenz-aktivier-Schlüssel-Schweinerein zu machen, aber das ist natürlich Ansichtssache.
  • Die anderen
    Eclipse, Atollic, Ride7 und Crossworks. Ich hab sie alle Installiert und mal reingeschnuppert. Alle recht komplex, teilweise mit beschränkten Funktionen, die gegen Bezahlung entsprechend erweitert werden können. Jeder hat so seine kleinen Gimmicks. Eclipse ist Kostenlos und sehr umfangreich, aber auch nicht ganz leicht zu konfigurieren. Atollic ist ähnlich umfangreich wie Eclipse, basiert ja auch darauf. Das Atollic Truestudio muss nicht großartig konfiguriert werden, ist dafür für Nichtzahler aber auch etwas beschränkt.

Zusammenfassend würde ich sagen, die Auswahl ist groß und man muss selbst entscheiden, welche man Verwendet.
Hier gibt es auch unterschiedliche Libarys, die Funktionen beinhalten, welche ihrerseits in diverse Register schreiben.

Bilder

  • Cameraboards
    Meine zwei STM32 Kameraboards. Das eine ist ein Multimediaboard mit Kameramodul, das andere ein direkt auf Kamera ausgelegtes Board. Beide haben ein LCD Display und den FIFO-Speicher dabei. Das kleinere Board, kann nur über SWD (Serial Wire Debug) an den ST-Link angeschlossen werden, was ich hier mit den 3 erforderlichen Steckleitungen gemacht habe.
  • ST-Link
    Der ST-Link Debugger wird von mir verwendet, um über JTAG oder SWD den Chip zu flashen und ggf. zu debuggen. Das kleinere Board hat die UART1 und SWD auf der gleichen Steckleiste, weshalb ich nicht das mitgelieferte Flachbandkabel verwende.
    Vor USB, hab ich das Board mit einem RS-232 -> TTL Adapter über UART1 angesteuert.
  • Keil µVision4 IDE
    Ein Screenshot, der die IDE und den Quellcode des Channelfilters zeigt.

Cameraboards
Auflösung: 1200x900

ST-Link
Auflösung: 1200x900

Keil µVision4 IDE
Auflösung: 1200x900

 
  •  
  •  
  •  

Hier noch diverse Infos, die ich für erwähnenswert halte:

AHB Advanced High Speed Bus
APB Advanced Peripherial Bus (APB1=36Mhz / AP2=72mhz)
CMIS Cortex Microcontroller Software Interface Standard
CRC Cyclic Redundancy Check (Checksumme)
DMA Direct Memory Access
FSMC Flexible static memory controller
HSE External High Speed Clock
HSI Internal High Speed Clock
ISR interrupt sub routine
LIN Local interconnect Bus
NVIC Nested Vector Interrupt Controller (16 level of priority,0 = highest, 15= lowest)
PLL Phase locked Loop
RCC Reset and Clock Control
ROTS Real Time Operatin Systen
WD Watchdog
WFE Wait for event
WFI Wait for Interrupt

Ausblenden / Schließen

Kameraboard

zurück zum Index


Ich habe mir am Anfang 2 verschiedene Cameraboards besorgt, welche sich in ihrem Funktionsumfang etwas unterscheiden. Beide benutzen die STM32F103 (performance line) Mikrocontoller, im Folgenden als µC abgekürzt. Infos zur Kamera in einem Artikel von mir: Kamerasensor.

Das eine ist ein Multimediaboard mit zusätzlichem Audiocodec und einigen anderen Schnickschnack. Unter anderem gibt es auch eine, für ein Kameramodul vorgesehene, Steckerleiste. Ich habe das Board zusammen mit Kameramodul und Source bestellt, konnte aber zuerst das Teil nicht Programmieren.
Ich hatte vorher nachgelesen, dass man das Board auch ohne ein extra Debugger Flashen kann. Das stimmt auch... aber nur wenn man mit einem RS-232 -> TTL Modul an das Board geht und noch ein paar Schalter umlegt. Dieser Vorgang wurde aber nirgends beschrieben. Es gab nur diverse Beispielprogramme und eine Schematische Übersicht (welche Chips sind wo verbaut und welche Pins sind wohin verbunden). Bis sich diesen Vorgang erkannte, hatte ich schon meinen später bestellten ST-Link Debugger.
Der USB Anschluss machte auch rein garnix. Das der µC aber auch als USB-Device programmiert werden kann und dieser Anschluss dafür vorgesehen war, wusste ich zu diesem Zeitpunkt noch nicht.
Über den Debugger hab ich das Kameraprogramm auf den µC transferiert und mich mit dessen Funktion etwas vertraut gemacht.
Im Grunde recht einfach:
- 2x 8bit vom Kameraport lesen
- zusammengesetzt als 16bit Wert an die LCD Funktion übergeben (welche ihrerseits mit 2x 8bit Transfer die Daten an das LCD Register übergibt).

Später hab ich noch ein weiteres Kameraboard besorgt, nachdem ich ein Beispielvideo davon gesehen habe. Die Bildqualität war sehr viel besser, als bei meinem Board und die FPS waren auch höher. Beim ersten Board konnte man noch erkennen, wie das Bild sich Zeilenweise aktualisierte. Darum hab ich das alte Board erst mal bei Seite gepackt und mich mit dem neuen auseinandergesetzt.
In der Hauptroutine, nachdem die ganzen Initialisierungen abgeschlossen waren, wurden nur 2 Takte erzeugt... mehr nicht.
Die Funktion lief hier etwas anders. Kamera und LCD liegen auf dem gleichen Datenbus am µC. Der µC ist auf Eingang geschaltet, liest aber nix am Port. Stattdessen werden über die Taktsignale Lesezyklen (vom Kamera FIFO Speicher) und Schreibzyklen (vom LCD) aufeinander abgestimmt. Anstatt (wie auf dem anderen Board) die Signale von einem Port zu lesen und an einen anderen weiter zu geben, wurde hier vom Speicher direkt an den LCD übergeben, was vom µC aus gesteuert wurde. Dadurch ergibt sich eine schnelle Wiedergabe, aber auch die Möglichkeit, es wie das erste zu betreiben. Außerdem werden so nur 8 Pins als Datenbus für beide belegt.

USB

USB ist inzwischen ja ein sehr geläufiges Bussystem. Der Einstig hat es aber durchaus in sich. So einfach wie mit der RS-232, Port auf und Senden, ist es dann doch nicht.
Es gibt viele Seiten, welche sehr tiefgreifende und gut dargestellte Informationen haben. Daher unterlasse ich es, hier weiter auf die Grundlagen einzugehen.

Ich bin gerade erst dabei, USB "zu entdecken". Vorläufig habe ich mich für die HID (Human Interface Device) Klasse entschieden.
Dadurch meldet sich das Gerät mit einer, von mir vorher festgelegten, Vendor/ProductID (VID/PID) an Windows an. Beide Nummern sind 16bit Variablen, es sind also sehr viele Kombinationen möglich. Beide Nummern dürfen in dieser Kombination nur einmal im System vorkommen. Daher sollte man eine freie Kombination verwenden, was in den eigenen 4 Wänden sicher kein Problem ist. Man kann sich wohl für 2000 $ als Vendor (Anbieter) registrieren lassen, was ich bestimmt lassen werde. Viele Anbieter verkaufen aber auch PIDs für wesentlich weniger (z.B. 10 Stk für 25€). Sowas wäre für mich aber nur ein Thema, wenn ich ein USB-Gerät entwickelt habe, dass sich auch außerhalb meiner Wohnung bewegen wird.
Treiber braucht er dafür nicht, da die im System schon mitgeliefert werden. Der µC nutzt damit die gleichen Treiber wie eine Maus oder Tastatur.
Im Gegensatz zur RS-232 wird dann im Programm nicht mehr ein Port angesprochen, sondern die Kombination VID/PID. Ich kann während des Betriebes auch einfach das Board entfernen und an einem anderen Port wieder ran stecken... 3 sec. später hat mein Programm das Board wieder erkannt und der Datenaustausch läuft wie vorher weiter. Das war mit der RS-232 natürlich so nicht machbar.

Hier noch ein paar Beispielbilder:

  • Kameraboards
    Hier beide Boards im Betrieb. An das kleinere, von mir vorrangig verwendete, habe ich einen USB -> RS232 Adapter direkt angelötet. Dadurch konnte ich früher das Board betreiben und steuern. Heute macht USB dasselbe. Außerdem sind die 3 Leitungen für SWD aus dem ST-Link raus geführt worden. Ich hab noch nicht viel mit JTAG und SWD rumprobiert, aber SWD wird von mir wegen der geringeren Leitungsmenge bevorzugt.
  • Channelfilter
    Hier ein einfacher Channelfilter. Der Code dazu steht oben im Screenshot der Keil IDE. Hier ist er darauf eingestellt, alle blau und grün Anteile raus zu filtern. Übrig bleibt nur rot und alles, was rot enthält (wie z.B. weiß, da es sich um die Additive Farbmischung handelt).
    Durch die Überblendung der Kamera etwas schwer zu erkennen: neben dem roten ist ein grünes Rechteck, darunter ein blaues.
  • Bilddownload
    Hier einer meine ersten, größeren USB Erfolge. Vom PC wird eine Anforderung für ein Bilddownload an den µC gesendet. Dieser schaltet daraufhin den Modus um und sendet nach und nach alle Bytes vom FIFO-Speicher über USB an den PC. Dieser setzt jeweils 2 davon zusammen (RGB565 Format) und erzeugt damit einen Farbpixel. Der Download dauert ca. 2 Sec. Die Übertragungsart Interrupt ist für solche Datenmengen ohnehin nicht vorgesehen... aber es funktioniert schon mal.

Kameraboards
Auflösung: 1200x900

Channelfilter
Auflösung: 1200x900

Bilddownload
Auflösung: 1200x900

 
  •  
  •  
  •  

Später hab ich mit Hilfe des Datenblattes eine Übersicht für den verwendeten µC erstellt. Schließlich wollte ich auch einige andere Funktionen genauer kennenlernen.

Pinbelegung

Auflösung: 1054x775

Der µC auf dem Board (STM32F103RCT6) ist vielseitiger, als ich zuerst annahm.
3 Ports liegen als Durchgangsbohrung vor. Somit können sie einfach verlötet werden (was ich bei der UART1 ja auch schon gemacht habe).
Nachdem ich gesehen habe, was der Chip so alles kann, wollte ich natürlich noch ein paar Sachen ausprobieren.

ADC

Der ADC ist beim STM32 wie vieles sehr komplex, aber auch recht leistungsstark. Genaugenommen sindbei diesem 2 AD Konverter im Chip. Aber es können mehrere Analogsignale erfasst werden, da vor dem ADC ein Multiplexer ist. Der Multiplexer schaltet gewissermaßen den ADC an den Anschluss, den man messen möchte. So kann man innerhalb weniger Millisekunden (1MHz conversion rate) z.B. 16 Analoge Signale abfragen (je nach Chip auch mehr). Die können dann Werte von 0-4095 haben, da es sich um 12bit ADCs handelt.
Die möglichen Analogeingänge sind: A0-A7, B0-B1, C0-C5 also insgesamt 16. Auf dem Board sind nur A0-A7 frei. Die anderen sind anderweitig belegt.

Zum testen, habe ich A0-A7 als Analogeingang konfiguriert und konnte dann auf dem Display dann 8 Verschiedene Analogwerte betrachten. Diese wurden allerdings immer nacheinander ausgelesen.
An DMA hab ich mich noch nicht weiter ran getastet. Es wäre aber eigentlich besser, aus dem Speicher den letzten Messwert zu holen, anstatt bei Interesse die Messung erst einzuleiten. Zumindest dann, wenn das Einleiten und durchführen der Messung zu Laufzeitproblemen führt.

Bilderfassung mit Kamera

Hier noch eine genauere Beschreibung der Arbeitsweise, wenn es um das Erfassen von Bildern mit der Kamera geht.

Die Kamera bekommt ihren Takt vom µC über den GPIO Pin A8. Dieser kann für die Funktion MCO (Main Clock Output) eingestellt werden. Es kann zwischen 4 Clock Quellen gewählt werden:

  • PLLCLK/2 (36MHz)
  • HSI (8MHz)
  • HSE (8MHz)
  • SYSCLK (72MHz... sehr wahrscheinlich, mein Oszi ist leider zu langsam, um es wie die anderen zu überprüfen)

Die maximale Eingangsfrequenz der Kamera liegt bei 48Mhz (laut Datenblatt). Durch die Kameraregister, kann man die Pixelclock (Ausgangsfrequenz) beeinflussen. Über Register werden auch weitere Takteinstellungen vorgenommen. Die PLL (x4, x6, x8) aber auch Teiler dafür (/1, /2, /4, /8, /16) werden dort festgelegt.
Bei mir liegt am Eingang (XCLK) der Kamera 8MHz und am Ausgang (PCLK) 16MHz. Die Kamera bekommt also 8MHz als Clock und übergibt mit 16MHz die Daten an den FIFO-Speicher.

Der Vsync Ausgang der Kamera geht direkt an den µC als Interrupt. Da Vsync einen Takt bei jedem fertigen Bild erzeugt, wird der µC bei jedem Bild unterbrochen und führt den Code der Interruptsteuerung aus.
Es gibt es eine Variable, die im Hauptprogramm, aber auch in der ISR (interrupt sub routine) abgefragt wird (darum ist sie auch als volatile deklariert). Sie entscheidet mit ihrem Zustand darüber, was der Vsync im µC so "anrichtet".
Die Abfolge ist dann so (stark vereinfacht):

Hauptprogramm Interruptsteuerung

volatile unsigned char Vsync; //Variable erstellen

While
(1)
{ //permanente Schleife
    if (Vsync == 2) {
       Bild_auslesen();
       Vsync = 0; //FIFO Reset und Datenaufnahme starten
    }
}

if (Vsync == 0) {
    FIFO_RESET();
    FIFO_WE_H(); //write enable on
    Vsync = 1; //Datenaufnahme stoppen
} else if (Vsync == 1) {
    FIFO_WE_L(); //write enable off
    Vsync = 2; //Bild fertig zum auslesen
}

Gewissermaßen wartet das Hauptprogramm nur darauf, dass ein Bild ausgelesen werden kann. Wenn es ausgelesen wurde, wird er Speicher zurückgesetzt. Der Reset am FIFO sorgt dafür, dass eventuelle "Restdaten" verworfen werden. Das Write Enable (FIFO_WE_H) sorgt dafür, dass wieder Daten von der Kamera empfangen werden können. Da Reset und Einschaltvorgang direkt nach dem Vsync der Kamera kommen, gehen die Bilddaten von Anfang an in den Speicher (daher sollte die Pixelclock auch nicht zu hoch sein, weil sonst schon Daten gesendet werden, noch bevor der Speicher sie aufnehmen kann).
Der Start des nächsten Bildes führt zum Abschalten des Speichereingangs (FIFO_WE_L), alle weiteren Kameradaten gehen nun verloren. Sobald das Bild ausgelesen wurde und die Variable wieder auf 0 steht, passiert so lange nix, bis die Kamera ihr nächstes Bild beginnt... und mit dem Interrupt wieder einen Speicherreset hervorruft.

Das Auslesen des Bildes, erfolgt entweder über einen Funktion wie oben beim Screenshot der Keil-IDE, oder
die Daten gehen direkt vom Speicher an den LCD, welcher seinerseits über ein 8Bit Interface gesteuert wird.
Wenn die Daten direkt übergeben werden, ist der Datenport am µC auf Eingang geschaltet (damit anliegende Signale nicht beeinflusst werden). Dann werden sowohl FIFO als auch LCD mit Chip Enable (CE) eingeschaltet. Zuerst bekommt der FIFO seinen Takt, damit er die Daten auf den Datenbus legt, dann folgt ein Takt für den LCD, damit er die Daten übernimmt... es folgt dann wieder der FIFO.
Vor dem Auslesen wird der Cursor des LCD in die Displayecke gesetzt. Mit jedem zweiten Takt ist ein Pixel fertig und er rückt automatisch 1 weiter. So wird Zeile für Zeile das Bild aufgebaut.
Das bedeutet aber auch, dass das eigentliche Bild nix weiter ist, als 307200 auf einander folgende Bytes. Daher muss das Timing stimmen. Der LCD weiß genauso wenig, wann eine neue Zeile beginnt, wie der Speicher. Daher muss die Ausgabe der Kamera in den FIFO genauso übereinstimmen wie die Übernahme auf den LCD.
Dafür kann aber im Register des LCD festgelegt werden, von wo bis wo die Pixel durchlaufen sollen. Bei der Kamera können "dummy lines" festgelegt werden. Damit werden nach jeder Linie zusätzliche Daten versendet, um letztendlich auf die richtige Datenmenge zu kommen. Wenn man also beide Register nicht aufeinander abstimmt, oder die Takte entsprechen anpasst, gibt es kein sauberes Bild (sondern diagonal verlaufende Linien).

Adressrechner

zurück zum Index


In dem SMT32 Insider's Guide (unter "nützliche Links" oben schon erwähnt, aber auch: hier) wird eine nette Möglichkeit erwähnt, einen GPIO Pin relativ direkt anzusteuern. Dazu kann man sich einen Pointer errechnen, welcher direkt auf das entsprechende Bit im Register zielt. Die dazugehörigen Register findet man im RM0008 Reference manual.

Ich hab hier mal einen kleinen Rechner gebastelt, mit dem man sich die einzelnen Pins der Ports einfach zusammenstellen kann. Oder man sucht sich selbst die entsprechenden Daten:
Boundary address auf S.44-46
Die Startadresse aus der Memory Map: 0x40010800 - 0x40010BFF für GPIO Port A
Damit sind Anfang und Ende eines Registerblocks gemeint.
Offset
Der Offset von der Startadresse. Damit wird das eigentliche Register angewählt.
Bit
Das gewollte Bit aus dem Register. Da es 32bit Register sind, kann das Bit 0-31 (0x00-0x1F) sein.

Adressrechner
GPIO Port: GPIO Pin:  Richtung:
boundary start address: Offset: Bit:
Ausgabe:

Software Reset
Hier ist auch ein anderer Register Pointer, den ich für nützlich halte. Damit kann man den µC auf einen Neustart schicken, anstatt ihn in gegenwärtiger (nicht) Funktion zu belassen.

#define RESET() (*((unsigned long *) 0x0E000ED0C)) = 0x05FA0004; while(1); //Software Reset

Vergleichsmessung
Ich wollte mal den Geschwindigkeitsvorteil gegenüber der Standardfunktion testen. Dazu wurde einen Impuls erzeugt und mit meinem Oszi (Rigol mit 40MHz Bandbreite) gemessen. Ich habe die Funktionen ihrer geschwindigkeit nach geordnet.
Die Pointer Methode scheint nicht die schnellste zu sein. Aber der Adressrechner war schon fertig... was solls.

Messung mit dem Oszilloskop Beispielcode
Eine Funktion aus der ST-Firmware: stm32f10x_gpio.c

GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);
GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);

Die Funktion ist mir über den Weg gelaufen, als ich die Firmware durchstöbert habe... ich kann mich nicht entsinnen, sie mal in einem Beispiel angetroffen zu haben. Aber sie ist ja auch nicht gerade ein Highlight.
Eine weitere Funktion aus der ST-Firmware: stm32f10x_gpio.c

GPIO_ResetBits(GPIOA,GPIO_Pin_0);
GPIO_SetBits(GPIOA,GPIO_Pin_0);
GPIO_ResetBits(GPIOA,GPIO_Pin_0);

Diese Funktionen hab ich schon öfter in Beispielen angetroffen. Sie lassen sich auch besser lesen als die erste (finde ich zumindest).
Hier der beschriebene Pointer auf das Ausgangsregister.

#define GPIOA_O0 (*((volatile unsigned long *) 0x42210180)) //

GPIOA_O0 = 0;
GPIOA_O0 = 1;
GPIOA_O0 = 0;

Die Pulsbreite ist nur noch halb so breit wie die der Standardfunktion. Es ist so also 50% schneller.
Hier werden nur noch 3 Anweisungen für einen Befehl generiert. Bei der Standardfunktion sind es 6. Mehr dazu im SMT32 Insider's Guide auf Seite 22.
 
Diese Funktion hab ich in der stm32f10x_gpio.c in den Funktionen gefunden, die oben aufgerufen wurden.

GPIOA->BRR = GPIO_Pin_0;
GPIOA->BSRR = GPIO_Pin_0;
GPIOA->BRR = GPIO_Pin_0;

Diese Funktion findet man, wenn man in den oberen 2 Funktionen nachschaut. Diese Befehle sind es, die aus der Firmware die Anweisungen an die Register übergeben. Interessanterweise ist diese Art etwas schneller, als die Pointer Methode.
Außerdem wird hier nicht das ODR (output data register) angewählt. Die Register (BRR und BSRR) können daher nur das eine, also nur auf High oder Low setzen. BSRR kann genaugenommen von 0-15 Bits setzen und von 16-31 Bits zurücksetzen. BRR hat nur 0-15, die anderen sind "reserviert".
Dennoch ist diese Funktion ähnlich einfach wie die ersten 2 und bietet sich daher an.

STM32 Tool

Ich hab einen Codegenerator für diverse Registereinstellungen erstellt. Dieser wird nach Bedarf und bei entsprechender Zeit erweitert. Link: STM32 Tool

zurück zum Index




 

Zuletzt geändert am: Oct 13 2013 um 10:18 PM

Zurück