cancel
Showing results for 
Search instead for 
Did you mean: 

Using ADC with DMA on M4 causes DMA transfer error

Emma
Associate II

We are trying to use circular DMA to transfer data from ADC1 into a buffer in MCU SRAM using CubeMX-generated code to configure the ADC and DMA. The DMA stream encounters a transfer error on transferring the first item. I have tried clearing the DMA error flags before starting the transfer with HAL_ADC_Start_DMA but that did not help.

The device is an STM32MP157C running in Production mode. ADC1 and DMA2 are assigned to the M4 core.

Using a debugger it can be seen that the peripheral address and memory address are configured correctly for the DMA stream. However, the DMA_HWCFGR1 register for DMA2 shows that all streams are in double-buffer mode despite the DBM bit being cleared in the stream configuration register, is this normal?

CubeMX-generated code:

static void MX_ADC1_Init(void)

{

 /* USER CODE BEGIN ADC1_Init 0 */

 /* USER CODE END ADC1_Init 0 */

 ADC_MultiModeTypeDef multimode = {0};

 ADC_ChannelConfTypeDef sConfig = {0};

 /* USER CODE BEGIN ADC1_Init 1 */

 /* USER CODE END ADC1_Init 1 */

 /** Common config

 */

 hadc1.Instance = ADC1;

 hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;

 hadc1.Init.Resolution = ADC_RESOLUTION_12B;

 hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;

 hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

 hadc1.Init.LowPowerAutoWait = DISABLE;

 hadc1.Init.ContinuousConvMode = ENABLE;

 hadc1.Init.NbrOfConversion = 8;

 hadc1.Init.DiscontinuousConvMode = DISABLE;

 hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;

 hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;

 hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;

 hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;

 hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;

 hadc1.Init.OversamplingMode = DISABLE;

 if (HAL_ADC_Init(&hadc1) != HAL_OK)

 {

   Error_Handler();

 }

 /** Configure the ADC multi-mode

 */

 multimode.Mode = ADC_MODE_INDEPENDENT;

 if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)

 {

   Error_Handler();

 }

 /** Configure Regular Channel

 */

 sConfig.Channel = ADC_CHANNEL_10;

 sConfig.Rank = ADC_REGULAR_RANK_1;

 sConfig.SamplingTime = ADC_SAMPLETIME_64CYCLES_5;

 sConfig.SingleDiff = ADC_SINGLE_ENDED;

 sConfig.OffsetNumber = ADC_OFFSET_NONE;

 sConfig.Offset = 0;

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

 {

   Error_Handler();

 }

/* Other channels omitted here */

}

void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)

{

 GPIO_InitTypeDef GPIO_InitStruct = {0};

 if(hadc->Instance==ADC1)

 {

 /* USER CODE BEGIN ADC1_MspInit 0 */

 /* USER CODE END ADC1_MspInit 0 */

   /* Peripheral clock enable */

   HAL_RCC_ADC12_CLK_ENABLED++;

   if(HAL_RCC_ADC12_CLK_ENABLED==1){

     __HAL_RCC_ADC12_CLK_ENABLE();

   }

/* GPIO init omitted here */

   /* ADC1 DMA Init */

   /* ADC1 Init */

   hdma_adc1.Instance = DMA2_Stream0;

   hdma_adc1.Init.Request = DMA_REQUEST_ADC1;

   hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;

   hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;

   hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;

   hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;

   hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;

   hdma_adc1.Init.Mode = DMA_CIRCULAR;

   hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;

   hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;

   if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)

   {

     Error_Handler();

   }

   __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1);

 /* USER CODE BEGIN ADC1_MspInit 1 */

 /* USER CODE END ADC1_MspInit 1 */

 }

static void MX_DMA_Init(void)

{

 /* DMA controller clock enable */

 __HAL_RCC_DMAMUX_CLK_ENABLE();

 __HAL_RCC_DMA2_CLK_ENABLE();

 /* DMA interrupt init */

 /* DMA2_Stream0_IRQn interrupt configuration */

 HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 5, 0);

 HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);

 /* DMA2_Stream1_IRQn interrupt configuration */

 HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 5, 0);

 HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);

 /* DMA2_Stream2_IRQn interrupt configuration */

 HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 4, 0);

 HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);

 /* DMA2_Stream3_IRQn interrupt configuration */

 HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 4, 1);

 HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);

 /* DMA2_Stream4_IRQn interrupt configuration */

 HAL_NVIC_SetPriority(DMA2_Stream4_IRQn, 4, 0);

 HAL_NVIC_EnableIRQ(DMA2_Stream4_IRQn);

 /* DMA2_Stream5_IRQn interrupt configuration */

 HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 4, 1);

 HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);

 /* DMA2_Stream6_IRQn interrupt configuration */

 HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 5, 1);

 HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);

}

void DMA2_Stream0_IRQHandler(void)

{

 /* USER CODE BEGIN DMA2_Stream0_IRQn 0 */

 /* USER CODE END DMA2_Stream0_IRQn 0 */

 HAL_DMA_IRQHandler(&hdma_adc1);

 /* USER CODE BEGIN DMA2_Stream0_IRQn 1 */

 /* USER CODE END DMA2_Stream0_IRQn 1 */

}

1 ACCEPTED SOLUTION

Accepted Solutions
Emma
Associate II

Hi @MMevo.1​ , @PatrickF​ ,

Yes, ST Support helped me with this. The missing piece was to add DMA2 to MCU isolation in the TF-A device tree.

To the etzpc node, add:

DECPROT(STM32MP1_ETZPC_DMA2_ID, DECPROT_MCU_ISOLATION, DECPROT_UNLOCK)

View solution in original post

10 REPLIES 10
mleo
Senior II

Hi @Emma​ ,

In you code fragment you didn't provide the DMA settings located in file stm32mp1xx_hal_msp.c

Could you for better inspection send the original ioc file?

I tend to think it's just matter of settings - the M4 core and this ADC DMA feature has been used frequently.

Best regards,

MIlan

Emma
Associate II

Hi @mleo​ ,

Please find the ioc file attached.

(In the project you can see that I2C1 and I2C3 are also configured to use DMA, but I couldn't get it working so I switched to using interrupts for the time being. I haven't looked into why the I2C DMA didn't work.)

Best Regards,

Emma

Emma
Associate II

I haven't been able to solve this and I'm also having the same problem with the DAC: Transferring data from a buffer in MCU SRAM to the DAC (DHR12R1) using DMA2 generates a DMA transfer error on the first data item.

The only DMA transfer I've been able to get to work on the M4 core is a memory-to-memory transfer. Because of this I'm assuming that the transfer error is caused by a bus error when accessing the ADC/DAC data registers and not when accessing the MCU SRAM.

What would cause such a bus error? I'm using half-word alignment which worked fine on an STM32F427 but I've also tried word alignment to make sure it's not an alignment issue.

MMevo.1
Associate II

Hi Emma,

I am experiancing the same issue with STM32H743-

did you manage to solve this problem?

Best Regards,

Maor

PatrickF
ST Employee

Hi @MMevo.1​, @Emma​ , did you also enable the ADC1 global interrupt (or relevant peripheral interrupt you want to use with DMA) in CubeMx ?

@MMevo.1​ , for further support on STM32H7, please enter a question on STM32 MCUs community

Regards.

In order 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.
Emma
Associate II

Hi @MMevo.1​ , @PatrickF​ ,

Yes, ST Support helped me with this. The missing piece was to add DMA2 to MCU isolation in the TF-A device tree.

To the etzpc node, add:

DECPROT(STM32MP1_ETZPC_DMA2_ID, DECPROT_MCU_ISOLATION, DECPROT_UNLOCK)

PatrickF
ST Employee

In order to give better visibility on the answered topics, please click on 'Select as Best' on the reply which solved your issue or answered your question. See also 'Best Answers'

In order 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.
MMevo.1
Associate II

Hi @Emma (Community Member)​, @PatrickF (ST Employee)​ ,

I am not familier with etzpc node.. Do you know if it relevant also to STM32H7?

I have enabled ADC1 Global interrupt as well (From the CubeMX).

Regards,

Maor

Hi,

not at all, this is related only to STM32MP1 series Cortex-A7 side with Linux.

Not relevant for STM32H7.

Maybe worth that you look at existing examples provided in STM32CubeH7 and if not enough please enter a question on STM32 MCUs community

Regards.

In order 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.