STm32, ADC, Continuous Conversion, DMA, Reihenfolge unklar

Gast #5652108
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
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.
Gast
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!

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 7 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.