AnsweredAssumed Answered

TIM triggered ADC DMA issue

Question asked by Luke on May 13, 2016
Latest reply on May 16, 2016 by FTITI.Walid
Hi all,
I am using an STM32F303 to sample PA7 via ADC2 when TIM8 update triggers it, and using DMA to put the samples in a circular buffer. Although I seem to have gotten things basically working in the code below, I am having an issue once the DMA buffer is filled... I seem to be getting regular samples updating in the buffer with each TIM8_UP interrupt, but this stops once the buffer is filled and does not cycle back to the start of the buffer as would be expected from the circular mode on the DMA.
Any ideas what I am doing wrong?

uint16_t adc[8];
void init_adc() {
     ADC_CommonInitTypeDef ADC_CommonInitStructure;
     ADC_InitTypeDef ADC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;


    // Activate clocks
    RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div2);
     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC12, ENABLE);
     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);

     // Timer
    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseStructure.TIM_Period = 1999;
    TIM_TimeBaseStructure.TIM_Prescaler = 8000;
    TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);
    TIM_SelectOutputTrigger(TIM8,TIM_TRGOSource_Update);
     //TIM_SelectMasterSlaveMode(TIM8, TIM_MasterSlaveMode_Enable);
    TIM_ITConfig(TIM8, TIM_IT_Update, ENABLE);

    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = TIM8_UP_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
    NVIC_Init(&NVIC_InitStructure);

     // Analog input PA7 -> ADC2_IN4
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
    GPIO_Init(GPIOA, &GPIO_InitStructure);


    // Capture DMA
    DMA_InitTypeDef DMA_InitStructure;
     DMA_DeInit(DMA2_Channel1);
     DMA_StructInit(&DMA_InitStructure);
     DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(adc);
     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC2->DR));
     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
     DMA_InitStructure.DMA_BufferSize = 8;
     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_Init(DMA2_Channel1, &DMA_InitStructure);
     DMA_Cmd(DMA2_Channel1, ENABLE);

     // Init struct
     ADC_StructInit(&ADC_InitStructure);
     ADC_CommonStructInit(&ADC_CommonInitStructure);

     ADC_Cmd(ADC2, DISABLE);
     ADC_DeInit(ADC2);

     // Initialize the ADC
     ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
     ADC_CommonInitStructure.ADC_Clock = ADC_Clock_SynClkModeDiv2;//ADC_Clock_AsynClkMode;//
     ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;//ADC_DMAAccessMode_1;//
     ADC_CommonInitStructure.ADC_TwoSamplingDelay = 0;//0x05;// ADC_TwoSamplingDelay_5Cycles;
     ADC_CommonInit(ADC2, &ADC_CommonInitStructure);


     // ADC2 init
     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
     ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//ENABLE;//
     //ADC_InitStructure.ADC_ScanConvMode = ENABLE;
     ADC_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_7;//TIM8_TRGO
     ADC_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_RisingEdge;//BothEdge;//None;//
     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
     ADC_InitStructure.ADC_OverrunMode = DISABLE;//ENABLE;//
     ADC_InitStructure.ADC_AutoInjMode = DISABLE;//ENABLE;//
     ADC_InitStructure.ADC_NbrOfRegChannel = 1;
     ADC_Init(ADC2, &ADC_InitStructure);


     // Configure channel (ADC2_IN4 <- PA7)
     ADC_RegularChannelConfig(ADC2, ADC_Channel_4, 1, ADC_SampleTime_19Cycles5);//1Cycles5);


     ADC_DMACmd(ADC2, ENABLE);
     ADC_Cmd(ADC2, ENABLE);
     TIM_Cmd(TIM8, ENABLE);

     ADC_StartConversion(ADC2);
}


void show_adc() {
     //uint32_t w = (uint32_t)adc[0];
     USART_word((uint32_t)adc[0]);
     USART_word((uint32_t)adc[1]);
     USART_word((uint32_t)adc[2]);
     USART_word((uint32_t)adc[3]);
     USART_word((uint32_t)adc[4]);
     USART_word((uint32_t)adc[5]);
     USART_word((uint32_t)adc[6]);
     USART_word((uint32_t)adc[7]);
     //USART_word(ADC2->DR);
}
void TIM8_UP_IRQHandler() {
        TIM_ClearITPendingBit(TIM8, TIM_IT_Update);
        show_adc();
}

Outcomes