cancel
Showing results for 
Search instead for 
Did you mean: 

ADC with DMA in STM32U545 MCU

itzthiru
Associate

I am experiencing issues with the ADC and DMA configuration. Specifically, I am encountering unexpectedly high ADC conversion time despite following the standard configuration steps. Below are the details of my setup and the problem I am facing:

Problem Description

I am using DMA to transfer ADC conversion data with a timer-triggered setup. The expected conversion time based on my configuration is significantly lower than the observed conversion time.

- AHB Clock Frequency to ADC: 4.604 MHz (HSE)

- Clock Prescaler : 2

- Expected ADC Conversion Time: Approximately 23 µs

              Tconv = (sampling time + conversion time)/ADC Clock

              Tconv =  (36+17) / (4.604/2) = 23 µs (Approx)

- Observed Conversion Time: 154 µs

ADC Configuration

static void MX_ADC1_Init(void)

{



ADC_ChannelConfTypeDef sConfig = {0};

 

hadc1.Instance = ADC1;

hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;

hadc1.Init.Resolution = ADC_RESOLUTION_14B;

hadc1.Init.GainCompensation = 0;

hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;

hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;

hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

hadc1.Init.LowPowerAutoWait = ENABLE;

hadc1.Init.ContinuousConvMode = DISABLE;

hadc1.Init.NbrOfConversion = 1;

hadc1.Init.DiscontinuousConvMode = DISABLE;

hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T2_TRGO;

hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;

hadc1.Init.DMAContinuousRequests = ENABLE;

hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;

hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;

hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;

hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;

hadc1.Init.OversamplingMode = DISABLE;

if (HAL_ADC_Init(&hadc1) != HAL_OK)

{

Error_Handler();

}

 

sConfig.Channel = ADC_CHANNEL_1;

sConfig.Rank = ADC_REGULAR_RANK_1;

sConfig.SamplingTime = ADC_SAMPLETIME_36CYCLES;

sConfig.SingleDiff = ADC_SINGLE_ENDED;

sConfig.OffsetNumber = ADC_OFFSET_NONE;

sConfig.Offset = 0;

 

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

{

Error_Handler();

}



if(HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED) != HAL_OK)

Error_Handler();

if(HAL_ADC_Start_DMA(&hadc1, (uint32_t *) adc_sample, 1) != HAL_OK)

Error_Handler();

 

}

 DMA Configuration

void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)

{

GPIO_InitTypeDef GPIO_InitStruct = {0};

DMA_NodeConfTypeDef NodeConfig;

RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

if(hadc->Instance==ADC1)

{

 

PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADCDAC;

PeriphClkInit.AdcDacClockSelection = RCC_ADCDACCLKSOURCE_HSE;

if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)

{

Error_Handler();

}



__HAL_RCC_ADC12_CLK_ENABLE();

__HAL_RCC_GPIOC_CLK_ENABLE();

 

GPIO_InitStruct.Pin = GPIO_PIN_0;

GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;

GPIO_InitStruct.Pull = GPIO_NOPULL;

HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

 

NodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;

NodeConfig.Init.Request = GPDMA1_REQUEST_ADC1;

NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;

NodeConfig.Init.Direction = DMA_PERIPH_TO_MEMORY;

NodeConfig.Init.SrcInc = DMA_SINC_FIXED;

NodeConfig.Init.DestInc = DMA_DINC_INCREMENTED;

NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;

NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;

NodeConfig.Init.SrcBurstLength = 1;

NodeConfig.Init.DestBurstLength = 1;

NodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;

NodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;

NodeConfig.Init.Mode = DMA_NORMAL;

NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;

NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;

NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;

if (HAL_DMAEx_List_BuildNode(&NodeConfig, &Node_GPDMA1_Channel1) != HAL_OK)

{

Error_Handler();

}

if (HAL_DMAEx_List_InsertNode(&List_GPDMA1_Channel1, NULL, &Node_GPDMA1_Channel1) != HAL_OK)

{

Error_Handler();

}

if (HAL_DMAEx_List_SetCircularMode(&List_GPDMA1_Channel1) != HAL_OK)

{

Error_Handler();

}

handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1;

handle_GPDMA1_Channel1.InitLinkedList.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT;

handle_GPDMA1_Channel1.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;

handle_GPDMA1_Channel1.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;

handle_GPDMA1_Channel1.InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;

handle_GPDMA1_Channel1.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;

if (HAL_DMAEx_List_Init(&handle_GPDMA1_Channel1) != HAL_OK)

{

Error_Handler();

}



if (HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel1, &List_GPDMA1_Channel1) != HAL_OK)

{

Error_Handler();

}



__HAL_LINKDMA(hadc, DMA_Handle, handle_GPDMA1_Channel1);



if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel1, DMA_CHANNEL_NPRIV) != HAL_OK)

{

Error_Handler();

}

 

}

}

Trigger Configuration:

The timer is set to trigger the ADC conversion every 250 µs (4 kHz).

Measurement setup:

I have configured a GPIO which will get set and reset inside the ADC Conversion complete callback and Time period elapsed callback functions respectively, and measured the conversion time using Oscilloscope.

Despite the configuration, the ADC conversion time remains at 154 µs, which is much higher than the expected value. I suspect that the DMA transfer time might be contributing to this delay. Could you provide insights on potential reasons for the high conversion time?

3 REPLIES 3
SofLit
ST Employee

Hello @itzthiru ,

In next time, please use </> button to paste your code. I'm editing your post then.

Please review our recommendation on this link on how to post a thread in this community.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
TDK
Guru

Toggling a GPIO is not a good way to measure a single sample. You're measuring mostly overhead which is ruining the calculation.

You can use GPIO, but you need to take 1000 or so samples to reduce the effect of overhead.

Showing the code you used to time would be helpful. You showed some but where the GPIO instructions are.

If you feel a post has answered your question, please click "Accept as Solution".
itzthiru
Associate

Thanks much for the reply. It's making some sense and can you tell me how to verify the Conversion time ?

I am attaching my timer configuration and GPIO toggle part below.

/* USER CODE BEGIN 4 */
static void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = TIMER_PRESCALER;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = sTxRxParams.CountofMasterPeriod;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = sTxRxParams.CountofMasterPulse;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */
  HAL_TIM_PWM_Start_IT(&htim2, TIM_CHANNEL_1 );
  /* USER CODE END TIM2_Init 2 */

}


// GPIO TOGGLING

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);
}

void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);	

}