cancel
Showing results for 
Search instead for 
Did you mean: 

How do I set up DMA to circular mode on STM32H5 without HAL

Miyuki
Associate II

Hello, 
I am looking for a way to set up DMA to transfer from peripheral to circular buffer triggered from Timer 

I hoped I could set it up just like it is described here, just change the source:
It samples data as expected but only once, it does not repeat when all 256 samples are taken. 
Do I understand that picture wrong or is it bad? Do I need to do some more settings? 
setup.png
So my code looks like this:

 

 

 

#define GPIO_DMA_SAMPLE_BUFFER (256)
uint16_t gGPIO_DMASampleBuffer[GPIO_DMA_SAMPLE_BUFFER] = {0};

void DMA_Init()
{
	//Enable DMA clock
	RCC->AHB1ENR |= RCC_AHB1ENR_GPDMA1EN | RCC_AHB1ENR_GPDMA2EN;

	//Destination address increase, Source = Destination 16 bit wide
	GPDMA1_Channel0->CTR1 = DMA_CTR1_DINC | DMA_CTR1_DDW_LOG2_0 | DMA_CTR1_SDW_LOG2_0;
	//Request by tim2_upd_dma
	GPDMA1_Channel0->CTR2 = 76;
	//Transfer buffer size
	GPDMA1_Channel0->CBR1 = GPIO_DMA_SAMPLE_BUFFER;
	//Source GPIOC
	GPDMA1_Channel0->CSAR = (uint32_t)&(GPIOC->IDR);
	//Destination Sample buffer
	GPDMA1_Channel0->CDAR = (uint32_t)gGPIO_DMASampleBuffer;
	//Circular buffer mode
	GPDMA1_Channel0->CLLR |= DMA_CLLR_UDA;

	//Activate DMA1 Channel 1
	GPDMA1_Channel0->CCR = DMA_CCR_HTIE | DMA_CCR_TCIE | DMA_CCR_EN;

	NVIC_SetPriority(GPDMA1_Channel0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 1, 0));
	NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);
}

void GPDMA1_Channel0_IRQHandler(void)
{
	unsigned int statusOfInputDatalines;
	extern uint16_t gGPIO_DMASampleBuffer[];

	if (GPDMA1_Channel0->CSR & DMA_CSR_TCF)
	{
		GPDMA1_Channel0->CFCR = DMA_CFCR_TCF; //clear flag

		for (int i = 128; i < 256; i++)
		{
			statusOfInputDatalines = (((gGPIO_DMASampleBuffer[i]) >> 6) & 0xFF);     // reading status of the port C (6-13) pins
			statusOfInputDatalines = (statusOfInputDatalines << 2) | ((statusOfInputDatalines >> 5) & 0x02) | ((statusOfInputDatalines >> 7) & 0x01); // reorder input pins

			_SaveDataToBuffer(statusOfInputDatalines);
		}
	}
	else if (GPDMA1_Channel0->CSR & DMA_CSR_HTF)
	{
		GPDMA1_Channel0->CFCR = DMA_CSR_HTF; //clear flag

		for (int i = 0; i < 128; i++)
		{
			statusOfInputDatalines = (((gGPIO_DMASampleBuffer[i]) >> 6) & 0xFF); // reading status of the port C (6-13) pins
			statusOfInputDatalines = (statusOfInputDatalines << 2) | ((statusOfInputDatalines >> 5) & 0x02) | ((statusOfInputDatalines >> 7) & 0x01); // reorder input pins

			_SaveDataToBuffer(statusOfInputDatalines);
		}
	}
}

 

 

 



1 ACCEPTED SOLUTION

Accepted Solutions
Miyuki
Associate II

It needed some more parameters. 
In the Reference manual, it was described, but that DMA presentation paper was very misleading. And even that description in the reference manual is somewhat cumbersome. 

This works as expected. 

#define GPIO_DMA_SAMPLE_BUFFER (256)
volatile uint16_t gGPIO_DMASampleBuffer[GPIO_DMA_SAMPLE_BUFFER] = {0};
__attribute__((aligned(32))) static uint32_t DesttinationAddress = (uint32_t)gGPIO_DMASampleBuffer;

void DMA_Init()
{
	//Enable DMA clock
	RCC->AHB1ENR |= RCC_AHB1ENR_GPDMA1EN | RCC_AHB1ENR_GPDMA2EN;

	//Destination address increase, Source = Destination 16 bit wide
	GPDMA1_Channel0->CTR1 = DMA_CTR1_DINC | DMA_CTR1_DDW_LOG2_0 | DMA_CTR1_SDW_LOG2_0;
	//Request by tim2_upd_dma
	GPDMA1_Channel0->CTR2 = 76;
	//Transfer buffer size
	GPDMA1_Channel0->CBR1 = GPIO_DMA_SAMPLE_BUFFER * 2;
	//Source GPIOC
	GPDMA1_Channel0->CSAR = (uint32_t)&(GPIOC->IDR);
	//Destination Sample buffer
	GPDMA1_Channel0->CDAR = (uint32_t)gGPIO_DMASampleBuffer;
	//Circular buffer mode
	GPDMA1_Channel0->CLLR = DMA_CLLR_UDA;

	//Setup Linked List
	GPDMA1_Channel0->CLBAR &= 0x0000FFFF;
	GPDMA1_Channel0->CLBAR |= (uint32_t)&DesttinationAddress & 0xFFFF0000;
	GPDMA1_Channel0->CLLR  |= (uint32_t)&DesttinationAddress & 0x0000FFFC;

	//Activate DMA1 Channel 1
	GPDMA1_Channel0->CCR = DMA_CCR_HTIE | DMA_CCR_TCIE | DMA_CCR_EN;

	NVIC_SetPriority(GPDMA1_Channel0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 1, 0));
	NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);
}

 

View solution in original post

4 REPLIES 4

First, do it in HAL (or find a HAL example which does it).

Then pick the bits you need from that ...

Danish1
Lead II

Also study the DMA chapter of the Reference Manual for your stm32.

I know this is a long and complicated document and it takes effort to understand, but that just reflects the fact that stm32 are extremely powerful devices.

Miyuki
Associate II

It needed some more parameters. 
In the Reference manual, it was described, but that DMA presentation paper was very misleading. And even that description in the reference manual is somewhat cumbersome. 

This works as expected. 

#define GPIO_DMA_SAMPLE_BUFFER (256)
volatile uint16_t gGPIO_DMASampleBuffer[GPIO_DMA_SAMPLE_BUFFER] = {0};
__attribute__((aligned(32))) static uint32_t DesttinationAddress = (uint32_t)gGPIO_DMASampleBuffer;

void DMA_Init()
{
	//Enable DMA clock
	RCC->AHB1ENR |= RCC_AHB1ENR_GPDMA1EN | RCC_AHB1ENR_GPDMA2EN;

	//Destination address increase, Source = Destination 16 bit wide
	GPDMA1_Channel0->CTR1 = DMA_CTR1_DINC | DMA_CTR1_DDW_LOG2_0 | DMA_CTR1_SDW_LOG2_0;
	//Request by tim2_upd_dma
	GPDMA1_Channel0->CTR2 = 76;
	//Transfer buffer size
	GPDMA1_Channel0->CBR1 = GPIO_DMA_SAMPLE_BUFFER * 2;
	//Source GPIOC
	GPDMA1_Channel0->CSAR = (uint32_t)&(GPIOC->IDR);
	//Destination Sample buffer
	GPDMA1_Channel0->CDAR = (uint32_t)gGPIO_DMASampleBuffer;
	//Circular buffer mode
	GPDMA1_Channel0->CLLR = DMA_CLLR_UDA;

	//Setup Linked List
	GPDMA1_Channel0->CLBAR &= 0x0000FFFF;
	GPDMA1_Channel0->CLBAR |= (uint32_t)&DesttinationAddress & 0xFFFF0000;
	GPDMA1_Channel0->CLLR  |= (uint32_t)&DesttinationAddress & 0x0000FFFC;

	//Activate DMA1 Channel 1
	GPDMA1_Channel0->CCR = DMA_CCR_HTIE | DMA_CCR_TCIE | DMA_CCR_EN;

	NVIC_SetPriority(GPDMA1_Channel0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 1, 0));
	NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);
}

 


@Miyuki wrote:

that DMA presentation paper was very misleading.


What "presentation paper" was it?

Please give a link.