Hallo,
ich werde aus den ganzen Datenblätter nicht schlau:
habe ein grundsätzliches Verständnisproblem beim STM32F103 wenn ich den
ADC per DMA im circular mode auslesen möchte.
Es geht um das "End Of Conversion Interrupt Enable Bit" im CR1 und das
"DMA" bit im CR2 (Control register 2)
wenn ich mit DMA arbeiten muss, warum dieses Interrupt Enable Bit ?!?
ich dachte, dass der DMA eigenständig läuft ? klar muss man diesen
konfigurieren, aber warum löst der ADC einen interrupt aus um den DMA zu
rufen dass eine Conversion fertig ist und er diese bitte abholen
kann/soll ?
Es gibt beim ADC doch auch das EOC flag bit was ja auch sagt, dass eine
Konversion fertig ist. Warum kann dieses EOC Flag nicht den DMA rufen ?
Ein DMA request ist gleich einem Interrupt ?
Und welche Bedeutung hat das DMA Bit im Control Register 2 des ADC
Wandlers ?
ok jetzt muss ich doch konkreter werden:
ich habe 3 Channels, welche jeweils in ein bestimmtes Array-Field
geschrieben werden sollen:
Ch1 in Field 1
Ch2 in Field 2
Ch3 in Field 3
und wieder von vorne. Es dürfen keine Umwandlungen verloren gehen sonst
kommt die Reihenfolge durcheinander. Heisst: jede einzelne Conversion
des ADC muss per DMA in das richtige Array Field geschrieben werden.
"Getakted wird die DMA vom ADC, das wird über das "DMA-Bit"
freigegeben."
der ADC läuft doch auf einem anderen Takt als der AHB Bus über den der
DMA läuft ?! ADC hat max. 14 MHZ der AHB Bus 72 MHz oder habe ich Dich
da jetzt falsch verstanden ?
Der ADC teilt dem DMA Controller mit, wann er fertig ist und DMA holt
das Datum ab und speichert es im Feld ab. 'Taktung' ist nicht das
passende Wort - Request wäre treffender.
Interrupts sind dafür nicht nötig. Die DMA Buffersize muss aber passen.
Wenn du 3 Kanäle abfragst, sollte Buffersize also auch 3 sein, sonst
gibt Kuddelmuddel.
alex schrieb:> ok jetzt muss ich doch konkreter werden:>> ich habe 3 Channels, welche jeweils in ein bestimmtes Array-Field> geschrieben werden sollen:>> Ch1 in Field 1> Ch2 in Field 2> Ch3 in Field 3>> und wieder von vorne. Es dürfen keine Umwandlungen verloren gehen sonst> kommt die Reihenfolge durcheinander. Heisst: jede einzelne Conversion> des ADC muss per DMA in das richtige Array Field geschrieben werden.>> "Getakted wird die DMA vom ADC, das wird über das "DMA-Bit"> freigegeben."
Ja, etwas lässig beschrieben.
Jedes Ende einer Wandlung stößt einen DMA-Transfer an. Verloren gehen
wird da nichts, da sind ja keine eventuell gesperrten Interrupts im
Spiel.
Und das Ende eines Durchlaufs wird von der DMA signalisiert. Welche
Kanäle in welcher Reihenfolge gewandelt werden, muß im ADC eingestellt
werden.
Mit letzterem hab ich bisher keine Erfahrung, aber per DMA hab ich über
Timer/PWM 2x4 Kanäle on-the-Fly erzeugten Sound ausgegeben. Da hat sich
die DMA nie vertan.
> der ADC läuft doch auf einem anderen Takt als der AHB Bus über den der> DMA läuft ?! ADC hat max. 14 MHZ der AHB Bus 72 MHz oder habe ich Dich> da jetzt falsch verstanden ?
Mit "getaktet" war das Auslösen des DMA-Transfers gemeint, nicht der
Bus-Takt.
PS: ich habe meine HW-Konfigurationsfragen via Debugger gelöst.
Eclipse/GnuMcu/OpenODC/ST/Link-Clone.
Dazu svd-Datei des Chips, dann kann man online in der Peripherie
stochern.
Matthias S. schrieb:> Der ADC teilt dem DMA Controller mit, wann er fertig ist und DMA holt> das Datum ab und speichert es im Feld ab. 'Taktung' ist nicht das> passende Wort - Request wäre treffender.
ok nur wie teilt der ADC dem DMA das mit ? auf welcher "Leitung" oder
mit welchem Signal ?
reicht es das DMA Bit im CR2 des ADC auf 1 zu setzen ? das EOC flag im
Statusregister des ADCs brauche ich dann so nicht
Carl D. schrieb:> Jedes Ende einer Wandlung stößt einen DMA-Transfer an. Verloren gehen> wird da nichts, da sind ja keine eventuell gesperrten Interrupts im> Spiel.
dieses Anstoßen eines DMA Transfers macht der ADC wenn ich also in
dessen CR2 das DMA Bit auf 1 stelle, richtig ?
das EOCIE (End of conversion interrupt enable) Bit brauche ich dann
nicht.
Vielen Dank auch Dir Carl für Deine Hilfe.
alex schrieb:> ich habe 3 Channels, welche jeweils in ein bestimmtes Array-Field> geschrieben werden sollen:>> Ch1 in Field 1> Ch2 in Field 2> Ch3 in Field 3>> und wieder von vorne.
Ähemm..
Und das einfach so? Ohne daß irgend ein Programmstück mit diesen Werten
irgendwas anfängt?
W.S.
NichtWichtig schrieb:> CubeMX löst das alles wunderbar ohne in den Tiefen der Register zu> buddeln.
ich möchte aber in den Tiefen der Register "buddeln" :) weil ich es
richtig lernen und verstehen möchte. Zudem möchte ich nicht mit HAL
arbeiten.
W.S. schrieb:> Und das einfach so? Ohne daß irgend ein Programmstück mit diesen Werten> irgendwas anfängt?
doch, sicherlich fange ich mit den Werten was an, aber darum geht es mir
hier nicht. Die Fragestellung war ja wie der ADC dem DMA das mitteilt,
dass er fertige Daten "zur Abholung" für den DMA hat.
Reicht das also wenn im ADC Control Register das DMA Bit auf "1" gesetzt
wird so dass der ADC den DMA jedesmal nach einer Conversion einen
Request schickt?
alex schrieb:> Reicht das also wenn im ADC Control Register das DMA Bit auf "1" gesetzt> wird so dass der ADC den DMA jedesmal nach einer Conversion einen> Request schickt?
Du musst auch den ADC einmal starten. Ich kann dir gerne mal ein SPL
Beispiel für 4 Kanäle posten.
NbrOfChannels des ADC und Buffersize des DMA sollten gleich gross sein.
DMA auf HalfWords einstellen und die MemoryAdresse auf deine struct mit
den ADC Ergebnissen und Increment stellen. PeripheralAdress auf &ADC->DR
zeigen lassen - ohne Increment.
Matthias S. schrieb:> Du musst auch den ADC einmal starten.
Hallo Matthias, wie meinst Du das "den ADC einmal starten" ? Ich
konfiguriere den ADC und den DMA und dann starte ich die Conversion
indem ich den ADC starte (nach Kalibrierung). Dann sollte alles
automatisch gehen. Die Adressen sollten (hoffe ich jetzt einmal) kein
Problem darstellen, soweit sollte es mir klar sein. Mir geht es um die
Sache des DMA Request durch den ADC also wie dieser Request stattfindet.
Wahrscheinlich über das DMA Bit im CR2 des ADC weiss dieser also, dass
er mit dem DMA gemeinsame Sache machen soll
alex schrieb:> Hallo Matthias, wie meinst Du das "den ADC einmal starten" ? Ich> konfiguriere den ADC und den DMA und dann starte ich die Conversion> indem ich den ADC starte (nach Kalibrierung).
Ja, genau so.
alex schrieb:> Dann sollte alles> automatisch gehen.
Tut es.
alex schrieb:> Mir geht es um die> Sache des DMA Request durch den ADC also wie dieser Request stattfindet.
Muss dich gar nicht interessieren, da ADC und DMA das unter sich
aushandeln, wenns richtig konfiguriert ist - und das macht das DMA Bit
im ADC->CR2 Register.
W.S. schrieb:> Und das einfach so? Ohne daß irgend ein Programmstück mit diesen Werten> irgendwas anfängt?
Das kann uns wurscht sein. Wichtig ist nur, das die Felder für die ADC
Ergebnisse volatile deklariert sind, denn die werden ja nur vom DMA
geändert.
Das Datenblatt Kapitel zum ADC ist da nicht ganz klar formuliert. Ich
hatte damals auch ein bisschen Probleme bis es funktionierte.
Will man mehrere Wandlungen Hintereinander machen (ADC_SQR1_L > 1) geht
das nur mithilfe das DMA.
Will man das der ADC am Ende wieder mit dem ersten Kanal automatisch von
vorne startet, muss das ADC_CR1_SCAN Bit gesetzt sein.
Hier ein paar Funktion Schnipsel aus meinen Projekten (Nicht
vollständig, soll nur als Denkansatz dienen, Headers, Typdefs und Enums
fehlen)
Es werden ADC0, ADC1 und ADC2 Zyklisch vom ADC gewandelt und mittels DMA
in das Array geschrieben.
Alles Interrupts.
DMA:
Matthias S. schrieb:> Muss dich gar nicht interessieren, da ADC und DMA das unter sich> aushandeln, wenns richtig konfiguriert ist - und das macht das DMA Bit> im ADC->CR2 Register.
Matthias !! Vielen lieben Dank, Du hast mir echt viel geholfen !! Ich
werde das am Wochenende mal umsetzen.
Christian K. schrieb:> Will man das der ADC am Ende wieder mit dem ersten Kanal automatisch von> vorne startet, muss das ADC_CR1_SCAN Bit gesetzt sein.
ich hatte das bisher immer so verstanden, dass das SCAN Bit alle im SQR
Register (nach Sequenzreihenfolge) eingetragenen Channels von Channel x
bis Channel y "durchscannt", mehr nicht
will man den Scan-Vorgang im Loop muss man das Cont-Bit im ADC CR setzen
(Continuous)
Du hast natürlich recht.
ADC_CR2_CONT Bit ist dafür da, das automatisch wieder von vorne
gestartet wird.
ADC_CR1_SCAN mit der Kombination ADC_SQR1_L größer null geht nur mit
DMA.
Christian K. schrieb:> Du hast natürlich recht.>> ADC_CR2_CONT Bit ist dafür da, das automatisch wieder von vorne> gestartet wird.>> ADC_CR1_SCAN mit der Kombination ADC_SQR1_L größer null geht nur mit> DMA.
ok dann bin ich beruhigt ! Achja: Vielen Dank für Deinen Code!
jetzt habe ich aber ein anderes Problem:
ich arbeite mit CooCox und einem Nucleo 64 Board mit STM32F103RBT6.
Ich möchte 3 Kanäle per ADC scannen.
ADC_IN0
ADC_IN1
ADC_IN4
Die Sequenz Reihenfolge gebe ich im SQR Register 3 mit :
Erstens: Ch0
Zweitens: Ch1
Drittens: Ch4
und wieder von vorne (Circular continuous). Da ich im SCAN Mode arbeite,
verwende ich auch den DMA Controller.
Jeder der drei Channel Ch0, Ch1 und Ch4 sollen einen festen Platz in
einem Array RGB[3] bekommen. Ch0 also RGB[0], Ch1 in RGB[1] und Ch4 in
RGB[2].
Das sage ich dem DMA Controller:
independent mode enable
memory increment enable
circular mode enable
direction bit > lesen von Peripherie
adresse vom ADC Datenregister (uint32_t)&ADC1->DR;
adresse vom Array: (uint32_t)RGB;
Menge an Daten: 3 (dann wieder von vorne)
da ich keine andere Möglichkeit habe zu sehen was denn nun wirklich
passiert lasse ich immer den Debugger laufen und beoachte dort
schrittweise per Mausklick das RGB Array und habe dort ständig
springende Werte drin. Drehe ich eines der Potis an den ADC Eingängen,
wandert dieser Wert fleissig durch die Array Fields.
Was mache ich falsch ? Ist das Debugging hier vllt völlig nutzlos wenn
man mit ADC und DMA arbeitet ?
alex schrieb:> Was mache ich falsch ?
Es klingt so, als ob dein DMA Puffer eine andere Größe hat, als die
Anzahl der eingestellten ADC Kanäle. Eventuell stimmt die Größe der
Werte (16/32bit) nicht.
Christian K. schrieb:> Hast du beachtet, die Bits in ADC_SQR1_L sind Kanalanzahl minus 1?
Ich glaub ich spinne.....
Du bist der Beste !!! Ja ich hab zwar die 2 da reingeschrieben weil ich
3 Conversions machen möchte, aber gerade beim Nachsehen folgendes
feststellen müssen:
ADC1->SQR1 |= ~(2<<20);
Dir/Euch fällt jetzt bestimmt was auf ?
Das "~" ist noch von einem bits resetten vergessen worden weil ich immer
wieder am Code rumgelöscht und umgeschrieben habe...
Ich werde das morgen ausprobieren und Dir / Euch auf jeden Fall Bescheid
geben. Für heute ist mein Kopf nicht mehr aufnahmefähig :D
Stefan ⛄ F. schrieb:> alex schrieb:>> Was mache ich falsch ?>> Es klingt so, als ob dein DMA Puffer eine andere Größe hat, als die> Anzahl der eingestellten ADC Kanäle. Eventuell stimmt die Größe der> Werte (16/32bit) nicht.
auch Du hattest Recht !!! Vielen Dank ich bin gerade sowas von
erleichtert (siehe meine vorletzte Antwort)
Es ist auch echt heftig wie schnell ihr euch da reindenken konntet und
mich auf die richtige Fährte gebracht habt... vor allem es war von mir
nur ein Leichtsinnsfehler (Copy paste machen aber das "~" nicht
weglöschen) nur weil zu faul zum schreiben war.
Ich liebe dieses Forum!
ich geb Euch morgen Bescheid
Es funktioniert !!! Die Werte in den Array fields wandern nun nicht
mehr.
Es war nur ein copy+paste Fehler der mir da unterlaufen ist.
Vielen Dank für Eure Hilfe.