Guten Morgen,
ich habe gerade ein Brett vorm Kopf und suche jemanden mit Kneifzange.
Ich nutze den ARM-GCC und in einer Funktion wird die Variable "value"
wegoptimiert - und ich sehe gerade nicht warum.
1
voidglcd_putsth(charvalue,uint8_tRS){
2
// Neuimplementierung write-Zyklus gemaess Datenblatt S. 14
GLCD_DATA_OFFSET ist 8, Ergebnis ist, daß alle Pins ständig high sind.
So langsam setzt bei mir die Codeblindheit ein und ich sehe Fehler, wo
keine sind. Kann mir jemand kurz helfen?
Viele Grüße
W.T.
Bring mal den ganzen Code zu der Funktion. Da fehlt was am Anfang.
Verlass dich nicht darauf, dass die Quellcodezeilen immer an der
richtigen Stelle eingefügr werden, das geht oft daneben.
Lass das mit den Fliesskommazahlen bei delay_us lieber. Diese Funktion
ist für so kurze Zeiten problematisch. Woher stammt die?
Bei dem Delay kommt mir noch was komisch vor:
08000b2a <L_LOOPUS_194>:
8000b2a: 3801 subs r0, #1
8000b2c: f47f affd bne.w 8000b2a <L_LOOPUS_194>
R0 ist jetzt 0. Nirgendwo hier wird R0 verändert. R0 bleibt also 0.
08000b44 <L_LOOPUS_203>:
8000b44: 3801 subs r0, #1
8000b46: f47f affd bne.w 8000b44 <L_LOOPUS_203>
Wenn dieser Code mit R0=0 anläuft, dann ist Geduld angesagt.
Danke für's Lesen.
Ich hoffe, ich habe jetzt alle Teile aus dem Listing richtig
zusammengeklaubt (list.lss). Wer sich das wirklich antun will kann auch
einen Blick ins komplette Listing werfen (lang_und_zaeh.lss).
Daß GLCD_DATA_OFFSET 8 ist bin ich mir sicher - daß mir da ein zweites
Makro hineinfuhrwerkt war ja auch mein erster Gedanke. Und immerhin
funktioniert ja noch die Variante mit der Standard-Peripheral-Library
meines STM32, also muß die Pinzuordnung schon einmal stimmen.
Walter Tarpan schrieb:> Daß GLCD_DATA_OFFSET 8 ist bin ich mir sicher
Der Code fürs BSSR passt dazu und ist auch völlig korrekt:
8000b32: 022d lsls r5, r5, #8
8000b38: f045 457f orr.w r5, r5, #0xff000000
8000b42: 6115 str r5, [r2, #16]
Ich frage mich eher, ob das Timing stimmt. Einerseits die
Delay-Funktion, wie beschrieben. Andererseits ist GPIO_xxxBits viel
langsamer als die anderen nicht funktionierenden Varianten.
A. K. schrieb:> [...]>> Ich frage mich eher, ob das Timing stimmt. Einerseits die> Delay-Funktion, wie beschrieben. Andererseits ist GPIO_xxxBits viel> langsamer als die anderen nicht funktionierenden Varianten.
Das war auch mein erster Gedanke. Deswegen hatte ich bei Vorversuchen
auch viele nops eingefügt.
A. K. schrieb:> Lass das mit den Fliesskommazahlen bei delay_us lieber. Diese Funktion> ist für so kurze Zeiten problematisch. Woher stammt die?
Damit hast Du mich auf den rechten Weg gebracht: Die delay-Routine habe
ich in den Weiten des WWWs gesucht und in eine Makro-Form gebracht, weil
ich ARM-Assembler nicht kann. Und sie ist so definiert:
Wenn ich die letzte Zeile durch 9 "nop"s ersetze geht alles. Was auch
erklärt, warum sich der Debugger ständig aufgehängt hat. Ich vermisse
irgendwie die hervorragend funktionierenden _delay_xx vom AVR-GCC.
Vielen Dank für die hilfreichen Kommentare!
Bei dieser Delay-Funktion sollte an Stelle der Variablen SystemCoreClock
eine Konstante stehen. Andernfalls gibts, wie hier geschehen, eine
Berechnung zur Laufzeit und kurze Delays werden grottenfalsch.
Ausserdem kann es je nach exaktem Typ des Controllers und dem jeweiligen
Alignment der Schleife gewisse Schmutzeffekte geben, so dass das exakt
gleiche Delay an verschiedenen Stellen im Programm deutlich
unterschiedlich ausfällt.
Walter Tarpan schrieb:> #define delay_us_(delayval) \> asm volatile (\> "L_LOOPUS_%=: \n\t" \> "subs %0, %0, #1 \n\t" \> "bne L_LOOPUS_%= \n\t" \> : /* no outputs */ : "r" (delayval) )> [/c]
Das ist falsch, denn delayval wird verändert! Die Constraint könnte
sein:
> : "=r" (delayval) : "0" (delayval)
Allerdings muß delayval dann ein LVALUE sein. Anstatt des Makros würde
ich eine inline-Funktion machen.
Ich kenn zwar kein ARM-Code, aber das schein nicht zu funktionieren wenn
delayval = 0 ist. Du könntest
ergibt doch immer 0.
Der Wert von Value wird um 8 Bit nach oben verschoben und dann werden
die oberen Bits ausmaskiert. Damit kann der Compiler die Variable
wegoptimieren.
Gruß Carsten.
Carsten H. schrieb:> Der Wert von Value wird um 8 Bit nach oben verschoben und dann werden> die oberen Bits ausmaskiert. Damit kann der Compiler die Variable> wegoptimieren.
Also bei mir landet ein 8-Bit-Wert beim Verschieben um 8 Bit immer noch
im 16-Bit-Bereich. Und auf meinen µP auch. Also läuft das alles
problemlos seit ein paar Stunden.
Johann L. schrieb:> Ich kenn zwar kein ARM-Code, aber das schein nicht zu funktionieren wenn> delayval = 0 ist. Du könntest> static inline __attribute__((_always_inline_))> void delay_us (unsigned delayval)> {> if (delayval)> __asm volatile ("0:\n\t"> "subs %0, %0, #1 \n\t"> "bne 0b"> : "+r" (delayval));> }
Mit dem delay muß ich mal ausprobieren. Eine gute Delay-Funktion ist
nämlich immer noch Mangelware.
Johann L. schrieb:> Das ist falsch, denn delayval wird verändert!
Das ist der Grund, weshalb die zweite 0,450er Schleife stecken bleibt.
> Ich kenn zwar kein ARM-Code, aber das schein nicht zu funktionieren wenn> delayval = 0 ist.
Korrekt.
Carsten H. schrieb:> Der Wert von Value wird um 8 Bit nach oben verschoben und dann werden> die oberen Bits ausmaskiert.
Wie ich oben schon schrieb ist dieser Code völlig korrekt.
Wenn dich das (uint16_t)value irritiert: Der Cast ist für'n A..... Ich
würde aber empfehlen, als Parameter kein "char" zu verwenden. Das könnte
negativ sein und dann geht es bei einem Offset < 8 den Bach runter.
axel schrieb:> Das müssten schon 16 Bit sein, erst dann ist der Wert von value komplett> durch die Maskierung weg.
Allerdings würde man dann vmtl. kein 32-Bit I/O-Register vorfinden.
A. K. schrieb:>> Wenn dich das (uint16_t)value irritiert: Der Cast ist für'n A..... Ich> würde aber empfehlen, als Parameter kein "char" zu verwenden. Das könnte> negativ sein und dann geht es bei einem Offset < 8 den Bach runter.>
Bitte den obigen Code nicht zu ernst nehmen: Der Cast ist wirklich
Überflüssig. Es ist dieser Code, der entsteht, wenn man nicht mehr
weiter weiß (Variante1 funktioniert, Variante2 nicht und beide sehen
völlig gleich aus!) und das Assembler-Listing noch nicht richtig lesen
kann und dann alles explizit und fix castet, damit ja keine merkwürdige
Integer-Promotion-Regel mehr dazwischenpaßt.
printf("Test delay \n PB2 Pulsabstand 3µs\n Beenden durch Knopfdruck\a");
11
12
while(1){
13
GPIOB->BSRR=GPIO_Pin_2;
14
delay_us(3);
15
GPIOB->BSRR=GPIO_Pin_2<<16;
16
delay_us(6);
17
if(key_getstroke())return;// Liest Tastendruck ein
18
}
19
}
Wirft man einen Blick aufs Oszilloskop (sorry für den schlechten
Screenshot, die sphärische Verzerrung bekomme ich nicht heraus) sieht
man, daß der vorgeschlagene Delay sehr zuverlässig funktioniert (die
Verschiedungen kommen vom SysTick, ist der aus sind alle schön gleich
breit).
Das ist genau das, was ich gesucht habe. Vielen Danke für die Hilfe!
Walter Tarpan schrieb:> Wirft man einen Blick aufs Oszilloskop (sorry für den schlechten> Screenshot, die sphärische Verzerrung bekomme ich nicht heraus)
Das ist ein Witz, oder? Der Screenshot ist --abgesehen davon, daß
eigentlich das Oszilloskop so etwas selbst anfertigen können sollte--
doch vollkommen in Ordnung.