Forum: Mikrocontroller und Digitale Elektronik STM32F4 ADC DMA Multichannel


von Sebastian T. (sebastian_tsch)


Lesenswert?

Hi,

Ich versuche den ADC1 auf einem STM32F4 mit 2 Channels zu verwenden. Das 
Problem ist, dass aus irgend einem Grund der DMA Interrupt nur einmal 
aufgerufen wird und dann nie mehr. Der ADC sollte eigentlich durch den 
Timer immer wieder neu getriggert werden. Wenn ich zwei verschiedene 
ADC's verwende dann geht es, nur bei einem ADC mit mehreren Channels 
nicht. Hier mein Code:
1
/**
2
  ******************************************************************************
3
  * @file    main.c
4
  * @author  Ac6
5
  * @version V1.0
6
  * @date    01-December-2013
7
  * @brief   Default main function.
8
  ******************************************************************************
9
*/
10
11
12
#include "stm32f4xx.h"
13
#include "stm32f4_discovery.h"
14
15
#define VOLTAGE_REF 3.3 //Datasheet
16
17
void RCC_Configuration(void)
18
{
19
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
20
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
21
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
22
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
23
}
24
25
/***************************************************************************/
26
void GPIO_Configuration(void)
27
{
28
  GPIO_InitTypeDef GPIO_InitStructure;
29
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
30
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
31
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
32
  GPIO_Init(GPIOC, &GPIO_InitStructure);
33
}
34
/***************************************************************************/
35
void ADC_Configuration(void)
36
{
37
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
38
  ADC_InitTypeDef ADC_InitStructure;
39
  /* ADC Common Init */
40
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
41
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
42
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;
43
  // 2 half-words one by one, 1 then 2
44
  ADC_CommonInitStructure.ADC_TwoSamplingDelay =  ADC_TwoSamplingDelay_5Cycles;
45
  ADC_CommonInit(&ADC_CommonInitStructure);
46
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
47
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
48
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // Conversions Triggered
49
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
50
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
51
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
52
  ADC_InitStructure.ADC_NbrOfConversion = 2;
53
  ADC_Init(ADC1, &ADC_InitStructure);
54
  //ADC_Init(ADC2, &ADC_InitStructure); // Mirror on ADC2
55
  /* ADC1 regular channel 10 configuration */
56
57
  ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1,ADC_SampleTime_15Cycles);
58
  ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 2,ADC_SampleTime_15Cycles);
59
60
  //ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
61
  ADC_DMACmd(ADC1, ENABLE);
62
63
64
  /* Enable ADC1 */
65
  ADC_Cmd(ADC1, ENABLE);
66
67
}
68
69
/**************************************************************************/
70
# define BUFFERSIZE 900 // I+Q 200KHz x2 HT/TC at 1KHz
71
72
__IO uint16_t ADCDualConvertedValues[BUFFERSIZE]; // Filled as pairs ADC1, ADC2
73
74
static void DMA_Configuration(void)
75
{
76
  DMA_InitTypeDef DMA_InitStructure;
77
78
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;
79
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCDualConvertedValues;
80
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)0x40012308;
81
  // CDR_ADDRESS; Packed ADC1, ADC2
82
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
83
  DMA_InitStructure.DMA_BufferSize = BUFFERSIZE; // Count of 16-bit words
84
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
85
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
86
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
87
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
88
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
89
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
90
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
91
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
92
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
93
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
94
  DMA_Init(DMA2_Stream0, &DMA_InitStructure);
95
  /* Enable DMA Stream Half / Transfer Complete interrupt */
96
  DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_HT, ENABLE);
97
  /* DMA2_Stream0 enable */
98
  DMA_Cmd(DMA2_Stream0, ENABLE);
99
}
100
void TIM2_Configuration(void)
101
{
102
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
103
  /* Time base configuration */
104
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
105
  TIM_TimeBaseStructure.TIM_Period =(84000000 / 200000) - 1;
106
   // 200 KHz, from 84 MHz TIM2CLK (ie APB1 = HCLK/4, TIM2CLK = HCLK/2)
107
  TIM_TimeBaseStructure.TIM_Prescaler = 0;
108
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
109
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
110
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
111
  /* TIM2 TRGO selection */
112
  TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
113
  // ADC_ExternalTrigConv_T2_TRGO
114
 /* TIM2 enable counter */
115
  TIM_Cmd(TIM2, ENABLE);
116
}
117
118
/****************************************************************************/
119
void NVIC_Configuration(void)
120
{
121
 NVIC_InitTypeDef NVIC_InitStructure;
122
           /* Enable the DMA Stream IRQ Channel */
123
  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
124
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
125
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
126
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
127
  NVIC_Init(&NVIC_InitStructure);
128
}
129
130
/***********************************************************************/
131
void DMA2_Stream0_IRQHandler(void)//Called at 1 KHz for 200 KHz sample rate
132
{
133
 /* Test on DMA Stream Half Transfer interrupt */
134
 if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_HTIF0))
135
 {
136
  /* Clear DMA Stream Half Transfer interrupt pending bit */
137
  DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_HTIF0);
138
139
 }
140
141
 /* Test on DMA Stream Transfer Complete interrupt */
142
 if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0))
143
 {
144
  /* Clear DMA Stream Transfer Complete interrupt pending bit */
145
  DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
146
147
  // Add code here to process second half of buffer (pong)
148
  }
149
 }
150
151
 /*****************************************************************************/
152
153
 int main(void)
154
 {
155
  RCC_Configuration();
156
  GPIO_Configuration();
157
  NVIC_Configuration();
158
  TIM2_Configuration();
159
  DMA_Configuration();
160
  ADC_Configuration();
161
162
  /* Start ADC1 Software Conversion */
163
  ADC_SoftwareStartConv(ADC1);
164
165
  while(1) {// Don't want to exit
166
    float x=ADCDualConvertedValues[0];
167
    float y=ADCDualConvertedValues[1];
168
169
  }
170
 /***************************************************************************/
171
}

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


Lesenswert?

Sebastian T. schrieb:
> DMA_InitStructure.DMA_Memory0BaseAddr =
> (uint32_t)&ADCDualConvertedValues;
>   DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)0x40012308;

Gib hier mal lieber die richtigen Adressen vor:
1
  DMA_InitStructure.DMA_PeripheralBaseAddr =  (uint32_t)&(ADC1->DR); // source address
2
  DMA_InitStructure.DMA_Memory0BaseAddr = (u32)&ADCDualConvertedValues[0];      //  result memory location
Dann ist es sinnvoll, zu warten, bis die DMA soweit ist, bevor man den 
ADC startet:
1
  DMA_Cmd(DMA2_Stream0,ENABLE);
2
 // wait for the DMA Stream to be ready
3
  while(DMA_GetCmdStatus(DMA2_Stream0)==DISABLE){};
4
 // now run the ADC
5
  ADC_DMACmd(ADC1, ENABLE);
6
  ADC_Cmd(ADC1, ENABLE);
7
  ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
8
  ADC_ContinuousModeCmd(ADC1,ENABLE);
9
  ADC_SoftwareStartConv(ADC1);
Ich schreibe die ADC Ergebnisse statt in ein Array in ein Struct, aber 
das sollte nicht wirklich einen Unterschied machen.

: Bearbeitet durch User
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.