Forum: Mikrocontroller und Digitale Elektronik STM32L5 High-Speed Signalerfassung


von Microtechnics 1. (microtechnics)


Angehängte Dateien:

Lesenswert?

Hi zusammen,

also bevor ich anfange mir die Haare auszureißen, frage ich hier mal 
nach.

Folgende Situation (siehe Screenshot):

1.
Ein Puls tritt irgendwann auf (gelber Kanal).
2.
15µs nach der positiven Pulsflanke tritt ein Analogsignal auf, dessen 
Flankenhöhe ich bestimmen möchte.
3.
Da die Flanke fast senkrecht ist und ich den Peak ermitteln will, muss 
ich mit maximal möglicher Geschwindigkeitet abtasten.
4.
Bis zum nächsten Puls habe ich genug Zeit, die erfassten Daten zu 
verarbeiten.
5.
Ich hab hier ein Nucleo-144 mit dem STM32L552ZETxQ(110 MHz Core und 
80MHz am ADC) vor mir liegen und nutze die CubeMX IDE mit der HAL Lib.

Es ist klar, dass das Ganze nur mit DMA und ADC im Interleaved Mode 
laufen kann. Mit dem Interleaved Mode hab ich mich noch nicht groß 
befasst, denn erst mal muss das Grundprinzip laufen.

Bislang kann ich erfolgreich den Puls mit Timer1 im InputCapture Mode 
einfangen und ein Internal Trigger Event an den ADC schicken (TIM1 TRGO 
Update).
Die Daten des ADCs werden dann von einem DMA weggeschaufelt und in ein 
Array geschrieben.
So weit, so gut, wenn da nicht das böse böse Timing wäre...

Ich hab an diversen Einstellungen des Timers und des ADCs rumgeschraubt, 
aber irgendwie läuft die Sache nicht rund bzw nicht schnell genug...

Die angestrebten Ziele lauten also:
Nach dem Auftreten des Triggers (Screenshot, gelber Kanal) soll der ADC 
anfangen zu messen, im Idealfall im µs-Takt, also mit 1 MHz.
Der ADC soll 100 Messungen machen und dann stoppen und dies 
signalisieren.
Ebenso soll der DMA stoppen, damit die ersten Arrayfelder nicht 
überschrieben werden.

Ich spare mir, zu schreiben, was ich bis jetzt alles versucht habe und 
würde gerne stattdessen eure Lösungsansätze hören bzw lesen :)
Vielleicht denke ich ja in die völlig falsche Richtung.
Das ist mein erstes Projekt mit einem STM32 :o

Kleine Anmerkung:
Den ADC in der InputCapture ISR mit "HAL_ADC_Start_DMA(blabla..." zu 
starten, ist zu langsam. Die Messwerte im Array zeigen, dass ich da 
schon wieder auf der "Bergab-Straße" des Analogsignals bin. Die 
Startzeit und die Stabiliesierungszeit des ADC ist zu lang.

Vielen Dank im Voraus :)

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Micro T. schrieb:
> aber irgendwie läuft die Sache nicht rund bzw nicht schnell genug...

Was heißt das genau? Grundsätzlich sollte das Konzept so funktionieren. 
Hast du die ADC-Abtastung mal ohne den trigger getestet, ob der wirklich 
die 1 MHz macht?

von Microtechnics 1. (microtechnics)


Lesenswert?

Momentan geht es mir weniger um die Abtastfeuquenz des ADCs. Die kann 
ich mir im Nachgang noch hinbiegen, denke ich. Laut Manual kann der ADC 
5,33 MS/s bei 12bit Auflösung.

Aktuell muss ich das Prinzip hinkriegen:
- Puls kommt
- Messungen laufen innerhalb von 15µs oder schneller an
- 100x messen
- alles stoppt und der DMA hebt die Hand -> "Ich bin fertig"

Aktuell ist das Problem hauptsächlich, dass der DMA einfach weiterläuft, 
obwohl er NICHT im "circular mode" ist.
Der ADC hat den "Continuous Conversion Mode" disabled.
Prinzipiell sollte der ADC auch nur ein einziges mal messen, da der TIM1 
ja nur 1x feuert, wenn die positive Pulsflanke erkannt wurde.
Der DMA ist ja nur das Resultat eines nicht gestoppten ADCs, denke 
ich...

Ich krieg sozusagen dass Messsystem nicht mehr gestoppt, geschweige denn 
kontrolliert gestoppt nach einer definierten Anzahl von Messungen...

Und wenn es mal steht, muss es auch wieder in einem Zeitfenster von 15µs 
anlaufen...

: Bearbeitet durch User
von N. M. (mani)


Lesenswert?

Ich hätte evtl. den internen OP verwendet um zu triggern. Dann kann man 
sogar das Trigger Level festlegen. Aber das ist Geschmacksache.

Prinzipiell sieht es nicht so schlecht aus.

DMA und ADC konfigurieren und freigeben.
Trigger kommt einmalig von extern.
ADC läuft an und Samples selbständig.
DMA hört nach X Samples automatisch auf zu kopieren (siehe DMA_CNDTRx) 
und wirft einen Interrupt (siehe TCIFx Transfer complete). Da kannst du 
dann in aller Ruhe den ADC stoppen, die Daten verarbeiten (evtl 
Doppelpuffer?) und den Trigger wieder scharf schalten.

von ๑۩۞۩๑ (Gast)


Lesenswert?

>Flankenhöhe

misst jede Annalokschaltung.
Auch gerne in 15 ns.

von A. B. (Gast)


Lesenswert?

Microtechnics #. schrieb:
> Den ADC in der InputCapture ISR mit "HAL_ADC_Start_DMA(blabla..." zu
> starten, ist zu langsam. Die Messwerte im Array zeigen, dass ich da
> schon wieder auf der "Bergab-Straße" des Analogsignals bin. Die

Den ADC mit DMA im circular mode frei laufen lassen und nach dem 
Erfassen der Flanke stoppen?

von optimierung (Gast)


Lesenswert?

Microtechnics #. schrieb:
> Kleine Anmerkung:
> Den ADC in der InputCapture ISR mit "HAL_ADC_Start_DMA(blabla..." zu
> starten, ist zu langsam.

Mit Optimierung, also -O3 -flto ?
Kann ich mir kaum vorstellen, dass das dann länger als 10µs dauert.

Ansonsten setzt man im EXTI_Handler nur das conversion start bit dann 
ist der Delay < 1µs.

Man kann auch bei den DMA direkt über die steigende Flanke triggern, je 
nach STM32 Famlilie ist das aber mehr oder weniger Aufwand.
Die obige Methode reicht für 10µs.

von Microtechnics 1. (microtechnics)


Angehängte Dateien:

Lesenswert?

Okay, ich habs hinbekommen. Ich hab offensichtlich viel zu kompliziert 
gedacht...

Zuerst hatte ich Timer1 mit Input Capture laufen, welcher dann den ADC 
triggert. Dann hab ichs mit TIM1 mit dem Trigger als External Clock 
versucht. Alles Unsinn.

Nun hab ich beim ADC1 direkt die EXTI Line 11 als Trigger gesetzt und 
nen DMA hinten dran gehängt.
Die Callback-Funktion "void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* 
hadc)" wird ja dann vom DMA bedient, also kann man den ADC-Interrupt 
auch ausschalten.

Der ADC läuft im "Independent Mode" mit "Asynchronous Clock divided by 
1" und "Continuous Conversion Mode = Enabled". "DMA Continuous Requests 
= Disabled". "External Trigger @ EXTI Line 11" und reagiert auf "Rising 
Edge".

Vor der "while(1)" starte ich den ADC mit:
1
if(HAL_OK != HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED))
2
        {
3
          Error_Handler();
4
        }
5
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_buffer, (uint32_t)ADC_BUF_SIZE);
Soabld nun die positive Triggerflanke auftritt, rennt der ADC bzw DMA 
los und läuft in die ConversionComplete-Callback-Funktion. Dort starte 
ich den ADC sofort neu mit:
1
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
2
{
3
if(hadc == &hadc1)
4
 {
5
  HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_buffer,(uint32_t)ADC_BUF_SIZE);
6
  flag_data_ready++;
7
 }
8
}
Somit wird bei jedem Trigger ein Array mit 100 Zellen beschrieben und 
ich komme auf ein Messintervall von ca. 300ns.
Somit kann ich mir den Interleaved Mode auch sparen ;D

Bis zum nächsten Trigger hab ich in der Regel 10ms Zeit, also kann ich 
in Ruhe alles verabeiten, was ansteht. Perfekt.

Der Vollständigkeit halber habe ich eine kleine Visualisierung der 
Arraywerte im Vergleich mit dem Oszi angehängt :)

Danke für die Denkanstöße von euch! ;)

: Bearbeitet durch User
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.