Skip to main content
jogerh
Associate III
March 3, 2016
Question

STM32F373RB ADC+DMA+Interrupt

Posted on March 03, 2016 at 17:24

Dear Community

I have an STM32F373RB device and I try to use the DMA to read the ADC1. However the DMA interrupt is not triggered. Since there is no example on the µC how to use DMA and ADC together with interrupt I would be very happy if someone could give a hint what I could check in my next trial and error session.

Initialisation:

void ADC_1_Init() { 
GPIO_InitTypeDef GPIO_InitStructure; 
ADC_InitTypeDef ADC_InitStructure; 
DMA_InitTypeDef DMA_InitStructure; 
NVIC_InitTypeDef NVIC_InitStructure; //DMA Interupt 
// Enable DMA1 clock 
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); 
// Enable ADC1 clock 
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); 
RCC_ADCCLKConfig(RCC_PCLK2_Div4); // this I copied form the ADC_DMA example but I havent checked what it means so far 
//Enable GPIO Clock 
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE); 
// Configure PB.12 (ADC Channel8) in analog mode 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10 --> ADC_IN10 
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; 
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; 
GPIO_Init(GPIOC, &GPIO_InitStructure); 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //PB11 --> ADC_IN11 
GPIO_Init(GPIOC, &GPIO_InitStructure); 
//DMA1 Channel1 configuration 
DMA_DeInit(DMA1_Channel1); 
DMA_InitStructure.DMA_BufferSize = sizeof(ADC1_Buffer); 
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC1_Buffer; 
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; 
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 
DMA_InitStructure.DMA_Priority = DMA_Priority_High; 
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //DMA_Mode_Normal; // 
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; 
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; 
DMA_Init(DMA1_Channel1, &DMA_InitStructure); 
//DMA_IT_TC: Transfer complete interrupt mask 
//DMA_IT_HT: Half transfer interrupt mask 
//DMA_IT_TE: Transfer error interrupt mask 
// Enable DMA1 channel6 IRQ Channel 
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn; 
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ADC_Prio; 
NVIC_InitStructure.NVIC_IRQChannelSubPriority = ADC_subPrio; 
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
NVIC_Init(&NVIC_InitStructure); 
DMA_ITConfig(DMA1_Channel1,DMA_IT_TC, ENABLE); 
DMA_Cmd(DMA1_Channel1, ENABLE); 
// ADC1 configuration 
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //Enable for conti mode 
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //Enable for conti mode 
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2; //Trigger 
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; 
ADC_InitStructure.ADC_NbrOfChannel = 1; 
ADC_Init(ADC1, &ADC_InitStructure); 
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_7Cycles5); 
// Enable ADC1 DMA 
ADC_DMACmd(ADC1, ENABLE); 
//The folowing section is probably obsolete... 
// Enable ADC1 
ADC_Cmd(ADC1, ENABLE); 
// ADC1 reset calibration register 
ADC_ResetCalibration(ADC1); 
while(ADC_GetResetCalibrationStatus(ADC1)); 
// ADC1 calibration start 
ADC_StartCalibration(ADC1); 
while(ADC_GetCalibrationStatus(ADC1)); 
ADC_Cmd(ADC1, ENABLE); 
}

IRQ Handler:

void DMA1_Channel1_IRQHandler() { 
if(DMA_GetFlagStatus(DMA1_IT_TC1) != RESET) { 
ADC_Cmd(ADC1, DISABLE); 
} 
DMA_ClearITPendingBit(DMA1_IT_GL1); 
} 

Call from

DMA2_Channel3_IRQHandler()

: ADC_Cmd(ADC1, ENABLE); PS: This mechanism works on stm32L100 and now I try to migrate this to stm32373 for reaching higher performance.
    This topic has been closed for replies.

    3 replies

    Tesla DeLorean
    Guru
    March 3, 2016
    Posted on March 03, 2016 at 18:28

    Sorry, nobody has provided me with an F373 board,

    For the F3 DISCO, this blind port from a couple of other F3 examples I've posted

    // STM32 ADC 1UP DMA TIM STM32F3-Discovery - sourcer32@gmail.com
    /**************************************************************************************/
    // ADC1 ADC2 ADC3 ADC4
    // IN1 PA0* PA4 PB1 PE14*
    // IN2 PA1 PA5* PE9* PE15*
    // IN3 PA2 PA6* PE13* PB12
    // IN4 PA3 PA7* --- PB14
    // IN5 PF4 PC4 PB13 PB15
    //
    // *Used on STM32F3-Discovery
    // Free pins located in STM32F3-Discovery manual, UM1570
    // ADC1 Trigger EXT3 TIM2_CC2
    // Pins for this example PA1, PA4, PB1, PB12
    /**************************************************************************************/
    #include ''stm32f3_discovery.h''
    #include ''stm32f30x.h''
    /**************************************************************************************/
    #define BUFSIZE 10
    volatile uint16_t ADCConvertedValues[BUFSIZE];
    uint16_t CalibrationValue;
    /**************************************************************************************/
    void ADC_GPIO_Configuration(void)
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    /* Enable GPIOA Periph clock */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
    /* ADC Channels configuration */
    /* Configure PA1 as analog input */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    }
    /**************************************************************************************/
    void ADC12_DMA_Configuration(void)
    {
    DMA_InitTypeDef DMA_InitStructure;
    /* Enable DMA1 clock */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    /* DMA configuration */
    /* DMA1 Channel1 Init Test */
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; // The register of a singular ADC
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValues[0];
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = BUFSIZE;
    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_Medium;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel1, &DMA_InitStructure); // ADC1
    }
    /**************************************************************************************/
    void ADC_Configuration(void)
    {
    ADC_InitTypeDef ADC_InitStructure;
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    volatile int i;
    /* Configure the ADC clocks */
    RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div1);
    /* Enable ADC1/2 clocks */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC12, ENABLE);
    /* ADC GPIO configuration */
    ADC_GPIO_Configuration();
    /* ADC DMA Channel configuration */
    ADC12_DMA_Configuration();
    /* ADC Calibration procedure */
    ADC_VoltageRegulatorCmd(ADC1, ENABLE);
    /* Insert delay equal to 10 µs */
    for(i=0; i<10000; i++);
    ADC_SelectCalibrationMode(ADC1, ADC_CalibrationMode_Single);
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1) != RESET );
    CalibrationValue = ADC_GetCalibrationValue(ADC1);
    /* ADC configuration */
    ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_CommonInitStructure.ADC_Clock = ADC_Clock_AsynClkMode;
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; // Not Multi Mode
    ADC_CommonInitStructure.ADC_DMAMode = ADC_DMAMode_Circular;
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = 10;
    ADC_CommonInit(ADC1, &ADC_CommonInitStructure);
    /* */
    ADC_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Disable; // Triggered
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_3; // ADC1/2 EXT3 TIM2_CC2
    ADC_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_RisingEdge;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_OverrunMode = ADC_OverrunMode_Disable;
    ADC_InitStructure.ADC_AutoInjMode = ADC_AutoInjec_Disable;
    ADC_InitStructure.ADC_NbrOfRegChannel = 1;
    ADC_Init(ADC1, &ADC_InitStructure);
    /* ADC1 regular configuration */
    ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_61Cycles5); // PA1
    /* Configures the ADC DMA */
    ADC_DMAConfig(ADC1, ADC_DMAMode_Circular);
    /* Enable the ADC DMA */
    ADC_DMACmd(ADC1, ENABLE);
    /* Enable ADC1 */
    ADC_Cmd(ADC1, ENABLE);
    /* wait for ADC1 ADRDY */
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_RDY));
    /* Enable the DMA channel */
    DMA_Cmd(DMA1_Channel1, ENABLE);
    /* Start ADC1 Software Conversion */
    ADC_StartConversion(ADC1);
    }
    /**************************************************************************************/
    void TIM2_Configuration(void)
    {
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;
    /* Enable TIM2 Peripheral clock */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_Period = (SystemCoreClock / 50) - 1; // 50 Hz Sample Rate
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    /* PWM1 Mode configuration: Channel 2 */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 10; // Some arbitary width
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC2Init(TIM2, &TIM_OCInitStructure);
    TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);
    TIM_Cmd(TIM2, ENABLE);
    }
    /**************************************************************************************/
    void DMA1_Channel1_IRQHandler(void) // 5 Hz
    {
    /* Test on DMA1 Channel1 Transfer Complete interrupt */
    if(DMA_GetITStatus(DMA1_IT_TC1))
    {
    /* Clear DMA1 Channel1 Half Transfer, Transfer Complete and Global interrupt pending bits */
    DMA_ClearITPendingBit(DMA1_IT_GL1); // DMA1_IT_TC1 would suffice
    STM_EVAL_LEDToggle(LED3); // 2.5 Hz
    }
    }
    /**************************************************************************************/
    void TIM2_IRQHandler(void) // 50 Hz
    {
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
    {
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    STM_EVAL_LEDToggle(LED4); // 25 Hz
    }
    }
    /**************************************************************************************/
    void NVIC_Configuration(void)
    {
    NVIC_InitTypeDef NVIC_InitStructure;
    /* Enable the DMA1 CH1 and TIM2 global Interrupt */
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
    NVIC_Init(&NVIC_InitStructure);
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_Init(&NVIC_InitStructure);
    }
    /**************************************************************************************/
    int main(void)
    {
    /* Initialize LEDs available on STM32F-Discovery board */
    STM_EVAL_LEDInit(LED3);
    STM_EVAL_LEDInit(LED4);
    /* Turn on LD3 */
    STM_EVAL_LEDOn(LED3);
    STM_EVAL_LEDOn(LED4);
    NVIC_Configuration();
    TIM2_Configuration();
    ADC_Configuration();
    /* Enable DMA1 Channel1 Transfer Complete interrupt */
    DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
    /* TIM Interrupts enable */
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    while(1); // Don't want to exit
    }
    /**************************************************************************************/
    #ifdef USE_FULL_ASSERT
    /**
    * @brief Reports the name of the source file and the source line number
    * where the assert_param error has occurred.
    * @param file: pointer to the source file name
    * @param line: assert_param error line source number
    * @retval None
    */
    void assert_failed(uint8_t* file, uint32_t line)
    {
    /* User can add his own implementation to report the file name and line number,
    ex: printf(''Wrong parameters value: file %s on line %d
    
    '', file, line) */
    /* Infinite loop */
    while (1)
    {
    }
    }
    #endif
    /**************************************************************************************/

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    Tesla DeLorean
    Guru
    March 3, 2016
    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    jogerh
    jogerhAuthor
    Associate III
    March 6, 2016
    Posted on March 06, 2016 at 21:00

    Dear community,

    to use the ADC and the DMA together the STM32F373 requires

    ADC_SoftwareStartConv(ADC1); // found by trial and error

    Here is a working initialization for those who are searching for C&P Code (like me):

    void ADC_1_Init() {
    GPIO_InitTypeDef GPIO_InitStructure; 
    ADC_InitTypeDef ADC_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure; //DMA Interupt
    //*******CLOCK enable
    // Enable DMA1 clock 
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    // Enable ADC1 clock 
    RCC_ADCCLKConfig(RCC_PCLK2_Div2); 
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); 
    //Enable GPIO Clock
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
    // Configure PB.12 (ADC Channel8) in analog mode 
    //GPIO init
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PC0 --> ADC_IN10
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOC, &GPIO_InitStructure); 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //PC1 --> ADC_IN11
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    //DMA1 Channel1 configuration 
    DMA_DeInit(DMA1_Channel1); 
    DMA_InitStructure.DMA_BufferSize = sizeof(ADC1_Buffer); 
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC1_Buffer; //(uint32_t)&ADC1->DR
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //DMA_Mode_Normal; //
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);
    //DMA_IT_TC: Transfer complete interrupt mask 
    //DMA_IT_HT: Half transfer interrupt mask 
    //DMA_IT_TE: Transfer error interrupt mask
    // Enable DMA1 channel6 IRQ Channel
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ADC_Prio;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = ADC_subPrio;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    DMA_ITConfig(DMA1_Channel1,DMA_IT_TC, ENABLE);
    DMA_Cmd(DMA1_Channel1, ENABLE);
    // ADC1 configuration 
    ADC_InitStructure.ADC_ScanConvMode = DISABLE; //Enable for multichannel mode
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //Enable for conti mode
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO;// ADC_ExternalTrigConv_T2_CC2; //Trigger 
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 1; 
    ADC_Init(ADC1, &ADC_InitStructure);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_1Cycles5); 
    // Enable ADC1 DMA 
    ADC_DMACmd(ADC1, ENABLE); 
    // Enable ADC1 
    ADC_Cmd(ADC1, ENABLE); 
    // ADC1 reset calibration register 
    ADC_ResetCalibration(ADC1); 
    while(ADC_GetResetCalibrationStatus(ADC1)); 
    //ADC1 calibration start 
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1)); 
    ADC_Cmd(ADC1, ENABLE);
    ADC_SoftwareStartConv(ADC1); //this needs to be called 
    }
    void DMA1_Channel1_IRQHandler() {
    if(DMA_GetFlagStatus(DMA1_IT_TC1) != RESET) {
    ADC_Cmd(ADC1, DISABLE); 
    }
    DMA_ClearITPendingBit(DMA1_IT_GL1); 
    }