2019-01-22 02:15 PM
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
2019-01-22 02:58 PM
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
2019-01-22 03:44 PM
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?
2019-01-22 05:36 PM
My bad, frameBuffer is 174*144 bytes long. I made a mistake while rewriting code here
2019-01-22 05:44 PM
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
2019-01-22 09:02 PM
Experiment with DMA Cyclical mode to help understand what's wrong.
2019-01-23 02:37 AM
"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:
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?