Forum: Mikrocontroller und Digitale Elektronik STM32: Ich finde einfach keinen Fehler in meinem Code


von jogl (Gast)


Angehängte Dateien:

Lesenswert?

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.

von jogl (Gast)


Angehängte Dateien:

Lesenswert?

Habe den neuen Code vergessen :D

von (prx) A. K. (prx)


Lesenswert?

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;

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Diese Delay-Loops funktionieren? Compiler haben mitunter sehr eigene 
Ansichten zu Code, der ihnen völlig sinnlos vorkommt.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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?

: Bearbeitet durch Moderator
von jogl (Gast)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

Mit abgeschalteter Optimierung.

von jogl (Gast)


Lesenswert?

Aber kann jemand einen Fehler in meinem neuen Programm erkennen oder 
einen Unterschied zum alten?

von Bernd K. (prof7bit)


Lesenswert?

jogl schrieb:
> Haben bislang immer funktioniert.

Reiner Zufall. Kann morgen schon aufhören.

von Bernd K. (prof7bit)


Lesenswert?

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.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

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.

: Bearbeitet durch User
von jogl (Gast)


Lesenswert?

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.

von holger (Gast)


Lesenswert?

>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.

von Bernd K. (prof7bit)


Lesenswert?

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
static void delay(unsigned time) {
17
    for (unsigned i=0; i<time; i++)
18
        for (volatile unsigned j=0; j<20000; j++);
19
}
20
21
22
/**
23
 * Hello world blinky program
24
 *
25
 * @return never
26
 */
27
int main(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.

von Bernd K. (prof7bit)


Lesenswert?

Zwei Beispiele:
1
int zeitvertreib(void) {
2
    const int rot = 42;
3
    const int gruen = 43;
4
    const int blau = 44;
5
6
    int x = rot + gruen;
7
8
    return blau;
9
}
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
int zeitvertreib(void) {
2
    const int rot = 42;
3
    const int gruen = 43;
4
    const int blau = 44;
5
6
    volatile int x = rot + gruen;
7
8
    return blau;
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.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

jogl schrieb:
> 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.

Beitrag "Re: STM32: Ich finde einfach keinen Fehler in meinem Code"

von jogl (Gast)


Lesenswert?

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?

von Wrumm (Gast)


Lesenswert?

welchen compiler nehmt ihr denn? gcc linux?

von jogl (Gast)


Lesenswert?

keil µvision, das ist doch aber nicht vom compiler abhängig?

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

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).

von jogl (Gast)


Lesenswert?

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.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.