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 :)
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?
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
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.
>Flankenhöhe
misst jede Annalokschaltung.
Auch gerne in 15 ns.
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?
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.