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 ;-)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.