Skip to main content
Taylor Welsh
Associate II
June 29, 2018
Question

Multi channel ADC with DMA in circular mode using CubeMX and HAL, how do I use the half transfer complete and transfer complete callbacks?

  • June 29, 2018
  • 5 replies
  • 2970 views
Posted on June 29, 2018 at 03:03

I am using the STM32F091. I have been trying to use the ADC with DMA in circular mode writing to a large array for use as a sort of double buffer by shifting the first half of the values out on the half transfer complete callback the the other half on the transfer complete callback. However the documentation is super vague on what these callbacks are called and how they should be used.

Anybody know what these callbacks are called? How would I use them in my main to run code on a 

half transfer and transfer complete interrupt?

 
    This topic has been closed for replies.

    5 replies

    Tesla DeLorean
    Guru
    June 29, 2018
    Posted on June 29, 2018 at 04:05

    STM32Cube_FW_F0_V1.9.0\Projects\STM32F072RB-Nucleo\Examples\ADC\ADC_AnalogWatchdog\Src\main.c

    /**

      * @brief  Conversion complete callback in non blocking mode

      * @param  AdcHandle : ADC handle

      * @note   This example shows a simple way to report end of conversion

      *         and get conversion result. You can add your own implementation.

      * @retval None

      */

    void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *AdcHandle)

    {

    }

    /**

      * @brief  Conversion DMA half-transfer callback in non blocking mode

      * @param  hadc: ADC handle

      * @retval None

      */

    void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)

    {

    }

    STM32Cube_FW_F0_V1.9.0\Projects\STM32F072RB-Nucleo\Examples\ADC\ADC_AnalogWatchdog\Src\stm32f0xx_it.c

    /**

    * @brief  This function handles DMA interrupt request.

    * @param  None

    * @retval None

    */

    void ADCx_DMA_IRQHandler(void)

    {

      HAL_DMA_IRQHandler(AdcHandle.DMA_Handle);

    }

    >>How would I use them in my main to run code on a 

    half transfer and transfer complete interrupt?

     

    Honestly you'd want to do the work in the callback itself (memcpy ?), but if you want to do something in main(), have the callback flag via a 'volatile int'

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    Taylor Welsh
    Associate II
    June 29, 2018
    Posted on June 29, 2018 at 04:29

    Do the 

    HAL_ADC_ConvCpltCallback & 

    HAL_ADC_ConvHalfCpltCallback trigger on the end of conversion/sequence flag or are they tied to the DMA transfer? 

    What I am after, one way or another, is something that triggers when my buffer is half full/full. To keep overhead down that will likely be after 200 or more adc conversion sequences (of 8 channels so 1600 samples or more in the buffer). 

    What I don't want is something that triggers after every conversion sequence (8 samples in buffer), I could probably make this work but I'd rather not have to deal with that overhead.

    you're right it makes more sense to do the work in the callback.   

    Tesla DeLorean
    Guru
    June 29, 2018
    Posted on June 29, 2018 at 05:00

    >>Do the 

    HAL_ADC_ConvCpltCallback & 

    HAL_ADC_ConvHalfCpltCallback trigger on the end of conversion/sequence flag or are they tied to the DMA transfer? 

    I believe it is tied to the DMA, surely something trivially easy to prove.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    T J
    Senior III
    June 29, 2018
    Posted on June 29, 2018 at 07:04

    I can help if you are stuck, I have this running on the '091.

    typedef enum {

        Rs8_Ad1,   // initialised in the Cube

        Rs5_Ad5,

        Rs1_Ad6,

        Rs2_Ad7,

        Rs3_Ad8,

        Rs4_Ad9,

        CurrentSense_Ad13,

        Rs6_Ad14,

        Rs7_Ad15,

        VTemp_Ad16,

        VRef_Ad17,

        VBat_Ad18,

        ADC_ChannelCount,

    } ADCresultsAveColumn_t;

        HAL_ADC_Start_DMA(&hadc, (uint32_t *)ADC_DMABuffer, ADC_ChannelCount);

    I use this callback: I fill a row with this new set of DMAdata

    void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {  // transfer to 16 rows of data

            HAL_ADC_CompleteCycle = true;          // signal foreground to process

            // copy 15 results away now

            for(int i = 0 ; i < ADC_ChannelCount ; i++) {

                //here add 2nd dimension to the array

                HAL_ADC_Channel_Buffer[ADC_RowCounter][i] = ADC_DMABuffer[i];   // AVEColumnSum += HAL_ADC_Channel_Buffer [Ave_ADC_RowCounter][Ave_ADC_ChannelCounter];

            }

            ADC_RowCounter++;                              // for next time through the loop

            if(ADC_RowCounter >= ADC_RowCount) ADC_RowCounter = 0;        

    }
    Cyril FENARD
    ST Employee
    July 3, 2018
    Posted on July 03, 2018 at 12:02

    Hi

    taylor.welsh

    ,

    I share a participation to the following link: 

    https://community.st.com/0D50X00009XkXZ3SAN

    https://community.st.com/0D50X00009XkXZ3SAN

    It gives some details on how callbacks are done in other ADC use-case.

    Hoping this brings some help for your case also.

    Regards.

    Cyril