Hallo,
ich will das EA W202-XLG Display mit einem STM32F4 Discovery zum Laufen
bekommen. Ich verwende den 4-Bit Modus mit den Funktionen, wie im
Datenblatt auf Seite 5 beschrieben. Meinen Code habe ich angehängt und
hoffe, dass ihr mir weiterhelfen könnt. Ich kann einfach keinen Fehler
finden!!!
Ich habe davor ein Programm für das Display geschrieben, in welchem ich
keine Funktionen verwende - damit hat es geklappt. Nun habe ich diesen
Code geschrieben und es werden mir nur ganz kurz irgendwelche Zeichen
angezeigt, aber am Ende ist das Display leer. Ich habe nun extra an jede
Datenleitung eine LED gehängt und mit dem Debugger die einzelnen
Zustände kontrolliert. Dies war alles wie beim alten Programm und müsste
daher ja funktionieren.
Ich denke nicht, dass du Arbeitsweise und Sinn des BSRR richtig erfasst
hast. Es sollte zu denken geben, wenn man den Inhalt eines Register
lesen will, dass dies überhaupt nicht zulässt.
Pin(s) auf 1: BSRRL = mask;
Pin(s) auf 0: BSRRH = mask;
Pin(s) 0..3 auf Wert setzen, ohne an den anderen Pins was zu ändern:
BSRR = 0b1111<<16 | Wert & 0b1111;
A. K. schrieb:> Compiler haben mitunter sehr eigene Ansichten zu Code, der ihnen völlig> sinnlos vorkommt.
Compiler kontrollieren, ob sich nach aussen durch den Code irgendwas
ändert. Wenn nicht, dann können sie ihn wegoptimieren. Leere Schleifen
sind das erste, was dem Optimizer zum "Opfer" fällt. Denn sie ändern
nichts, machen aber alles unnötig langsam, und das Ergebnis der
Schleife kann im Voraus berechnet werden...
jogl schrieb:> Habe den neuen Code vergessen :D
Seit wann enthalten *.txt Files Code?
A. K. schrieb:> Diese Delay-Loops funktionieren? Compiler haben mitunter sehr eigene> Ansichten zu Code, der ihnen völlig sinnlos vorkommt.
Haben bislang immer funktioniert.
jogl schrieb:> Nun habe ich diesen> Code geschrieben und es werden mir nur ganz kurz irgendwelche Zeichen> angezeigt, aber am Ende ist das Display leer.
Geh doch mal mit dem Debugger schrittweise durch. Achte dabei auch bei
jedem Schritt auf den Zustand aller GPIO-Pins, ob sie so gesetzt sind
wie Du sie haben wolltest, etc.
Außerdem ist Deine Verwendung der BSRRH und BSRRL Register ziemlich
befremdlich.
Darüber hinaus solltest Du den Pins sinnvolle Namen geben anstatt
einfach nur 4 oder 5.
Und Deine Verzögerungsschleifen optimiert der Compiler weg, je nach
Mondphase entweder sofort oder erst morgen wenn Du was an den
Compilerflags änderst oder einfach so in der nächsten Version. Das musst
Du anders machen.
jogl schrieb:> Aber kann jemand einen Fehler in meinem neuen Programm erkennen oder> einen Unterschied zum alten?
Dein Umgang mit BSRR ist schlicht und einfach falsch.
Und: In einer Situation recht behalten zu willen, in der man schon ahnt,
dass man auf dem Holzweg ist, ist eine zweifelhafte Strategie. Auch wenn
es der Widerspruchsreflex so befiehlt.
Bernd K. schrieb:> Geh doch mal mit dem Debugger schrittweise durch. Achte dabei auch bei> jedem Schritt auf den Zustand aller GPIO-Pins, ob sie so gesetzt sind> wie Du sie haben wolltest, etc.
Haben die Zustände der GPIO-Pins über LEDs getestet und es waren alle so
wie ich sie haben wollte, beziehungsweise wie beim alten Programm.
Bernd K. schrieb:> Außerdem ist Deine Verwendung der BSRRH und BSRRL Register ziemlich> befremdlich.>> Darüber hinaus solltest Du den Pins sinnvolle Namen geben anstatt> einfach nur 4 oder 5.
Mhh, was ist daran denn sooooo falsch? Könntet ihr mir bitte zeigen, wie
ich beispielsweise Pin 3 von Port D auf High und dann wieder auf Low
setzt? Am besten, wenn dieser davor noch als "DB6" definiert wurde.
Bernd K. schrieb:> Und Deine Verzögerungsschleifen optimiert der Compiler weg, je nach> Mondphase entweder sofort oder erst morgen wenn Du was an den> Compilerflags änderst oder einfach so in der nächsten Version. Das musst> Du anders machen.
Habe nun noch eine weitere Variable in den Schleifen hochzählen lassen,
damit diese auf jeden Fall nicht wegoptimiert werden. Aber immer noch
nichts auf dem Display zu sehen.
>Habe nun noch eine weitere Variable in den Schleifen hochzählen lassen,>damit diese auf jeden Fall nicht wegoptimiert werden.
Die haut der Compiler trotzdem in die Tonne, es sei denn die
Variable ist volatile.
jogl schrieb:>> Außerdem ist Deine Verwendung der BSRRH und BSRRL Register ziemlich>> befremdlich.>>>> Darüber hinaus solltest Du den Pins sinnvolle Namen geben anstatt>> einfach nur 4 oder 5.>> Mhh, was ist daran denn sooooo falsch? Könntet ihr mir bitte zeigen, wie> ich beispielsweise Pin 3 von Port D auf High und dann wieder auf Low> setzt? Am besten, wenn dieser davor noch als "DB6" definiert wurde.
Dort schreibt man Einsen rein für die Bits die gesetzt (oder gelöscht)
werden sollen oder nullen für alle bits die GLEICH bleiben sollen.
Also kein verodern mit |= sondern das verodern macht die Hardware wenn
Du einfach die Maske mit den Bits mit = reinschreibst.
z.B. so (hier ist mal ein STM32F401 Hello-World Blinky Beispiel) das
illustriert eigentlich alle meine Punkte in einem vollständigen
Beispiel, das hatte ich zur Hand ohne jetzt erst was speziell dafür
schreiben zu müssen:
1
#include<stm32f401xe.h>
2
3
4
/*
5
* The green LED is connected to port A5,
6
* -> see schematic of NUCLEO-F401RE board
7
*/
8
#define LED_GPIO GPIOA
9
#define LED_PIN 5
10
11
/**
12
* Quick 'n' dirty delay
13
*
14
* @param time the larger it is the longer it will block
15
*/
16
staticvoiddelay(unsignedtime){
17
for(unsignedi=0;i<time;i++)
18
for(volatileunsignedj=0;j<20000;j++);
19
}
20
21
22
/**
23
* Hello world blinky program
24
*
25
* @return never
26
*/
27
intmain(void){
28
29
30
/*
31
* Turn on the GPIOA unit,
32
* -> see section 6.3.9 in the manual
33
*/
34
RCC->AHB1ENR|=RCC_AHB1ENR_GPIOAEN;
35
36
37
/*
38
* Set LED-Pin as output
39
* Note: For simplicity this assumes the pin was configured
40
* as input before, as it is when it comes out of reset.
41
* -> see section 8.4.1 in the manual
42
*/
43
LED_GPIO->MODER|=(0b01<<(LED_PIN<<1));
44
45
46
while(1){
47
48
/*
49
* LED on
50
* -> see section 8.4.7 in the manual
51
*/
52
LED_GPIO->BSRRL=(1<<LED_PIN);
53
54
delay(200);
55
56
/*
57
* LED off
58
*/
59
LED_GPIO->BSRRH=(1<<LED_PIN);
60
61
delay(200);
62
}
63
}
Erstens ich gebe meinen Ports und Pins logische Namen, dann liest sich
der Code leichter, es ist besser zu sehen welchen Pin ich da beackere,
besonders wenns später mehr werden. So kann ich auch später noch das
Platinenlayout ändern und nen anderen Pin nehmen und muss nur noch an
einer einzigen Stelle Anpassungen vornehmen, nicht mehr kreuz und Quer
über das Programm verstreut.
Zweitens beachte wie ich die BSRR Register verwende. Ich verodere da
nichts, ich schreibe einfach eine 1 an das Bit das gesetzt oder gelöscht
werden soll und nullen an alle anderen. Lies bitte nochmal im Referenz
Manual nach über das Thema, da stehts auch geschrieben, das gleiche
Konzept findet man auch bei vielen anderen Controllern.
> Bernd K. schrieb:>> Und Deine Verzögerungsschleifen optimiert der Compiler weg, je nach>> Mondphase entweder sofort oder erst morgen wenn Du was an den>> Compilerflags änderst oder einfach so in der nächsten Version. Das musst>> Du anders machen.>> Habe nun noch eine weitere Variable in den Schleifen hochzählen lassen,> damit diese auf jeden Fall nicht wegoptimiert werden. Aber immer noch> nichts auf dem Display zu sehen.
Beachte wie ich die innere Laufvariable als volatile deklariert habe. Es
ginge auch mit nur einer Schleife aber die Variable muss volatile sein.
Volatile bedeutet für den Compiler soviel wie: "Schreiben und Lesen
dieser Variable wechselwirkt mit der Außenwelt, das muss ich also in
genau der Reihenfolge und Anzahl durchführen wie es da steht sonst
ändert sich die Außenwirkung und das darf ich nicht, ich darf nur Sachen
wegoptimieren die nicht von außen oder nach außen wirken." Deshalb sind
auch alle Register für GPIO und andere Peripheriegeräte in den Headern
immer als volatile deklariert, damit der Compiler weiß daß das nicht nur
unsichtbares Schreiben in irgendein internes Register ist sondern jeder
Zugriff eine gewollte Außenwirkung darstellt.
Volatile Zugriffe müssen immer durchgeführt werden und immer exakt in
der Reihenfolge wie sie programmiert sind. Also mach Laufvariablen für
solche aus Sicht des Compilers sinnlose Schleifen (die nichts berechnen
was später noch verwendet würde) volatile, dann kann nichts passieren.
Das bedeutet: Geh da rein, dort findest Du drei Zahlen, addiere die
ersten zwei (im Kopf) und vergiss das alles sofort wieder, dann nimm die
blaue Zahl und komm mit der blauen Zahl wieder raus.
Jeder der nicht komplett auf den Kopf gefallen ist wird reingehen, die
blaue Zahl nehmen und wieder rauskommen. Pfeif auf die Berechnung, kann
ja per Definition keiner kontrollieren, das Ergebnis soll ja vergessen
werden, die einzig nachprüfbare Aufgabe (blaue Zahl holen) wurde ja
ordnungsgemäß erfüllt, der Rest ist Optimierung des Arbeitsablaufs.
1
intzeitvertreib(void){
2
constintrot=42;
3
constintgruen=43;
4
constintblau=44;
5
6
volatileintx=rot+gruen;
7
8
returnblau;
9
}
Das bedeutet: Geh da rein, dort findest Du drei Zahlen, addiere die
ersten zwei (und zwar schriftlich, und zwar am Fenster so daß ich es von
außen sehen kann) dann vergiss das Ergebnis, vernichte den Zettel, nimm
die blaue Zahl und komm damit wieder raus.
Jetzt kann derjenige nicht mehr bescheißen, auch wenn die Addition immer
noch sinnlos ist, er muß sie am Fenster durchführen so daß der Chef ihn
von außen beobachten kann.
So funktioniert Optimierung und so funktioniert volatile.
Das sind aber alles keine "schönen" delay Funktionen. Ich hätte gerne
eine Funktion, mit der das Programm eine genaue Zeit wartet.
Sowas hier: delay(1000); //wartet 1s
Kann mir hier bitte jemand weiterhelfen, konnte keine gute Erklärung
finden. Welchen Takt habe ich denn überhaupt beim STM32F4?
jogl schrieb:> Kann mir hier bitte jemand weiterhelfen, konnte keine gute Erklärung> finden. Welchen Takt habe ich denn überhaupt beim STM32F4?
In der HAL Library gibt es eine delay Funktion (HAL_Delay). Das basiert
aber auch nur darauf, die system clock interrupts zu zählen
(SysTick_Handler).
Torsten R. schrieb:> Das basiert> aber auch nur darauf, die system clock interrupts zu zählen> (SysTick_Handler).
Davon habe ich schon etwas gelesen, weiß aber nicht genau wie ich den
SysTick_Handler benutze bzw. was die Systicks überhaupt sind.
jogl schrieb:> Davon habe ich schon etwas gelesen, weiß aber nicht genau wie ich den> SysTick_Handler benutze bzw. was die Systicks überhaupt sind.
SysTick_Handler ist eine interrupt handler, der periodisch aufgerufen
wird und in der Regel verwendet wird, um eine globale Variable hoch zu
zählen. Durch das Beobachten der globalen Variable, kann man dann ein
Delay implementieren.
Guck es Dir einfach mal in den Sourcen der HA-Library an und lese
einfach mal das "Reset and clock control" Kapitel im Reference Manual zu
Deinem Controller. ggf. findest Du auch, dass einige Einstellungen
bereits im Startup Code von ST gemacht werden.