cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 ADC with DMA - DMA-Transfer not initiated

DSchl.1
Associate III

Hi everyone

I'm trying to get the ADC1 running with a DMA transfer on the STM32H757ZI. The goal is to measure 10 channels with 8 samples each and transfer these measurements to a separated SRAM1 buffer with DMA, each time the conversion sequence has been finished.

The problem I have is, that the ADC1 seems to work properly, since I'm reading some data in the DR, but the DMA transfer is never initiated. I have enabled the EOC and EOS interrupts, the corresponding ISR clears the EOC / EOS bits. I have set the DMNGT to DMA circular mode, which I assume enables the DMA functionality for the ADC peripheral. The transfer complete interrupt for the DMA is triggered, but no data is written to the buffer...

In addition, I have used the following DMA settings:

  • DMA1 clock enable
  • Set direction to peripheral to memory
  • disabled FIFO mode
  • Set memory size to Half Word
  • Set memory increment mode to increment
  • Set memory address to SRAM1 buffer address
  • Set mode to dma mode circular
  • Set peripheral size to Half Word
  • Set peripheral increment mode to no increment
  • Set peripheral request to DMAMUX1_REQ_ADC1
  • Set peripheral address to address of the DR
  • Enable TC interrupt

However, there's no data copied into the SRAM1 buffer... what am I missing here? Is there some additional setting I have to enable?

edit: I've set up the buffer according to this link :

https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices

I'm using Solution 2 - placing the buffer in a different memory region.

Regards

Daniel.

15 REPLIES 15
Mikhail Z
Senior II

Seeing the code would help.

Imen GH
ST Employee

​Hello,

There's an FAQ giving a good explanation and provides the solution.

https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices

The below link can help you to solve your problem (Please focus on my answer)

https://community.st.com/s/question/0D50X0000C7blnwSQA/adc-scan-continuous-mode-with-dma-in-stm32h7-all-values-are-0?t=1582799150965

Regards

It surely would.. I just thought there was an obvious thing I missed...

This is the init routine

void init_ADC()
{
	__ADC12_CLK_ENABLE();
	__HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP);
	LL_ADC_Disable(ADC1);
 
	LL_C1_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_ADC12);
 
	if (LL_ADC_IsDeepPowerDownEnabled(ADC1) != 0UL)
		LL_ADC_DisableDeepPowerDown(ADC1);
 
	if (LL_ADC_IsInternalRegulatorEnabled(ADC1) == 0UL)
	{
		LL_ADC_EnableInternalRegulator(ADC1); 								 
		__IO uint32_t wait_loop_index = 0UL;
		wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US / 10UL) * (SystemCoreClock / (100000UL * 2UL)))+1000;
		while (wait_loop_index != 0UL)
		{
		   wait_loop_index--;
		}
	}
 
	LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_CLOCK_ASYNC_DIV2);
	LL_ADC_SetResolution(ADC1, LL_ADC_RESOLUTION_16B);
	LL_ADC_REG_SetSequencerLength(ADC1, LL_ADC_REG_SEQ_SCAN_ENABLE_10RANKS);
	LL_ADC_SetLowPowerMode(ADC1, LL_ADC_LP_MODE_NONE);
	LL_ADC_REG_SetContinuousMode(ADC1, LL_ADC_REG_CONV_CONTINUOUS);
	LL_ADC_REG_SetSequencerDiscont(ADC1, LL_ADC_REG_SEQ_DISCONT_DISABLE);
	LL_ADC_REG_SetTriggerSource(ADC1, LL_ADC_REG_TRIG_SOFTWARE);
	LL_ADC_REG_SetTriggerEdge(ADC1, ADC_EXTERNALTRIGCONVEDGE_NONE);
	LL_ADC_REG_SetDataTransferMode(ADC1, LL_ADC_REG_DMA_TRANSFER_UNLIMITED);
	LL_ADC_REG_SetOverrun(ADC1, LL_ADC_REG_OVR_DATA_OVERWRITTEN);
	LL_ADC_SetOverSamplingScope(ADC1, LL_ADC_OVS_DISABLE);
 
	ADC1->PCSEL |= BIT(2)|BIT(3)|BIT(10)|BIT(11) // Preselect channels
				  |BIT(14)|BIT(15)|BIT(16)
				  |BIT(17)|BIT(18)|BIT(19);
 
	LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_2, 
        LL_ADC_SAMPLINGTIME_387CYCLES_5);
	LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_3, 
        LL_ADC_SAMPLINGTIME_387CYCLES_5);
	LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_10, 
        LL_ADC_SAMPLINGTIME_387CYCLES_5);
// other channels omitted
 
	LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_2, LL_ADC_SINGLE_ENDED);
	LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_3, LL_ADC_SINGLE_ENDED);
	LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_10, LL_ADC_SINGLE_ENDED);
// other channels omitted
 
	LL_ADC_SetOffset(ADC1, ADC_OFFSET_NONE, LL_ADC_CHANNEL_2, 0);
	LL_ADC_SetOffset(ADC1, ADC_OFFSET_NONE, LL_ADC_CHANNEL_3, 0);
	LL_ADC_SetOffset(ADC1, ADC_OFFSET_NONE, LL_ADC_CHANNEL_10, 0);
// other channels omitted
 
	LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1,  LL_ADC_CHANNEL_2);
	LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_2,  LL_ADC_CHANNEL_3);
	LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_3,  LL_ADC_CHANNEL_10);
// other channels omitted
 
	
	LL_ADC_EnableIT_EOS(ADC1); // End of regular sequence of conversions IR enable
	LL_ADC_EnableIT_EOC(ADC1); // End of conversion IR enable
}

This is the DMA init routine, called right after the one above:

void init_DMA_ADC()
{
	__HAL_RCC_DMA1_CLK_ENABLE();
	LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_STREAM_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
	LL_DMA_DisableFifoMode(DMA1, LL_DMA_STREAM_1);
	LL_DMA_SetMemoryBurstxfer(DMA1, LL_DMA_STREAM_1, LL_DMA_MBURST_SINGLE);
	LL_DMA_SetMemorySize(DMA1, LL_DMA_STREAM_1, LL_DMA_MDATAALIGN_HALFWORD);
	LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_STREAM_1, LL_DMA_MEMORY_INCREMENT);
	LL_DMA_SetMode(DMA1, LL_DMA_STREAM_1, LL_DMA_MODE_CIRCULAR);
	LL_DMA_SetPeriphBurstxfer(DMA1, LL_DMA_STREAM_1, LL_DMA_PBURST_SINGLE);
	LL_DMA_SetPeriphSize(DMA1, LL_DMA_STREAM_1, LL_DMA_PDATAALIGN_HALFWORD);
	LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_STREAM_1, LL_DMA_PERIPH_NOINCREMENT);
	LL_DMA_SetPeriphRequest(DMA1, LL_DMA_STREAM_1, LL_DMAMUX1_REQ_ADC1);
	LL_DMA_SetStreamPriorityLevel(DMA1, LL_DMA_STREAM_1, LL_DMA_PRIORITY_HIGH);
 
	LL_DMA_SetPeriphAddress(DMA1, LL_DMA_STREAM_1, reinterpret_cast<uint32_t>(&adcTypeDef->DR));
        LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_1, 0x3000A000); // SRAM1 buffer for ADC data
 
	LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_1);
}

The interrupts are enabled :

void enable_adc_interrupt()
{
	HAL_NVIC_SetPriority(ADC_IRQn, 6, 0);
	HAL_NVIC_EnableIRQ(ADC_IRQn);
}
 
void enable_dma_interrupt()
{
	HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 4, 0);
	HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
}

Then I enable and start the ADC :

void enable_ADC()
{
	LL_ADC_Enable(ADC1);
	while (LL_ADC_IsEnabled(adcTypeDef) == 0UL);
}
 
void start_ADC(uint32_t size)
{
	LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_1, size);
	LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_1);
	LL_ADC_REG_StartConversion(adcTypeDef);
}

In the ISR I clear the EOS / EOC flags if they are set. Same for the Transfer Complete flag of the DMA.

Hi,

I already know the FAQ... The buffer I'm using is a static buffer defined in the linker file and located in the SRAM1 at 0x3000A000. I can see that this address space gets correctly initialized to all zeros. In the MPU I have also configured this memory as not cacheable etc. In the second link, the address is 0x24000000 which would be AXI SRAM, but this should not be the issue here isn't it?

The point is, I have already set up the USART1 in a similar way, and this works without problems with DMA...

I can also see that the Transfer Complete interrupt is triggered, but no data is written...

Curtis B.
Senior

Hi, did you align the base adress of your buffer according to the buffersize? I struggled with this for a long time, but it seems that this information is now added in the FAQ. Back then, taht was one of these valuable informations that were only handed down from father to son...

The base address of the buffer is 0x3000A000, alignment is 2 Bytes. The ADC value is 16bits, and the DMA should automatically increase the memory pointer by half word, so the alignment should be ok. I have set up the USART1 TX DMA in a similar way regarding alignment and configuration, and this one works.

Hi Daniel,

it depends on the size you protect with your MPU. E.g. your DMA Buffer is 666 bytes in size you might set the Region size in the MPU to 1k. That means, that the region you protect with your MPU needs to be aligned to 1024 bytes. The DMA Buffer needs to be located in that region.

Regards,

Daniel

Hi Daniel

My buffer meets these requirements, doesn't it?

Regards

> I can also see that the Transfer Complete interrupt is triggered,

And how are other DMA status bits set? Isn't there an error flag set?

JW