Forum: Mikrocontroller und Digitale Elektronik STM32 ADC DMA


von Hanspi (Gast)


Lesenswert?

Ich bin neu auf dem Gebiet und habe eine simple Frage:

Ich habe einen ADC_DMA Transfer eingerichtet um Sensor-Werte einzulesen: 
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC1ConvertedValue, 1)

Das funktioniert um stets die Variable ADC1ConvertedValue zu 
aktualisieren.

Aber wie kann ich die Buffer-Grösse einstellen? Schlussendlich möchte 
ich z.B. 1000 Sensor-Werte mittels DMA speichern, dann einen Interrupt 
erhalten und diese 1000 Werte alle aufs mal verarbeiten.

Vielen Dank und vergebt mir, falls die Frage dumm ist ;-)

von Bernd (Gast)


Lesenswert?

Die Anzahl Sample pro Channel * Channelanzahl kommen bei mir nur im 
Startkommando als Buffergröße vor.
Aber der ADC und der DMA müssen natürlich richtig konfiguriert sein.
Ich sample 4 channel nacheinander in einer "regular group" jeweils 32 
mal hintereinander. Am Ende bekomme ich einen HAL_ADC_ConvCpltCallback() 
wo ich meinen Buffer auswerten kann. Ich stoppe dort den DMA und starte 
ihn später manuell wieder. Je Kanal bilde ich dann über die 32 
gesampelten Werte einen Mittelwert mit dem ich dann weiter arbeite. So 
bekomme ich bei jedem Conversion complete Callback 32 frische Werte je 
Kanal per DMA.


Hier ein paar Codeausschnitte auf einem STM32F429:
1
HAL_ADC_Start_DMA(&hadc3, (uint32_t*)ADC3_DMA_Buffer, ADC3_DMA_BUFFER_SIZE);
2
3
#define ADC3_DMA_NR_OF_CHANNELS  4
4
#define ADC3_DMA_NR_OF_SAMPLES  32  // muss eine Zweierpotenz sein
5
#define ADC3_DMA_BUFFER_SIZE  (ADC3_DMA_NR_OF_CHANNELS * ADC3_DMA_NR_OF_SAMPLES)  // es werden 4 ADC Channel je DMA Aufruf ADC3_DMA_NR_OF_SAMPLES mal gesampelt
6
extern volatile uint16_t ADC3_DMA_Buffer[];
7
8
static void ConfigureDMA2_Stream0(void)
9
{
10
    __DMA2_CLK_ENABLE();
11
    hadc3dma.Instance = DMA2_Stream0;
12
13
    hadc3dma.Init.Channel  = DMA_CHANNEL_2;
14
    hadc3dma.Init.Direction = DMA_PERIPH_TO_MEMORY;
15
    hadc3dma.Init.PeriphInc = DMA_PINC_DISABLE;
16
    hadc3dma.Init.MemInc = DMA_MINC_ENABLE;
17
    hadc3dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
18
    hadc3dma.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
19
    hadc3dma.Init.Mode = DMA_NORMAL;  // DMA_NORMAL is needed to avoid DMA buffer index shift if ADC is not stopped fast enough in continuous mode, if ADC not in continuous mode DMA_CIRCULAR is needed
20
    hadc3dma.Init.Priority = DMA_PRIORITY_HIGH;
21
    hadc3dma.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
22
    hadc3dma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;  // only relevant if FIFO mode enabled
23
    hadc3dma.Init.MemBurst = DMA_MBURST_SINGLE;
24
    hadc3dma.Init.PeriphBurst = DMA_PBURST_SINGLE;
25
26
    HAL_DMA_Init(&hadc3dma);
27
28
    __HAL_LINKDMA(&hadc3, DMA_Handle, hadc3dma);
29
30
    HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
31
    HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
32
}
33
34
// ADC3 init function
35
void MX_ADC3_Init(void)
36
{
37
  ADC_ChannelConfTypeDef sConfig;
38
39
    // Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
40
41
  hadc3.Instance = ADC3;
42
  hadc3.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
43
  hadc3.Init.Resolution = ADC_RESOLUTION_12B;
44
  hadc3.Init.ScanConvMode = ENABLE;      // enables the sampling of a regular group
45
  hadc3.Init.ContinuousConvMode = ENABLE;  // continuous mode is needed to trigger with one DMA start more than one group conversion (but ADC must be disabled manually after DMA stream complete), if ADC not in continuous mode DMA_CIRCULAR is needed
46
  hadc3.Init.DiscontinuousConvMode = DISABLE;
47
  hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
48
  hadc3.Init.ExternalTrigConv = ADC_SOFTWARE_START;
49
  hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;
50
  hadc3.Init.NbrOfConversion = 4;        // Anzahl der ADC channels in regular group
51
  hadc3.Init.DMAContinuousRequests = ENABLE;  // enable, sonst kann der DMA nur einmal gestartet werden
52
  hadc3.Init.EOCSelection = ADC_EOC_SEQ_CONV;  // hat bei DMA vermutlich keinen Einfluss
53
  if (HAL_ADC_Init(&hadc3) != HAL_OK)
54
  {
55
    _Error_Handler(__FILE__, __LINE__);
56
  }
57
58
  __HAL_ADC_DISABLE(&hadc3);  // bei ExternalTrigConv = ADC_SOFTWARE_START eigentlich unnötig, aber vorsichtshalber trotzdemn ADC definitiv anhalten
59
60
    // Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
61
62
  sConfig.Channel = ADC3_CH_ACC_X;
63
  sConfig.Rank = 1;
64
  sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
65
  sConfig.Offset = 0;
66
  if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
67
  {
68
    _Error_Handler(__FILE__, __LINE__);
69
  }
70
71
  sConfig.Channel = ADC3_CH_ACC_Y;
72
  sConfig.Rank = 2;
73
  sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
74
  sConfig.Offset = 0;
75
  if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
76
  {
77
    _Error_Handler(__FILE__, __LINE__);
78
  }
79
80
  sConfig.Channel = ADC3_CH_ACC_Z;
81
  sConfig.Rank = 3;
82
  sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
83
  sConfig.Offset = 0;
84
  if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
85
  {
86
    _Error_Handler(__FILE__, __LINE__);
87
  }
88
89
  sConfig.Channel = ADC3_CH_POTI;
90
  sConfig.Rank = 4;
91
  sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
92
  sConfig.Offset = 0;
93
  if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
94
  {
95
    _Error_Handler(__FILE__, __LINE__);
96
  }
97
98
  ConfigureDMA2_Stream0();
99
100
  ADC3_inited = 1;
101
}
102
103
void DMA2_Stream0_IRQHandler(void)
104
{
105
// end of transfer
106
    HAL_DMA_IRQHandler(&hadc3dma);
107
}
108
109
void ADC_IRQHandler(void)
110
{
111
// seems to be not called with DMA?
112
    HAL_ADC_IRQHandler(&hadc3);
113
}
114
115
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* adcHandle)
116
{
117
  if (adcHandle->Instance == ADC3) {
118
    // Stream transfer complete (can be after multiple ADC group scanns)
119
    __HAL_ADC_DISABLE(adcHandle);  // to interrupt ADC continuous mode
120
    // alle 3ms Start einer neuen ADC DMA Wandlung im HAL_SYSTICK_Callback()
121
    // Wandlung von 4 Kanälen mit den hier gemachten Einstellungen dauert ca.10us
122
123
// die Daten liegen immer so im Buffer ch1 ... ch4, ch1 ... ch4, ...
124
...
125
}
126
127
// einfacher Mittelwert über ADC_DMA_NR_OF_SAMPLES Werte
128
uint16_t md_ADC3_avgDMAvalues(ADC3_NAME_t adc_name) {
129
  uint32_t buffer = 0;
130
  uint16_t retVal;
131
132
  #if (ADC3_DMA_NR_OF_SAMPLES == 1)
133
    uint8_t anz_bit = 0;
134
    return ADC3_DMA_Buffer[adc_name];
135
  #elif (ADC3_DMA_NR_OF_SAMPLES == 2)
136
    uint8_t anz_bit = 1;
137
  #elif (ADC3_DMA_NR_OF_SAMPLES == 4)
138
    uint8_t anz_bit = 2;
139
  #elif (ADC3_DMA_NR_OF_SAMPLES == 8)
140
    uint8_t anz_bit = 3;
141
  #elif (ADC3_DMA_NR_OF_SAMPLES == 16)
142
    uint8_t anz_bit = 4;
143
  #elif (ADC3_DMA_NR_OF_SAMPLES == 32)
144
    uint8_t anz_bit = 5;
145
  #elif (ADC3_DMA_NR_OF_SAMPLES == 64)
146
    uint8_t anz_bit = 6;
147
  #elif (ADC3_DMA_NR_OF_SAMPLES == 128)
148
    uint8_t anz_bit = 7;
149
  #elif (ADC3_DMA_NR_OF_SAMPLES == 256)
150
    uint8_t anz_bit = 8;
151
  #elif (ADC3_DMA_NR_OF_SAMPLES == 512)
152
    uint8_t anz_bit = 9;
153
  #elif (ADC3_DMA_NR_OF_SAMPLES == 1024)
154
    uint8_t anz_bit = 10;
155
  #elif (ADC3_DMA_NR_OF_SAMPLES == 2048)
156
    uint8_t anz_bit = 11;
157
  #elif (ADC3_DMA_NR_OF_SAMPLES == 4096)
158
    uint8_t anz_bit = 12;
159
  #else
160
    #error no valid size for division by shifting
161
  #endif
162
163
  // in ADC_DMA_Buffer liegen immer die 4 ADC Kanäle hintereinander
164
  for (uint32_t i=adc_name; i < ADC3_DMA_BUFFER_SIZE; i=i+ADC3_DMA_NR_OF_CHANNELS) {
165
    buffer += ADC3_DMA_Buffer[i];
166
  }
167
168
  retVal = (buffer >> anz_bit);
169
170
  return retVal;
171
}

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.