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