cancel
Showing results for 
Search instead for 
Did you mean: 

DMA running only once

D��ug
Associate II

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

6 REPLIES 6

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

Piranha
Chief II

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?

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

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

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

Piranha
Chief II

"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?