cancel
Showing results for 
Search instead for 
Did you mean: 

DMA throwing transfer error when reading from the ADC

dknipe
Associate II

Processor: STM32H753

I am attempting to continuously read an ADC, and transfer the data into a circular data buffer with the ADC. I configured everything in CubeMX. No matter what I try, I get a transfer error from the DMA the first time it reads. I tried  both DMA1 and DMA2 with different streams thinking maybe there is a limitation on which stream I can use to read ADC2. I extracted the configuration code for testing and example purposes, which gets run at startup.

Init():

   // void MX_ADC2_Init(void)
   hadc2.Instance = ADC2;
   hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV256; // ADC clock = 62.5 MHz / 256 = 244 kHz
   hadc2.Init.Resolution = ADC_RESOLUTION_12B;
   hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
   hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
   hadc2.Init.LowPowerAutoWait = DISABLE;
   hadc2.Init.ContinuousConvMode = ENABLE; // Enable continuous conversion mode
   hadc2.Init.NbrOfConversion = 1;
   hadc2.Init.DiscontinuousConvMode = DISABLE;
   hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
   hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
   hadc2.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
   hadc2.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
   hadc2.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
   hadc2.Init.OversamplingMode = DISABLE;
   if (HAL_ADC_Init(&hadc2) != HAL_OK) {
      LOG(LOG_LEVEL_ERROR, "HAL_ADC_Init Error");
   }


   ADC_ChannelConfTypeDef sConfig = {0};
   sConfig.Channel = ADC_CHANNEL_8;
   sConfig.Rank = ADC_REGULAR_RANK_1;
   sConfig.SamplingTime = ADC_SAMPLETIME_16CYCLES_5; // Sampling time = 16.5 cycles
   sConfig.SingleDiff = ADC_SINGLE_ENDED;
   sConfig.OffsetNumber = ADC_OFFSET_NONE;
   sConfig.Offset = 0;
   sConfig.OffsetRightShift = DISABLE;
   sConfig.OffsetSignedSaturation = DISABLE;
   if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) {
      LOG(LOG_LEVEL_ERROR, "HAL_ADC_ConfigChannel Error");
   }

   hdma_adc2.Instance = DMA2_Stream0;
   hdma_adc2.Init.Request = DMA_REQUEST_ADC2;
   hdma_adc2.Init.Direction = DMA_PERIPH_TO_MEMORY;
   hdma_adc2.Init.PeriphInc = DMA_PINC_DISABLE;
   hdma_adc2.Init.MemInc = DMA_MINC_ENABLE;
   hdma_adc2.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
   hdma_adc2.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
   hdma_adc2.Init.Mode = DMA_CIRCULAR; // Enable circular mode
   hdma_adc2.Init.Priority = DMA_PRIORITY_HIGH;
   hdma_adc2.Init.FIFOMode = DMA_FIFOMODE_DISABLE;

   if (HAL_DMA_Init(&hdma_adc2) != HAL_OK) 
   {
      LOG(LOG_LEVEL_ERROR, "HAL_DMA_Init Error");
   }

   __HAL_LINKDMA(&hadc2, DMA_Handle, hdma_adc2);

   // MX_DMA_Init()
   __HAL_RCC_DMA2_CLK_ENABLE();

   HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 12, 0);
   HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);

 I then start the DMA a little later in the Init routine:

   rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(100));

   // Motor current ADC DMA
   _ARMV7M_Set_exception_priority_and_handler(
             ARMV7M_VECTOR_IRQ(DMA2_Stream0_IRQn),
             (14 << 4),
             TestIRQHandler);


   LOG(LOG_LEVEL_DEBUG, YELLOW("hdma_adc2.Init.Request=%lu hdma_adc2.Init.Mode=%lu DMA_CIRCULAR=%lu"),
       hdma_adc2.Init.Request, hdma_adc2.Init.Mode, DMA_CIRCULAR);
   LOG(LOG_LEVEL_DEBUG, YELLOW("&hdma_adc2=%p hadc2.DMA_Handle=%p"), &hdma_adc2, hadc2.DMA_Handle);
   LOG(LOG_LEVEL_DEBUG, YELLOW("&hadc2=%p hdma_adc2.Parent=%p"),
       &hadc2, hdma_adc2.Parent);
   LOG(LOG_LEVEL_DEBUG, YELLOW("hdma_adc2.DMAmuxChannel->CCR=0x%lx hdma_adc2.DMAmuxRequestGen->RGCR=0x%lx"),
       hdma_adc2.DMAmuxChannel->CCR, hdma_adc2.DMAmuxRequestGen->RGCR);

   LOG(LOG_LEVEL_DEBUG, BLUE("HWIO::init hadc2.State=0x%lx hadc2.ErrorCode=0x%lx"), hadc2.State, hadc2.ErrorCode);
   LOG(LOG_LEVEL_DEBUG, BLUE("HWIO::init hdma_adc2.State=0x%x hdma_adc2.ErrorCode=0x%lx"), hdma_adc2.State, hdma_adc2.ErrorCode);
   LOG(LOG_LEVEL_DEBUG, BLUE("hdma_adc2.DMAmuxChannelStatus->CSR=0x%lx hdma_adc2.DMAmuxRequestGenStatus->RGSR=0x%lx"),
       hdma_adc2.DMAmuxChannelStatus->CSR, hdma_adc2.DMAmuxRequestGenStatus->RGSR);

   HAL_StatusTypeDef halStatus = HAL_ADC_Start_DMA(&hadc2, motorCurrentBuffer, MOTOR_CURRENT_BUFFER_SIZE);
   if (halStatus == HAL_OK)
   {
      LOG(LOG_LEVEL_DEBUG, "HWIO::init DMA started");
   }
   else
   { 
      LOG(LOG_LEVEL_ERROR, "HWIO::init DMA failed to start");
   }
   LOG(LOG_LEVEL_DEBUG, GREEN("HWIO::init hadc2.State=0x%lx hadc2.ErrorCode=0x%lx"), hadc2.State, hadc2.ErrorCode);
   LOG(LOG_LEVEL_DEBUG, GREEN("HWIO::init hdma_adc2.State=0x%x hdma_adc2.ErrorCode=0x%lx"), hdma_adc2.State, hdma_adc2.ErrorCode);
   LOG(LOG_LEVEL_DEBUG, GREEN("hdma_adc2.DMAmuxChannelStatus->CSR=0x%lx hdma_adc2.DMAmuxRequestGenStatus->RGSR=0x%lx"),
       hdma_adc2.DMAmuxChannelStatus->CSR, hdma_adc2.DMAmuxRequestGenStatus->RGSR);

   rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(100));

   LOG(LOG_LEVEL_DEBUG, MAGENTA("HWIO::init hadc2.State=0x%lx hadc2.ErrorCode=0x%lx"), hadc2.State, hadc2.ErrorCode);
   LOG(LOG_LEVEL_DEBUG, MAGENTA("HWIO::init hdma_adc2.State=0x%x hdma_adc2.ErrorCode=0x%lx"), hdma_adc2.State, hdma_adc2.ErrorCode);
   LOG(LOG_LEVEL_DEBUG, MAGENTA("hdma_adc2.DMAmuxChannelStatus->CSR=0x%lx hdma_adc2.DMAmuxRequestGenStatus->RGSR=0x%lx"),
       hdma_adc2.DMAmuxChannelStatus->CSR, hdma_adc2.DMAmuxRequestGenStatus->RGSR);
   LOG(LOG_LEVEL_DEBUG, MAGENTA("HWIO::init [0]=%lu [1]=%lu [2]=%lu [3]=%lu dmaIRQCalls=%d"), 
       motorCurrentBuffer[0], motorCurrentBuffer[1], motorCurrentBuffer[2], motorCurrentBuffer[3], dmaIRQCalls);
   dmaIRQCalls = 0;

 

Here is the output of the debug prints above:

DEBUG>  hdma_adc2.Init.Request=10 hdma_adc2.Init.Mode=256 DMA_CIRCULAR=256
DEBUG>  &hdma_adc2=0x2001c87c hadc2.DMA_Handle=0x2001c87c
DEBUG>  &hadc2=0x2001c940 hdma_adc2.Parent=0x2001c940
DEBUG>  hdma_adc2.DMAmuxChannel->CCR=0xa hdma_adc2.DMAmuxRequestGen->RGCR=0x3
DEBUG>  HWIO::init hadc2.State=0x1 hadc2.ErrorCode=0x0
DEBUG>  HWIO::init hdma_adc2.State=0x1 hdma_adc2.ErrorCode=0x0
DEBUG>  hdma_adc2.DMAmuxChannelStatus->CSR=0x0 hdma_adc2.DMAmuxRequestGenStatus->RGSR=0x3
DEBUG>  HWIO::init DMA started
DEBUG>  HWIO::init hadc2.State=0x100 hadc2.ErrorCode=0x0
DEBUG>  HWIO::init hdma_adc2.State=0x2 hdma_adc2.ErrorCode=0x0
DEBUG>  hdma_adc2.DMAmuxChannelStatus->CSR=0x0 hdma_adc2.DMAmuxRequestGenStatus->RGSR=0x3
ERROR>  ADC Error Callback
ERROR>  HAL_ADC_ErrorCallback hadc->State=0x140 hadc->ErrorCode=0x4
ERROR>  HAL_ADC_ErrorCallback hadc->DMA_Handle->StreamIndex=0x0
DEBUG>  HWIO::init hadc2.State=0x140 hadc2.ErrorCode=0x4
DEBUG>  HWIO::init hdma_adc2.State=0x1 hdma_adc2.ErrorCode=0x1
DEBUG>  hdma_adc2.DMAmuxChannelStatus->CSR=0x0 hdma_adc2.DMAmuxRequestGenStatus->RGSR=0x3
DEBUG>  HWIO::init [0]=0 [1]=0 [2]=0 [3]=0 dmaIRQCalls=1

I've verified nothing else is using ADC2. I am completely out of ideas.

Any idea what I am doing wrong?

4 REPLIES 4

Read out and check/post content of given DMA Stream's registers.

JW

 DMA2_Stream0 CR=0x0000001a NDTR=0x000003ff PAR=0x40022140 M0AR=0x20009d84 FCR=0x00000021

The registers I posted above were after the DMA threw a transfer error. Here is a bit more info:

 

 

Before Starting:
DMA2_Stream0 CR=0x00000000 NDTR=0x00000000 PAR=0x00000000 M0AR=0x00000000 FCR=0x00000021

After Starting:
DMA2_Stream0 CR=0x0000001f NDTR=0x00000400 PAR=0x40022140 M0AR=0x20009d84 FCR=0x00000021

After Transfer Error:
DMA2_Stream0 CR=0x0000001a NDTR=0x000003ff PAR=0x40022140 M0AR=0x20009d84 FCR=0x00000021

 

M0AR matches the buffer address. Buffer size is 1024, so NDTR is correct. The CR doesn't seem to match the configuration.

 

0x20009d84 is in DTCM

waclawekjan_0-1721143757381.png

In 'H753, there's no route from DMA1/DMA2 to DTCM:

waclawekjan_1-1721143830728.png

JW