Hi zusammen,
ich hoffe mir kann hier jemand helfen!
Ich versuche per DMA die Werte des ADC1 einzulesen und abzuspeichern. Dabei soll der ADC1 per Timer2 getriggert werden (ich möchte eine bestimmte Abtastfrequenz einstellen können).
Zusätzlich soll double-buffering konfiguriert werden.
Folgendes hab ich:
zwei Arrays
meine setup-Funktion für den ADC1, TIM2, DMA2:
Mein Interrupt der DMA:
Habe im Interrupt zu Beginn ein GPIO auf SET und am Ende auf RESET um am Oszi den Verlauf zu sehen. Und hier kommt mein Problem:
Es ist vollkommen egal, wie ich den Timer einstelle (Prescaler und Period), am Oszi lese ich immer einen Takt von 1,8kHz ab, da der Interrupt nur alle 1000 Werte kommt arbeitet der ADC also mit 1,8MHz. Ziel sind 48kHz.
Ich komm einfach nicht darauf, was ich bei der Konfiguration falsch gemacht oder vergessen habe.
Hat jemand von euch einen Tipp? Wäre top, bin ein wenig am Verzweifeln.
Danke schon mal!
Markus
ich hoffe mir kann hier jemand helfen!
Ich versuche per DMA die Werte des ADC1 einzulesen und abzuspeichern. Dabei soll der ADC1 per Timer2 getriggert werden (ich möchte eine bestimmte Abtastfrequenz einstellen können).
Zusätzlich soll double-buffering konfiguriert werden.
Folgendes hab ich:
zwei Arrays
Code:
#define ADC_BUFFER_SIZE 1000
uint16_t adc_buffer_0[ADC_BUFFER_SIZE]={0};
uint16_t adc_buffer_1[ADC_BUFFER_SIZE]={0};
meine setup-Funktion für den ADC1, TIM2, DMA2:
Code:
void setupADC1()
{
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
DMA_InitTypeDef DMA_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBase_InitStructure;
TIM_OCInitTypeDef OC_InitDef;
// Clocks für DMA2, ADC1, TIM2, GPIOC->PC3
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// DMA2 Stream0 globaler Interrupt-Channel konfigurieren
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// Timer2 globaler Interrupt konfigurieren
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// DMA2 Stream0 channel0 --> ADC1 (alternativ DMA2 Stream4 Channel0)
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&adc_buffer_0;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = ADC_BUFFER_SIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
//DMA2 Stream0 DoubleBuffer
DMA_DoubleBufferModeConfig(DMA2_Stream0, (uint32_t)&adc_buffer_1, DMA_Memory_0);
DMA_DoubleBufferModeCmd(DMA2_Stream0, ENABLE);
//<--muss evtl nach DMA-Start?!??
//DMA2 Stream0 starten
DMA_Cmd(DMA2_Stream0, ENABLE);
//DMA bestimmte Interrupts anschalten (Transmission complete)
//DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_HT, ENABLE);
DMA_ITConfig(DMA2_Stream0, DMA2_Stream0_IRQn, ENABLE); //alle Interrupts an
// ADC1 Channel13 pin (PC3)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
//Timer2 als Trigger des ADC1
//RCC_PCLK1Config (RCC_HCLK_Div1);
TIM_TimeBaseStructInit(&TIM_TimeBase_InitStructure); //auf standard stellen
TIM_TimeBase_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBase_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBase_InitStructure.TIM_Period = 1750-1; //-->84MHz bzw der Takt von TIM2 wird vorgeteilt auf 21MHz (glaub ich)
TIM_TimeBase_InitStructure.TIM_Prescaler = 1000-1;
TIM_TimeBaseInit(TIM2, &TIM_TimeBase_InitStructure);
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
//Timer noch nicht starten
//TIM_Cmd(TIM2, ENABLE);
// ADC Common Init
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
// ADC1
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStructure);
// ADC1 Channel13
ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 1, ADC_SampleTime_3Cycles); //evtl auch ADC_SampleTime_15Cycles?!?
// Alles einschalten
// DMA Request nachdem ADC1 fertig
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
// ADC1 DMA anschalten
ADC_DMACmd(ADC1, ENABLE);
// ADC1 anschalten
ADC_Cmd(ADC1, ENABLE);
//------------------------------------------------brauch ich das?!?
//ADC_SoftwareStartConv(ADC1);
//ich glaube ich muss nur den Timer starten
TIM_Cmd(TIM2, ENABLE);
}
Mein Interrupt der DMA:
Code:
//DMA2 Stream0 Channel0 --> ADC1
extern "C" void DMA2_Stream0_IRQHandler(void)
{
GPIO_SetBits(GPIOD,GPIO_Pin_13);
//Übertragung komplett fertig (ein Buffer vollständig beschrieben)
if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0) != RESET)
{
//TIM_Cmd(TIM2, DISABLE);
//Bit zurücksetzen
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
//Flag setzten, welche Buffer jetzt bearbeitet werden darf
if (flag_adc_buffer)
flag_adc_buffer=0;
else
flag_adc_buffer=1;
flag_adc_copy_ready=1; //ADC ist fertig, buffer kann bearbeitet werden
//Software-Interrupt für Filter und Buffer kopieren starten
EXTI_GenerateSWInterrupt(EXTI_Line0);
//-->und weiter gehts
//TIM_Cmd(TIM2, ENABLE);
}
if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_HTIF0) != RESET)
{
//Bit zurücksetzen
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_HTIF0);
}
GPIO_ResetBits(GPIOD,GPIO_Pin_13);
}
Habe im Interrupt zu Beginn ein GPIO auf SET und am Ende auf RESET um am Oszi den Verlauf zu sehen. Und hier kommt mein Problem:
Es ist vollkommen egal, wie ich den Timer einstelle (Prescaler und Period), am Oszi lese ich immer einen Takt von 1,8kHz ab, da der Interrupt nur alle 1000 Werte kommt arbeitet der ADC also mit 1,8MHz. Ziel sind 48kHz.
Ich komm einfach nicht darauf, was ich bei der Konfiguration falsch gemacht oder vergessen habe.
Hat jemand von euch einen Tipp? Wäre top, bin ein wenig am Verzweifeln.
Danke schon mal!
Markus