Hallo, der Kunde möchte ein Mess-System, welches die Messdaten mit einem Clock-Stamp in einem RAM-Ringbuffer abspeichert. Das Messsystem (STM32F05) soll eine SPI-Slave Schnittstelle haben, wo der SPI-Master (Raspberry-PI3) die Daten als einen Block (bis 5KB) rauslesen kann. Dabei soll es möglich sein, dass der Master mit hoher Frequenz kleine Blöcke abholt, oder mit kleiner Häufigkeit große Blöcke. Das Protokoll ist ganz einfach: Master sendet eine CMD (1 Byte), danach antwortet der Slave mit der aktuellen Buffer-Länge. Dann schickt der Master eine andere CMD-ID, worauf der Slave den kompletten Buffer ausgibt. Mit DMA ist das schwierig: der Buffer ist nicht an einem Stück, sondern als Ringbuffer angelegt. D.h. bei der obersten Adresse müsste der DMA stoppen und von ganz vorne beginnen, während der Master den Slave mit 500kHz taktet. Frage: kennt jemand irgendwelche Vorlagen für solche Übertragungen? Ich persönlich würde lieber einen Doppelbuffer verwenden mit fester Größe, und diese abwechselnd übertragen.
Bei einem Takt von 500KHz sind das bei 8 Datenbits doch gerade mal ~60 kbyte/s. Der STM32F0 kann doch mit 48 MHz getaktet werden, d.h. er hätte dann wenigstens um die 800 Taktzyklen um den DMA neu zu starten wenn er das Ende des Ringbuffers erreicht hat. Außerdem gibt es - zumindest bei STM32F030 - einen circular mode. Evtl. könnte man damit etwas anfangen?
Sende dem Master halt im der Puffer-Größe immer die Anzahl Bytes, die sich mit einem einzelnen DMA-Transfer übertragen lassen. Wenn man so am oberen Ende des Ringpuffers angekommen ist, kommt der Rest halt erst beim nächsten Kommando. Oder du setzt den DMA im Transfer Finish Interrupt neu auf, dafür hast du ja 768 Takte Zeit.
Schon komisch das wir als Hobbyisten jemandem bei trivialen Sachen helfen müssen, der etwas an "Kunden" verkauft ;-)
Markus M. schrieb: > Schon komisch das wir als Hobbyisten jemandem helfen müssen, der > etwas > an "Kunden" verkauft ;-) Vielleicht gibts hier ja ne Gewinnbeteiligung?
Üblicherweise ist oben und unten bei einem Ringpuffer unsinnig. Die meisten Ringpuffer verwenden vier Routinen. 1. Reset (leeren) [Anfang=Ende] 2. Eini (eg. Push) 3. Aussi (eg. Pop) 4. Jemand daheim? Bolean oder Anzahl (0 ... n-1) Mehr ist da nicht dran. Üblicherweise wird auch nicht mehr gebraucht Es kann natürlich, bei aufwändigen Implementationen noch ein Status mitgeschleppt werden, also: Überlauf oder Versuch leeren Puffer zu lesen am liebsten aber OK Wo tatsächlich die Daten im Puffer rumhängen interessiert kein Schwein. Übrigens: 500 KHz sind rund um den I²C unüblich. Meist werden 100 oder 400 KHz verwendet. Manche Chips können auch 1 MHz, aber die Rasterung oberhalb von 400 KHz ist wohl dem Implementierer überlassen.
Sebastian S. schrieb: > Die meisten Ringpuffer verwenden vier Routinen. Und welche ist dafür zuständig, einen kontinuierlichen Datenblock an das DMA zu übergeben? Für jedes einzelne Byte "pop" aufzurufen ist doch sehr ineffizient. Sebastian S. schrieb: > Übrigens: 500 KHz sind rund um den I²C unüblich. Niemand hat von I²C geredet.
@DeErr Sommer Aus prinzipielle Gründen - schau' Dir mal eine Implementation an - ist die Pop-Routine relativ einfach und somit auch schnell. Die Alternative wäre ja: So lange den Status aufzurufen, bis die gewünschte Menge für einen ganzen Block vorhanden ist. Übrigens sollte es kein Problem sein einen Block-Copy Befehl zu implementieren, solange gesichert ist, dass genügend Daten vorhanden sind. Andernfalls besteht die Gefahr, dass sich das System selber blockiert und jeglicher Vorteil verloren geht. Eine weitere Möglichkeit wäre: Bei jedem Push den Status abfragen und beim erreichen von ??? einen DMA-Transfer zu initialisieren. Das läuft aber ebenfalls auf die ständige Abfrage des Status (beim Pushen), wenn auch intern, heraus.
Sebastian S. schrieb: > Aus prinzipielle Gründen - schau' Dir mal eine Implementation an - ist > die Pop-Routine relativ einfach und somit auch schnell. Selbst wenn sie nur 1 Takt braucht, sind das bei 5kB immer noch 5120 Takte mehr als wenn man DMA nutzen würde. Du willst nicht ernsthaft behaupten dass die Nutzung von DMA nicht sinnvoll ist? Selbst wenn Rechenzeit genug ist, spart man so zumindest doch eine Menge Energie. Offensichtlich hat der TO ja schon entschieden, dass DMA sinnvoll ist. Sebastian S. schrieb: > Die Alternative wäre ja: So lange den Status aufzurufen, bis die > gewünschte Menge für einen ganzen Block vorhanden ist. Oder auf einen Interrupt warten und währenddessen den Core schlafen legen oder andere Aufgaben bewältigen. Sebastian S. schrieb: > Das läuft > aber ebenfalls auf die ständige Abfrage des Status (beim Pushen), wenn > auch intern, heraus. Es sei denn das Befüllen geht auch per DMA. Ich habe schon sehr schnelle Datenübertragungen mit DMA und Ringpuffern implementiert. Damit kann man auf viele MByte/Sec kommen, indem man eben nicht jedes einzelne Byte in Software (push/pop-Methoden) behandelt.
den gesamten Ringbuffer mit einem DMA transfer kann ich wohl nicht mit DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; erreichen (?) So wie ich das sehe, kann ich die DMA_BufferSize einstellen und die DMA_Memory0BaseAddr. Aber er müsste ja nicht am Anfange (BaseAddr) beginnen, sondern irgendwo in der Mitte (last Output-Index), bis zur Buffergröße inkrementieren, dann auf die Base-Addr zurückspringen,... Also geht es nur als 2 Blöcke.(?)
stm32-ianer schrieb: > den gesamten Ringbuffer mit einem DMA transfer kann ich wohl nicht > mit > DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; > erreichen (?) Nicht so wirklich. Dabei wird immer der gleiche Puffer von Anfang-Ende gelesen/geschrieben. Du kannst nicht in der Mitte anfangen und dann am Anfang weitermachen. Einige größere STM32 wie der STM32F407 haben einen Doppel-Puffer-Modus beim DMA, damit geht das.
Warum nicht den Puffer am Stück übertragen und zusätzlich Start- und Endadresse, dann am Raspberry umschaufeln?
pegel schrieb: > Warum nicht den Puffer am Stück übertragen und zusätzlich Start- > und > Endadresse, dann am Raspberry umschaufeln? Die interne Datenstruktur nach außen zeigen? Wehe man will die später noch ändern... Das Problem ist nicht so schwer zu bewältigen. Man muss halt im Transfer Complete Interrupt schnell das DMA neu konfigurieren. Ist zu schaffen.
Naja, man kann den Transfer ja in zwei DMA-Transfers teilen. Wie schon oben angemerkt hat die CPU bei 500KHz SPI Takt 768 Zyklen Zeit den nächsten DMA zu starten. Das ist nun wahrlich keine Raketentechnik. Man muss natürlich schauen wie die Messungen realisiert sind und ggfs. an den Interruptprioritäten schrauben.
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.