cancel
Showing results for 
Search instead for 
Did you mean: 

STM32U575ZI Configuring ADC1 with GPDMA (without Linked List)

TTaie.1
Associate II

Hi !

I'm trying to configure the ADC1 to 7 ranks conversion and a GPDMA1 channel (0) in "Standard Request Mode" to transfer the ADC data into the memory.

First, I've configured the ADC without GPDMA channel, and it worked fine (Polling mode, no interrupts).

Then, I tried to configure the GPDMA channel, and got stuck on a situation that the GPDMA transfers only one byte of the data of the ADC, and it moves the data only on the first element of my memory buffer (destination of DMA not incrementing).

Notice that I do get a "TC" and "HT" interrupts and not getting any of the errors interrupts, I'll be glad to get some help with that.

Here's my code (using the LL_Drivers):

LL_DMA_LinkNodeTypeDef Node_GPDMA1_Channel0;

/* ADC data buffer */
__attribute__ ((aligned (32))) unsigned short pusAdcData[7];

/* GPDMA Clock enable */

LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPDMA1);

/* ADC and DMA configurations */

static void MX_ADC1_Init(void)
{
 
  /* USER CODE BEGIN ADC1_Init 0 */
 
  LL_DMA_DisableChannel(GPDMA1, LL_DMA_CHANNEL_0);
  /* USER CODE END ADC1_Init 0 */
 
  LL_ADC_CommonInitTypeDef ADC_CommonInitStruct = {0};
  LL_ADC_InitTypeDef ADC_InitStruct = {0};
  LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
 
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
  LL_DMA_InitNodeTypeDef NodeConfig = {0};
  LL_DMA_InitLinkedListTypeDef DMA_InitLinkedListStruct = {0};
 
  LL_RCC_SetADCDACClockSource(LL_RCC_ADCDAC_CLKSOURCE_SYSCLK);
 
  /* Peripheral clock enable */
  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_ADC12);
 
  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
  /**ADC1 GPIO Configuration
  PA3   ------> ADC1_IN8
  PA5   ------> ADC1_IN10
  PA4   ------> ADC1_IN9
  PB1   ------> ADC1_IN16
  PA2   ------> ADC1_IN7
  PB2   ------> ADC1_IN17
  PB0   ------> ADC1_IN15
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_3|LL_GPIO_PIN_5|LL_GPIO_PIN_4|LL_GPIO_PIN_2;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  GPIO_InitStruct.Pin = LL_GPIO_PIN_1|LL_GPIO_PIN_2|LL_GPIO_PIN_0;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
  /* ADC1 DMA Init */
 
  /* GPDMA1_REQUEST_ADC1 Init */
  NodeConfig.DestAllocatedPort = LL_DMA_DEST_ALLOCATED_PORT1;
  NodeConfig.DestHWordExchange = LL_DMA_DEST_HALFWORD_PRESERVE;
  NodeConfig.DestByteExchange = LL_DMA_DEST_BYTE_PRESERVE;
  NodeConfig.DestBurstLength = 1;
  NodeConfig.DestIncMode = LL_DMA_DEST_INCREMENT;
  NodeConfig.DestDataWidth = LL_DMA_DEST_DATAWIDTH_HALFWORD;
 
  NodeConfig.SrcAllocatedPort = LL_DMA_SRC_ALLOCATED_PORT0;
  NodeConfig.SrcByteExchange = LL_DMA_SRC_BYTE_PRESERVE;
  NodeConfig.DataAlignment = LL_DMA_DATA_ALIGN_ZEROPADD;
  NodeConfig.SrcBurstLength = 1;
  NodeConfig.SrcIncMode = LL_DMA_SRC_FIXED;
  NodeConfig.SrcDataWidth = LL_DMA_SRC_DATAWIDTH_HALFWORD;
 
  NodeConfig.TransferEventMode = LL_DMA_TCEM_BLK_TRANSFER;
  NodeConfig.TriggerPolarity = LL_DMA_TRIG_POLARITY_MASKED;
  NodeConfig.BlkHWRequest = LL_DMA_HWREQUEST_SINGLEBURST;
  NodeConfig.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
  NodeConfig.Request = LL_GPDMA1_REQUEST_ADC1;
  NodeConfig.BlkRptCount = 1;
  NodeConfig.UpdateRegisters = (LL_DMA_UPDATE_CTR1 | LL_DMA_UPDATE_CTR2 | LL_DMA_UPDATE_CBR1 | LL_DMA_UPDATE_CSAR | LL_DMA_UPDATE_CDAR | LL_DMA_UPDATE_CLLR);
  NodeConfig.NodeType = LL_DMA_GPDMA_LINEAR_NODE;
 
  NodeConfig.SrcAddress = LL_ADC_DMA_GetRegAddr(ADC1, LL_ADC_DMA_REG_REGULAR_DATA);
  NodeConfig.DestAddress = (unsigned long)&(pusAdcData[0]);
  NodeConfig.BlkDataLength = sizeof(pusAdcData);
 
  LL_DMA_CreateLinkNode(&NodeConfig, &Node_GPDMA1_Channel0);
 
  LL_DMA_ConnectLinkNode(&Node_GPDMA1_Channel0, LL_DMA_CLLR_OFFSET5, &Node_GPDMA1_Channel0, LL_DMA_CLLR_OFFSET5);
 
  LL_DMA_SetLinkedListBaseAddr(GPDMA1, LL_DMA_CHANNEL_0, (uint32_t)&Node_GPDMA1_Channel0);
 
  DMA_InitLinkedListStruct.Priority = LL_DMA_HIGH_PRIORITY;
  DMA_InitLinkedListStruct.LinkStepMode = LL_DMA_LSM_FULL_EXECUTION;
  DMA_InitLinkedListStruct.LinkAllocatedPort = LL_DMA_LINK_ALLOCATED_PORT0;
  DMA_InitLinkedListStruct.TransferEventMode = LL_DMA_TCEM_BLK_TRANSFER;
  LL_DMA_List_Init(GPDMA1, LL_DMA_CHANNEL_0, &DMA_InitLinkedListStruct);
 
  /* USER CODE BEGIN ADC1_Init 1 */
  LL_DMA_ConfigAddresses(GPDMA1, LL_DMA_CHANNEL_0, LL_ADC_DMA_GetRegAddr(ADC1, LL_ADC_DMA_REG_REGULAR_DATA), (unsigned long)&(pusAdcData[0]));
  LL_DMA_SetBlkDataLength(GPDMA1, LL_DMA_CHANNEL_0, sizeof(pusAdcData));
 
  LL_DMA_EnableIT_DTE(GPDMA1, LL_DMA_CHANNEL_0);
  LL_DMA_EnableIT_ULE(GPDMA1, LL_DMA_CHANNEL_0);
  LL_DMA_EnableIT_USE(GPDMA1, LL_DMA_CHANNEL_0);
  LL_DMA_EnableIT_TC(GPDMA1, LL_DMA_CHANNEL_0);
 
  /* USER CODE END ADC1_Init 1 */
 
  /** Common config
  */
  LL_ADC_SetTriggerFrequencyMode(ADC1, LL_ADC_TRIGGER_FREQ_HIGH);
  ADC_CommonInitStruct.CommonClock = LL_ADC_CLOCK_ASYNC_DIV4;
  LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(ADC1), &ADC_CommonInitStruct);
  ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_14B;
  ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE;
  ADC_InitStruct.LeftBitShift = LL_ADC_LEFT_BIT_SHIFT_NONE;
  LL_ADC_Init(ADC1, &ADC_InitStruct);
  LL_ADC_SetGainCompensation(ADC1, 0);
  ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_EXT_EXTI_LINE11;
  ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_ENABLE_7RANKS;
  ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
  ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_CONTINUOUS;
  ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_OVERWRITTEN;
  ADC_REG_InitStruct.DataTransferMode = LL_ADC_REG_DMA_TRANSFER_UNLIMITED;
  LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
  LL_ADC_SetOverSamplingScope(ADC1, LL_ADC_OVS_DISABLE);
  LL_ADC_REG_SetTriggerEdge(ADC1, LL_ADC_REG_TRIG_EXT_FALLING);
 
  /* Disable ADC deep power down (enabled by default after reset state) */
  LL_ADC_DisableDeepPowerDown(ADC1);
  /* Enable ADC internal voltage regulator */
  LL_ADC_EnableInternalRegulator(ADC1);
  /* Delay for ADC internal voltage regulator stabilization. */
  /* Compute number of CPU cycles to wait for, from delay in us. */
  /* Note: Variable divided by 2 to compensate partially */
  /* CPU processing cycles (depends on compilation optimization). */
  /* Note: If system core clock frequency is below 200kHz, wait time */
  /* is only a few CPU processing cycles. */
  __IO uint32_t wait_loop_index;
  wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
  while(wait_loop_index != 0)
  {
    wait_loop_index--;
  }
 
  /** Configure Regular Channel
  */
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_7, LL_ADC_SINGLE_ENDED);
  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_7);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_7, LL_ADC_SAMPLINGTIME_20CYCLES);
  LL_ADC_SetChannelPreselection(ADC1, LL_ADC_CHANNEL_7);
 
  /** Configure Regular Channel
  */
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_8, LL_ADC_SINGLE_ENDED);
  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_2, LL_ADC_CHANNEL_8);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_8, LL_ADC_SAMPLINGTIME_20CYCLES);
  LL_ADC_SetChannelPreselection(ADC1, LL_ADC_CHANNEL_8);
 
  /** Configure Regular Channel
  */
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_9, LL_ADC_SINGLE_ENDED);
  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_3, LL_ADC_CHANNEL_9);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_9, LL_ADC_SAMPLINGTIME_20CYCLES);
  LL_ADC_SetChannelPreselection(ADC1, LL_ADC_CHANNEL_9);
 
  /** Configure Regular Channel
  */
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_10, LL_ADC_SINGLE_ENDED);
  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_4, LL_ADC_CHANNEL_10);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_10, LL_ADC_SAMPLINGTIME_20CYCLES);
  LL_ADC_SetChannelPreselection(ADC1, LL_ADC_CHANNEL_10);
 
  /** Configure Regular Channel
  */
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_15, LL_ADC_SINGLE_ENDED);
  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_5, LL_ADC_CHANNEL_15);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_15, LL_ADC_SAMPLINGTIME_20CYCLES);
  LL_ADC_SetChannelPreselection(ADC1, LL_ADC_CHANNEL_15);
 
  /** Configure Regular Channel
  */
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_16, LL_ADC_SINGLE_ENDED);
  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_6, LL_ADC_CHANNEL_16);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_16, LL_ADC_SAMPLINGTIME_20CYCLES);
  LL_ADC_SetChannelPreselection(ADC1, LL_ADC_CHANNEL_16);
 
  /** Configure Regular Channel
  */
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_17, LL_ADC_SINGLE_ENDED);
  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_7, LL_ADC_CHANNEL_17);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_17, LL_ADC_SAMPLINGTIME_20CYCLES);
  LL_ADC_SetChannelPreselection(ADC1, LL_ADC_CHANNEL_17);
  /* USER CODE BEGIN ADC1_Init 2 */
 
  LL_ADC_SetCalibrationOffsetFactor(ADC1, LL_ADC_SINGLE_ENDED, 0U);
  LL_ADC_StartCalibration(ADC1, LL_ADC_CALIB_LINEARITY);
  while(LL_ADC_IsCalibrationOnGoing(ADC1)) {};
 
  wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
  while(wait_loop_index != 0)
  {
    wait_loop_index--;
  }
 
  //LL_ADC_EnableIT_OVR(ADC1);
  //LL_ADC_EnableIT_EOC(ADC1);
  LL_ADC_ClearFlag_ADRDY(ADC1);
  LL_ADC_Enable(ADC1);
  while(LL_ADC_IsActiveFlag_ADRDY(ADC1) != 0)
  ;
  LL_ADC_ClearFlag_ADRDY(ADC1);
  LL_DMA_EnableChannel(GPDMA1, LL_DMA_CHANNEL_0);
  LL_ADC_REG_StartConversion(ADC1);
 
  /* USER CODE END ADC1_Init 2 */
 
}

/* Main Function */

  if(LL_DMA_IsActiveFlag_TC(GPDMA1, LL_DMA_CHANNEL_0))
  {
  LL_DMA_ConfigAddresses(GPDMA1, LL_DMA_CHANNEL_0, LL_ADC_DMA_GetRegAddr(ADC1, LL_ADC_DMA_REG_REGULAR_DATA), (unsigned long)&(pusAdcData[0]));
  LL_DMA_SetBlkDataLength(GPDMA1, LL_DMA_CHANNEL_0, sizeof(pusAdcData));
 
  LL_DMA_ClearFlag_HT(GPDMA1, LL_DMA_CHANNEL_0);
  LL_DMA_ClearFlag_TC(GPDMA1, LL_DMA_CHANNEL_0);
  LL_DMA_EnableChannel(GPDMA1, LL_DMA_CHANNEL_0);
  }
 
  if( LL_DMA_IsActiveFlag_USE(GPDMA1, LL_DMA_CHANNEL_0)
  || LL_DMA_IsActiveFlag_ULE(GPDMA1, LL_DMA_CHANNEL_0)
  || LL_DMA_IsActiveFlag_DTE(GPDMA1, LL_DMA_CHANNEL_0) )
  {
  LL_DMA_ClearFlag_DTE(GPDMA1, LL_DMA_CHANNEL_0);
  LL_DMA_ClearFlag_ULE(GPDMA1, LL_DMA_CHANNEL_0);
  LL_DMA_ClearFlag_USE(GPDMA1, LL_DMA_CHANNEL_0);
  LL_DMA_EnableChannel(GPDMA1, LL_DMA_CHANNEL_0);
  }

Thanks,

Tal.T

 

1 REPLY 1
Pierre_Paris
ST Employee

Hello @TTaie.1 ,

Thank you for your question, I have listed some points :

  • First, here is a great article on how to configure the GPDMA. 
  • A source (and destination) burst is programmed with a burst length by the field SBL_1[5:0] (respectively DBL_1[5:0]), and with a data width defined by the field SDW_LOG2[1:0] (respectively DDW_LOG2[1:0]) in the GPDMA_CxTR1 register. You have to check those values.
  • Is the GPDMA channel suspended and resumed ?
  • Can you please zip me your project ?

Best regards,

Pierre

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.