Forum: Mikrocontroller und Digitale Elektronik STM32F4 Werte-offset bei DMA Transfer vom ADC1


von Werner A. (gnuopfer)


Lesenswert?

Hallo Zusammen,

Ihc hab hier ein kurioses  Probme mit demn DMA Transfer auf einem 
STM32F407VG (STM32DISCOVERY Board),

Ich lese über den ADC1 10 Kanäle ein. Der Transfer läuft über DMA 
Channel2 in ein Array mit 10 Words.
Das Ganze funktioniert im Prinzip, mit einem Haken: Die ADC-Werte im 
Ziel-Array des DMA-Transfers starten nicht mit dem Channel mit ADC-Rank 
1, sondern mit irgendeinem Anderen. D.h. Der DMA-Transfer startet mitten 
in eiem Conversion Cycle des ADCs, nicht am Anfang. Durch den 
"CircularMode" Transfer der DMA werden so zwar alle Werte übertragen, 
aber mit einem Offset zum Start des Arrays.
Das Problem scheint etwas mit dem Timing des ADC zu tun zu haben;Wenn 
die SamplingTime der Kanäle geändert wird, ändert sich auch der Offset.

Ist schon mal wer auf dieses Problem aufgelaufen ?
Gibt es einen Weg die DMA manuell mit dem ADC zu synchronisiern ?


mfg

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Werner A. schrieb:
> Gibt es einen Weg die DMA manuell mit dem ADC zu synchronisiern ?

Ohne den Code zu kennnen, habe ich nur eine Antwort - zuerst die DMA 
scharf schalten und dann den ADC starten, dann klappt es.
Allerdings ist die Organisation der ADC Werte interessant.
Hier mal ein Codeschnipsel für 4 Kanäle mit StdPeripheralLib:
1
typedef struct ADCValues
2
{
3
  uint16_t channel0;
4
  uint16_t channel1;
5
  uint16_t channel2;
6
  uint16_t channel3;
7
  uint16_t spare;
8
} ADCValues_t;
9
10
// DMA Target for ADC
11
volatile ADCValues_t ADCRead;
12
13
/* temporary use the internal 12-bit ADC for audio input, but it sounds bad */
14
void ADCInit(void) {
15
ADC_CommonInitTypeDef ADC_CommonInitStructure;
16
ADC_InitTypeDef     ADC_InitStructure;
17
DMA_InitTypeDef      DMA_InitStructure;
18
19
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
20
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
21
/* ADC1 configuration
22
 * 4 channel continuous
23
 */
24
//ADC_DeInit(ADC1);
25
ADC_CommonStructInit(&ADC_CommonInitStructure);
26
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
27
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
28
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
29
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
30
ADC_CommonInit(&ADC_CommonInitStructure);
31
32
ADC_StructInit(&ADC_InitStructure);
33
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
34
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
35
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
36
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
37
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO;
38
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;
39
ADC_InitStructure.ADC_NbrOfConversion = 4;
40
/* Now do the setup */
41
ADC_Init(ADC1, &ADC_InitStructure);
42
/* Enable ADC1 and configure channels*/
43
ADC_RegularChannelConfig(ADC1,INPUT0_CHANNEL,1,ADC_SampleTime_15Cycles);
44
ADC_RegularChannelConfig(ADC1,INPUT1_CHANNEL,2,ADC_SampleTime_15Cycles);
45
ADC_RegularChannelConfig(ADC1,INPUT2_CHANNEL,3,ADC_SampleTime_15Cycles);
46
ADC_RegularChannelConfig(ADC1,INPUT3_CHANNEL,4,ADC_SampleTime_15Cycles);
47
48
/* DMA1 channel1 configuration ----------------------------------------------*/
49
  DMA_DeInit(DMA2_Stream0);    // Clear everything we had
50
  DMA_StructInit(&DMA_InitStructure);
51
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;
52
  DMA_InitStructure.DMA_PeripheralBaseAddr =  (uint32_t)&(ADC1->DR); // source address
53
  DMA_InitStructure.DMA_Memory0BaseAddr = (u32)&ADCRead.channel0;      //  result memory location
54
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;   // from Peripheral to RAM
55
  DMA_InitStructure.DMA_BufferSize = 2;    /// Note that we have 4 Channels
56
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  // Source stays same address
57
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;     // Destination will be incremented
58
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  // 16 bit results
59
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;   // yeah same size -> 16 bit
60
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  // Wrap around the destination address
61
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;   //
62
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
63
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
64
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
65
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
66
  DMA_Init(DMA2_Stream0, &DMA_InitStructure);   // Init the stuff finally
67
  DMA_Cmd(DMA2_Stream0,ENABLE);
68
 // wait for the DMA Stream to be ready
69
  while(DMA_GetCmdStatus(DMA2_Stream0)==DISABLE){};
70
 // now run the ADC
71
  ADC_DMACmd(ADC1, ENABLE);
72
  ADC_Cmd(ADC1, ENABLE);
73
  ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
74
  ADC_ContinuousModeCmd(ADC1,ENABLE);
75
  ADC_SoftwareStartConv(ADC1);
76
}

: Bearbeitet durch User
von Werner A. (gnuopfer)


Lesenswert?

Matthias S. schrieb:
>   while(DMA_GetCmdStatus(DMA2_Stream0)==DISABLE){};


Es schaut so aus, als ob das Problem es durch das Einfügen dieser 
Warteschleife behoben ist. Ich warte zusätzlich auch noch auf den 
READY-Status des ADCs; Selbst wenn es nichts hilft, schaden wird's 
sicher nicht.


mfg

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
Noch kein Account? Hier anmelden.