Forum: Mikrocontroller und Digitale Elektronik FIFO beim stm32f10


von Peter (Gast)


Lesenswert?

hallo,

ich habe einen stm32f103 und möchte gerne den DMA als FIFO einsetzen. 
der DMA funktioniert soweit, aber wie kann ich daraus einen FIFO machen?

von 6A66 (Gast)


Lesenswert?

Peter schrieb:
> DMA funktioniert soweit, aber wie kann ich daraus einen FIFO machen?

Hmmm, was meinst Du damit?
Du willst verschiedene Anforderungen (Transferanforderungen, Kopiere 
Speicher von A nach B) FIFO (first in First out) in den DMA reinstecken? 
Dann brauchst Du eine linked list in die Du die Anforderungen auf der 
einen Seite reinsteckst und auf der anderen Seite wieder rausholst (ist 
in SW zu lösen) und dann den Inhalt der jeweils elektierten Elements in 
die DMA reinschiebst.

Oder doch was anderes?

rgds

von Peter (Gast)


Lesenswert?

ne ich möchte die bytes welche ich über die usart empfange im fifo 
zwischenspeichern und später auslesen

von 6A66 (Gast)


Lesenswert?

Peter schrieb:
> ne ich möchte die bytes welche ich über die usart empfange im fifo
> zwischenspeichern und später auslesen

Die Zeichen der USART kommen, wenn die FIFI enabled wird, automatisch in 
die FIFO. Die löst normalerweise bei einer einstellbaren 
Schwellwertmarke (z.B. halbe Füllung) einen Interrupt oder DMA aus. Wie 
Du dann weitermachst ist klar: entweder mit DMA die Zeichen aus der FIFO 
in einen Transferbuffer (Ringpuffer) übertragen lassen wobei Du den DMA 
dann immer richtig nachführen musst (Wohin das letzte Zeichen gegangen 
ist dorthin+1 muss der nächste DMA gehen). Oder Du machst das mit 
Interrupt und überträgst den FIFO-Inhalt normal in den Ringpuffer. Das 
Nachführen der Zieladresse ist auch in diesem Fall nötig.

Empfehlung: FIFO Verständnis vertiefen, DMA Verständnis vertiefen.

Weitere Fragen?

rgds

von Peter (Gast)


Lesenswert?

ich würde halt gerne das FIFO in gewissen zeitabständen auslesen, also 
über timer interrupt gesteuert. da ich unterschiedlich viele Bytes pro 
telegramm empfangen möchte und ich somit keinen interrupt bei halber 
Füllung oder so auslösen kann

von 6A66 (Gast)


Lesenswert?

Peter schrieb:
> ich würde halt gerne das FIFO in gewissen zeitabständen auslesen, also
> über timer interrupt gesteuert. da ich unterschiedlich viele Bytes pro
> telegramm empfangen möchte und ich somit keinen interrupt bei halber
> Füllung oder so auslösen kann

Aber Du kannst Doch einen Interrupt vom Timer auslösen lassen und dann 
einfach aus der Fifio rauslesen bis die leer ist. Wo ist das Problem? 
Und wie soll das mit dem DMA in Verbindung zu bringen sein?

rgds

von Peter (Gast)


Lesenswert?

der dma muss ja als fifo arbeiten. der stm32f10x hat ja sonst kein fifo

von Bemerjk (Gast)


Lesenswert?

Peter schrieb:
> der dma muss ja als fifo arbeiten. der stm32f10x hat ja sonst kein fifo

Das nennt sich Puffer und nicht FIFO!

von Bastler (Gast)


Lesenswert?

FIFO ist doch nur die Zugriffsart auf einen Puffer, oder sehe ich da was 
Falsch?

Der DMA Puffer muss als FIFO funktionieren, sond kämen ja alle Daten 
durcheinander.

von Peter (Gast)


Lesenswert?

ich will eben die schnittstelle übern timerinterrupt einlesen und damit 
ich höhere übertragungsraten machen kann und nicht immer im timer 
interrupt hängen möchte sollen die bytes im dma zwischengespeichert 
werden. also ich schaue im timer interrupt ob daten im dma sind und lese 
die dann aus

von 6A66 (Gast)


Lesenswert?

Peter schrieb:
> ich will eben die schnittstelle übern timerinterrupt einlesen und damit
> ich höhere übertragungsraten machen kann und nicht immer im timer
> interrupt hängen möchte sollen die bytes im dma zwischengespeichert
> werden. also ich schaue im timer interrupt ob daten im dma sind und lese
> die dann aus

Hallo Peter,

bitte belies Dich UNBEDINGT über die Funktionsweise des DMA und der 
FIFO.
a) FIFO ist ein Speicher/eine Registerkette die einen Eingang und einen 
Ausgang hat und die FirstInFirstOut betrieben wird - daher der Name.
b)DMA ist eine Controller der in der Lage ist auf eine Anforderung oder 
ein Startsignal hin automatisch Speicherbereiche zu kopieren.

Im DMA-Controller hast Du Register um den automatischen Speichertransfer 
einzustellen (woher, wohin, wie lange, automatische Inkrementierung, 
...). Da kannst Du NICHTS zwischenspeichern.

In der FIFO der Schnittstelle - siehe oben - landen bei entspechender 
Einstellung die empfangenen Daten automatisch. Das ist wie in Rohr in 
das man Bälle reinsteckt: der Ball der zuerst reinkam kommt zuerst 
wieder raus (wenn man ihr rauslässt).

rgds

von Peter (Gast)


Lesenswert?

Und wie kann ich das fifo beim stm 32 f 10x programmieren?

von 6A66 (Gast)


Lesenswert?

Peter schrieb:
> Und wie kann ich das fifo beim stm 32 f 10x programmieren?

RTFM
Wenn Du die Peripheral Lib verwendest ist das relativ einfach. Siehe 
auch dort.

rgds

von Peter (Gast)


Lesenswert?

6A66 schrieb:
> RTFM
> Wenn Du die Peripheral Lib verwendest ist das relativ einfach. Siehe
> auch dort.

also in der Ref manual kann ich nix von einem FIFO für den USART finden

von 6A66 (Gast)


Lesenswert?

Peter schrieb:
> also in der Ref manual kann ich nix von einem FIFO für den USART finden

Hallo Peter,

wenn der Baustein keinen FIFO an der USART hat, bleibt Dir nur die 
SW-Implementierung dieser FIFO (meist als Ringpuffer, ist keine 
Weltraumphysik aber auch nicht trivial: Zwei Pointer, einer ist nächstes 
Ausgabeelement und einer ist letztes Eingabelement). Dann kannst Du auch 
mit dem DMA (bei entsprechnder Programmierung) die Daten in Deinen 
Puffer übertragen lassen.

rgds

von Peter (Gast)


Lesenswert?

6A66 schrieb:
> wenn der Baustein keinen FIFO an der USART hat, bleibt Dir nur die
> SW-Implementierung dieser FIFO (meist als Ringpuffer, ist keine
> Weltraumphysik aber auch nicht trivial: Zwei Pointer, einer ist nächstes
> Ausgabeelement und einer ist letztes Eingabelement). Dann kannst Du auch
> mit dem DMA (bei entsprechnder Programmierung) die Daten in Deinen
> Puffer übertragen lassen.

ja genau, und genau das möchte ich mit dem DMA machen, was aber nicht 
funktioniert. mit der zeit bekomm ich nämlich nen fehle das er im 
HardFault_Handler fest hängt

von 6A66 (Gast)


Lesenswert?

Peter schrieb:
> ja genau, und genau das möchte ich mit dem DMA machen, was aber nicht
> funktioniert. mit der zeit bekomm ich nämlich nen fehle das er im
> HardFault_Handler fest hängt

Hallo Peter,

Peter schrieb:
> ich habe einen stm32f103 und möchte gerne den DMA als FIFO einsetzen.
> der DMA funktioniert soweit, aber wie kann ich daraus einen FIFO machen?

Zwischen dem was Du ursprünglich sagtest und dem was Du jetzt sagst sind 
aber große Unterschiede - sei's drum.

Bei Fehlern hilft da nur: systematisches Debugging. Ein allgemeines 
Rezept zur Umsetzung von Ringpufferen gib's nicht. Vielleicht hilft es 
ja, dass Du Dein Konzept einmal versuchst auf's Papier zu bringen und 
darlegts. Dann müssen wir hier nicht raten.

rgds

von Bastler (Gast)


Lesenswert?

Von der DMA erhältst du ja eine der beiden Zeiger (letztes 
Eingabelement)
und den anderen (nächstes Ausgabeelement) musst du ja sowieso in deiner 
Ausgabefunktion haben.

von Peter (Gast)


Lesenswert?

also ich rufe im timer interrupt eine Funktion auf mit folgendem Inhalt:

if(DMA1_Channel5->CNDTR != USART1_BUFFER_GROESSE)
{
   bWritePtrUsart1DMA = USART1_BUFFER_GROESSE - DMA1_Channel5->CNDTR;
   while((bWritePtrUsart1DMA != bReadPtrUsart1DMA))
   {
  read_buffer1[bWritePtr1++] =
                                   USART1_DMA_RxBuffer[bReadPtrUsart1DMA++];
  if(bWritePtr1 > USART1_BUFFER_GROESSE)
  {
     bWritePtr1 = 0;
     bReadPtrUsart1DMA = 0;
  }
}
   DMA_SetCurrDataCounter(DMA1_Channel5, USART1_BUFFER_GROESSE);
}

hierbei schau ich mit der if bedingung ob zeichen im dma stehen, wenn ja 
lese ich die zeichen aus dem dma in ein array (read_buffer1). in einer 
weiteren Funktion die die Telegramme auswertet vergleiche ich den 
bWritePtr1 mit einem bReadPtr1, um zu sehen ob neue zeichen in 
read_buffer1 sind

von 6A66 (Gast)


Lesenswert?

Peter schrieb:
> if(DMA1_Channel5->CNDTR != USART1_BUFFER_GROESSE)
> {
>    bWritePtrUsart1DMA = USART1_BUFFER_GROESSE - DMA1_Channel5->CNDTR;
>    while((bWritePtrUsart1DMA != bReadPtrUsart1DMA))
>    {
>   read_buffer1[bWritePtr1++] =
>                                    USART1_DMA_RxBuffer[bReadPtrUsart1DMA++];
>   if(bWritePtr1 > USART1_BUFFER_GROESSE)
>   {
>      bWritePtr1 = 0;
>      bReadPtrUsart1DMA = 0;
>   }
> }
>    DMA_SetCurrDataCounter(DMA1_Channel5, USART1_BUFFER_GROESSE);
> }

Hallo Peter,

das ist jetzt aber kein Konzept sondern nur ein Codeschnipsel.
Da müsste ich jetzt mal annehmen:
USART1_BUFFER_GROESSE = die maximale Buffergröße für den USART Buffer.
Wenn dem so ist würde deine erste if-Bedingung
if(DMA1_Channel5->CNDTR != USART1_BUFFER_GROESSE)
mitnichten das machen was Du wünschst:
hierbei schau ich mit der if bedingung ob zeichen im dma stehen.

Denn in CNDTR steht nach Datenblatt "Number of Data to be transferred" 
und die wird nach jedem Transfer geringer.

rgds

von Peter (Gast)


Lesenswert?

6A66 schrieb:
> Denn in CNDTR steht nach Datenblatt "Number of Data to be transferred"
> und die wird nach jedem Transfer geringer.

ja, und wenn der CNDTR ungleich der maximalen Buffer größe ist dann 
befinden sich ja zeichen im dma, die lese ich dann alle ein und setze 
den CNDTR zurück auf die maximale buffer größe

von 6A66 (Gast)


Lesenswert?

Peter schrieb:
> ja, und wenn der CNDTR ungleich der maximalen Buffer größe ist dann
> befinden sich ja zeichen im dma, die lese ich dann alle ein und setze
> den CNDTR zurück auf die maximale buffer größe

Und woher soll man das wissen?

rgds

von Peter (Gast)


Lesenswert?

6A66 schrieb:
> Und woher soll man das wissen?

woher soll man was wissen?

von 6A66 (Gast)


Lesenswert?

Peter schrieb:
> woher soll man was wissen?

Sorry, war gerade gedanklich in anderem Thread.

Wenn ich Deinen Code richtig verstehe (Alles Annahmen da Du ja bisher 
nicht mehr zu Variablen sagst und auch vom Code nicht mehr zeigst) 
versuchst Du nachdem der DMA Transfer den Wert(die Werte) in den 
"USART1_DMA_RxBuffer" eingetragen hat diese in eine zweiten Puffer 
"read_buffer1" umzukopieren. Warum bearbeitest Du nicht den DMA_RxBuffer 
direkt?
Wie kommt beim Überlauf "bWritePtr1 > USART1_BUFFER_GROESSE" die 
korrekten daten in den DMA?

Ich schlage vor - um uns hier nicht weiter im Trüben fischen zu lassen - 
Dir DEIN Konzept selbst mal aufzuzeichnen und zu analysieren und uns 
dran teilhaben zu lassen bevor wir hier Codeschnipsel mit der Glaskugel 
analysieren.

rgds

von Peter (Gast)


Lesenswert?

6A66 schrieb:
> Peter schrieb:
>> woher soll man was wissen?
>
> Sorry, war gerade gedanklich in anderem Thread.
>
> Wenn ich Deinen Code richtig verstehe (Alles Annahmen da Du ja bisher
> nicht mehr zu Variablen sagst und auch vom Code nicht mehr zeigst)
> versuchst Du nachdem der DMA Transfer den Wert(die Werte) in den
> "USART1_DMA_RxBuffer" eingetragen hat diese in eine zweiten Puffer
> "read_buffer1" umzukopieren. Warum bearbeitest Du nicht den DMA_RxBuffer
> direkt?
> Wie kommt beim Überlauf "bWritePtr1 > USART1_BUFFER_GROESSE" die
> korrekten daten in den DMA?
>
> Ich schlage vor - um uns hier nicht weiter im Trüben fischen zu lassen -
> Dir DEIN Konzept selbst mal aufzuzeichnen und zu analysieren und uns
> dran teilhaben zu lassen bevor wir hier Codeschnipsel mit der Glaskugel
> analysieren.
>
> rgds

meine Auswertung arbeitet mit dem read_buffer1, sowie der Interrupt. 
also man kann die Schnittstelle per Interrupt oder per DMA arbeiten 
lassen, muss halt in der Software ein define entsprechend setzen. 
deswegen kopiere ich den DMA Buffer in den anderen um.

> Wie kommt beim Überlauf "bWritePtr1 > USART1_BUFFER_GROESSE" die
> korrekten daten in den DMA?

Das wäre nicht gegangen, aber ich hätte einen Fehler verhindert. dieser 
Code Teile habe ich aber inzwischen auskommentiert. ich schau jetzt 
regelmäßig den Write und Read Pointer an und wenn diese gleich sind, 
weis ich das alle empfangenen bytes ausgewertet sind und ich kann sie 
ohne Datenverlust zu 0 setzen. das war vorher mein problem das die 
Pointer irgendwann mal außerhalb des buffers standen und dann ging gar 
nichts mehr.

Also die Kommunikation über DMA läuft jetzt so ab, das die Schnittstelle 
die empfanenen Bytes in den DMA schreibt und über den Timer interrupt 
schaue ich alle 5ms nach ob Zeichen im DMA stehen und wenn ja kopiere 
ich diese in den anderen Buffer. wenn keine zeichen im DMA stehen und 
die zwei Pointer (Read/Write) gleich sind, dann setze ich diese zu 0. 
Ich muss halt momentan gewährleisten das der DMA die größe der maximalen 
Telegramlänge hat.

Ob ein großer DMA irgendwelche andere negative folgen hat weis ich noch 
nicht, vlt kannst du mir da nochmal helfen?

danke

von 6A66 (Gast)


Lesenswert?

Peter schrieb:
> Schnittstelle
> die empfanenen Bytes in den DMA schreibt

Die Schnittstelle schreibt garnichts!
Der DMA-Controller schreibt die Daten in den Puffer!
Nochmals: Der DMA Controller ist nichts anderes als ein kleiner 
"Prozessor" dem man sagt er solle auf Anforderung N Bytes von A nach B 
(Puffer) kopieren!

Peter schrieb:
> ob Zeichen im DMA stehen

Es stehen keine Zeichen Im DMA sondern höchstens im Puffer den der DMA 
bedient.

von Peter (Gast)


Lesenswert?

ja entschuldigung für die falsche ausdrucksweise, aber du weist ja was 
ich meine

von 6A66 (Gast)


Lesenswert?

Hallo Peter,

warum machst Du das überhaupt mit DMA. Ich denke mal dass das mit 
Interrupt einfacher ist. Jedesmal wenn ein Zeichen ankommt dieses in den 
Puffer kopieren. Wenn Telegrammende erkannt (z.B. CRLF oder NULL) ein 
Signal absetzen und Verabreitung beginnen.
Wenn Du unbekannte Länge hast musst Du ja den DMA immer auf maximale 
Telegrammlänge aufziehen und dann trotzdem hinterherlaufen und prüfen ob 
das Ende erreicht ist.

rgds

von Peter (Gast)


Lesenswert?

der stm32 hat ja noch andere dinge zu tun als die schnittstelle. bei 
hohen baudraten würde er ja viel in dem schnittstelleninterrupt hängen. 
mit dem DMA wird quasi das empfangen ausgelagert und nur hin und wieder 
geschaut, ob der dma was empfangen hat und diese zeichen dann 
ausgewertet.

von 6A66 (Gast)


Lesenswert?

Peter schrieb:
> der stm32 hat ja noch andere dinge zu tun als die schnittstelle. bei
> hohen baudraten würde er ja viel in dem schnittstelleninterrupt hängen.

Also: 110kbaud ist alle 8us ein bit, ist alle 80..100us ein Zeichen. Das 
ist ja noch langsam. Bei einer Interuptroutine die nur ein Zeichen 
umkopiert kommt man bei 64MHz sicher bei 1..2us hin. Sind 1-2%.

rgds

von Bastler (Gast)


Lesenswert?

Also empfangen ich kann mit einem STM8 (8-bitter mit 16MHz) mit 
"normaler" ISR mit 187,5k problemlos.
Und in der ISR habe ich eine State-Machine drin um ein Protokoll zu 
erkennen, nicht nur ein einfaches "Zeichenkopiere".
Ansonsten läuft ein kleines Menü im Display, LED-Anzeige, ...
.. wie gesagt problemlos!

von 6A66 (Gast)


Lesenswert?

6A66 schrieb:
> Also: 110kbaud ist alle 8us ein bit, ist alle 80..100us ein Zeichen. Das
> ist ja noch langsam. Bei einer Interuptroutine die nur ein Zeichen
> umkopiert kommt man bei 64MHz sicher bei 1..2us hin. Sind 1-2%.

Das soll jetzt nicht heißen dass DMA nicht nützlich ist. Im Gegenteil. 
Ich habe damit schon - unabhängig von der CPU die dann eben ganz andere 
Aufgaben macht - über die angeschlossene Peripherie nette Dinge nach 
Aussen erledigt.

rgds

von Peter (Gast)


Lesenswert?

ich empfang ja nicht nur ein zeichen sondern zwischen 8 bytes und 260 
bytes. da ist es doch sinnvoll wenn der dma es empfängt und ich nachher 
nur noch kopieren muss

von 6A66 (Gast)


Lesenswert?

Peter schrieb:
> ich empfang ja nicht nur ein zeichen sondern zwischen 8 bytes und 260
> bytes. da ist es doch sinnvoll wenn der dma es empfängt und ich nachher
> nur noch kopieren muss

Mach es wie Du es für sinnvoll erachtest.

rgds

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.