Hallo,
ich bräuchte Hilfe bei der Verwendung des DMA in Kombination mit dem ADC
(hab noch nie DMA verwendet).
Ich verwende den 32bit µC AT32UC3C1128C, das Datenblatt dazu:
http://www.atmel.com/Images/doc32117.pdf
Damit möchte ich nun folgendes machen:
Es sollen 6 ADC- Eingänge verwendet werden, um 6 verschiedene
Analogwerte einzulesen. Diese Werte sollen dann einem Reglermodul zur
Verfügung stehen, um bestimmte Größen zu regeln. Nachdem nur 1 ADC mit
16 Kanälen zur Verfügung steht, müsste ich den Kanal ständig in einer
Schleife umschalten, um die Werte nach der Reihe einzulesen.
Um den Prozessor nun nicht unnötig zu belasten, würde ich gerne den
DMA-Controller verwenden, um dies zu erledigen, ist das prinzipiell
möglich? Ich hab mich zwar schon in das Thema eingelesen, jedoch ist mir
nicht ganz klar, wie ich DMA verwenden kann.
Kann mir jemand dazu einen Gedankenanstoß geben?
Danke sehr!
Werner13 schrieb:> Ich hab mich zwar schon in das Thema eingelesen,Werner13 schrieb:> jedoch ist mir> nicht ganz klar, wie ich DMA verwenden kann.
Schließt sich irgendwie doch gegenseitig aus, oder?
Werner13 schrieb:> Kann mir jemand dazu einen Gedankenanstoß geben?
DMA wird verwendet für die automatische Bewegung von Daten zwischen
verschiedenen Speicherplätzen. Wenn davon zufällig ein Speicherplatz der
ADC Datenregister ist und der zweite Speicherplatz im Flash ist, so
liest der DMA z.B. das Datenregister aus und legt es im Flash ab. Eine
Verfeinerung wäre z.B. die Adresse des Speicherplatzes im Flash
automatisch im DMA zu inkrementieren.
Das sollte als Denkanstoss genügen. Der Rest steht im Manual/Datenblatt
oder wo auch immer
Danke zunächst mal für die Antwort...
Dass DMA die Daten hin- und her schaufelt, ist mir klar.
Ich verstehe aber den Zusammenhang mit dem ADC nicht ganz:
Ich hab ein Reglermodul (c-File), in dem ich die 6 ADC Werte benötige,
um damit zu regeln. Das heißt, DMA müsste mir diese Daten vom ADC zur
Verfügung stellen.
Meine Unklarheiten:
1.) Wie wird eine AD-Wandlung getriggert? Muss ich die ADC Kanäle
genauso initielieren, wie wenn ich kein DMA verwenden würde? Wie erfolgt
die Kanalumschaltung der 6 ADC-Kanäle? Wird das auch durch DMA erledigt
oder muss ich das trotzdem in einer Ringschleife machen?
Danke, lG
Ja, es ist möglich und gar nicht mal sooo kompliziert...
Mir haben die Beispiele aus dem ASF recht gut geholfen.
Werner13 schrieb:> Kann mir jemand dazu einen Gedankenanstoß geben?
Ja...
1. ADC+Sequencer konfigurieren --> adcifa_get_calibration_data,
adcifa_calibrate_offset, adcifa_configure, adcifa_configure_sequencer
2. DMA konfigurieren --> pdca_init_channel
3. DMA einschalten --> pdca_enable
4. Sequencer starten --> adcifa_start_sequencer
5. Wenn der DMA fertig ist (Interrupt oder pollen auf
PDCA_TRANSFER_COMPLETE) der Applikation mitteilen, dass neue Daten da
sind und ggf. die Geschichte neu starten (es reicht die Register
AVR32_PDCA.channel[KANAL].mar,AVR32_PDCA.channel[KANAL].tcr,
AVR32_PDCA.channel[KANAL].cr und AVR32_ADCIFA.cr neu zu schreiben).
Hallo,
bin gerade bei der Konfiguration des ADC, im Datenblatt steht:
"The ADC is fully differential. To perform single ended measures, the
user can perform pseudo
unipolar conversions by connecting ground onto the negative input. User
can connect it to an
external ground through pads or internal ground depending on if there's
one connected onto the
negative input multiplexer. Since conversion results are always 12 bits
in 2's complement representation,
the sign bit will not change, and then the resulting resolution is 11
bits max."
Ich benötige keine differentiellen Messungen, sondern gegen Masse. Heißt
das nun, dass ich den ADCREFN-PIN des µC hardwaremäßig auf Masse legen
muss?
THX Werner
Und noch eine Frage:
Wenn man den ADC im FreeRunningModus betreibt, werden vom Prozessor die
meisten Ressourcen gebraucht oder? Ich stelle mir das so vor, wenn eine
neue Wandlung unmittelbar nach Abschluss der alten Wandlung startet,
dann wandelt der µC ja nur noch, ohne Zeit für andere Aufgaben zu haben.
Geht das in die richtige Richtung oder verstehe ich da was falsch?
Nachdem ich nur alle Min. ca eine neue Wandlung brauche, denke ich, dass
es besser ist, die Wandlung mit einem Timer nach einer Min. zu
triggern...
Sehe ich das richtig?
@martin:
ich finde im ASF nur die Funktionen, die ich im adcifa.h auch
beschrieben habe. Allerdings ist mir da noch einiges unklar, ich bin
bald am verzweifeln...
Ich finde da keine expliziten beispiele, könntest du mir ev. einen link
schicken? Das ist wirklich sehr kompliziert für einen Anfänger :(
Ich poste mal meinen code, vielleicht kann mir jemand helfen:
1
// ADC config
2
adcifa_opt_tadc_options={
3
.frequency=100000,// internal ADC frequency (has to be between 32 kHz and 1,5 MHz)
.sample_and_hold_disable=false,// higher accuracy when disabled (but in this case only single sequencer availaible -> we need dual sequencer, so leave S&H enabled)
6
.single_sequencer_mode=true,// only one sequencer
7
.free_running_mode_enable=false,// don't run free (trigger with provided timer)
8
.sleep_mode_enable=false
9
};
10
11
//ADC sequencer config
12
adcifa_sequencer_opt_tadc_sequencer_options={
13
.convnb=ADC_CHANNELS_TEC,// 4 channels
14
.resolution=ADCIFA_SRES_12B,// resolution 12 Bit
15
.trigger_selection=ADCIFA_TRGSEL_ITIMER,// trigger with internal timer
16
.start_of_conversion=ADCIFA_SOCB_ALLSEQ,// A complete sequence is performed on a SOC event
17
.sh_mode=ADCIFA_SH_MODE_OVERSAMP,// oversampling acivated, higher accuracy, but a conversion takes two clock cycles
Werner13 schrieb:> Heißt> das nun, dass ich den ADCREFN-PIN des µC hardwaremäßig auf Masse legen> muss?
Nein. Nur, dass Du dem Sequencer sagst, dass jeweils eine Seite der
channels (P oder N) GND sein soll, wie es auch in Deinem Codeschnipsel
schon drin ist.
Werner13 schrieb:> Wenn man den ADC im FreeRunningModus betreibt, werden vom Prozessor die> meisten Ressourcen gebraucht oder? Ich stelle mir das so vor, wenn eine> neue Wandlung unmittelbar nach Abschluss der alten Wandlung startet,> dann wandelt der µC ja nur noch, ohne Zeit für andere Aufgaben zu haben.> Geht das in die richtige Richtung oder verstehe ich da was falsch?
Free running Mode heisst nur, dass der ADC dauernd beschäftigt ist. Die
CPU im µC hat da erstmal nix mit zu tun. Allerdings ist die Kombination
FreeRunning und ADC etwas seltsam. Ich habe das nie richtig zum laufen
bekommen - irgendwann hat der Speicher nicht mehr mit der
Sequencer-Reihenfolge zusammengepasst (z.B. 1. Sequencerpos an 5.
Speicherstelle). Also am besten so machen, wie ich es oben umrissen hab.
UWie schnell musst/willst Du denn eigentlich sein? Der AVR32 ist auch
ohne DMA schon ziemlich flott.
Ich musste auf DMA zurückgreifen, da ich zeitkritische Sachen im
10µs-Takt machen will/muss (ein bisschen Rechnen, beide SPI bedienen,
Analogwerte verwurschten, falls vorhanden und noch ein bisschen mehr)...
Da gings einfach nicht mehr ohne.
Hey martin,
danke für die Hilfe... bin noch Anfänger :)
Also zwecks geschwindigkeit kann ich leider nicht viel sagen, bearbeite
nur einen Teil eines projektes und mir ist gesagt worden, ich soll DMA
für diese Sache verwenden..
OK, free running werd ich e nicht nutzen, verwende den internen Timer
zum Triggern einer Wandlung... (itimer, der anscheinend extra dafür
vorgesehen ist)..
Was mir noch nicht ganz klar ist:
1.) Wie funktioniert das mit dem adcifa_calibrate_offset. Muss ich da
einmalig Masse an den Eingang legen und schaun was rauskommt, diesen
Offset dann in ein Register legen? Ist das einmalig oder muss ich das
vor jedem Start machen?
2.) Wie muss ich den sequencer initialisieren, wenn ich bei den
sequencer_conv_options ein Array [4] habe. Funktioniert das dann so
überhaupt
>Also zwecks geschwindigkeit kann ich leider nicht viel sagen, bearbeite>nur einen Teil eines projektes und mir ist gesagt worden, ich soll DMA>für diese Sache verwenden..
Ihr Helden, aber ob der ADC schnell genug ist (min 6x) habt ihr
evaluiert?
gruß Jonas
Jetz versteh ich gar nichts mehr, wie gesagt, hab DMA noch nie
verwendet, bin Anfänger... bitte klär mich auf was du damit meinst...
Ich habe mir bis jetzt überlegt: ich mach jede Sekunde eine AD-Wandlung
(Sequenz) und diese Ergebnisse werden dann per DMA dem Reglermodul zur
Verfügung gestellt...
Hallo,
lassen wir das mit dem DMA mal weg, ich will zunächst nur die richtigen
Werte des sequencers einlesen...
Der ADC ist wie oben beschrieben konfiguriert, ich lese dann mit dem
Befehl
die werte ein.
wenn ich die 4 array elemente dann betrachte, kommen folgende werte raus
(Referenzspannung ADC = 2,51V):
Kanal 1: Spannung am ADCIN-PIN: 16mV ADC Wert: 65527
Kanal 2: Spannung am ADCIN-PIN: 207mV ADC Wert: 260
Kanal 3: Spannung am ADCIN-PIN: 3,3V ADC Wert: 2039
Kanal 4: Spannung am ADCIN-PIN: 990mV ADC Wert: 1990
Nachdem das Ergebnis im 2er-Komplemet dargestellt wird, hab ich nur noch
11 Bit auflösung, was einen maximalen Wert von 2048 bedeutet. Bei sehr
kleinen Werten kann ich mir vorstellen, dass durch einen Offset ein
negativer Wert rauskommt und dann durch die 2er Komplementdarstellung
der 16-Bit_int so hoch ist (Kanal 1)
Kanal 2: Hier würd es ungefähr passen (theoretisch sollte der wert ca
bei 170 liegen)
Kanal 3: auch das scheint mir zu passen, weil die spannugn über der
referenzspannugn liegt und somit (fast, theoretisch sollte es so sein)
das maxuimum ausgegeben wird
Kanal4: den hohen Wert kann ich mir nicht erklären...
Was sagt ihr dazu? Mache ich hier möglicherweise noch irgendetwas mit
dem Auslesen des wertes (2er Komplement usw) falsch?
Hallo!
In meinem Post von 19.12 ist dwer Code zu sehen. Kann mir jemand sagen,
welchen Wert ich für ITIMER_1s einsetzen muss, damit eine Wandlung in 1s
durchgeführt wird (also nach jeder Sekunde eine Wandlung)? Ich habe zur
Zeit den Wert 99999, aber die Wandlungen passieren viel zu schnell! KAnn
mir dabei jemand helfen?
Danke, lG
Zur erinnerung: ich trigger den ADC mit dem internen ITIMER; bleibt das
interrupt flag gesetzt, wenn die ISR einmal ausgeführt wurde? das würde
dann bedeuten, dass sofort wieder in die ISR gesprungen wird?
Werner13 schrieb:> Kann mir jemand sagen,> welchen Wert ich für ITIMER_1s einsetzen muss, damit eine Wandlung in 1s> durchgeführt wird (also nach jeder Sekunde eine Wandlung)?
--> Number of ADC clock cycles to wait for is (ITMC + 1).
Sofern Deine Clocks richtig konfiguriert sind und die o.g. Frequenz
stimmt, müsste 99999 passen. Da ITMC 17 bit lang ist, sollte das sogar
gehen.
Werner13 schrieb:> Kann es sein, dass ich vergessen habe, das Interrupt flag zu löschen?> muss man das in jeder ISR machen? Wie mach ich das in meinem Fall?
Weiß ich jetzt leider nicht auswendig, ob Du das machen musst - lies
entweder selber nach oder probier es aus. Nachdem es aber eine
adcifa_clear_interrupt Funktion gibt, liegt es nahe, dass Du es machen
müsstest.
Ich kann mir leider keinen ADCIFA-Interrupt leisten (damit würde der
Jitter bei meinem 10µs-Timer-Interrupt zu groß), sonst könnte ich Dir
vielleicht besser helfen.