von
kuds (Gast)
23.05.2016 21:01
Hi,
ich habe ein STM32F407 und möchte die drei onboard-ADCs mit einem Timer
(TIM2) getriggert via DMA (DMA2, Stream 4, Channel 0) auslesen. (Ein
ganz ähnliches Problem hatten wir hier schonmal
Beitrag "stm32F4 + ADC + Timer + DMA" )
Mein Timer läuft mit den Einstellungen in unten stehendem Code mit genau
100Hz. Das habe ich auch mit einem "normalen" Interrupt getestet und
nachgemessen.
In meiner DMA-Konfiguration verwende ich den TripleADC-Modus.
Das Problem ist, dass der DMA-Interrupt-Handler viel häufiger aufgerufen
wird als er sollte... Ich denke also irgendwas läuft mit der Triggerung
falsch oder ich muss an irgendeiner Stelle was deaktivieren. Ich weiß
nur nicht wo.
Meine Funktion zum Konfigurieren des Timers: 1 void timer_init ()
2 {
3 RCC_APB1PeriphClockCmd ( RCC_APB1Periph_TIM2 , ENABLE );
4 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure ;
5 TIM_TimeBaseStructure . TIM_Period = 99 ; //diese kombi aus Period und Prescaler gibt 100 HZ (ist getestet!)
6 TIM_TimeBaseStructure . TIM_Prescaler = 2099 ;
7 TIM_TimeBaseStructure . TIM_ClockDivision = 0 ;
8 TIM_TimeBaseStructure . TIM_CounterMode = TIM_CounterMode_Up ;
9 TIM_TimeBaseInit ( TIM2 , & TIM_TimeBaseStructure );
10
11 TIM_SelectOutputTrigger ( TIM2 , TIM_TRGOSource_Update );
12 }
Meine Funktion zur Konfiguration des DMAs: 1 void PDHADC_DMA_init ()
2 {
3 RCC_AHB1PeriphClockCmd ( RCC_AHB1Periph_DMA2 , ENABLE ); // Enable the DMA clock
4
5 // Enable the DMA Stream IRQ Channel
6 NVIC_InitTypeDef NVIC_InitStructure ;
7 NVIC_InitStructure . NVIC_IRQChannel = DMA2_Stream4_IRQn ;
8 NVIC_InitStructure . NVIC_IRQChannelPreemptionPriority = 0 ;
9 NVIC_InitStructure . NVIC_IRQChannelSubPriority = 0 ;
10 NVIC_InitStructure . NVIC_IRQChannelCmd = ENABLE ;
11 NVIC_Init ( & NVIC_InitStructure );
12
13 DMA_InitTypeDef DMA_InitStructure ;
14
15 DMA_Cmd ( DMA2_Stream4 , DISABLE );
16 DMA_DeInit ( DMA2_Stream4 );
17
18 // Set the parameters to be configured
19 DMA_InitStructure . DMA_Channel = DMA_Channel_0 ; //use channel 0
20 DMA_InitStructure . DMA_PeripheralBaseAddr = ( uint32_t ) & ADC -> CDR ; // Read from common mode register
21 DMA_InitStructure . DMA_Memory0BaseAddr = ( uint32_t ) & PDHADC_buffer [ 0 ]; // Send the data to the RAM buffer
22 DMA_InitStructure . DMA_DIR = DMA_DIR_PeripheralToMemory ; // periphery -- into --> memory
23 DMA_InitStructure . DMA_BufferSize = 3 ; //einfachster fall: DMA sollte nach einer Triple-ADC-Konversion auslösen.
24 DMA_InitStructure . DMA_PeripheralInc = DMA_PeripheralInc_Disable ; //the periphery address stays the same
25 DMA_InitStructure . DMA_MemoryInc = DMA_MemoryInc_Enable ; //but the memory address is incremented (buffer[0], buffer[1], ... buffer[BUFFER_SIZE])
26 DMA_InitStructure . DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord ; //16bit=Half Word (the actual data are only 12 bits)
27 DMA_InitStructure . DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord ; //buffer type is also 16bit.
28 DMA_InitStructure . DMA_Mode = DMA_Mode_Circular ; //if one reaches the end start from 0 again
29 DMA_InitStructure . DMA_Priority = DMA_Priority_Medium ;
30 DMA_InitStructure . DMA_FIFOMode = DMA_FIFOMode_Disable ;
31 DMA_InitStructure . DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull ;
32 DMA_InitStructure . DMA_MemoryBurst = DMA_MemoryBurst_Single ;
33 DMA_InitStructure . DMA_PeripheralBurst = DMA_PeripheralBurst_Single ;
34 DMA_Init ( DMA2_Stream4 , & DMA_InitStructure ); //write the configuration
35
36 DMA_ITConfig ( DMA2_Stream4 , DMA_IT_TC , ENABLE ); // Enable DMA Transfer Complete (TC) interrupt
37 }
und der zugehörige Interrupt-Handler:
1 extern "C" void DMA2_Stream4_IRQHandler ( void )
2 {
3 if ( DMA_GetITStatus ( DMA2_Stream4 , DMA_IT_TCIF4 ))
4 {
5 //hier kommt spaeter noch was hin...
6 DMA_ClearITPendingBit ( DMA2_Stream4 , DMA_IT_TCIF4 );
7 }
8 }
Meine Funktion zur Konfiguration des Triple-ADC:
1 void ADC_init ()
2 {
3 //create init structures
4 GPIO_InitTypeDef GPIO_InitStructure ;
5 ADC_InitTypeDef ADC_InitStructure ;
6 ADC_CommonInitTypeDef ADC_CommonInitStructure ;
7
8 //configure ADC_Common
9 ADC_CommonInitStructure . ADC_Mode = ADC_TripleMode_RegSimult ; //ADC1 as master, ADC2+3 as slaves
10 ADC_CommonInitStructure . ADC_Prescaler = ADC_Prescaler_Div2 ; //default
11 ADC_CommonInitStructure . ADC_DMAAccessMode = ADC_DMAAccessMode_1 ; //ADC1[0], ADC2[0], ADC3[0], ADC1[1], ADC2[1]...
12 ADC_CommonInitStructure . ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles ;
13 ADC_CommonInit ( & ADC_CommonInitStructure );
14
15 RCC_AHB1PeriphClockCmd ( RCC_AHB1Periph_GPIOA , ENABLE ); //enable clocks for ADC pins (A0, A1, A2)
16 RCC_APB2PeriphClockCmd ( RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC3 | RCC_APB2Periph_ADC3 , ENABLE ); //enable clock for ADCs itself
17
18 //configure ADC pins is analog input.
19 GPIO_InitStructure . GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 ;
20 GPIO_InitStructure . GPIO_Mode = GPIO_Mode_AIN ;
21 GPIO_InitStructure . GPIO_PuPd = GPIO_PuPd_NOPULL ;
22 GPIO_Init ( GPIOA , & GPIO_InitStructure );
23
24 ADC_InitStructure . ADC_Resolution = ADC_Resolution_12b ; //12bit
25 ADC_InitStructure . ADC_ScanConvMode = DISABLE ; //only 1 channel per ADC --> no scan
26 ADC_InitStructure . ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising ; //trigger on rising edge of trigger event
27 ADC_InitStructure . ADC_ContinuousConvMode = DISABLE ; //only one conversion per trigger event?
28 ADC_InitStructure . ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO ; //triggered by TIM2
29 ADC_InitStructure . ADC_DataAlign = ADC_DataAlign_Right ; // 0b0000(Bit12)(Bit11)....(Bit0) with Bit12 being MSB
30 ADC_InitStructure . ADC_NbrOfConversion = 1 ; //only one channel per ADC
31
32 ADC_Init ( ADC1 , & ADC_InitStructure ); //master
33 //hier bin ich unsicher... kann ich mit dem selben struct auch ADC2 und ADC3 (die slaves) initialisieren?
34 ADC_Init ( ADC2 , & ADC_InitStructure );
35 ADC_Init ( ADC3 , & ADC_InitStructure );
36
37 ADC_RegularChannelConfig ( ADC1 , ADC_Channel_0 , 1 , ADC_SampleTime_15Cycles );
38 ADC_RegularChannelConfig ( ADC2 , ADC_Channel_1 , 1 , ADC_SampleTime_15Cycles );
39 ADC_RegularChannelConfig ( ADC3 , ADC_Channel_2 , 1 , ADC_SampleTime_15Cycles );
40
41 ADC_MultiModeDMARequestAfterLastTransferCmd ( ENABLE );
42 }
Ich starte mein Programm folgendermaßen: 1 ...
2 timer_init ();
3 dma_init ();
4 adc_init ();
5
6 ...
7 TIM_Cmd ( TIM2 , ENABLE );
8 DMA_Cmd ( DMA2_Stream4 , ENABLE );
9 ADC_DMACmd ( ADC1 , ENABLE );
10 //ADC_DMACmd(ADC2, ENABLE); //die slaves hier brauch ich nicht, oder?
11 //ADC_DMACmd(ADC3, ENABLE);
12
13 ADC_Cmd ( ADC1 , ENABLE );
14 ADC_Cmd ( ADC2 , ENABLE );
15 ADC_Cmd ( ADC3 , ENABLE );
16 ADC_SoftwareStartConv ( ADC1 );
17 ...
Wie gesagt: Das Problem ist, dass der DMA Interrupt-Handler viel zu
häufig aufgerufen wird; also viel häufiger als 100Hz, die der TIM2
vorgeben sollte. Die Kopplung von Timer und ADC/DMA scheint also nicht
zu funktionieren. Habt ihr eine Idee?
Vielen Dank für eure Hilfe!
von
kuds (Gast)
25.05.2016 12:59
Lösung selbst gefunden. Für alle, die ein ähnliches Problem haben:
Es kommt auf die Initialisierungsreihenfolge an!
Folgende Reihenfolge funktioniert bei mir:
1. RCC
2. NVIC
3. DMA
4. GPIO
5. TIM
6. ADC
von
kuds (Gast)
25.05.2016 13:00
und das
ADC_DMACmd(ADC1, ENABLE)
braucht man NICHT!
von
Marcus H.
(Firma: www.harerod.de)
(lungfish )
25.05.2016 14:04
kuds schrieb:
> Lösung selbst gefunden. Für alle, die ein ähnliches Problem haben:
> Es kommt auf die Initialisierungsreihenfolge an!
> Folgende Reihenfolge funktioniert bei mir:
> 1. RCC
> 2. NVIC
> 3. DMA
> 4. GPIO
> 5. TIM
> 6. ADC
Mmmh, spontan hätte ich die Initialisierung in dieser Reihenfolge
durchgeführt:
1. RCC <- Power!
4. GPIO <- Portpins aktivieren
6. ADC <- ADC parametrieren
2. NVIC <- Interrupt-System parametrieren
3. DMA <- DMA Kanäle parametrieren
5. TIM <- Timer loslaufen lassen
25.05.2016 14:04 :
Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.