Forum: Mikrocontroller und Digitale Elektronik ADC + DMA Anwendung, Zeit fehlerhaft


von dotcom (Gast)


Lesenswert?

Guten Tag liebe Community!

Bei der folgenden Anwendung wird das STM32f4 Board verwendet und ich 
benutze die Programmierumgebung KeilUV4.

Ich beschäftige mich schon seit längerer Zeit mit dem Messen 4 
verschiedener Signale, die alle die gleiche Periodendauer haben.
Ich verwende dazu den ADC1 mit 4 verschiedenen Kanälen und dazu brauche 
ich dann den DMA. Ich starte die Wandlung alle 20us, mein Signal hat 
eine Periodendauer T=4,5ms. Es werden 4 Kanäle verwendet und daraus 
ergibt sich eine Buffergröße von 900(Im angehängten Programm 
kommentiert).
Ich habe ein Signal mit einer Peridendauer von 4,5ms angelegt und den 
DMA ausgelesen. Jedoch bekomme ich dann nicht die erwartete 
Periodendauer von 4,5ms sonden ein Signal mit der Periodendauer von etwa 
45ms. Die Amplitude des Signal stimmt mit dem angelegten Signal überein.
Ich habe echt schon viel ausprobiert, jedoch kann ich den Fehler meines 
Programmes nicht finden und darum ist die gewünschte Messung immer 
fehlerhaft.
Ich kann zwar den Sysreload ändern, aber ich verstehe nicht, wieso meine 
Berechnung nicht stimmt.
Wenn ich den Sysreload auf 360 ändere, bekomme ich ein gemessenes Signal 
mit der Periodendauer von 4,8ms. Ich brauche aber unbedingt eine 
Periodendauer von 4,5ms.

Vielen Dank im Voraus für eure Hilfe!
MfG Coman

1
  #include "stm32f429i_discovery_lcd2.h"
2
  #include "stdlib.h"
3
  #include "tm_stm32f4_usart.h"
4
5
6
        #define Sysreload 3600  
7
        // 3600/180MHz = 20us--> Interrupt alle 20us
8
                                    
9
10
        #define Buffergroesse 900      
11
        // Signal hat eine Periodendauer 4,5ms
12
        // 225*20us = 4,5ms
13
        // --> ADC mit 4 Kanäle--> 225*4 = 900
14
15
    void adc1_init(void);  
16
    uint16_t ADC1_result[Buffergroesse];
17
    u16 Transferwerte[Buffergroesse];    
18
19
int main(void)
20
{  
21
  
22
  SysTick_Config(Sysreload);      // IR alle 20us
23
  adc1_init();  
24
  while(1)
25
  {  
26
27
  }
28
29
30
}
31
32
33
void DMA2_Stream0_IRQHandler(void)
34
{
35
36
  DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0); 
37
}
38
39
void SysTick_Handler(void)
40
{
41
42
  ADC_SoftwareStartConv(ADC1);
43
44
}
45
46
void adc1_init(void)
47
{
48
  
49
  GPIO_InitTypeDef   GPIO_InitStruct;                                             
50
  ADC_InitTypeDef  ADC_InitStructure;
51
  ADC_CommonInitTypeDef  ADC_CommonInitStructure;
52
  NVIC_InitTypeDef   NVIC_InitStructure;
53
  DMA_InitTypeDef DMA_InitStructure;
54
55
  
56
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);                          //Takt AHB1 fuer PC freischalten    
57
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);                          //Takt AHB1 fuer PC freischalten    
58
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);                          //Takt APB2 (ADC1) freischalten
59
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
60
61
  
62
/*******Konfigurieren des Ports PC1 (ADC1 Channel11) als analog input **********/
63
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
64
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;
65
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL ;
66
  GPIO_Init(GPIOC, &GPIO_InitStruct);
67
  
68
//PC2 PC1 PA7 PA5 funktionieren für ADC
69
/*******Konfigurieren des Ports PC2 (ADC1 Channel12) als analog input **********/
70
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
71
  GPIO_Init(GPIOC, &GPIO_InitStruct);
72
  
73
/*******Konfigurieren des Ports PA7 (ADC1 Channel7) als analog input **********/
74
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
75
  GPIO_Init(GPIOA, &GPIO_InitStruct);
76
  
77
/*******Konfigurieren des Ports PA5 (ADC1 Channel5) als analog input **********/
78
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
79
  GPIO_Init(GPIOA, &GPIO_InitStruct);
80
  
81
82
  DMA_StructInit(&DMA_InitStructure);
83
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;  
84
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);
85
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC1_result;
86
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
87
  DMA_InitStructure.DMA_BufferSize = Buffergroesse;
88
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
89
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
90
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
91
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
92
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
93
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
94
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
95
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
96
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
97
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
98
  DMA_Init(DMA2_Stream0, &DMA_InitStructure);
99
  DMA_Cmd(DMA2_Stream0, ENABLE);
100
  
101
  DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);
102
103
  // NVIC: IR für ADC einschalten und auf die niedrigste Priorität setzen
104
  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
105
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
106
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0D;
107
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
108
  NVIC_Init(&NVIC_InitStructure);  
109
110
111
/* ----------Allgemeine Initialisierung der ADCs -------------------------------*/
112
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;                        //Nur 1 einzelner ADC
113
  
114
  
115
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;                      //ADC Takt wird auf die hälfte geteilt = *  1/2
116
        
117
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;         //kein DMA  
118
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;     //minimale Verzögerung zwischen 2 Abtastungen    
119
  ADC_CommonInit(&ADC_CommonInitStructure);
120
121
/*------------------ Initialisierung des ADC1  ---------------------------------*/
122
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;                          //12 Bit Auflösung
123
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;                                    // nur ein Kanal
124
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                              // single mode conversion
125
  
126
  //Keine externe Triggerung der Wandlung, 
127
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;  
128
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;  
129
  
130
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                           //Datenausrichtung
131
  ADC_InitStructure.ADC_NbrOfConversion = 4;                                      // nur ein Kanal
132
  ADC_Init(ADC1, &ADC_InitStructure);
133
134
135
/*----------- ADC1 Konfiguration des Kanals (regular group) --------------------*/        
136
  ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_15Cycles);        //Kanal 13, 1. Kanal, minimale Abtastzeit
137
  ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 2, ADC_SampleTime_15Cycles);
138
  ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 3, ADC_SampleTime_15Cycles);
139
  ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 4, ADC_SampleTime_15Cycles);
140
  ADC_DiscModeCmd(ADC1,ENABLE);                                                      //Betriebsart Discontinuos Mode, eig. default
141
142
  
143
  ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
144
145
  ADC_DMACmd(ADC1, ENABLE);
146
  
147
  
148
/* ----------------Enable ADC1 ------------------------------------------------*/
149
  ADC_Cmd(ADC1, ENABLE);
150
}

von dotcom (Gast)


Lesenswert?

suche noch immer nach einer Lösung

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

dotcom schrieb:
> #define Sysreload 3600
>         // 3600/180MHz = 20us--> Interrupt alle 20us

Vergewissere dich erstmal, das das auch stimmt und in 
'system_stm32f4xx.c' auch so gesetzt wird. Für meine 168 Mhz SYSCLK 
steht dazu folgendes drin:
1
#define PLL_M      4
2
#define PLL_N      168
3
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */ 
4
// PLL VCO ist mit dem 8Mhz Quarz: 8/4 * 168 = 336 MHz 
5
// 
6
#define PLL_P      2
7
// SYSCLK = PLL_VCO / PLL_P
du setzt also für 180 MHz PLL_N auf 180 statt auf 168.
Du kannst dir testweise mal ein paar subclocks (AHB oder APB) auf MCO1 
oder MCO2 ausgeben lassen. Auch ein Timer im PWM Modus hilft dir, die 
Clockkonfiguration herauszufinden.

von Ingo L. (corrtexx)


Lesenswert?

Lass doch einfach mal einen Pin in dem Systick Interrupt toggeln. Dann 
müsstest du dort 25kHz messen!

von dotcom (Gast)


Lesenswert?

Hallo, danke für die Antworten!

Ich habe in der system_stm32f4xx.c nachgesehen und folgendes für meinen 
uC(STM32F429l) gefunden.

1
#if defined (STM32F427_437xx) || defined (STM32F429_439xx)
2
  uint32_t SystemCoreClock = 180000000;
3
#endif /* STM32F427_437x || STM32F429_439xx */


Ich habe GPIO_ToggleBits(GPIOB, GPIO_Pin_4) in den Systick_Handler 
geschrieben um ein Signal auszugeben.
Da habe ich gemessen, dass ein Puls 63us hat.

Ich habe den Sysreload auf 1200 gesetzt, nun messe ich 20us.

D.h. ich muss den Sysreload einfach auf 1200 setzen um die gewünschten 
Ergebnisse zu erhalten. Jedoch verstehe ich die Theorie dahinter nicht.
Denn meine Berechnungen müssten eigentlich richtig sein.

Anschließend habe ich GPIO_ToggleBits(GPIOB, GPIO_Pin_4) in den 
DMA2_Stream0_IRQHandler geschrieben.
Bei einem Sysreload von 1200 habe ich jetzt die gewünschten 20us beim 
Systick_Handler. Wenn ich die  Buffergröße von 900 einstelle messe ich 
hier 18ms.

Eigentlich müssen dass aber 4,5ms sein.
Denn:
Buffergröße: 900
Systick_Handler: 20us
Kanäle: 4

D.H. 20us * 225 = 4,5ms
1
/*------------------ Initialisierung des ADC1  ---------------------------------*/
2
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;                          //12 Bit Auflösung
3
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;                                    // nur ein Kanal
4
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                              // single mode conversion
5
  
6
  //Keine externe Triggerung der Wandlung, 
7
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;  
8
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;  
9
  
10
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                           //Datenausrichtung
11
  ADC_InitStructure.ADC_NbrOfConversion = 4;                                      // nur ein Kanal
12
  ADC_Init(ADC1, &ADC_InitStructure);

Laut diesen Einstellungen müsste der uC pro ADC_SoftwareStartConv(ADC1); 
alle 4 Kanäle messen und nicht immer einen.

Als ich das jedoch im Debugger angesehen habe, habe ich festgestellt, 
dass pro ADC_SoftwareStartConv(ADC1); nur ein Wert in den Buffer 
geschrieben wird und nicht 4.

Vielen Dank im Voraus für eure Hilfe!
MfG Coman

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

dotcom schrieb:
> #if defined (STM32F427_437xx) || defined (STM32F429_439xx)
>   uint32_t SystemCoreClock = 180000000;
> #endif /* STM32F427_437x || STM32F429_439xx */

Sehr schön, aber das heisst noch lange nicht, das die PLL auch so 
gesetzt wird. Scroll mal in der Datei runter und suche die Werte, die 
wirklich in die PLL Register geschrieben werden. Wenn du schon dabei 
bist, schau auch gleich mal nach den AHB und APB Prescalern.

> Ich habe den Sysreload auf 1200 gesetzt, nun messe ich 20us.
Scheint also mit 60MHz zu laufen, wenn ich richtig rechne.

von dotcom (Gast)


Lesenswert?

Danke für die schnelle Antwort!

Ich habe in der Datei folgendes für mein Board nachgesehen:
1
#if defined (STM32F427_437xx) || defined (STM32F429_439xx)
2
#define PLL_N      360
3
/* SYSCLK = PLL_VCO / PLL_P */
4
#define PLL_P      2
5
#endif /* STM32F427_437x || STM32F429_439xx */
6
7
8
9
 __I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};

Am Anfang des files steht noch im Kommentar:
1
*                    Supported STM32F42xxx/43xxx devices
2
  *-----------------------------------------------------------------------------
3
  *        System Clock source                    | PLL (HSE)
4
  *-----------------------------------------------------------------------------
5
  *        SYSCLK(Hz)                             | 180000000
6
  *-----------------------------------------------------------------------------
7
  *        HCLK(Hz)                               | 180000000
8
  *-----------------------------------------------------------------------------
9
  *        AHB Prescaler                          | 1
10
  *-----------------------------------------------------------------------------
11
  *        APB1 Prescaler                         | 4
12
  *-----------------------------------------------------------------------------
13
  *        APB2 Prescaler                         | 2
14
  *-----------------------------------------------------------------------------
15
  *        HSE Frequency(Hz)                      | 25000000
16
  *-----------------------------------------------------------------------------
17
  *        PLL_M                                  | 25
18
  *-----------------------------------------------------------------------------
19
  *        PLL_N                                  | 360
20
  *-----------------------------------------------------------------------------
21
  *        PLL_P                                  | 2
22
  *-----------------------------------------------------------------------------
23
  *        PLL_Q                                  | 7
24
  *-----------------------------------------------------------------------------
25
  *        PLLI2S_N                               | NA
26
  *-----------------------------------------------------------------------------
27
  *        PLLI2S_R                               | NA
28
  *-----------------------------------------------------------------------------
29
  *        I2S input clock                        | NA
30
  *-----------------------------------------------------------------------------
31
  *        VDD(V)                                 | 3.3
32
  *-----------------------------------------------------------------------------
33
  *        Main regulator output voltage          | Scale1 mode
34
  *-----------------------------------------------------------------------------
35
  *        Flash Latency(WS)                      | 5
36
  *-----------------------------------------------------------------------------
37
  *        Prefetch Buffer                        | ON
38
  *-----------------------------------------------------------------------------
39
  *        Instruction cache                      | ON
40
  *-----------------------------------------------------------------------------
41
  *        Data cache                             | ON
42
  *-----------------------------------------------------------------------------
43
  *        Require 48MHz for USB OTG FS,          | Disabled
44
  *        SDIO and RNG clock                     |
45
  *-----------------------------------------------------------------------------
46
  *=============================================================================

MfG Coman

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.