Hallo, ich wollte gern gleichzeitig Signale mit dem ADC des stm32F107VC
aufnehmen und mit dem DAC ausgeben. Signal Ein- wie Ausgabe werde mit
Hilfe der DMA durchgeführt. Die Werte des ADCs sollen dabei auf eine
Variable geschrieben werden, nach dem Schreiben auf eine andere kopiert
werden um von dort mit dem DAC ausgegeben zu werden. Dies soll als
Grundlage zum manipulieren und erfassen der Daten dienen. Das Signal hat
somit zwischen ADC und DAC ein Timerinterrupt Verzögerung.
Angesteuert werden ADC wie DAC vom Timer3 TRGO Interrupt. Wird der Timer
zwischendurch abgeschaltet werden weder vom ADC noch vom DAC Daten
geschrieben oder ausgegeben, somit nehme ich an, dass die Zeiten
eingehalten werden (Momentan 4000 * 4000 auf 72MHz Basis). Neben dem
Problem, dass der ADC eher einen Schätzometer als ein Spannungsmesser
darstellt habe ich das Problem, dass mein DAC mir irgendwelche sinnlosen
wild springenden Werte ausgibt. Diese ändern sich zwar mit Höhe der ADC
Spannung, aber nicht sinnvoll (springen auf Null, Drift in die
entgegengesetzte Richtung ect.). Der ADC funktioniert vom Prinzip her
und der DAC gibt wenn man feste Werte vorgibt oder den Wert in der
Variablen hoch zählen lässt auch die Werte aus die man vorgibt.
Mein erster Versuch war es die Übergabe direkt in der „while(1)“
Schleife der main zu tätigen (DAC_wertespeicher = ADC_wertespeicher).
Dabei dachte ich könnte der DAC eventuell genau auf die Zeit zugegriffen
haben wo Daten geschrieben werden und deswegen so merkwürdige Werte
ausspucken. Aber auch im Interrupt der DMA des ADC (DMA1_IT_TC1) brachte
die Werteübergabe keine Besserung.
Wie kann man am besten im Hauptprogramm ohne Interrupt zur geeigneten
Zeit Werte übertragen, sprich: welche Flags kann man nutzen bzw. kann
man vielleicht auch die Interrupt Flags nutzen ohne die Clocks für einen
Interrupt Aufruf zu verschwenden. Und was könnte der Fehler bei der
Geschichte sein.
Wie gesagt ADC und DAC funktionieren für sich und direktes Schreiben auf
die DAC Variable funktioniert auch, nur wenn die Übernahme von ADC- auf
DAC Variable stattfindet gibt es Probleme.
Gruß Marcus
DMA ist in deinem Fall wahrscheinlich nicht das optimale. Damit werden
größere Mengen Daten auf/von einen Buffer geschrieben/gelesen.Wenn ich
dich richtig verstanden habe, willst du einen ADC Wert so schnell wie
möglich auf den DAC ausgeben. Das geht am besten wenn du das im ADC
interrupt machst(ganz ohne DMA). Mit DMA musst du einen
Wechselpufferbetrieb einrichten wobei sich damit die Verzögerung
unmittelbar mit der Puffergröße ändert. D.h. während der eine Buffer
mittels DMA über den ADC beschrieben wird, wird der andere Buffer
verarbeitet bzw. ausgegeben.Vorsicht ist beim Bufferwechsel geboten,
weil du sicherstellen musst, dass die Bufferadressen in der DMA
innerhalb einer ADC Abtastung geändert werden.
Grüsse
Meintest du dass die Adressen NICHT innerhalb der ADC Abtastung geändert
werden?
Ich dachte die DMA wäre auch für einzelne Werte gewinnbringend nutzbar,
da in einem ST Beispiel (ext. Trigger) auch die DMA verwendet wurde um
auf Tastendruck ADC Werte auslesen zu können.
Ich habe mir so eine Entlastung der CPU erhofft, da doch recht oft
abgetastet werden sollte.
Ich habe mir mal die Speicher-Variable für den DAC angeschaut. Die
enthält z.B. den Wert 3000 und ausgegeben bekomme ich einen Wert von 0
bzw. Schwankungen über den gesamten Bereich.
Ich versuche mal die Ausgabe ohne DMA.
Achso und ich verwende DMA1 für den ADC und DMA2 für den DAC, also
dachte ich die beiden könnten gleichzeitig laufen und es würden sich
keine Probleme aus irgendwelchen Puffern ergeben.
Gruß Marcus
>Ich habe mir so eine Entlastung der CPU erhofft, da doch recht oft>abgetastet werden sollte.
was ist oft bei dir?
Glaub mir, die CPU ist wirklich sehr schnell.
>Ich habe mir mal die Speicher-Variable für den DAC angeschaut. Die>enthält z.B. den Wert 3000 und ausgegeben bekomme ich einen Wert von 0>bzw. Schwankungen über den gesamten Bereich.
Da hat's wohl was.
Wenn du mal sagen würdest was du vor hast, würde das die Sache ungemein
erleichtern.
Grüsse
Ich möchte vorerst ein Sinussignal bis 3KHz abtasten, es aufzeichnen,
manipulieren und wieder ausgeben können und das so schnell wie möglich,
am besten wäre also wenn das aufgenommene Sample beim nächsten Sample
schon wieder ausgegeben wird. Um auf Spitzenwertspeicher und sonstige
Hardwarebeschaltungen zu verzichten und die Sache etwas flexibler zu
gestalten dachte ich mir ich taste das Signal so oft wie möglich ab und
gebe es real wieder aus anstelle einer Lookup table. Zwischendurch
möchte ich die Frequenz und die Amlitude über CAN oder USB an einen
Rechner schicken bzw. von diesem das Signal beeinflussen.
Da sollten bei ausreichend Samples nicht mehr allzuviel übrig bleiben
von den einstigen 72Mhz die ich als Sysclock verwende.
Ich habe jetzt mal eine Ausgabe ohne DMA geschrieben und die DAC
Spannung folgt jetzt "exakt" der ADC Spannung. Sofern man bei dem
geribbel was der ADC schon ausließt von exakt sprechen kann.
Dazu folgende Zeilen in der While(1)
####################
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
DAC1_Ausgabe_Wert = ADC1_Konv_Wert;
DAC_SetChannel1Data(DAC_Align_12b_R ,DAC1_Ausgabe_Wert );
####################
Was mich außerdem wundert ist dass sich die ADC Variable scheinbar viel
zu oft ändert, das kann aber auch mein Fehler sein, weil im Debug Modus
der Timer wohl weiter läuft, auch wenn ein Breakepoint erreicht ist.
Ich werde mal versuchenden den alten Code einzustellen(müsste ihn erst
mal etwas lese tauglich gestalten)
Eine generelle Frage bleibt noch: bringt es nun etwas einzelne Werte mit
der DMA auszulesen?
Gruß und danke für die Hilfe bisher
Ich habe gerade den Fehler gefunden.... ich hatte einen Zahlendreher in
der DAC Adresse und anstelle der12Bit die 8 Bit Register angegeben,
deswegen auch die merkwürdigen Sprünge.
Entschuldigt die dumme Fragerei.
Sollte trotzdem jemand an billigem Code interessiert sein kann ich ihn
trotzdem noch einstellen, wäre aber eher peinlich als Gewinnbringend^^.
Die Frage nach besseren Lösungen und der Effizienz der DMAsteht trotzdem
noch.
>Ich möchte vorerst ein Sinussignal bis 3KHz abtasten, es aufzeichnen,>manipulieren und wieder ausgeben können und das so schnell wie möglich,>am besten wäre also wenn das aufgenommene Sample beim nächsten Sample>schon wieder ausgegeben wird.
Gut, das schließt DMA eigentlich aus. Was meinst du mit manipulieren?
>dachte ich mir ich taste das Signal so oft wie möglich ab und>gebe es real wieder aus anstelle einer Lookup table
was zum Teufel hat der look-up table mit deinem Signal zu tun?
>Was mich außerdem wundert ist dass sich die ADC Variable scheinbar viel>zu oft ändert
???
>Eine generelle Frage bleibt noch: bringt es nun etwas einzelne Werte mit>der DMA auszulesen?
Nein, es sollten doch so mindestens 5 Werte sein, sonst ist die
DMA-initialisierung aufwändiger.
Ich schick dir mal ein Beispiel für 12 Werte mit Wechselbuffer.
Grüsse
>Gut, das schließt DMA eigentlich aus. Was meinst du mit manipulieren?
Manipulieren heißt in dem Fall für mich z.B. die Amplitude zu ändern.
>was zum Teufel hat der look-up table mit deinem Signal zu tun?
Die look-up table hat in so fern etwas mit meinem Signal zu tun, dass
ich momentan nur ein reines Sinussignal ausmessen möchte und für die
Rekonstruktion theoretisch nur die Amplitude und die Frequenz nötig
wären. Die Signalform würde man sich in diesem Fall aus einer look-up
table holen.
>???
Ich hatte am Anfang das Gefühl, dass sich die Variable schneller ändert,
als ich es dem ADC durch den Timer vorgegeben habe.
>Nein, es sollten doch so mindestens 5 Werte sein, sonst ist die>DMA-initialisierung aufwändiger.>Ich schick dir mal ein Beispiel für 12 Werte mit Wechselbuffer.
Gut dann nehme ich die DMA wieder raus. Mit welcher Methode kann man
eigentlich testen wieviele Zyklen man noch zur Verfügung hat, ich dachte
ich lasse einfach mal eine Variable hochzählen vom ADC Start bis ADC
Ende, das scheint nicht gerade von Erfolg gekrönt zu sein.
Danke für den Hinweis und das Beispiel, ich schau es mir gleich mal an.
Gruß Marcus
Im übrigen weiß ich, dass ich die DAC und ADC aus dem Timer IRQ heraus
starten kann, aber wie kann ich sie direkt durch das
"ADC_ExternalTrigConv_T3_TRGO" starten? Ohne DMA scheint diese Funktion
nicht mehr zu greifen.