cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F746-discovery, how to define a Transfer Complete Callback function for DMA on Multichannel ADC scan?

Francesco1
Associate
Posted on April 02, 2017 at 18:19

Hi all,

I am developing an application with my STM32F746G-Discovery board; for this application I need to acquire 4 to 6 analog signals from external sensors.

My application uses the Arduino UNO headers on the back of the discovery board to interface with a motor driver shield by Pololu; I was already able to generate the logic and PWM signals to control the motor status, direction and rotation speed by means of an LCD GUI.

Now I need to acquire some analog signals from external sensors, possibly using DMA to transfer ADC samples in memory.

Until now I was able to initialize the ADC and DMA using STM32CubeMX, defining the needed ADC3 channels, associated ranks, working mode and so on.

This is the MX_ADC3_Init function generated by STM32CubeMX:

/* ADC3 init function */

static void MX_ADC3_Init(void)

{

   ADC_ChannelConfTypeDef sConfig;

    /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)

    */

  hadc3.Instance = ADC3;

  hadc3.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8;

  hadc3.Init.Resolution = ADC_RESOLUTION_12B;

  hadc3.Init.ScanConvMode = ENABLE;

  hadc3.Init.ContinuousConvMode = ENABLE;

  hadc3.Init.DiscontinuousConvMode = DISABLE;

  hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;

  hadc3.Init.ExternalTrigConv = ADC_SOFTWARE_START;

  hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;

  hadc3.Init.NbrOfConversion = 2;

  hadc3.Init.DMAContinuousRequests = ENABLE;

  hadc3.Init.EOCSelection = ADC_EOC_SEQ_CONV;

  if (HAL_ADC_Init(&hadc3) != HAL_OK)

  {

    Error_Handler();

  }

    /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.

    */

  sConfig.Channel = ADC_CHANNEL_0;

  sConfig.Rank = 1;

  sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;

  if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)

  {

    Error_Handler();

  }

    /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.

    */

  sConfig.Channel = ADC_CHANNEL_7;

  sConfig.Rank = 2;

  if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)

  {

    Error_Handler();

  }

}

and this is the DMA Init function:

/**

  * Enable DMA controller clock

  */

static void MX_DMA_Init(void)

{

  /* DMA controller clock enable */

  __HAL_RCC_DMA2_CLK_ENABLE();

  /* DMA interrupt init */

  /* DMA2_Stream0_IRQn interrupt configuration */

  HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);

  HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);

}

Using this template code and following some online demos I was able to intercept the single ADC channel conversion complete interrupt but I would like to define a DMA Transfer Complete Callback function to scale all sensors readings using a single function; however I can't figure out how to do this.

I tried to define a custom XferCpltCallback function with this prototype

void myADC_DMA_XferCpltCallback(DMA_HandleTypeDef* hdma_adc)

{

        // ADC readings scaling code

}

and pointing to it inserting this code after the MX_DMA_init() call:

if (HAL_DMA_RegisterCallback(&hdma_adc3, HAL_DMA_XFER_CPLT_CB_ID, myDMA_XferCpltCallback) != HAL_OK)

        return 0;

and then starting the DMA with:

if (HAL_ADC_Start_DMA(&hadc3, (uint32_t*) ADC_BUF, 2) != HAL_OK)

        return 0;

before the infinite loop in the main function.

Debugging the code I can see that both functions return HAL_OK, so I can guess that the callback is correctly registered and that the DMA starts without errors.

However if I put an interrupt at the beginning of the callback function I can see that it is never called and that the ADC samples buffer (ADC_BUF) is never updated.

Can anyone of you give me some hint on how I should define this callback and how I should point to it?

Thanks in advance for any help.

#dma #adc #sdram #multichannel #stm32f746g-discovery
1 ACCEPTED SOLUTION

Accepted Solutions
Francesco1
Associate
Posted on April 05, 2017 at 11:31

OK, after a long debug activity, I found the solution by myself: the problem was caused by the initialization of the external SDRAM bank of the STM32F746G-DISCO by the BSP_SDRAM_Init() function that in my original code was called after the initialization of the DMA with MX_DMA_Init() function.

The external SDRAM is requested by the CMSIS RTOS to manage the GUI on the LCD; with a step-by-step execution I noted that the configuration of DMA2 used to take samples from ADC3 in my application was completely modified after the call to BSP_SDRAM_Init().

Exchanging the relative positions of calls of MX_DMA_Init() and BSP_SDRAM_Init() in the main function solved the problem.

View solution in original post

1 REPLY 1
Francesco1
Associate
Posted on April 05, 2017 at 11:31

OK, after a long debug activity, I found the solution by myself: the problem was caused by the initialization of the external SDRAM bank of the STM32F746G-DISCO by the BSP_SDRAM_Init() function that in my original code was called after the initialization of the DMA with MX_DMA_Init() function.

The external SDRAM is requested by the CMSIS RTOS to manage the GUI on the LCD; with a step-by-step execution I noted that the configuration of DMA2 used to take samples from ADC3 in my application was completely modified after the call to BSP_SDRAM_Init().

Exchanging the relative positions of calls of MX_DMA_Init() and BSP_SDRAM_Init() in the main function solved the problem.