Im Grunde initialisiere ich das Kernsystem, den Clock und den
PORTA/PORTD, um die Led LD15 auf der Platine leuchten zu lassen. Ich
sende ein Byte über mein PC zu dem Board, ein Interrupt wird ausgelöst
und der Byte wird zu einer als volatile bezeichneten Variable
zugewiesen (rx_data).
Die LED leucht aber gar nicht...
Ihr fragt nun bestimmt: "Na klar..ist die serielle Verbindung nicht
i.O".
Doch wenn ich die USART2_IRQHandler funktion wie folgend umschreibe:
/* Aus dem main-Loop entfernt und hier heruntergebracht */
9
if(rx_data=='X'){
10
GPIO_SetBits(GPIOD,GPIO_Pin_15);
11
}
12
}
13
14
USART_ClearITPendingBit(USART2,USART_IT_RXNE);
15
}
dann geht doch. Nach Übertragung der gewünschten Buchstabe, leuchtet die
LED wie erwartet.
So dachte ich mir..."es sieht so aus, als ob die while-Schleife in dem
Loop wegoptimiert worden ist..."
Hier die Flags, die ich in meinem Makefile eingestellt habe:
Egal welche Optimierungsstufe eingebe - -O[s0123] - kriege ich immer
dasselbe zurück. Die Led leuchtet gar nicht.
Wo ist der Fehler?
Wie gesagt, das ist ein minimal Beispiel. Das echte Programm ist etwa
komplexer. Ich möchte aber herausfinden, wo das Problem auftrifft und
warum.
Ich danke Euch für Eure Hilfe.
Gruß
Salam,
guck dir nochmals die Reihenfolge der Initialierungen an.
Das hier:
> GPIO_PinAFConfig( GPIOA, GPIO_PinSource2, GPIO_AF_USART2 );> GPIO_PinAFConfig( GPIOA, GPIO_PinSource3, GPIO_AF_USART2 );> USART_ITConfig( USART2, USART_IT_RXNE, ENABLE );
kommt mir Spanisch vor. Kann aber auch richtig sein, da du die neuere
lib hast.
Jedenfalls, Interrupts wie
> USART_ClearITPendingBit( USART2, USART_IT_RXNE );
müssen gleich anfangs einer ISR gelöscht werden.
mfg
Eiermann schrieb:> Das hier:>> GPIO_PinAFConfig( GPIOA, GPIO_PinSource2, GPIO_AF_USART2 );>> GPIO_PinAFConfig( GPIOA, GPIO_PinSource3, GPIO_AF_USART2 );>>> USART_ITConfig( USART2, USART_IT_RXNE, ENABLE );> kommt mir Spanisch vor. Kann aber auch richtig sein, da du die neuere> lib hast.
Sorry...
und was ist verkehrt in der obigen Reihenfolge?
Zu sagen "schau mal..." hilft mir nicht wirklich weiter.
Wie soll es sonst sein?
Falls es dir Spanisch vorkommt, das schaue mal in den von mir geposteten
Link oben. In den Beispiele ist die Reihenfolge genauso, wie ich
gepostet habe.
> Jedenfalls, Interrupts wie>> USART_ClearITPendingBit( USART2, USART_IT_RXNE );> müssen gleich anfangs einer ISR gelöscht werden.
Sicher? Und was ist wenn der Mikro ein zweites Zeichen nach dem ersten
empfängt?
Außerdem habe ich festfestellt, dass auch ohne den Interrupt zu löschen,
wird die IRQHandler() wieder aufgerufen.
Das Problem ist, wie gesagt, dass der hautmain Loop einfach ignoriert
wird. Obwohl ich die Variable als volatile deklariert habe.
Da ich auch gerade am Spielen mit einem Discovery-Board (STM32F407) bin
habe ich mir das mal 1:1 reinkopiert. In meiner Entwicklungsumgebung
(VisualGDB) entfällt das
1
SystemConfiguration()
und der Interrput wird so initialisiert:
1
NVIC_EnableIRQ(USART2_IRQn);
Der Rest ist unverändert. Die Variante mit der volatile-Variablen
funktioniert bei mir sowohl in der Debug als auch in der
Release-Version. Ich kann da auch keinen Fehler erkennen.
>Sicher? Und was ist wenn der Mikro ein zweites Zeichen nach dem ersten>empfängt?
Sollte man nicht genau aus diesem Grund das Flag so schnell wie möglich
zurücksetzen (also möglichst am Anfang der ISR)?
Dave A. schrieb:> Ich habe aber nun das Problem, dass mein Programm nicht das gewünschte> Resultat liefert.
Nein, du hast ganz andere Probleme.
Zuvörderst, daß du dich mit Linux betust, weswegen du auch Linkerfiles,
Makefiles und dergleichen benutzt, was in vielen Fällen Fehlerurschen
beherbergt und wozu ich als Windows-Benutzer dir keinen Ratschlag geben
kann.
Sodann hast du das Problem, daß du völlig unstrukturiert
drauflosschreibst, so daß alles bunt durcheinanderpurzelt und selbst
sowas wie Details von Treibersetup's in main vorkommen. Obendrein lese
ich sowas wie "GPIO_StructInit".
Such einfach mal in diesem Forum, ich hatte vor einiger Zeit schon mal
nen Unit für die U(S)ART's beim STM32F302 gepostet, an anderen Stellen
findet sich auch ne Menge an Lehrreichem, was die vernünftige
Strukturierung und diverse Peripherie-Treiber nebst deren Schnittstellen
zur restlichen Firmware betrifft. Also stell dich nicht so an.
Ich würde an deiner Stelle zu allererst und in folgender Reihenfolge
tun:
1. nen Startupcode für deinen µC in Assembler
schreiben/beschaffen/kopieren und lesen und verstehen.
2. ne separate Quelle zum allgemeinen Systemsetup schreiben, wo die
Pinverwendung in sinnvoller Weise erledigt wird, dann der Takt
aufgesetzt wird und ggf. sowas wie externern SDRAM oder so aufgesetzt
wird.
3. ne Quelle für eine Systemuhr auf SysTick-Basis schreiben
4. ein main schreiben, was aber bittesehr NICHT mit
Peripherie-Firlefanz zugepflastert wird
5. dieses Minimalzeugs erstmal mit wackelndem Pin am Oszi oder so zum
Laufen bringen
6. dann Peripherietreiber schreiben für UART's und ggf. VCP via USB.
(Quelle dazu gibt's hier auch, such einfach danach)
W.S.
Cube_S schrieb:> Sollte man nicht genau aus diesem Grund das Flag so schnell wie möglich> zurücksetzen (also möglichst am Anfang der ISR)?
Du hast offensichtlich weder das Manual wirklich gründlich gelesen, noch
den E/A Verkehr per Interrupt selbst ausprobiert.
Also: Es gibt je nach Chip und peripherem Core unterschiedliche
Verhaltensweisen der HW bezüglich Interrupts: manche erzeugen z.B. nen
TxEmpty-Interrupt nur beim Leer-WERDEN, andere beim Leer-SEIN.
Entsprechend muß das Verhalten des Handlers sein: entweder garnix tun
oder bei nachfolgendem Nichtbedarf des Interrupts den Interrupt im
Peripheriecore abschalten.
Viele Flags kann man nämlich überhaupt nicht zurücksetzen. Die setzen
sich nur dann zurück, wenn man z.B. den Sendepuffer mit dem nächsten
Byte füllt. Hat man aber kein nächstes Byte, dann wird man das TxEmpty
Flag niemals mehr los bis zur nächste Ausgabe zum UART. Folglich muß
man, um nicht im Dauer-Interrupt zu ersticken, das TXEIE ausschalten und
mit dem nächsten Schreiben in den internen Ringpuffer eben wieder
einschalten.
Klaro?
W.S.
> Klaro?
Und wie. Ich habe schon ein paar funktionierende Interrupt-Routinen am
laufen, da mach Dir mal keine Sorgen.
Je länger man aber damit wartet ein Interrupt-Flag zu löschen (ob nun
automatisch wie hier oder nicht) desto größer wird die Chance, dass ein
Neusetzen des Flags durch die Hardware aufgrund eines verspäteten
Löschens durch die Software verpasst wird.
Klaro?
Cube_S schrieb:> Da ich auch gerade am Spielen mit einem Discovery-Board (STM32F407) bin> habe ich mir das mal 1:1 reinkopiert. In meiner Entwicklungsumgebung> (VisualGDB) entfällt das>
1
SystemConfiguration()
und der Interrput wird so initialisiert:
>
1
>NVIC_EnableIRQ(USART2_IRQn);
2
>
> Der Rest ist unverändert. Die Variante mit der volatile-Variablen> funktioniert bei mir sowohl in der Debug als auch in der> Release-Version. Ich kann da auch keinen Fehler erkennen.>>>Sicher? Und was ist wenn der Mikro ein zweites Zeichen nach dem ersten>>empfängt?> Sollte man nicht genau aus diesem Grund das Flag so schnell wie möglich> zurücksetzen (also möglichst am Anfang der ISR)?
Danke Cube_S!!
Kannst Du mir bitte sagen, welche Optimierungsstufen bzw. Optionen dem
Compiler eingegeben hast?
W.S. schrieb:> Obendrein lese> ich sowas wie "GPIO_StructInit".
Dagegen ist nichts zu sagen, damit wird eine grundlegende Vorbelegung
der Struct initialisiert - alles bestens.
W.S. schrieb:> Nein, du hast ganz andere Probleme.>> ...
Ehy, deine Arroganz und deine Klugscheißerei passen hier nicht so ganz.
Vor allem, weil du nur gelabert hast, ohne die Kernfrage - scheinbar -
gelesen und verstanden zu haben. Und zwar, warum das Programm in die
Interrupt-Schleife geht und nicht in die MainRoutine.
Cube_S hat netterweise das Programm auf seinem Board getestet und somit
mir eine wichtige Info gegeben. Ein Forum oder eine Community - wie
diese - zeichnet sich durch Hilfsbereitschaft und Ideeaustausch und noch
mehr aus. Daher...wenn du dich wegen den Libs von STM angekotzt fühlst,
dann vermeide diesen Thread. Keiner hat dich eingeladen. Und keiner will
dass Diskussionen jedesmal eskalieren.
Wenn du irgendwas interessant in der Vergangenheit gepostet hast, kannst
du hier posten. Ohne zu nörgeln.
Im alten Atollic hatte ich merkwürdige Effekte, wenn ich in einer
(Timer) ISR Unterprogramme aufrief, die aber auch nur aus der ISR
aufgerufen wurden.
Sie wurden einfach nicht ausgeführt und der MC sprang in den Hard-Fault
Handler. Das triffts bei dir nicht ganz, spricht aber für manchmal
eigenartigen ISR Benimm.
Ich habe das Programm damals abgeändert, den Code aber dann nie mehr
durch mein derzeitiges Coocox gejagt, weil das Projekt auf Eis gelegt
wurde.
Die Frage ist nun, ist DMA nicht sinnvoller als eine ISR und was
möchtest du eigentlich mit dem empfangenen Zeichen anfangen? Als erstes
würde ich mal das IRQ Flag direkt am Anfang löschen und dann eine
sinnvolle Behandlung des Zeichens einfügen, z.B. Schreiben in einen
Buffer oder so. Evtl. löst sich das Problem von alleine.
Ach, du kannst übrigens beim F417 gerne auch hard math einschalten, der
MC hat eine FPU, die sich sonst langweilt. Aber das hat mit dem Problem
nix zu tun.