Forum: Mikrocontroller und Digitale Elektronik Zwei ADC über DMA laufen lassen STM32


von Bert S. (kautschuck)


Angehängte Dateien:

Lesenswert?

Ich versuche ADC1 und ADC2 über den DMA auszulesen, doch bleibt das 
Programm in der Interrupt Routine vom DMA für den ADC1 Channel hängen.
Ich verwende HAL und habe die ADC's nach den Bildern im Anhang 
konfiguriert.

Ich starte die ADC's folgendermassen:
1
HAL_ADC_Start_DMA(&hadc1, (uint16_t*)adc_array, ADC_SIZE);
2
HAL_ADC_Start_DMA(&hadc2, (uint16_t*)adc_array2, ADC_SIZE);

Wenn ich aber nur HAL_ADC_Start_DMA(&hadc1, (uint16_t*)adc_array, 
ADC_SIZE); ausführe und nicht noch die zweite Codezeile, dann 
funktioniert es. Jemand eine Idee warum das in der Interrupt Routine vom 
DMA (welche man ja nicht deaktivieren kann) hängen bleibt?

EDIT: Anscheinend liegt es nur an ADC2, denn HAL_ADC_Start_DMA(&hadc2, 
(uint16_t*)adc_array2, ADC_SIZE); geht auch nicht, wenn ich die erste 
Codezeile auskommentiere.

Datenblatt (STM32F303K8T6):
http://www.st.com/content/ccc/resource/technical/document/reference_manual/4a/19/6e/18/9d/92/43/32/DM00043574.pdf/files/DM00043574.pdf/jcr:content/translations/en.DM00043574.pdf

: Bearbeitet durch User
von Jim M. (turboj)


Lesenswert?

Wie sehen Deinen Quellcode nicht, und meine Glaskugel ist in Reparatur.

von Bert S. (kautschuck)


Lesenswert?

Die ADC's sind wie folgt initialisiert und werden über die oben 
genannten zwei Codezeilen gestartet.
1
static void MX_ADC1_Init(void)
2
{
3
4
  ADC_MultiModeTypeDef multimode;
5
  ADC_ChannelConfTypeDef sConfig;
6
7
    /**Common config 
8
    */
9
  hadc1.Instance = ADC1;
10
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
11
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
12
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
13
  hadc1.Init.ContinuousConvMode = DISABLE;
14
  hadc1.Init.DiscontinuousConvMode = DISABLE;
15
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
16
  hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T2_TRGO;
17
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
18
  hadc1.Init.NbrOfConversion = 1;
19
  hadc1.Init.DMAContinuousRequests = ENABLE;
20
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
21
  hadc1.Init.LowPowerAutoWait = DISABLE;
22
  hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
23
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
24
  {
25
    Error_Handler();
26
  }
27
28
    /**Configure the ADC multi-mode 
29
    */
30
  multimode.Mode = ADC_MODE_INDEPENDENT;
31
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
32
  {
33
    Error_Handler();
34
  }
35
36
    /**Configure Regular Channel 
37
    */
38
  sConfig.Channel = ADC_CHANNEL_4;
39
  sConfig.Rank = 1;
40
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
41
  sConfig.SamplingTime = ADC_SAMPLETIME_601CYCLES_5;
42
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
43
  sConfig.Offset = 0;
44
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
45
  {
46
    Error_Handler();
47
  }
48
49
}
50
51
/* ADC2 init function */
52
static void MX_ADC2_Init(void)
53
{
54
55
  ADC_ChannelConfTypeDef sConfig;
56
57
    /**Common config 
58
    */
59
  hadc2.Instance = ADC2;
60
  hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
61
  hadc2.Init.Resolution = ADC_RESOLUTION_12B;
62
  hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE;
63
  hadc2.Init.ContinuousConvMode = DISABLE;
64
  hadc2.Init.DiscontinuousConvMode = DISABLE;
65
  hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
66
  hadc2.Init.NbrOfConversion = 2;
67
  hadc2.Init.DMAContinuousRequests = ENABLE;
68
  hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
69
  hadc2.Init.LowPowerAutoWait = DISABLE;
70
  hadc2.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
71
  if (HAL_ADC_Init(&hadc2) != HAL_OK)
72
  {
73
    Error_Handler();
74
  }
75
76
    /**Configure Regular Channel 
77
    */
78
  sConfig.Channel = ADC_CHANNEL_1;
79
  sConfig.Rank = 1;
80
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
81
  sConfig.SamplingTime = ADC_SAMPLETIME_181CYCLES_5;
82
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
83
  sConfig.Offset = 0;
84
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
85
  {
86
    Error_Handler();
87
  }
88
89
    /**Configure Regular Channel 
90
    */
91
  sConfig.Channel = ADC_CHANNEL_2;
92
  sConfig.Rank = 2;
93
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
94
  {
95
    Error_Handler();
96
  }
97
98
}

von Christopher J. (christopher_j23)


Lesenswert?

Bert S. schrieb:
> Ich verwende HAL und habe die ADC's nach den Bildern im Anhang
> konfiguriert.

Ist das malen nach Zahlen?

Bert S. schrieb:
> Ich versuche ADC1 und ADC2 über den DMA auszulesen, doch bleibt das
> Programm in der Interrupt Routine vom DMA für den ADC1 Channel hängen.

Welche DMA? Ich sehe nur die Konfiguration des ADC.

Bert S. schrieb:
> Jemand eine Idee warum das in der Interrupt Routine vom
> DMA (welche man ja nicht deaktivieren kann) hängen bleibt?

Welche Interrupt-Routine? Ich sehe keine. Eine Interrupt-Routine die man 
nicht deaktivieren kann halte ich übrigens für ein Gerücht. Allerdings 
macht für mich DMA ohne Interrupt eher keinen Sinn. Du willst doch 
wissen wann der Buffer voll ist, oder nicht? Warum willst du den 
Interrupt deaktivieren?

von Dr. Sommer (Gast)


Lesenswert?

Bert S. schrieb:
> Jemand eine Idee warum das in der Interrupt Routine vom DMA (welche man
> ja nicht deaktivieren kann) hängen bleibt?

Vielleicht weiß das ja der Debugger, der kann dir sogar genau die Zeile 
sagen in der es stecken bleibt. Sich diese Zeile anzusehen kann ungemein 
helfen im Vergleich zum kompletten Blindflug und raten.

von Christian J. (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Vielleicht weiß das ja der Debugger, der kann dir sogar genau die Zeile
> sagen in der es stecken bleibt.

Zumindest bei EmBitz habe ich die Erfahrung gemacht, dass wenn es 
"hängt", dann auch so, dass der swd Debugger sich nicht mehr stoppen 
lässt. Das sind bei mir inzwischen 2/3 aller Fälle, wo echt was schief 
läuft. Meine DMA Frickelei mit dem ADC habe ich auch im Blindflug 
erstellt, da es öfter mal die "Hardware Default Exception" gab und da 
ich von Asm eh Null Plan habe, ich da auch nicht weiter reingekrochen 
bin.

von Bert S. (kautschuck)


Lesenswert?

So, ich habe mich dem Problem nochmals angenommen, jedoch immer noch 
keine Lösung gefunden. Ich verwende gemäß dem folgenden Datenblatt den 
Dual regular simultaneous mode:
http://www.st.com/content/ccc/resource/technical/document/application_note/48/64/0d/61/be/65/48/ae/DM00069390.pdf/files/DM00069390.pdf/jcr:content/translations/en.DM00069390.pdf

Die initialisierung erfolgt so:
1
int main(void)
2
{
3
4
  /* USER CODE BEGIN 1 */
5
6
  /* USER CODE END 1 */
7
8
  /* MCU Configuration----------------------------------------------------------*/
9
10
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
11
  HAL_Init();
12
13
  /* USER CODE BEGIN Init */
14
15
  /* USER CODE END Init */
16
17
  /* Configure the system clock */
18
  SystemClock_Config();
19
20
  /* USER CODE BEGIN SysInit */
21
22
  /* USER CODE END SysInit */
23
24
  /* Initialize all configured peripherals */
25
  MX_GPIO_Init();
26
  MX_DMA_Init();
27
  MX_TIM2_Init();
28
  MX_ADC1_Init();
29
  MX_ADC2_Init();
30
31
  /* USER CODE BEGIN 2 */
32
33
  /* USER CODE END 2 */
34
35
  /* Infinite loop */
36
  /* USER CODE BEGIN WHILE */
37
38
  //TIMER
39
  HAL_TIM_OC_Start_IT(&htim2,TIM_CHANNEL_1) ; //Start Timer 2, Channel 1
40
  HAL_TIM_OC_Start_IT(&htim2,TIM_CHANNEL_2) ; //Start Timer 2, Channel 2
41
  HAL_TIM_OC_Start_IT(&htim2,TIM_CHANNEL_3) ; //Start Timer 2, Channel 3
42
  HAL_TIM_OC_Start_IT(&htim2,TIM_CHANNEL_4) ; //Start Timer 2, Channel 4
43
44
45
  HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED);
46
  HAL_ADCEx_Calibration_Start(&hadc2,ADC_SINGLE_ENDED);
47
48
  HAL_ADCEx_MultiModeStart_DMA(&hadc1, adc_array, 99);
49
50
51
  while (1)
52
  {
53
54
  }
55
  /* USER CODE END 3 */
56
57
}
58
59
/* ADC1 init function */
60
static void MX_ADC1_Init(void)
61
{
62
63
  ADC_MultiModeTypeDef multimode;
64
  ADC_ChannelConfTypeDef sConfig;
65
66
    /**Common config 
67
    */
68
  hadc1.Instance = ADC1;
69
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
70
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
71
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
72
  hadc1.Init.ContinuousConvMode = DISABLE;
73
  hadc1.Init.DiscontinuousConvMode = DISABLE;
74
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
75
  hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T2_TRGO;
76
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
77
  hadc1.Init.NbrOfConversion = 1;
78
  hadc1.Init.DMAContinuousRequests = ENABLE;
79
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
80
  hadc1.Init.LowPowerAutoWait = DISABLE;
81
  hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
82
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
83
  {
84
    _Error_Handler(__FILE__, __LINE__);
85
  }
86
87
    /**Configure the ADC multi-mode 
88
    */
89
  multimode.Mode = ADC_DUALMODE_REGSIMULT;
90
  multimode.DMAAccessMode = ADC_DMAACCESSMODE_12_10_BITS;
91
  multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_1CYCLE;
92
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
93
  {
94
    _Error_Handler(__FILE__, __LINE__);
95
  }
96
97
    /**Configure Regular Channel 
98
    */
99
  sConfig.Channel = ADC_CHANNEL_4;
100
  sConfig.Rank = 1;
101
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
102
  sConfig.SamplingTime = ADC_SAMPLETIME_601CYCLES_5;
103
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
104
  sConfig.Offset = 0;
105
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
106
  {
107
    _Error_Handler(__FILE__, __LINE__);
108
  }
109
110
}
111
112
/* ADC2 init function */
113
static void MX_ADC2_Init(void)
114
{
115
116
  ADC_ChannelConfTypeDef sConfig;
117
118
    /**Common config 
119
    */
120
  hadc2.Instance = ADC2;
121
  hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
122
  hadc2.Init.Resolution = ADC_RESOLUTION_12B;
123
  hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE;
124
  hadc2.Init.ContinuousConvMode = DISABLE;
125
  hadc2.Init.DiscontinuousConvMode = DISABLE;
126
  hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
127
  hadc2.Init.NbrOfConversion = 2;
128
  hadc2.Init.DMAContinuousRequests = ENABLE;
129
  hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
130
  hadc2.Init.LowPowerAutoWait = DISABLE;
131
  hadc2.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
132
  if (HAL_ADC_Init(&hadc2) != HAL_OK)
133
  {
134
    _Error_Handler(__FILE__, __LINE__);
135
  }
136
137
    /**Configure Regular Channel 
138
    */
139
  sConfig.Channel = ADC_CHANNEL_1;
140
  sConfig.Rank = 1;
141
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
142
  sConfig.SamplingTime = ADC_SAMPLETIME_181CYCLES_5;
143
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
144
  sConfig.Offset = 0;
145
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
146
  {
147
    _Error_Handler(__FILE__, __LINE__);
148
  }
149
150
    /**Configure Regular Channel 
151
    */
152
  sConfig.Channel = ADC_CHANNEL_2;
153
  sConfig.Rank = 2;
154
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
155
  {
156
    _Error_Handler(__FILE__, __LINE__);
157
  }
158
159
}
160
161
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
162
{
163
164
  GPIO_InitTypeDef GPIO_InitStruct;
165
  if(hadc->Instance==ADC1)
166
  {
167
  /* USER CODE BEGIN ADC1_MspInit 0 */
168
169
  /* USER CODE END ADC1_MspInit 0 */
170
    /* Peripheral clock enable */
171
    HAL_RCC_ADC12_CLK_ENABLED++;
172
    if(HAL_RCC_ADC12_CLK_ENABLED==1){
173
      __HAL_RCC_ADC12_CLK_ENABLE();
174
    }
175
  
176
    /**ADC1 GPIO Configuration    
177
    PA3     ------> ADC1_IN4 
178
    */
179
    GPIO_InitStruct.Pin = GPIO_PIN_3;
180
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
181
    GPIO_InitStruct.Pull = GPIO_NOPULL;
182
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
183
184
    /* ADC1 DMA Init */
185
    /* ADC1 Init */
186
    hdma_adc1.Instance = DMA1_Channel1;
187
    hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
188
    hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
189
    hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
190
    hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
191
    hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
192
    hdma_adc1.Init.Mode = DMA_CIRCULAR;
193
    hdma_adc1.Init.Priority = DMA_PRIORITY_MEDIUM;
194
    if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
195
    {
196
      _Error_Handler(__FILE__, __LINE__);
197
    }
198
199
    __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1);
200
201
  /* USER CODE BEGIN ADC1_MspInit 1 */
202
203
  /* USER CODE END ADC1_MspInit 1 */
204
  }
205
  else if(hadc->Instance==ADC2)
206
  {
207
  /* USER CODE BEGIN ADC2_MspInit 0 */
208
209
  /* USER CODE END ADC2_MspInit 0 */
210
    /* Peripheral clock enable */
211
    HAL_RCC_ADC12_CLK_ENABLED++;
212
    if(HAL_RCC_ADC12_CLK_ENABLED==1){
213
      __HAL_RCC_ADC12_CLK_ENABLE();
214
    }
215
  
216
    /**ADC2 GPIO Configuration    
217
    PA4     ------> ADC2_IN1
218
    PA5     ------> ADC2_IN2 
219
    */
220
    GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5;
221
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
222
    GPIO_InitStruct.Pull = GPIO_NOPULL;
223
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
224
225
    /* ADC2 DMA Init */
226
    /* ADC2 Init */
227
    hdma_adc2.Instance = DMA1_Channel2;
228
    hdma_adc2.Init.Direction = DMA_PERIPH_TO_MEMORY;
229
    hdma_adc2.Init.PeriphInc = DMA_PINC_DISABLE;
230
    hdma_adc2.Init.MemInc = DMA_MINC_ENABLE;
231
    hdma_adc2.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
232
    hdma_adc2.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
233
    hdma_adc2.Init.Mode = DMA_CIRCULAR;
234
    hdma_adc2.Init.Priority = DMA_PRIORITY_MEDIUM;
235
    if (HAL_DMA_Init(&hdma_adc2) != HAL_OK)
236
    {
237
      _Error_Handler(__FILE__, __LINE__);
238
    }
239
240
    __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc2);
241
242
  /* USER CODE BEGIN ADC2_MspInit 1 */
243
244
  /* USER CODE END ADC2_MspInit 1 */
245
  }
246
247
}

von Robin S. (der_r)


Lesenswert?

Ich habe leider nicht die Zeit und das Board, um dein Problem selber 
nachzuvollziehen. Aber ich weiß, dass bei den BluePill-Boards 
(STM32F103) der D.R.Simultaneous Mode so funktioniert, dass die DMA die 
Werte beider ADC auf das Datenregister von ADC1 vereint (obere 16 Bit = 
ADC2, untere = ADC1) und du sie von dort aus abholst.

Das hatte ich auch schon funktionierend in Betrieb genommen, wenn du 
magst, suche ich mal den Quellcode raus, vielleicht hilft dir das als 
Denkanstoß auch für deinen F3.

von Christopher J. (christopher_j23)


Lesenswert?

Beim F3 ist das ganz ähnlich. Da landen beide Werte im "Common Data 
Register", also in ADC12_CDR bzw. ADC34_CDR, je nachdem ob man ADC1 und 
ADC2 bzw. ADC3 und ADC4 zusammen nutzt. Es gibt dazu von ST jeweils eine 
Appnote "STM32 ADC modes and their applications". Für den F3 wäre das 
diese hier:
www.st.com/resource/en/application_note/dm00069390.pdf

In dem Fall wird das aber nichts mit dem Auslesen aus dem CDR, weil im 
ADC1 nur ein Kanal gesamplet wird und bei ADC2 sind es zwei Kanäle. Das 
macht aber nichts, weil man wie gehabt beide ADCs einzeln auslesen kann, 
d.h. man startet einen DMA-Transfer bei jedem EOC-Ereignis. Aber machst 
du das denn auch? Ich glaube nicht.

Bert S. schrieb:
> multimode.DMAAccessMode = ADC_DMAACCESSMODE_12_10_BITS;

Hier hast du das User Manual für den HAL des F3: 
www.st.com/resource/en/user_manual/dm00122016.pdf

Den ominösen Interrupt-Handler in dem angeblich alles hängenbleibt sehe 
ich übrigens immer noch nicht.

von Bert S. (kautschuck)


Lesenswert?

Zumindest funktioniert jetzt das auslesen beider ADC's mit dem 
Multimode, aber eben nur 1 Channel von ADC2. Das Problem war, dass ich 
den DMA nur im HalfWord Modus betrieben hatte.

Christopher J. schrieb:
> Es gibt dazu von ST jeweils eine
> Appnote "STM32 ADC modes and their applications". Für den F3 wäre das
> diese hier:

Dort steht ja drin, dass man beide DMA verwenden kann, doch ich blicke 
nicht durch wie ich hier denn Multimode starte und zwei verschiedene 
Buffer übergebe? Ich muss das auslesen ja mit folgendem Befehl starten:
1
HAL_ADCEx_MultiModeStart_DMA(&hadc1, adc_array, 100);

Christopher J. schrieb:
> Den ominösen Interrupt-Handler in dem angeblich alles hängenbleibt sehe
> ich übrigens immer noch nicht.

Ich weiss auch nicht warum der gehängt hat, ich habe aber ein neues 
Programm erstellt und jetzt klappts.

von Christopher J. (christopher_j23)


Lesenswert?

Bert S. schrieb:
> ADC_MultiModeTypeDef multimode;

Bert S. schrieb:
> multimode.Mode = ADC_DUALMODE_REGSIMULT;
>   multimode.DMAAccessMode = ADC_DMAACCESSMODE_12_10_BITS;
>   multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_1CYCLE;
>   if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
>   {
>     _Error_Handler(_FILE_, _LINE_);
>   }

Die entsprechende Zeile hatte ich dir sogar vorher schon markiert. Hast 
du eigentlich jemals in den Quelltext der HAL-Funktionen bzw. ins 
User-Manual geschaut? Das würde ich an deiner Stelle mal machen.

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.