Skip to main content
D��ug
Associate II
January 22, 2019
Question

DMA running only once

  • January 22, 2019
  • 6 replies
  • 1680 views

I have Timer configured in Input Capture Mode and DMA2 Channel 6 Stream 1 configured to transfer data from GPIOC to frame_buffer. It works, but only once - after first use there was data and in next transfers there where only zeros. To have it working again I have to load another project and then load this one. Seems like a problem with flags - previously I had an DMA interrupt and program could not get out of it

I'm using STM32F411 Discovery Board

Here's my code:

uint8_t frame_buffer[174*144];
 
void TimerAndDMAConfigure(void){
	GPIO_InitTypeDef gpioPCLK;
	TIM_ICInitTypeDef icTIM1;
	DMA_InitTypeDef dmaPerToMem;
 
	NVIC_InitTypeDef nvic;
 
	//GPIOE config
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
 
	gpioPCLK.GPIO_Mode = GPIO_Mode_AF;
	gpioPCLK.GPIO_OType = GPIO_OType_OD;
	gpioPCLK.GPIO_Pin = GPIO_Pin_9;
	gpioPCLK.GPIO_PuPd = GPIO_PuPd_NOPULL;
	gpioPCLK.GPIO_Speed = GPIO_High_Speed;
	GPIO_Init(GPIOE, &gpioPCLK);
	GPIO_PinAFConfig(GPIOE, GPIO_PinSource9, GPIO_AF_TIM1);
 
 
	//Timer config
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
 
	icTIM1.TIM_Channel = TIM_Channel_1;
	icTIM1.TIM_ICPolarity = TIM_ICPolarity_Rising;
	icTIM1.TIM_ICSelection = TIM_ICSelection_DirectTI;
	icTIM1.TIM_ICPrescaler = TIM_ICPSC_DIV1;
	icTIM1.TIM_ICFilter = 0;
	TIM_ICInit(TIM1, &icTIM1);
 
	TIM_CtrlPWMOutputs(TIM1, ENABLE);
	TIM_SelectOutputTrigger(TIM8 , TIM_TRGOSource_Reset);
	TIM_Cmd(TIM1, ENABLE);
	TIM_DMAConfig(TIM1, TIM_DMABase_CCR1, TIM_DMABurstLength_1Transfer);
	TIM_DMACmd(TIM1, TIM_DMA_CC1, ENABLE);
 
 
	//DMA config - peripheral to memory
	//DMA2 Stream 1 Channel 6
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
 
	DMA_DeInit(DMA2_Stream1);
 
	dmaPerToMem.DMA_BufferSize = 174*2;
	dmaPerToMem.DMA_Channel = DMA_Channel_6;
	dmaPerToMem.DMA_DIR=DMA_DIR_PeripheralToMemory;
	dmaPerToMem.DMA_FIFOMode = DMA_FIFOMode_Disable;
	dmaPerToMem.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
	dmaPerToMem.DMA_Memory0BaseAddr = (uint32_t) frame_buffer;
	dmaPerToMem.DMA_MemoryBurst = DMA_MemoryBurst_Single;
	dmaPerToMem.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	dmaPerToMem.DMA_MemoryInc = DMA_MemoryInc_Enable;
	dmaPerToMem.DMA_Mode = DMA_Mode_Normal;
	dmaPerToMem.DMA_PeripheralBaseAddr = (uint32_t) (&GPIOC->IDR);
	dmaPerToMem.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
	dmaPerToMem.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	dmaPerToMem.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	dmaPerToMem.DMA_Priority = DMA_Priority_Medium;
	DMA_Init(DMA2_Stream1, &dmaPerToMem);
 
	DMA_ITConfig(DMA2_Stream1, DMA_IT_TC, ENABLE);
	//DMA_Cmd(DMA2_Stream1, ENABLE);
	//DMA2 - Interrupt
	//nvic.NVIC_IRQChannel = DMA2_Stream1_IRQn;
	//nvic.NVIC_IRQChannelCmd = ENABLE;
	//nvic.NVIC_IRQChannelPreemptionPriority = 10;
	//nvic.NVIC_IRQChannelSubPriority = 10;
	//NVIC_Init(&nvic);
 
}
 
int main(void)
{
 
	SystemInit();
 
	GPIO_SetBits(GPIOD, GPIO_Pin_12);
	TimerAndDMAConfigure();
 
	DMA_Cmd(DMA2_Stream2, DISABLE);
	while (DMA2_Stream2->CR & DMA_SxCR_EN);
 
	DMA_Cmd(DMA2_Stream1, ENABLE);
	while(1){
		DMA_Cmd(DMA2_Stream1, ENABLE);
		while(DMA_GetFlagStatus(DMA2_Stream1, DMA_FLAG_TCIF1) == RESET){
			continue;
		}
		for(int i = k; i<k + 10; i++){
			value = frame_buffer[i];
			next = value;
		}
		k+=1;
		if(k==18)k=0;
		DMA_ClearFlag(DMA2_Stream1, DMA_FLAG_FEIF1|DMA_FLAG_DMEIF1|DMA_FLAG_TEIF1|DMA_FLAG_HTIF1|DMA_FLAG_TCIF1);
 
		DMA_Cmd(DMA2_Stream2, DISABLE);
		while (DMA2_Stream2->CR & DMA_SxCR_EN);
		Delay(10);
 
	}
}
 
/*void DMA2_Stream1_IRQHandler(void)
{
 
 
		for(int i = 200; i<210; i++){
			uint8_t value = frame_buffer[i];
			Serial_sendb(value);
			Delay(100);
		}
 
		DMA_Cmd(DMA2_Stream1, DISABLE);
}
*/
 

I'm probably doing something wrong with the flags, but I can't find where the problem is

This topic has been closed for replies.

6 replies

waclawek.jan
Super User
January 22, 2019

I don't understand SPL but it appears to me that you are trying to transfer 174*2 bytes into a buffer 174 bytes long...?

JW

D��ug
D��ugAuthor
Associate II
January 23, 2019

My bad, frameBuffer is 174*144 bytes long. I made a mistake while rewriting code here

Piranha
Principal III
January 22, 2019

You must set DMA buffer size each time between disabling and enabling stream. And, as Jan said, correct the buffer size.

Also You are setting DMA to GPIOC, but not enabling GPIOC clock. And reading only first (lower) byte from IDR register - is this what is intended?

D��ug
D��ugAuthor
Associate II
January 23, 2019

Fixed, but same result.

Setting GPIOC is done in other function - I just did not include that here

Yes, that is correct. I've got 8 data lines connected to PC0-PC7

Problem is not that DMA isn't working at all. It transfers data, but only once. Then it stuck somewhere and does not want to copy data anymore

S.Ma
Principal
January 23, 2019

Experiment with DMA Cyclical mode to help understand what's wrong.

Piranha
Principal III
January 23, 2019

"You must set DMA buffer size each time between disabling and enabling stream."

Have You done that? I should remind that setting dmaPerToMem.DMA_BufferSize after initialization doesn't do anything. You must set it with DMA_SetCurrDataCounter() like here:

https://community.st.com/s/question/0D50X00009XkgBdSAJ/stm32f103-uart-dmarx-and-tx-can-execute-only-once-

By the way line 84 is useless.

"Seems like a problem with flags - previously I had an DMA interrupt and program could not get out of it"

Did You call DMA_ClearITPendingBit() from interrupt handler?