Forum: Mikrocontroller und Digitale Elektronik STM32F303 USART in Kombination mit Timer+ADC+DMA


von Andreas (Gast)


Lesenswert?

Hallo zusammen,

für ein größeres Projekt benötige ich relativ viel Peripherie meines 
STM32F303.
Das Ganze läuft aber nicht so ganz wie es soll.
Das System ist folgendermaßen aufgebaut:

TIM1 erzeugt 6 PWM Signale @ 20kHz
ADC1 und ADC2 laufen im Dualmode
Die ADCs werden werden durch TRGO2 des TIM1 getriggert.
Die gesampelten Werte der beiden ADCs werden durch DMA1_Channel1 
abgeholt und in ein Array gespeichert.

Im DMA1_Channel1_IRQHandler Interrupt werden die Daten dann verarbeitet. 
Soweit läuft alles perfekt. Die Verarbeitung der Daten im 
DMA1_Channel1_IRQHandler Interrupt dauert nicht zu lange und wird lange 
vor dem nächsten Interrupt fertig abgearbeitet.

Jetzt möchte ich zusätzlich Daten per USART1 empfangen und versenden.
USART1 ist so konfiguriert, dass empfangene Daten automatisch im 
Hintergrund von DMA1_Channel5 abgeholt werden, sprich ich habe keinen 
USART Rx Interrupt.
Versendet werden die Daten folgendermaßen:
1
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
2
USART_SendData(USART1, '!'); // sende Ausrufezeichen

Versendet werden die Daten aus der while(1) Schleife in der main - 
Funktion, also asynchron zu meiner Datenverarbeitung im 
DMA1_Channel1_IRQHandler.

Es funktioniert auch alles eine Zeit lang: Es werden PWM Signale 
erzeugt, ADC Werte richtig gemessen und der DMA1_Channel1_IRQHandler 
Interrupt im richtigen Zeitpunkt ausgeführt und die Kommunikation per 
USART1 läuft auch. Alles per Scope nachgemessen.

Wenn die USART Kommunikation allerdings aktiv ist, hört der uC nach 
einer unbestimmten, zufälligen Zeit (ca 1 - 120s) auf, den 
DMA1_Channel1_IRQHandler Interrupt aufzurufen, sprich der Rumpf des 
Interrupts wird irgendwann nicht mehr betreten. Die while(1) Schleife in 
der main - Funktion läuft allerdings weiter und die USART Kommunikation 
funktioniert weiterhin.

Der "Absturz" des Interrupts erfolgt viel schneller wenn ich per USART 
Variablen versende, welche auch im DMA1_Channel1_IRQHandler Interrupt 
manipuliert werden. Diese habe ich aber natürlich als volatile 
deklariert.

Zu sagen wäre noch, dass der uC mit dem internen RC Glied und PLL @ 
64MHz läuft. Die Clock habe mit dem von ST gelieferten 
"STM32F30x_Clock_Configuration_V1.0.0.xls" konfiguriert.
Als IDE verwende ich CooCox.

Habt ihr allgemeine Ideen, warum das Problem auftritt oder hatte 
vielleicht jemand das gleiche Problem?

Viele Grüße
Andreas

von hp-freund (Gast)


Lesenswert?

Klingt für mich als wenn die Interrupt Prioritäten nicht passen.

von Andreas (Gast)


Lesenswert?

Hallo hp-freund,

insgesamt habe ich nur einen Interrupt, diese ist so in die NVIC Tabelle 
eingetragen:
1
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
4
5
/* Enable DMA1 channel1 IRQ Channel */
6
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
7
NVIC_Init(&NVIC_InitStructure);

einen USART Interrupt habe ich nicht, weil die Rx Daten von 
DMA1_Channel5 geholt werden.

von Eric B. (beric)


Lesenswert?

Ohne Code keine Lösungen ;-)

Aber im Mainloop noch mal blockierend warten ist bestimmt Nicht Gut[TM]
1
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
2
USART_SendData(USART1, '!'); // sende Ausrufezeichen

Dann eher so:
1
if (USART_GetFlagStatus(USART1, USART_FLAG_TXE) != RESET) {
2
  USART_SendData(USART1, '!'); // sende Ausrufezeichen
3
}

Ich glaube aber nicht, dass das das Problem ist. Eher hast du Probleme 
mit simultane Zugriff auf globale Variabelen. Sie nur als volatile 
deklarieren reicht da nicht aus. Stichworte: critcial section, mutual 
exclusion (mutex).

von Andreas (Gast)


Lesenswert?

Eric B. schrieb:
> Probleme mit simultane Zugriff auf globale Variabelen

Auch wenn ich die Variablen, die im Interrupt bearbeitet werden, im 
USART nicht berühre, tritt das Problem auf. Oder kann es trotzdem zu 
Problemen kommen?

Eric B. schrieb:
> Aber im Mainloop noch mal blockierend warten ist bestimmt Nicht Gut[TM]

Da hast du natürlich recht, das ganze wird später auf state machine 
umgestellt :-)

von Dev P. (dev_p)


Lesenswert?

Ich hatte ein ähnliches Problem als ich externe Signale per Interrupt 
abgefragt hatte, ein
Timer lief und UART per Interrupt gearbeitet hat. Nachdem UART nicht 
mehr über Interrupt lief hatte ich keine Probleme. Ist das eine Option 
dies zu testen?

von W.S. (Gast)


Lesenswert?

Andreas schrieb:
> Jetzt möchte ich zusätzlich Daten per USART1 empfangen und versenden.
> USART1 ist so konfiguriert, dass empfangene Daten automatisch im
> Hintergrund von DMA1_Channel5 abgeholt werden, sprich ich habe keinen
> USART Rx Interrupt.
> Versendet werden die Daten folgendermaßen:
> ...
> Versendet werden die Daten aus der while(1) Schleife in der main

Das ist m.E. ein schlimmer Entwurfsfehler. Wozu soll ein DMA für den 
USART-betrieb denn gut sein? Um nicht nur mit dem USART zu tun zu 
haben,sondern auch mit dem DMA? Nein, USART Rx und Tx sollen per 
Interrupt gefahren werden, wobei der Treiber die asynchron anfallenden 
Daten in beiden Richtungen zwischenspeichern muß und der I/O-Verkehr aus 
den höheren Schichten der Firmware nur über diese Puffer geht. Der 
Interrupt dazu braucht keine hohe Priorität, ich würde ihn eine Stufe 
über dem System-Tick ansiedeln. Aber Rx per DMA und Tx per Grundschleife 
ist dumm, denn du versaust dir dabei den Status des USART jedesmal.

ist schon komisch: ich hatte doch in den letzten Tagen jemand anderem 
nen Komplett-Treiber für die U(S)ART's im STM32F30x gepostet.

W.S.

von hust (Gast)


Lesenswert?

verarbeitung der Daten im DMA interrupt..
versuche dort mal einen DMA overrun error abzufangen ...

dann würde ich das auch auslagern ...
die ISR gibt nur ein signal zum verarbeiten

von raichgeb (Gast)


Lesenswert?

Habe ein ähnliches Problem mit dem gleichzeitigen Betrieb von 2 
DMA-Kanälen gehabt. Möchte mich W.S. anschließen, den Uart mit Interrupt 
zu betreiben.
Grüsse

von Andreas (Gast)


Lesenswert?

Hallo zusammen,

Dev P. schrieb:
> Nachdem UART nicht
> mehr über Interrupt lief hatte ich keine Probleme

Per Interrupt läuft bei mir die Datenverarbeitung, nicht der USART

W.S. schrieb:
> Wozu soll ein DMA für den
> USART-betrieb denn gut sein?

Damit meine CPU nicht wegen jedem Byte einen Kontext Wechsel machen 
muss. Warum gibt es dann deiner Meinung nach einen DMA Channel zum Rx 
des USART? Der DMA erledigt für die von dir beschriebene Pufferung der 
Daten.

W.S. schrieb:
> denn du versaust dir dabei den Status des USART jedesmal

Das könnte wirklich sein, mein Problem ist allerdings dass der 
Timer+ADC+DMA(Interrupt) nicht mehr läuft.

hust schrieb:
> dann würde ich das auch auslagern ...
> die ISR gibt nur ein signal zum verarbeiten

Ist grundsätzlich natürlich besser, aber kann es etwas mit meinem 
Problem zu tun haben? Der USART läuft ja ungestört weiter.

Bei der Datenverarbeitung im Interrupt des DMA (Timer+ADC+DMA) handelt 
es sich um eine FOC Motorregelung @ 20kHz. Ein Durchlauf des 
Regelungsalgorithmus dauert ca 30uS. Der Mikrocontroller ist also 
alleine schon mit der Regelung ca 60% seiner Rechenzeit beschäftigt.
Wenn ich jetzt einen USART mit 115200Baud/s per Interrupt laufen lasse, 
wird meine FOC Regelung total zerhackt, weil ich ständige USART Rx 
Interrupts habe.

Habt Ihr noch weitere Ideen, wie der USART meinen ADC+DMA Interrupt 
stören kann?

Gruß
Andreas

von W.S. (Gast)


Lesenswert?

Andreas schrieb:
> Damit meine CPU nicht wegen jedem Byte einen Kontext Wechsel machen
> muss.

Andreas schrieb:
> Per Interrupt läuft bei mir die Datenverarbeitung, nicht der USART

Andreas schrieb:
> Habt Ihr noch weitere Ideen, wie der USART meinen ADC+DMA Interrupt
> stören kann?

Du bist mir schon ein recht Seltsamer.

Erstens gibt es bei einem Interrupt keinen Kontextwechsel (sowas ist ein 
Begriff aus der Multitasking-Welt), sondern eben lediglich einen 
Interrupt.

Zweitens solltest du mal erklären wie du dir den Rx-Betrieb per DMA denn 
so vorgestellt hast - einschließlich des Tx-Betriebes in der 
Grundschleife. So ein DMA kann m.W. lediglich Daten von einem Register 
in einen linearen Puffer schreiben (oder umgekehrt oder mem-to-mem). Er 
kann nicht wirklich mit einem Ringpuffer umgehen, weil dies eben auch 
eine geordnete Abfrage ( if(IsCharAvailable()) ...;) beinhalten muß und 
auch den Pufferüberlauf sinnvoll vermeiden muß.

Warum so ein USART überhaupt an den DMA-Core angeschlossen ist, kann man 
ganz leicht beantworten: Weil diese USART's für weitaus mehr als nur den 
asynchronen Datenverkehr auf einer seriellen Strippe geeignet sind und 
es dort auch Modi gibt, die paketweise arbeiten. Was meinst du, wehalb 
manche USART-Cores mit Adreßerkennungen usw. ausgestattet sind? Eben 
deshalb.

Wenn bei dir die Datenverarbeitung im Interrupt läuft und nicht in der 
Grundschleife, dann hast du entweder ein eher exotisches Problem oder du 
machst etwas GANZ GANZ falsch. Ich könnte mir bestenfalls ne 
Signalverarbeitung denken, also Filterung, digitale Mischerei und 
Dekodiererei im Interrupt, aber das läuft dann eher mit einer 
Interruptrate von 48 kHz oder gar 96 kHz. Bei solchen Interruptraten muß 
man sich sehr genau überlegen, ob man damit den µC nicht zustopft. 
Obendrein muß man sich bei sowas überlegen, ob man dort Gleitkomma 
verwenden will oder nicht, denn die FPU-Register müßten dann je nach 
Verwendung ebenfalls auf den Stack und das kostet Zeit.

Ob ich noch weitere Ideen hab? Na klar. Ich sag nur soviel: Mach's 
richtig. Und versuche nicht, mit deinen bereits gefaßten Vorsätzen durch 
die Wand rennen zu wollen. Du holst dir nur ne Beule am Kopf. Nimm 
stattdessen nen Rat an: "geh nen Schritt zur Seite, dort ist ne Tür und 
die ist offen".

W.S.

von Andreas (Gast)


Lesenswert?

W.S. schrieb:
> Du bist mir schon ein recht Seltsamer.
> ...

Nun entspann dich etwas und bleib bitte sachlich.

Wenn ich in der Interrupt Routine nur eine einzige Variable um 1 erhöhe 
und sonst nichts mache, habe ich genau den gleichen Fehler, dass es 
irgendwann plötzlich keine DMA Interrupts mehr kommen.

Gruß
Andreas

von W.S. (Gast)


Lesenswert?

Andreas schrieb:
> Nun entspann dich etwas und bleib bitte sachlich.

Ich hab damit kein Problem. Aber du hast eines: Deine Firmware läuft 
nämlich nicht und du überschaust jetzt die ganze Sache nicht mehr. Ich 
hab dir ne ganze Reihe guter Ratschläge gegeben, jetzt ist es deine 
Sache, was du tust. Jetzt kannst du dir denken "ich bin ja so toll und 
die anderen sind mir zu doof" oder du nimmst den einen oder anderen Rat 
eben an. Ist deine Sache und dein Problem - nicht meines.

W.S.

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.