Hallo,
klappt leider noch nicht so, wie gewünscht, bräuchte da mal Hilfe.
Der ADC1 Kanal 0 soll einfach stetig in ein Array kopiert werden.
Allerdings nicht so schnell wie möglich, sondern soll das softwaremässig
getriggert werden, zb aus einem zyklischen Timer Interrupt. Nur um das
Einsortieren in den Array soll sich die Hardware kümmern.
Tut es aber nicht, es steht einmal Werte im Array, die dem AD WWert auch
entsprechen und das war es dann auch.
Ich hoffe ich verstehe das richtig: Harware kann einen "DMA Request"
einleiten, denn irgendwie muss ja ein Startsignal kommen. In meinem Fall
soll dieses Startsignal allerdings immer manuell kommen. Nur wie weiss
ich noch nicht.
Aktuell schreibt er 16 Mal das gleiche in den Array rein und bleibt dann
stehen.
Hier mal mein Code
1
voidInit_DMA_LDR()
2
{
3
#define ADC1_DR_Address 0x4001244C // ADC Regular Data Register
Du kannst (mußt?) einen Timer-IRQ zum Triggern des DMA-Requests
benutzen. Hab ich schon gemacht, allerdings vom RAM zum DAQ. Ist aber so
lange her, dass ich genaues grad nicht weiß. Es sind nicht alle Timer
für alle DMA-Kanääle zu verwenden. Must mal das Manual wälzen.
Servus,
errata sagt, dass PA0 ungeeignet ist als ADC.
Weiterhin darf der ADC clock nicht mehr wie 14MHz sein.
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //hier bei 72Mhz hat man 12Mhz
RCC_APB2Periph_AFIO nicht aktiv ;(
Bitte, bitte.
PS: guck mal hier vorbei:
http://www.diller-technologies.de/stm32.html#dma
PA0 klappt ganz normal bei mir.
Man muss einfach den ADC auf Single Shot einstellen und ihn an den DMA
koppeln, wenn er fertig gewandelt hat. Außerdem muss man ihn von allen
Evenst abkoppeln, die ihmn starten könnten und das muss manuell
passieren, im Struct aber auch per Befehl.
Der Befehl
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
irgendwo plaziert startet dann jedesmal eine neue Wandlung die der DMA
dann brav ablegt.
PS: Diller kenne ich auswendig, ausgedruckt als Heft :-)
1
/* Initiiert den Transfer zwischen ADC1
2
Kanal und dem Array LDR */
3
voidInit_DMA_LDR()
4
{
5
#define ADC1_DR_Address 0x4001244C // ADC Regular Data Register
>Servus,>errata sagt, dass PA0 ungeeignet ist als ADC.>>Weiterhin darf der ADC clock nicht mehr wie 14MHz sein.>RCC_ADCCLKConfig(RCC_PCLK2_Div6); //hier bei 72Mhz hat man 12Mhz>>RCC_APB2Periph_AFIO nicht aktiv ;(
Bitte wichtige Infos nicht überlesen, sondern anwenden!
Hier nochmals:
http://www.st.com/st-web-ui/static/active/jp/resource/technical/document/errata_sheet/CD00190234.pdf>providing that PA0 is driven with an impedance lower than 5kΩ
Und das hier:
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
Ist irgendwie ein widerspruch! Mache aus DMA_Mode_Circular ==>
DMA_Mode_Normal. Und starte jedesmal eine neue Konversation mit:
ADC_SoftwareStartConvCmd(ADC1, DISABLE);
DMA_Cmd(DMA1_Channel1, DISABLE);
DMA1_Channel1->CNDTR = 2;
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
DMA_Cmd(DMA1_Channel1, ENABLE);
aSma>> schrieb:> Bitte wichtige Infos nicht überlesen, sondern anwenden!
Du, das steht drin .... und zwar direkt nach SysInit, ganz am Anfang :-)
Und noch viele Male bei anderen Dingen, die das auch brauchen.
>>Und das hier:>>ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;>>DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
Ist schon ok so. Dann läuft der Zeiger nämlich wieder auf LDR[0] nachdem
er das letzte Element fertig hatte. Sonst wird der nicht zurück gesetzt
auf 0.
Wenn Du
ADC_ContinuousConvMode = ENABLE
setzt rattert der DMA binnen Mikrosekunden das Array voll.
Und DMA wird manuell gestartet indem der ADC angestossen wird. Mit PA0
kannste Recht haben aber bei mir passt es am 5kOhm LDR, der eh nur
hell/dunkel merken muss.
1
/* System Grundeinstellungen, Clock, APB1,2 usw. */
Da habe ich mir auch den Affen dran gesucht :-((( Ein Blick ins Errata
hätte mir Stunden erspart..grr....
Debugging Stop mode and system tick timer
Description If the system tick timer interrupt is enabled during the
Stop mode debug (DBG_STOP bit set in the DBGMCU_CR register ), it will
wakeup the system from Stop mode. Workaround To debug the Stop mode,
disable the system tick timer interrupt.
aSma>> schrieb:> ADC_SoftwareStartConvCmd(ADC1, DISABLE);> DMA_Cmd(DMA1_Channel1, DISABLE);> DMA1_Channel1->CNDTR = 2;> ADC_SoftwareStartConvCmd(ADC1, ENABLE);> DMA_Cmd(DMA1_Channel1, ENABLE);
Was soll das bringen? Faktisch spielt er den Array jedesmal dann genauso
voll wie vorher. >Ich brauche DMA nur 1 Mal zu starten und er kreist
endlos herum, triggert jedesmal wenn ich eine Wandlung anstosse. Du
lädst es händisch nach, ich automatisch. Dafuer ist es ja da....
Christian J. schrieb:> Was soll das bringen? Faktisch spielt er den Array jedesmal dann genauso> voll wie vorher. >Ich brauche DMA nur 1 Mal zu starten und er kreist> endlos herum, triggert jedesmal wenn ich eine Wandlung anstosse. Du> lädst es händisch nach, ich automatisch. Dafuer ist es ja da....
Das ist ein Trugschluß, denn die DMA brauch auch ein wenig CPU! K.A aber
sagen wir so 20-30%. Durch das automatischen Reloaden läuft das Ding
ohne Ende.
WOZU?
aSma>> schrieb:> Das ist ein Trugschluß, denn die DMA brauch auch ein wenig CPU! K.A aber> sagen wir so 20-30%. Durch das automatischen Reloaden läuft das Ding> ohne Ende.
Ähm .... gibt es irgendwo Beweise für diese Behauptung? Dass die DMA
20-30% "CPU braucht"? Klingt völlig aus der Luft gegriffen, so wie "ADC
Wandler immer abschalten nach Gebrauch, geht sonst schneller kaputt."
Und ja, es ist Sinn der Sache, dass das Ding ohne Ende läuft. Die DMA
schiesst die Daten in den Array rein und der Timer INT rechnet nebenbei
laufende die Mittelwerte usw aus. Naja, Spass am programmieren, ne
ernsthafte Anwendung steckt da nicht hinter.
Rrrrrrrrr......
1
/* ---- Timer 3 Time Base ------
2
3
Holt die AD Werte ab fuer die LED Steuerung
4
5
*/
6
voidTIM3_IRQHandler()
7
{
8
staticuint16_tcnt=0;
9
staticuint32_tsum=0;
10
11
/* Fehlerhafte IRQ Anforderungen ausblenden */
12
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==RESET)
13
return;
14
15
/* Clear IRQ Flag */
16
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
17
18
/* Mittelwert des gesamten Arrays bilden, bei jedem Durchlauf
Servus,
die DMA läuft bekannter maßen durch einen Bus. Wenn dieser Bus voll ist,
weil die DMA die ganze Zeit rumeiert, dann läuft auch die Anwendung
langsamer ab:
http://www.embedds.com/using-direct-memory-access-dma-in-stm23-projects/
Du machst das ja richtig. Die DMA läuft nur kurz, durch einen timer
triggerung.
Hier habe ich auch was gelernt, dass mit:
>ADC_SoftwareStartConvCmd(ADC1, ENABLE);
und
>ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;>DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
Sich ja 5 Zeilen Code sparen kann. Das teste ich später dann.
Danke.
Aber es gibt bekannter maßen mehrere Wege nach Rom.
aSma>> schrieb:> Servus,> die DMA läuft bekannter maßen durch einen Bus. Wenn dieser Bus voll ist,> weil die DMA die ganze Zeit rumeiert, dann läuft auch die Anwendung> langsamer ab:
Natürlich teilen sich CPU und DMA den Bus. Aber wo bei mir der
Flasschenhals sein soll weiss ich nicht. Der ADC wird mit einer Rate von
200ms per Hand getriggert in einem der Rundlauf Timer ISR's. Und dann
schnubbeln die Daten direkt in den Array rein, sieht man schön im
Debugger. Die ISR bildet dann auch einen fliessenden Mittelwert. Auch
wenn man fliessende Mittelwerte mit einer Formel berechnen kann, die den
neuen Wert gegen die alten gewichtet, so brauche ich doch kein
Fliesskomma.
Schön, schön..... tolles Steinchen und gegenüber den F429 noch
übersichtlich.