mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik STM32 DMA aktivieren in USART-Interrupt -> Byte doppelt


Autor: Janis W. (jotwe)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich habe hier einen Effekt, den ich nicht nachvollziehen kann: Ich 
empfange Datenpakete an der USART1 eines STM32, die im vierten Byte eine 
Längeninformation enthalten. Sobald ich diese Längeninformation habe, 
möchte ich von Interrupt-Betrieb auf DMA umschalten. Dazu konfiguriere 
ich in der USART-Interrupt-Routine den DMA:
// Configure and activate DMA for reception
DMA_Cmd(DMA1_Channel5, DISABLE);
// Set DMA address
DMA1_Channel5->CMAR = (uint32_t)&(receptionBuffer[bufferWriteIndex].buffer[4]);
// Set received length
DMA1_Channel5->CNDTR = receptionBuffer[bufferWriteIndex].buffer[3];
DMA_Cmd(DMA1_Channel5, ENABLE);

Nun wird aber - für mich überraschend - in meinem Buffer das Längen-Byte 
zweimal abgelegt, einmal durch den USART-Interrupt (gewünscht) und 
einmal durch den DMA (unerwünscht). Aus einem Paket

0xFF 0xFF 0x01 0x02 0x01 0xFB

mit der Längeninformation 0x02 wird damit

0xFF 0xFF 0x01 0x02 0x02 0x01. Eigentlich müsste durch das Auslesen per
// Get received byte
receivedByte = USART_ReceiveData(USART1);

doch der USART-Buffer geleert worden sein?! Auch ein vorheriges 
manuelles Rücksetzen des RXNE-Flags ändert nichts. Warum erkennt der DMA 
das Byte trotzdem noch einmal als "neu" empfangen? Im Reference Manual 
konnte ich bisher keine Erklärung finden...

Im Anhang ist mein kompletter Quellcode mit Initialisierung der USART 
und des DMA. Hier meine etwas verkürzte USART-Interrupt-Routine:
void USART1_IRQHandler(void) {

// Private variables
uint8_t receivedByte;

// USART receive data register is not empty
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {

// Get received byte
receivedByte = USART_ReceiveData(USART1);

// If packet does not start with two start bytes, refuse packet and reset
// reception buffer
if ((receptionBuffer[bufferWriteIndex].length < 2) && (receivedByte != 0xFF)) {

// Reset reception buffer
receptionBuffer[bufferWriteIndex].length = 0;

return;

}

// If packet length is not valid, refuse packet and reset reception buffer
if ((receptionBuffer[bufferWriteIndex].length == 3) && ((receivedByte < 2) || (receivedByte > 250))) {

// Reset reception buffer
receptionBuffer[bufferWriteIndex].length = 0;

return;

}

// Copy received byte to buffer and increase buffer length
receptionBuffer[bufferWriteIndex].buffer[receptionBuffer[bufferWriteIndex].length++] = receivedByte;

// If packet length is known, configure and activate DMA for reception
if (receptionBuffer[bufferWriteIndex].length == 4) {

// Configure and activate DMA for reception
DMA_Cmd(DMA1_Channel5, DISABLE);
// Set DMA memory address
DMA1_Channel5->CMAR = (uint32_t)&(receptionBuffer[bufferWriteIndex].buffer[4]);
// Set DMA length
DMA1_Channel5->CNDTR = receptionBuffer[bufferWriteIndex].buffer[3];
DMA_Cmd(DMA1_Channel5, ENABLE);

}

}

}

Autor: Joachim K. (minifloat)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Datenblatt und errata genau angesehen?
Hersteller konsultiert(Mail/Telefon)?

Und als dreckiger Workaround: Längenangabe auslesen aber zunächst nicht 
in deinen (zu dem Zeitpunkt noch Software-)Puffer stecken. Dann DMA 
anmachen, weitere Bytes liegen im Puffer, dann dein Längenangabe Byte 
über das vom DMAC unerwünscht erzeugte drüberschreiben.
mfg mf

Autor: Janis W. (jotwe)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Mini Float,

so einen ähnlichen "dreckigen" Workaround habe ich zur Zeit laufen. 
Leider habe ich gelegentlich Übertragungsfehler und wollte es deshalb 
mal "sauber" lösen...

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist der DMA abgeschaltet wenn alle seine Bytes durch sind? Oder hängt 
der mit count=0 aber enabled und hat sich den Request irgendwie gemerkt?

Autor: Janis W. (jotwe)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Im DMA-Interrupt setze ich das Transfer-Complete-Flag zurück und 
deaktiviere den DMA:
// DMA interrupt handler
void DMA1_Channel5_IRQHandler(void) {

// DMA transfer complete
if (DMA_GetITStatus(DMA1_IT_TC5)) {

// Clear interrupt flag
DMA_ClearITPendingBit(DMA1_IT_TC5);

// Deactivate DMA
DMA_Cmd(DMA1_Channel5, DISABLE);

...

}

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schon versucht, DMAR (UART Bit) passend dazu aus/einzuschalten?

Autor: Janis W. (jotwe)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hm, bisher nicht. Das aktiviere ich bei der Initialisierung und lasse es 
dann immer aktiviert. Aber das könnte in der Tat eine Möglichkeit sein. 
Werde das morgen direkt mal probieren. Danke für den Hinweis!

Autor: Janis W. (jotwe)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe das DMAR-Bit in USART_CR3 jetzt berücksichtigt und die 
Kommunikation eine Weile getestet. Es scheint wirklich zu funktionieren! 
Das doppelte Byte ist nicht mehr da und die Kommunikation läuft stabil.

Vielen Dank nochmal für alle Tipps!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.