Forum: Mikrocontroller und Digitale Elektronik STM32F7 mit externem ADC - Geschwindigkeit und Durchsatz


von S------- R. (simonr)


Lesenswert?

Hallo zusammen!

Ich möchste mit einem STM32F7 (Ich habe ein STM32F746ZG-Nucleo Board) 
Daten aufnehmen und im RAM speichern.

Das ganze soll mittels 16Bit Paralleler Schnittstelle funktionieren. 
Dafür habe ich ein ganz normales GPIO Register als Input Pins 
deklariert.

Ein ADC liefert mit die Daten und ein Timer startet einen DMA request 
welcher die Daten des GPIO in ein 1000er Array schreibt.

Der DMA schreibt immer nur 16 Bit Blöcke, ist das fertig, wird 
umkonfiguriert auf die nächsten 16Bit im Array und schreibt wieder die 
16Bit aus dem GPIO register ins Array. u.s.w.


Code:
.
.
.
hdma_tim1_up.XferCpltCallback = &DMATransferComplete; //Interrupts
hdma_tim1_up.XferHalfCpltCallback = NULL;
hdma_tim1_up.XferErrorCallback = NULL;
uint16_t data[1000];
uint16_t transCounter=0;
uint8_t errFlag=0;

.
.
.

void DMATransferComplete(DMA_HandleTypeDef *hdma) {

  //This means the DMA transfer has finished

  transCounter++;
  if (transCounter<1000) { //haben wir schon 1000 werte ?
  if (HAL_DMA_Start_IT(&hdma_tim1_up, (uint32_t)&GPIOD->IDR, 
(uint32_t)&data[transCounter], 1) != HAL_OK)
  {
    errFlag = 1;
  }
}
}
.
.
.


Das Problem ist nun, dass ich damit auf etwa 90ksps komme. Und das trotz 
dessen, dass ich den STM32F7 auf 288MHz raufgetaktet habe. Wie kann das 
sein ? Was dauert hier so lange ?
Ein test das ganze ohne Timer, ohne DMA einfach freilaufend in einen 
loop zu schreiben machte es schon erheblich schneller.
Scheinbar ist es sinnlos einmal einen 16Bit block per DMA zu schicken 
und ihn dann neu zu konfigurieren.
Die Problemstellung besteht dennoch: Im 1MHz (besser 10MHz) stehen 16Bit 
an die in einen Array rein sollen. Geht das ernsthaft nicht mit einem 
STM32F7 Cortex M7 ?!

Besten Dank schonmal wenn ihr mir helfen könnt. Eure Erfahrung ist 
meistens Goldwert
Gruß, Simon

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

S------- R. schrieb:
> Scheinbar ist es sinnlos einmal einen 16Bit block per DMA zu schicken
> und ihn dann neu zu konfigurieren.

Ja, sehr. Ganz normal in Software 1 16bit-Wert in den RAM zu schreiben 
dauert ca 2 Takte. Den DMA zu konfigurieren, Cache zu leeren 
(invalidate), den Interrupt zu betreten, die DMA-Flags zu verarbeiten, 
den Cache nochmal leeren dauert viel länger.

S------- R. schrieb:
> Geht das ernsthaft nicht mit einem
> STM32F7 Cortex M7 ?!

Doch, aber du darfst nicht jedes 16bit-Wort einzeln verarbeiten. In 
einer Schleife direkt einlesen sollte gehen, dann bleibt aber nicht mehr 
viel Rechenzeit für anderes. Hier sollte man darauf achten effizienten 
Code zu schreiben und die Compiler-Optimierungen zu nutzen.

Ist die Frequenz, mit der die Werte ankommen, fix? Kannst du den Timer 
nicht auf genau die Frequenz einstellen, den Timer direkt die 
DMA-Transfers auslösen lassen, und per DMA 1000 Werte auf einmal 
abfragen? Gibt es eine Art Trigger-Eingang? Vielleicht lässt sich mit 
Input-Capture o.ä. das Einlesen automatisch starten.
Alternativ lässt sich vielleicht mit dem FSMC etwas machen.

Muss es parallel sein? Bei 10 MHz ist ggf. QSPI auch hilfreich...

: Bearbeitet durch User
von Jim M. (turboj)


Lesenswert?

S------- R. schrieb:
> Was dauert hier so lange ?

Da wird u.a. jedes Mal ein Interrupt aufgerufen, und das dauert auf 
einem Cortex-M.

Man muss mit dem DMA in größeren Blöcken arbeiten, damit es effizient 
wird.

Also DMA mit großen Blöcken (1KB zum Bleistift), und dann jeweils 
Trigger via Timer oder externem Pin. So wird nur alle 512 Werte (bei 1KB 
Daten) der Interrupt Handler aufgerufen.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Stell dir vor du möchtest 1000 Brötchen kaufen, organisierst dir einen 
LKW, holst damit jedes Brötchen einzeln und wunderst dich warum dies 
langsamer ist, als jedes Brötchen einzeln mit einem Kleinwagen zu 
fahren.

von S------- R. (simonr)


Lesenswert?

Danke für eure schnellen Antworten.

Niklas G. schrieb:
> Ja, sehr. Ganz normal in Software 1 16bit-Wert in den RAM zu schreiben
> dauert ca 2 Takte. Den DMA zu konfigurieren, Cache zu leeren
> (invalidate), den Interrupt zu betreten, die DMA-Flags zu verarbeiten,
> den Cache nochmal leeren dauert viel länger.

OK - verstanden. Macht auch Sinn.

Niklas G. schrieb:
> Doch, aber du darfst nicht jedes 16bit-Wort einzeln verarbeiten. In
> einer Schleife direkt einlesen sollte gehen, dann bleibt aber nicht mehr
> viel Rechenzeit für anderes. Hier sollte man darauf achten effizienten
> Code zu schreiben und die Compiler-Optimierungen zu nutzen.


Das Problem ist, dass ich eben nur im festen MHz Rhythmus neue Werte 
bekomme. stehen diese an muss ich sie einlesen.
Habe gerade die bekannten -O1/2/3 flags getestet - es macht bereits 
einiges aus. Hätte ich nicht gedacht bei diesem wenigen "trivialen" 
Code.

Niklas G. schrieb:
> Ist die Frequenz, mit der die Werte ankommen, fix? Kannst du den Timer
> nicht auf genau die Frequenz einstellen, den Timer direkt die
> DMA-Transfers auslösen lassen, und per DMA 1000 Werte auf einmal
> abfragen? Gibt es eine Art Trigger-Eingang? Vielleicht lässt sich mit
> Input-Capture o.ä. das Einlesen automatisch starten.
> Alternativ lässt sich vielleicht mit dem FSMC etwas machen.


Ja, ist fix. Ein "Burst" wäre zwar toll aber kann warten. Den DMA auf 
größere Blöcke zu setzten funktioniert nicht denn das geschieht ohne 
Trigger. Das geht zwar richtig schnell aber nicht im schönen. von mir 
gewünschten Abstand. Deshalb muss ich den praktisch jedes mal neu 
starten. Trigger Eingang wäre vorhanden und soll auch genutzt werden. 
Ich habe nur zu Testzwecken einen internen Timer genommen welcher den 
DMA startet und bin eben dort schon auf Probleme gestoßen.

FSMC Schnittstelle ist interessant, genauso wie die DCMI Schnittstelle 
(Display)
Problem ist nur, dass ich es partout nicht schaffe diese als 
stinknormales Paralleles Interface zu nutzen und sich ST darüber auch 
richtig ausschweigt. Weiterhin ist es für mich fraglich ob die schneller 
sind.

Niklas G. schrieb:
> Muss es parallel sein? Bei 10 MHz ist ggf. QSPI auch hilfreich...

Hab ich extra wegen der Geschwindigkeit und den viele IOs des STMs 
genommen ;)

QSPI hätte der auch - hmmm

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

S------- R. schrieb:
> Das geht zwar richtig schnell aber nicht im schönen. von mir
> gewünschten Abstand. Deshalb muss ich den praktisch jedes mal neu
> starten.

Du kannst einen Timer auf die gewünschten 10MHz stellen und direkt die 
DMA-Transfers auslösen lassen (ohne ISR).

S------- R. schrieb:
> Trigger Eingang wäre vorhanden und soll auch genutzt werden.

Kommt der Trigger denn mit 10MHz? Oder hast du irgendeine Form von Takt 
oder Strobe-Signal, welches angibt, wann ein neuer 16bit-Wert anliegt? 
Es müsste mit Timern möglich sein, auf dieses zu reagieren und direkt 
einen DMA-Transfer auszulösen.

S------- R. schrieb:
> Habe gerade die bekannten -O1/2/3 flags getestet - es macht bereits
> einiges aus. Hätte ich nicht gedacht bei diesem wenigen "trivialen"
> Code.
Ja, ohne Optimierungen ist wie angezogene Handbremse. Der Compiler fügt 
dann jede Menge ziemlich nutzlosen Code ein, sodass selbst simpler 
C-Code stark verlangsamt wird.

von m.n. (Gast)


Lesenswert?

S------- R. schrieb:
> Weiterhin ist es für mich fraglich ob die schneller
> sind.

FSMC ist auf jeden Fall schneller als Port-IO.

von Alex D. (daum)


Lesenswert?

Es sollte möglich sein, den DMA so zu konfigurieren, dass du den 
Channel, der vom Timer getriggert wird benutzt, dann stellst du beim 
Timer ein, dass bei jedem UpdateEvent ein DMA Transfer ausgelöst wird.

Beim DMA wird dann MADDR auf den Array Start gelegt, PADDR auf das GPIO 
IDR, PINC auf 0 und MINC auf 1. Dann den Count im DMA richtig 
einstellen, Timer Frequenz richtig einstellen und starten und es sollte 
bei jedem Timer Update Event ein Wert vom GPIO in das Array eingelesen 
werden.

Ich bin im HAL von ST nicht so bewandert, schreibe meinen Code 
normalerweise direkt auf Register Level. Auch mit dem F7 hab ich noch 
nichts gemacht, aber sollte, denke ich, ja ähnlich sein wie bei den F4 
mit denen ich Erfahrung habe. Die Erklärung ist jetzt mal nur so 
prinzipiell, wenn du willst, könnte ich es auch etwas genauer 
ausarbeiten, hoffentlich ist es so wenigstens halbwegs klar.

von Harry L. (mysth)


Lesenswert?

S------- R. schrieb:
> Das ganze soll mittels 16Bit Paralleler Schnittstelle funktionieren.
> Dafür habe ich ein ganz normales GPIO Register als Input Pins
> deklariert.

Genau dafür haben die eine FSMC-Schnittstelle.

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.