AnsweredAssumed Answered

Stm32F4: Timer2 trigger ADC, load data into DMA, WRONG frequency!

Question asked by chen.richie on Jan 12, 2015
Latest reply on Mar 7, 2016 by Clive One
Hi all,

I am trying to trigger ADC2 with a timer at around 100kHz. The data will be loaded into DMA. However, the data obtained through DMA has a much higher frequency than the timer.
For the ADC1, I plan to use randomly using ADC_SoftwareStartConv(ADC1).

Could you please give me a hand?

int main(void)
{
    TIM2_Config();
    Config_ADC();
    Config_DMA();
    TIM_Cmd(TIM2, ENABLE);
    while (1);
}
 
void TIM2_Config(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    /* TIM2 clock enable */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    /* Time base configuration */
    //AHB1 runs at 42MHz,
    //timer clock = 84MHz =AHB1 CLK * 2 , since AHB1 PRESC = 4 (!1)
    TIM_Cmd(TIM2, DISABLE);
    TIM_DeInit(TIM2);
    TIM_TimeBaseStructure.TIM_Prescaler = 16; // 84MHz/16 = 5.25MHz
    TIM_TimeBaseStructure.TIM_Period = 42 - 1;  // 5.25MHz/42 = 125kHz(adjust according to analog BP)
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //no division
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    /* TIM IT enable */
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    /* TIM2 TRGO selection */
    TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); // Timer2 will trigger ADC2: ADC_ExternalTrigConv_T2_TRGO
 }
  
void DMA2_Stream2_IRQHandler(void)
{  
    //For double buffer mode: every time this interrupt is entered, only one array is updated
    //Check if the transfer complete interrupt flag has been set
    if(DMA_GetITStatus(DMA2_Stream2, DMA_IT_TCIF2) == SET)
    {
        DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TCIF2);
    }
}
void Config_ADC(void)
{
  ADC_InitTypeDef       ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
  GPIO_InitTypeDef      GPIO_InitStructure;
     
  /* Enable ADC1, ADC2 and GPIO clocks ****************************************/
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
     
  /* Configure ADC1 Channel10 pin as analog input ******************************/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_2; //DC -> PC0; 2k -> PC2
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
    ADC_DeInit();
  /* 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 Init ****************************************************************/
    ADC_StructInit(&ADC_InitStructure);
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//we will convert one time
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//select no external triggering
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfConversion = 1;        //single channel conversion
  ADC_Init(ADC1, &ADC_InitStructure); //INIT ADC1
     
    //Triggered by a timer
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO; //triggered by timer 2
    ADC_Init(ADC2, &ADC_InitStructure); //INIT ADC2
 
    /* ADC2 regular channel configuration *************************************/
  ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_3Cycles); //DC channel
  ADC_RegularChannelConfig(ADC2, ADC_Channel_12, 1, ADC_SampleTime_3Cycles); //2kHz channel
  
  /* Enable DMA request after last transfer (Single-ADC mode) */
  ADC_DMARequestAfterLastTransferCmd(ADC2, ENABLE);
     
  /* Enable ADC1 and ADC2 */
  //ADC_Cmd(ADC1, ENABLE);
    ADC_Cmd(ADC2, ENABLE);
    //Enable ADC DMA command
    ADC_DMACmd(ADC2, ENABLE);
}
 
 
void Config_DMA(void)
{
    //DMA2 Channel 1, stream 2, will be used for ADC 2
    NVIC_InitTypeDef NVIC_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;
     
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);                        //Init DMA clock
    DMA_Cmd(DMA2_Stream2, DISABLE);
    while (DMA2_Stream2->CR & DMA_SxCR_EN);
    DMA_DeInit(DMA2_Stream2);
    //Double buffer mode
    DMA_StructInit(&DMA_InitStructure);
    DMA_InitStructure.DMA_Channel = DMA_Channel_1;//ADC2
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC2 -> DR); //data register address of ADC2
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCDataRec1[0];      //Set the memory1 location
    DMA_InitStructure.DMA_DIR  = DMA_DIR_PeripheralToMemory;                    //Sending data from memory to the peripheral's Tx register
    DMA_InitStructure.DMA_BufferSize  = 960;                                    //Define the number of bytes to send
    DMA_InitStructure.DMA_PeripheralInc  = DMA_PeripheralInc_Disable;           //Don't increment the peripheral 'memory'
    DMA_InitStructure.DMA_MemoryInc  = DMA_MemoryInc_Enable;                    //Increment the memory location
    DMA_InitStructure.DMA_PeripheralDataSize  = DMA_PeripheralDataSize_HalfWord;//HalfWord size memory transfers
    DMA_InitStructure.DMA_MemoryDataSize  = DMA_PeripheralDataSize_HalfWord;    //HalfWord size memory transfers
    DMA_InitStructure.DMA_Mode  = DMA_Mode_Circular;                            //circular mode
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
    DMA_InitStructure.DMA_Priority  = DMA_Priority_High;                        //Priority is high to avoid saturating the FIFO since we are in direct mode
    DMA_InitStructure.DMA_FIFOMode  = DMA_FIFOMode_Enable;                      //FIFO enabled
    DMA_InitStructure.DMA_MemoryBurst =DMA_MemoryBurst_INC8;
    DMA_InitStructure.DMA_PeripheralBurst =DMA_PeripheralBurst_Single;
    DMA_Init(DMA2_Stream2, &DMA_InitStructure);                                
    //Enable the transfer complete interrupt for DMA2 Stream2
    DMA_ITConfig(DMA2_Stream2, DMA_IT_TC, ENABLE);                              //Enable the Transfer Complete interrupt   
 
    //Enable Double buffer mode
    DMA_DoubleBufferModeConfig(DMA2_Stream2, (uint32_t)&ADCDataRec2[0], DMA_Memory_0);
    DMA_DoubleBufferModeCmd(DMA2_Stream2, ENABLE);
     
    //Enable the DMA2 Stream2 (SPI1_RX) Interrupt
    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
     
    //Enable DMA
    DMA_Cmd(DMA2_Stream2, ENABLE); 
}
 
void TIM2_IRQHandler(void)
{
  if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
  {
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
  }
}

Outcomes