Skip to main content
Visitor II
October 24, 2024
Solved

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

  • October 24, 2024
  • 3 replies
  • 1914 views

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);
		}
	}
}

 

 

 



    This topic has been closed for replies.
    Best answer by Miyuki

    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);
    }

     

    3 replies

    Super User
    October 24, 2024

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

    Then pick the bits you need from that ...

    Graduate
    October 24, 2024

    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.

    MiyukiAuthorAnswer
    Visitor II
    October 24, 2024

    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);
    }

     

    Super User
    October 24, 2024

    @Miyuki wrote:

    that DMA presentation paper was very misleading.


    What "presentation paper" was it?

    Please give a link.