Forum: Mikrocontroller und Digitale Elektronik STm32, ADC, Continuous Conversion, DMA, Reihenfolge unklar


von Michael (Gast)


Lesenswert?

Hallo

Ich möchte Analogwerte mit dem ADC eines STM32-Mikrocontrollers 
auswerten. Dafür möchte ich den ADC im Continuous Conversion Modus 
laufen lassen, die Werte per DMA in den Speicher übertragen lassen und 
von dort zu bestimmten Zeitpunkten lesen und weiter verarbeiten.

Die Grundkonfiguration habe ich mit STM32CubeMX erstellt.:
1
/* USER CODE END 0 */
2
3
ADC_HandleTypeDef hadc1;
4
DMA_HandleTypeDef hdma_adc1;
5
6
/* ADC1 init function */
7
void MX_ADC1_Init(void)
8
{
9
  ADC_ChannelConfTypeDef sConfig = {0};
10
11
  /**Common config 
12
  */
13
  hadc1.Instance = ADC1;
14
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
15
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
16
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
17
  hadc1.Init.ContinuousConvMode = ENABLE;
18
  hadc1.Init.DiscontinuousConvMode = DISABLE;
19
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
20
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
21
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
22
  hadc1.Init.NbrOfConversion = 1;
23
  hadc1.Init.DMAContinuousRequests = ENABLE;
24
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
25
  hadc1.Init.LowPowerAutoWait = DISABLE;
26
  hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
27
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
28
  {
29
    Error_Handler();
30
  }
31
  /**Configure Regular Channel 
32
  */
33
  sConfig.Channel = ADC_CHANNEL_5;
34
  sConfig.Rank = ADC_REGULAR_RANK_1;
35
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
36
  sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
37
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
38
  sConfig.Offset = 0;
39
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
40
  {
41
    Error_Handler();
42
  }
43
44
}
45
46
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
47
{
48
49
  GPIO_InitTypeDef GPIO_InitStruct = {0};
50
  if(adcHandle->Instance==ADC1)
51
  {
52
  /* USER CODE BEGIN ADC1_MspInit 0 */
53
54
  /* USER CODE END ADC1_MspInit 0 */
55
    /* ADC1 clock enable */
56
    __HAL_RCC_ADC1_CLK_ENABLE();
57
  
58
    __HAL_RCC_GPIOC_CLK_ENABLE();
59
    __HAL_RCC_GPIOA_CLK_ENABLE();
60
    __HAL_RCC_GPIOB_CLK_ENABLE();
61
    /**ADC1 GPIO Configuration    
62
    PC0     ------> ADC1_IN6
63
    PC1     ------> ADC1_IN7
64
    PC2     ------> ADC1_IN8
65
    PC3     ------> ADC1_IN9
66
    PA0     ------> ADC1_IN1
67
    PA1     ------> ADC1_IN2
68
    PA4     ------> ADC1_IN5
69
    PA6     ------> ADC1_IN10
70
    PA7     ------> ADC1_IN15
71
    PB0     ------> ADC1_IN11
72
    PB1     ------> ADC1_IN12
73
    PB11     ------> ADC1_IN14 
74
    */
75
    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
76
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
77
    GPIO_InitStruct.Pull = GPIO_NOPULL;
78
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
79
80
    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_6 
81
                          |GPIO_PIN_7;
82
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
83
    GPIO_InitStruct.Pull = GPIO_NOPULL;
84
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
85
86
    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_11;
87
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
88
    GPIO_InitStruct.Pull = GPIO_NOPULL;
89
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
90
91
    /* ADC1 DMA Init */
92
    /* ADC1 Init */
93
    hdma_adc1.Instance = DMA1_Channel1;
94
    hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
95
    hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
96
    hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
97
    hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
98
    hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
99
    hdma_adc1.Init.Mode = DMA_CIRCULAR;
100
    hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
101
    if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
102
    {
103
      Error_Handler();
104
    }
105
106
    __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
107
108
  /* USER CODE BEGIN ADC1_MspInit 1 */
109
110
  /* USER CODE END ADC1_MspInit 1 */
111
  }
112
}

Leider gibt es ein paar Dinge, die ich bis jetzt nicht herausfinden 
konnte:

1.
In welcher Reihenfolge stehen am Ende die Werte der verschiedenen 
ADC-Kanäle im Puffer?
In der Dokumentation steht: "The multichannel, or scan, continuous mode 
can be used to convert some channels successively with the ADC in 
independent mode. With the sequencer, you can configure any sequence of 
up to 16 channels successively with different sampling times and 
different orders. "
Im von STM32CubeMX erzeugten Code wird aber keine Gruppe aus Kanälen mit 
bestimmter Reihenfolge erzeugt.

2.
Warum wird nur Kanal 5 konfiguriert?
Laut Dokumentation kann ja auch im Continuous Conversion Mode jeder 
Kanal unterschiedlich konfiguriert sein.


Gruß
Michael

von Vincent H. (vinci)


Lesenswert?

Michael schrieb:
> 1.
> In welcher Reihenfolge stehen am Ende die Werte der verschiedenen
> ADC-Kanäle im Puffer?
> In der Dokumentation steht: "The multichannel, or scan, continuous mode
> can be used to convert some channels successively with the ADC in
> independent mode. With the sequencer, you can configure any sequence of
> up to 16 channels successively with different sampling times and
> different orders. "
> Im von STM32CubeMX erzeugten Code wird aber keine Gruppe aus Kanälen mit
> bestimmter Reihenfolge erzeugt.

Die Channel-Konfiguration ist jene hier:
1
  /**Configure Regular Channel 
2
  */
3
  sConfig.Channel = ADC_CHANNEL_5;
4
  sConfig.Rank = ADC_REGULAR_RANK_1;
5
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
6
  sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
7
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
8
  sConfig.Offset = 0;
9
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
10
  {
11
    Error_Handler();
12
  }

Rank entspricht dabei dem Index in der Conversion-Sequenz. Für jeden 
Kanal der in der Sequenz landen soll muss HAL_ADC_ConfigChannel 
aufgerufen werden. Also um Beispielsweise Kanal 6 hinzuzufügen würdest 
du schreiben:
1
  sConfig.Channel = ADC_CHANNEL_6;
2
  sConfig.Rank = ADC_REGULAR_RANK_2;
3
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
4
  {
5
    Error_Handler();
6
  }

Weiters musst du ganz oben die Anzahl der Kanäle anpassen, die ist 
aktuell nämlich nur 1.
1
hadc1.Init.NbrOfConversion = 1;


> 2.
> Warum wird nur Kanal 5 konfiguriert?
> Laut Dokumentation kann ja auch im Continuous Conversion Mode jeder
> Kanal unterschiedlich konfiguriert sein.

CubeMX sollte eigentlich auch alle Kanäle Konfigurieren, wenn man jene 
denn entsprechend einstellt.

von Michael (Gast)


Lesenswert?

Vincent H. schrieb:
> Weiters musst du ganz oben die Anzahl der Kanäle anpassen, die ist
> aktuell nämlich nur 1.
> hadc1.Init.NbrOfConversion = 1;

Danke, das war die fehlende Information. Ich dachte, dieser Wert hätte 
bei Continuous Conversion keine Bedeutung.

Vincent H. schrieb:
> CubeMX sollte eigentlich auch alle Kanäle Konfigurieren, wenn man jene
> denn entsprechend einstellt.

Ich hatte nicht einmal Kanal 5 konfiguriert. Keine Ahnung, warum der 
Code dafür erzeugt worden ist.


Danke auf jeden Fall!

von Mike R. (thesealion)


Lesenswert?

Michael schrieb:
> Ich hatte nicht einmal Kanal 5 konfiguriert. Keine Ahnung, warum der
> Code dafür erzeugt worden ist.

Wahrscheinlich ist Kanal 5 der erste ADC Kanal den du ausgewählt hast.
Und so ganz ohne Kanal zum sample wollte CubeMx den ADC dann doch nicht 
konfigurieren :)

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.