Forum: Mikrocontroller und Digitale Elektronik ADC mit DMA - Komisches Verhalten - STM32-CubeMx-HAL


von Peter (Gast)


Lesenswert?

Hallo,

ich verwende einen STM32F410RB-Controller und die CubeMx-Libraries.

Unter anderem muss die Software in diesem Projekt 11 ADC-Kanäle 
kontinuierlich messen.
Die primäre Funktion ist jedoch eine andere, für die ich relativ kurze 
Zykluszeiten haben muss.

Da der ADC das System unnötig aufhalten würde (und weils aus meiner 
Sicht sowieso die schönere Lösung als "Polling" ist) wird der DMA 
verwendet um die ADC-Daten in ein Array zu laden.

Nun stelle ich aber teilweise sehr komische Verhaltensweisen fest. 
Einzelne Messungen zeigen extreme Ausreißen (sowohl nach oben als auch 
nach unten um bis zu 50%) obwohl diese eigentlich nicht vorhanden sein 
dürften (ich habs mit dem Oszilloskop nachgeprüft).

Kleinere Schwankungen kann ich mir ja noch vorstellen (Rauschen oder 
so), aber hier muss es fast ein Fehler in meiner Konfiguration bzw. 
meinem Programmablauf geben, den ich leider nicht finde.

Eines vielleicht vorweg: Ein Überlauf bzw. ein Rundungsfehler beim 
Umrechnen vom ADC-Wert kann ich bereits ausschließen.


Meine ADC-Konfig sieht so aus:
1
handle_adc.Instance = ADC1;
2
handle_adc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
3
handle_adc.Init.Resolution = ADC_RESOLUTION_12B;
4
handle_adc.Init.ScanConvMode = ENABLE;
5
handle_adc.Init.ContinuousConvMode = ENABLE;
6
handle_adc.Init.DiscontinuousConvMode = DISABLE;
7
handle_adc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
8
handle_adc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
9
handle_adc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
10
handle_adc.Init.NbrOfConversion = 11;
11
handle_adc.Init.DMAContinuousRequests = ENABLE;
12
handle_adc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
13
if (HAL_ADC_Init(&handle_adc) != HAL_OK) {
14
    system_debugMessage("ADC - Init failed");
15
    system_errorHandler();
16
}

Dann Konfigurier ich mir noch den Sequencer:
1
sConfig.Channel = P12V_MON_AdcChannel;
2
sConfig.Rank = 1;
3
sConfig.SamplingTime = ADC_SAMPLE_TIME;
4
if (HAL_ADC_ConfigChannel(&handle_adc, &sConfig) != HAL_OK) {
5
    system_debugMessage("ADC - Init failed (P12V_MON)");
6
    system_errorHandler();
7
}
Für die anderen 10 Kanäle sieht das dann ähnlich aus.

Dann muss noch der DMA-Konfiguriert werden:
1
handle_dma.Instance = DMA2_Stream0;
2
handle_dma.Init.Channel  = DMA_CHANNEL_0;
3
handle_dma.Init.Direction = DMA_PERIPH_TO_MEMORY;
4
handle_dma.Init.PeriphInc = DMA_PINC_DISABLE;
5
handle_dma.Init.MemInc = DMA_MINC_ENABLE;
6
handle_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
7
handle_dma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
8
handle_dma.Init.Mode = DMA_CIRCULAR;
9
handle_dma.Init.Priority = DMA_PRIORITY_HIGH;
10
handle_dma.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
11
if (HAL_DMA_Init(&handle_dma) != HAL_OK) {
12
    system_debugMessage("ADC - Init failed (DMA)");
13
    system_errorHandler();
14
}
15
16
__HAL_LINKDMA(&handle_adc, DMA_Handle, handle_dma);

Schlussendlich starte ich dann noch die Messung mit
1
HAL_ADC_Start_DMA(&handle_adc, adcResults, 11);
und sollte dann zyklisch die Werte in meinen "adcResults"-Array 
reinkriegen.

Im normal Programmzyklus wird dann geprüft ob die Werte aktualisiert 
wurden und werden dann entsprechend umgerechnet (Der normale 
Programmzyklus ist mit ca. 60us Durchlaufzeit wesentlich schneller als 
der ADC, der ca. 2ms für alle Messungen braucht).
1
if(adcResults[10] != 0) {
2
    //Factor 1:16 (Volt)
3
    states->chan1_mV = (adcResults[0] * 16 * 3300) / 4096;
4
    states->chan2_mV = (adcResults[1] * 16 * 3300) / 4096;
5
6
    //... 
7
8
    adcResults[10] = 0;
9
}

Hat jemand eine Idee was das sein könnte bzw. wie man den Code 
verbessern könnte?

Danke im Voraus!

von Stefan F. (Gast)


Lesenswert?

Peter schrieb:
> adcResults[0] ∙ 16 ∙ 3300

Wenn adcResults ein 16 Bit Integer ist, kann diese Berechnung zu einem 
Überlauf führen. Ändere die 16 in 16L, dann sollte das gehen.

von Peter (Gast)


Lesenswert?

Stefanus F. schrieb:
> Wenn adcResults ein 16 Bit Integer ist, kann diese Berechnung zu einem
> Überlauf führen. Ändere die 16 in 16L, dann sollte das gehen.

Danke für die Antwort.

adcResults ist ein uint32_t. Sollte also kein Problem darstellen.

von offgrid (Gast)


Lesenswert?

Ich habe ein ähnliches Problem bei einem System mit STM32F401RET6. Die 
Ursache dafür sind Störungen auf der Versorgungsspannung, die von einem 
MPPT Laderegler ausgehen. Die einzige, nicht sehr befriedigende 
Massnahme ist bis jetzt ein restart des ADC / DMA. Der STM ADC mit DMA 
scheint ein wesentlich zarteres Pfänzchen zu sein als die ADCs der AVR, 
mit denen ich nie vergleichbare Probleme hatte (bei gleicher Umgebung). 
Der STM selber ist mir übrigens noch nie abgeschmiert.

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.