Hallo liebe Forumsmitglieder, ich habe eine Entdeckung in einem meiner Programme für den STM32 gemacht und wollte wissen ob das ein Problem des Compilers oder meines Verständnisses ist. Zur Hardware, angetrieben wird alles von einem STM32F103RBT6 auf dem Board befinden sich mehrere LED Controller die über SPI angesprochen werden, 9 Pushbuttons die über zwei ADC Kanäle ausgelesen werden und 7 Drehenkoder. Der Status der ADC Kanäle und der Drehenkoder wird über einen Timer alle 500 uS abgerufen. DMA Channel 1 versorgt den ADC DMA Channel 2 und 3 sind für SPI1 zuständig Insofern sich etwas geändert werden dann die neuen werte in ein Array geschrieben, die Adresse des DMA Controllers wird auf das Array gesetzt und der Transfer gestartet. Um den Status des SPI zu verfolgen habe ich die globale variable volatile uint8_t SPI1_BLOCK definiert. Möchte ich einen SPI transfer starten prüfe ich zunächst ob der SPI Bus blockiert ist, dann setze ich zuvor meine global definierte variable auf einen definierten wert. Zum einen wird hierdurch gezeigt das der SPI Bus busy ist, zum anderen weiss die ISR hierdurch später welcher Chip Select bedient werden muss. Am Ende der ISR wird dieser Wert wieder auf 0 gesetzt und somit der SPI Bus frei gegeben. Zu der Beobachtung. In meinem Programm prüfe ich wie gesagt ob der SPI Bus frei ist. Der Code den ich zunächst verwendet habe war while(SPI1_BLOCK != SPI_BLOCK_FREE); das funktioniert allerdings nicht. Der Status von SPI1_BLOCK ändert sich nicht, das Programm blockiert an der stelle. Folgender Code läuft allerdings. while(SPI1_BLOCK != SPI_BLOCK_FREE) { if(i<64) { i++; } else { i=SPI1_BLOCK; } } Ich habe erwartet, das auch das erste Konstrukt funktioniert weil die Variable ja volatile definiert ist und deswegen doch bei jedem Aufruf erneut aus dem Speicher gelesen wird. Denke ich da falsch?
Willem B. schrieb: > Der Status von SPI1_BLOCK ändert sich > nicht, das Programm blockiert an der stelle. Woher weisst du, dass SPI_BLOCK1 sich ändert? Also sich wirklich ändert, nicht nur im Kopf.
schau doch einfach mal im ASM code nach, ob er die Variabel wirklich prüft. Außerdem ist es eine schlechte Idee alles Großbuchstaben für Variablen zu verwenden. Das sollte man nur für defines machen.
@A. K. Also ich weiss aus dem Debugger, dass das Programm an der Stelle denkt SPI1_BLOCK bleibt unverändert. und andersherum weiss ich aus dem zweiten Code das SPI1_BLOCK sich ändert. Es wird 0 und das Programm läuft weiter. Die Zeilen sind die einzigen Unterschiede die ich gemacht habe und der eine Code läuft, der andere nicht. Um es zu vereinfachen habe ich auch folgendes getestet while(SPI1_BLOCK != SPI_BLOCK_FREE); // läuft nicht uint8_t i; while(SPI1_BLOCK != SPI_BLOCK_FREE) // läuft { i=SPI1_BLOCK; } das sind die einzigen Unterschiede im Programm. @Peter II schau doch einfach mal im ASM code nach, ob er die Variabel wirklich prüft. OK, das werde ich machen Außerdem ist es eine schlechte Idee alles Großbuchstaben für Variablen zu verwenden. Das sollte man nur für defines machen. Ich hatte ausschliesslich meine globalen Variablen auch mit Großbuchstaben definiert um sie zu unterscheiden. Aber da lasse ich mir dann was anderes einfallen.
:
Bearbeitet durch User
Poste mal deinen ganzen Code (Pastebin oder so). Zudem sollte deine Variable nicht nur volatile sein, nein, sie sollte auch atomic sein. http://www.gnu.org/software/libc/manual/html_node/Atomic-Types.html Imho könntest du dich in die Multithreading Problematik einlesen, dort werden Locks, Mutex, Semaphore usw. aufgezeigt. http://www.csc.villanova.edu/~mdamian/threads/posixsem.html
Philipp R. schrieb: > Zudem sollte deine Variable nicht nur volatile sein, nein, sie sollte > auch atomic sein. Wieviele auch in C programmierbare Controller kennst du, bei denen Lade- und Speicheroperationen auf ein Byte nicht atomar sind? Willem B. schrieb: > volatile uint8_t SPI1_BLOCK definiert. Philipp R. schrieb: > Multithreading Problematik einlesen Worin besteht der Zusammenhang mit diesem Problem?
:
Bearbeitet durch User
@Philipp R. OK, hier die relevanten Funktionen oder soll ich alles posten? http://pastebin.com/Yfg3vrEu
Zunächst mal kannst Du Code auch hier als Anhang posten. Das ist besser, weil man dann alles an einem Ort hat. Ob Pastebin langfristig lesbar sind, weiß man nicht. Soviel dazu. Ich habe den Code nicht detailliert untersucht, aber mir fällt auf, dass Du die Variablen an mehreren Stellen schreibst und das sie mehrere Zustände haben kann. Dazu ist es eigentlich unnötig, so ein Flag innerhalb einer ISR zu setzen und dann wieder zurückzusetzen, denn es kann während der Ausführung der ISR sowieso kein anderer Code (ausser anderen ISR beim ARM) ausgeführt werden. Aber ich kann nicht erkennen (wohlgemerkt: ich habe nur oberflächlich hingeguckt) dass diese Variable in anderen ISRs verwendet wird. Diese mehrfachen Bedeutungen der Variable solltest Du voneinander trennen. Das macht es einfacher und übersichtlicher. Falls das tatsächlich ein konkretes Problem darstellt, solltest Du im Debugger auch den Wert sehen können, wenn die while-Schleife nicht verlassen wird. Entspricht der Wert einem der anderen, die Du verwendest? An sich wäre es auch gut, wenn Du einmal ausführlich erklären würdest, welche Wirkung die verschiedenen möglichen Werte der Variablen haben sollen. Wenigstens für Dich um Klarheit zu erlangen. Ein Zustandsdiagramm wäre vieleicht auch nützlich.
Also es gibt vier tlc5947 led driver, einen tlc5926 led driver und einen as1108 siebensegment driver. Alle teilen den spi Bus, jedes hat ein eigenes Chip Select. Jeder chip hat eine Zahl zugeordnet. Möchte ich nun Daten an Chip 1 senden prüfe ich ob SPI1_BLOCK 0 ist und setze es auf 1, dadurch weiss 1. Das Programm der spi Bus ist blockiert. Denn der Rest des Programms läuft ja weiter wenn der dma gestartet ist und könnte auf die Idee kommen auch den spi Bus zu starten. 2. Die Spi1_send Funktion welcher Chip select bedient wird. 3. Die ISR welcher Chip select bedient wird. Nachdem die ISR durchgelaufen ist wird SPI1_BLOCK auf 0 gesetzt. Der Bus ist dadurch wieder frei gegeben.
:
Bearbeitet durch User
Nun, daraus scheint mir hervorzugehen, dass es keineswegs unmöglich ist, dass die while-Schleife nicht verlassen wird, denn die Variable kann noch andere Werte als SPI_BLOCK_FREE haben. Diese Konstruktion mit dem kopieren nach i, sollte eine Optimierung an sich nicht austricksen, denn wenn der Compiler - von Dir unbeabsichtigt - davon ausgehen sollte, dass sich die Variable nicht ändern kann, dann kann er auch schliessen, dass i immer den Wert der Variablen haben wird. Die Details kann man so nicht erkennen. Es fehlt auch die Variablendeklaration. Ich würde zunächst, wie oben schon gesagt, einfach mal schauen, welchen Wert die Variable hat, wenn die Schleife nicht verlassen wird, obwohl Du es erwartest. Vermutlich ist einfach einer der Interrupts noch nicht ausgeführt worden und die Umkopiervariante braucht einfach zusätzlich Zeit, die dann ausreicht, dass der Interrupt ausgeführt wird. Das würdest Du an dem tatsächlichen Wert sehen können, vermute ich. Dennoch würde ich meinen obigen Rat wiederholen und ein Flag, dass anzeigt strikt von einer Zielangabe (die das CS-Bit auswählt) trennen. Das ist sozusagen mehr "straight-forward". Zwar ist, was Du versuchst nicht streng falsch aber es verquickt zwei Bedeutungen miteinander, die ihrem inneren Sinn nach, nichts miteinander zu tun haben.
Willem B. schrieb: > Um den Status des SPI zu verfolgen habe ich die globale variable > volatile uint8_t SPI1_BLOCK definiert. Hast Du die in den anderen Modulen denn auch als
1 | extern volatile uint8_t SPI1_BLOCK; |
deklariert? Oder hast Du da etwa
1 | extern uint8_t SPI1_BLOCK; |
gemacht?
ich habe in meiner spi.h
1 | extern volatile uint8_t SPI1_BLOCK; |
stehen und dann einfach den header eingebunden
:
Bearbeitet durch User
... von welchem Compiler reden wir denn überhaupt?
Es ist ein gcc arm-none-eabi version 4.8
Willem B. schrieb: > ich habe in meiner spi.h > >
1 | extern volatile uint8_t SPI1_BLOCK; |
stehen und dann einfach den
> header eingebunden
Eine "extern"-Deklaration ist noch keine "Definition", die Speicherplatz
reserviert. Es ist nur die Information an den Compiler, dass in einer
anderen Quellcode-Datei eine "Definition" existiert. Man müsste die
"Definition" sehen. Dazwischen besteht ein klar beschriebener
Unterschied.
Falls da was schief läuft müsste man (bei den Compilern, die ich kenne)
auch Warnings sehen. Wie schon mal geschrieben: Zeige am besten den
kompletten Code. Oder reduziere den Code auf ein äquivalentes,
compilierbares Beispiel, bei dem das Verhalten auch auftritt.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.