Forum: Mikrocontroller und Digitale Elektronik STM32F405 DMA Setup


von Kevin B. (bucki)


Lesenswert?

Heyho liebe Forengemeinde,

ich habe Probleme beim korrekten Konfigurieren des DMA Controllers. Ich 
möchte gern eine kontinuierliche ADC Messung an Channel 14 durchführen 
und die Werte ablegen, um (wenn ich endlich weiter komme..) 48000 Werte 
zu speichern und damit eine FFT durchzuführen. Der ADC ist soweit 
richtig konfiguriert, da ich ohne Nutzung der DMA und über Auslesen des 
Datenregisters die richtigen Werte erhalte. Sobald ich aber versuche den 
DMA zu initialisieren und "auszulesen", erhalte ich nur den 
unveränderten Initialwert des Datenarrays. Der Wert wird also aktuell 
nie neu beschrieben.. ich weiß nur absolut nicht woran es gerade noch 
scheitert. Dazu mal mein Code-Ausschnitt:
1
void ADC_Init(){
2
3
  /*
4
   * Maximum possible ADC frequency = 36MHz, Typical 30MHz
5
   * APB2 Clock prescaler = 2, F_CPU = 168MHz --> APB2_CLK = 84MHz
6
   * 84MHz / 4 = 21 MHz < 30MHz
7
   */
8
  // change prescaler to not exceed 30MHz
9
  ADC->CCR |= ADC_CLOCKPRESCALER_PCLK_DIV4; // clock divider for all ADC's
10
  //ADC1->CR2 |= ADC_CLOCKPRESCALER_PCLK_DIV4; // Clock divider same as Timer divider
11
12
  //enable the ADC Clock
13
  RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
14
  //enable the GPIO port C (Pin_C4) CLK
15
  RCC->APB1ENR |= RCC_AHB1ENR_GPIOCEN;
16
  //enable the DMA1 Controller clock
17
  RCC->APB1ENR |= RCC_AHB1ENR_DMA2EN;
18
19
  //configure GPIO as analog input
20
  GPIOC->MODER |= GPIO_MODER_MODE4_0 | GPIO_MODER_MODE4_1; // set bit 0 & 1 to high --> 11 = analog input
21
22
  // 10bit Resolution should be sufficient enough. Means a conversion rate 13 ADCCLK cycles (3+10bit)
23
  //sampling at Channel IN14
24
  ADC1->CR1 |= ADC_RESOLUTION10b; // Set resolution to 10bit.
25
26
  ADC1->SMPR1 |= ADC_SMPR1_SMP14_1; // set bit 1 to high --> 28 cycles per conversion
27
  // 28+13 ADC_CLK-cycles/conversion = 41/21MHz = 1.95us / sample. --> 1.95us * 48000 samples = 93.7ms / complete sample block#
28
  // --> equals 10 FPS TFT updating-rate (if the FFT is as fast as the ADC conversion)
29
  // 30Hz shall be the lowest FFT frequency --> 30Hz/10FPS = 3 times sampling of the lowest frequency --> Nyquist approved
30
31
  //even without using the scan mode, we need to set a "sequence" so the CPU knows which ADC Channel we want to MUX
32
  // SQ1 = which channel do we want to measure at first in the sequence, SQ2 would mean which channel as second
33
  // Bit 1,2,3 = 01110b = 14 i.e. CHANNEL 14
34
  ADC1->SQR3 |= ADC_SQR3_SQ1_1 | ADC_SQR3_SQ1_2 | ADC_SQR3_SQ1_3;
35
36
  //enable ADC and set it to continous mode
37
  ADC1->CR2 |= ADC_CR2_CONT | ADC_CR2_ADON;
38
39
  //wait power up time minimum of t_Stab = 2-3us
40
  HAL_Delay(1);
41
  //run calibration
42
  ADC1->CR2    |=  1 <<  3;             /* Initialize calibration registers   */
43
  while (ADC1->CR2 & (1 << 3));         /* Wait for initialization to finish  */
44
  ADC1->CR2    |=  1 <<  2;             /* Start calibration                  */
45
  while (ADC1->CR2 & (1 << 2));         /* Wait for calibration to finish     */
46
  ADC1->CR2    |=  1 << 22;             /* Start first conversion             */
47
48
  /* DMA Settings */
49
50
  DMA2_Stream0->PAR |= (uint32_t)(&(ADC1->DR)); // Base address of the peripheral data register from which the data will be read
51
  DMA2_Stream0->M0AR |= (uint32_t)&ADC_value; // Base address of Memory area 0 to which the data will be written.
52
  DMA2_Stream0->NDTR |= 2; // Number of data items to transfer
53
  DMA2_Stream0->CR |= DMA_SxCR_CIRC | DMA_SxCR_MINC | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0; // enable circular mode, Memory Size 01 --> 16bit, Peripheral Size 01 --> 16bit
54
  DMA2_Stream0->CR |= DMA_SxCR_EN; // enable the now fully set up DMA controller
55
56
  ADC1->CR2 |= ADC_CR2_DDS; // enabling a new DMA request after a completed ADC conversion
57
  ADC1->CR2 |= ADC_CR2_DMA; // activate the DMA1 controller specifically for the ADC1
58
59
  ADC1->CR2 |=  ADC_CR2_SWSTART;             /* Start first conversion             */
60
}

Danke schonmal im Voraus! :)

Grüße,
Bucki

von pegel (Gast)


Lesenswert?

Gibt es auch irgendwo ein "(HAL_)DMA_Start"?

von Alex -. (alex796)


Angehängte Dateien:

Lesenswert?

Kevin B. schrieb:
> //enable the DMA1 Controller clock
>   RCC->APB1ENR |= RCC_AHB1ENR_DMA2EN;
DMA2 sitzt an AHB1ENR und nicht APB1ENR?
1
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;

von STM32-Verwender (Gast)


Lesenswert?

Kevin B. schrieb:
> DMA2_Stream0->NDTR |= 2; // Number of data items to transfer

Im NDTR steht die Anzahl an Datenitems, die zu transferieren sind. Hier 
scheinst du eher die Anzahl an Bytes pro Data Item konfiguriert zu 
haben. Also 2 Byte wegen der 10 Bits pro Sample. NDTR müsste in deinem 
Fall 48000 sein.

von Kevin B. (bucki)


Lesenswert?

@ Alex: Loool... oh man, manchmal sieht man echt den Wald vor lauter 
Bäumen nicht.. Alex ich danke dir vielmals, genau das wars! Das ist auch 
an den beiden anderen Clock Defs falsch, nur hatte ich die anscheinend 
schon an anderer Stelle "richtig" initialisiert.

@STM32-Verwender: Danke für die Bemerkung. Hatte es aber noch nicht so 
weit initialisiert, sondern wollte mit einer einzelnen Auslesung erstmal 
die Peripherie korrekt in Betrieb nehmen und dann das alles anpassen. 
Aber natürlich hast du recht. ;)

Grüße,
Bucki

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.