2018-09-11 08:35 AM
I encountered a complex problem and I don't understand where should I start untangle it.
What I want to do:
I have a buffer (allocated in SRAM_1) that filling up with DMA. DMA pass TIM2_CCR1 value into buffer's cells.
Flow:
unsigned int dma_buffer[15360*4];
DMA1_Stream0->NDTR = 15360*4;
TIM2 input capture timer see event (high transition or low transition in my case I'm capture both), update CCR1 and kicks in DMA, that pass this(TIM2->CCR1) into dma_buffer, Increment addres, when next event occurs pas another value and so far and so forth.
when dma_buffer is half filled (thus (DMA1_Stream0 ->NDTR > 15360*2) -> half of the buffer length).
I want to transfer this half of buffer via USB_FS, the fastest way I found is:
for(int i = 0; i < 2; ++i) {
//SCB_InvalidateDCache();
CDC_Transmit_FS(buffer+SIZE*i, SIZE*sizeof(unsigned int));
while(((USBD_CDC_HandleTypeDef*)(hUsbDeviceFS.pClassData))->TxState != 0);
} // transfer via USB first half of buffer
and when DMA interrupt occurs I set flipFlag
void DMA1_Stream0_IRQHandler(void) {
// clear interrupt flag
DMA1->LIFCR |= (0x1 << 3) | (0x1 << 5);
dmaFlag++;
flipFlag++; // <-- indicates that second half of dma_buffer is already filled and we can transfer it
}
after I transfer second part of dma_buffer:
for(int i = 2; i < 4; ++i) {
//SCB_InvalidateDCache();
CDC_Transmit_FS(buffer + SIZE*i, SIZE*sizeof(unsigned int));
while(((USBD_CDC_HandleTypeDef*)(hUsbDeviceFS.pClassData))->TxState != 0);
} // transfer second part of dma_buffer
the problem:
I have inconsistent data transferred like
first 15360 buffer entries 15360-15360*2 15360*2 - 15360*3 15360*3 - 15360*4
1-2-3-4 |5-6-7-8 |9 - 32 - 33 - 34 |35-36-37-38
the first two data chunks of SIZE(15360*sizeof(unsigned int)) are transferred correctly (first hald of dma_buffer).
but the third data chunk of SIZE starts correctly but soon became incoherent with the rest of data, it's like just some big number was added to.
Real life example:
dma_buffer[0] = 145 dma_buffer[1] = 604 dma_buffer[2] = 1103 dma_buffer[3] = 1604
......
dma_buffer[15360] = 7680113
......
dma_buffer[30720] = 15360115
.......
dma_buffer[31166] = 15583113
dma_buffer[31167] = 25692048 --> approx 10E6 incrementation ERROR
dma_buffer[31168] = 25694103
dma_buffer[31168] = 25694604 --> same ~500 delta from previous and starts going to the end
Any idea why is this happening? Both cache enabled (usb and uart transfer didn't seem to work without) I was trying invalidate cache before any data usages, but problem stays.
I have some ideas in my head:
My experience in this fild is HIGHLY limited so I just don't know where to start, so any ideas and recommendations will be highly appreciated.
2018-09-11 08:41 AM
The USB transmission lasts too long, so the buffer gets overwritten by DMA while transmitted.
JW
2018-09-12 12:54 AM
This happens even with the situation where DMA circular buffer mode enabled, so DMA should only fill buffer once. I have simple code like:
my_DMA_init();
my_TIM2_initInputCaptureTimer();
my_initTIM6();
unsigned int circ_buffer_ptr = 0;
unsigned int counter = 0;
unsigned int stopFlag = 0;
while (1)
{
if(!stopFlag) {
for(int i = 0; i < 2; ++i) {
writeFile();
}
counter = 1;
}
if(counter == 1) {
counter = 0;
stopFlag = 1;
// end of transmission
//writeFile();
//printDebugBuffer();
buffer[0] = 0x00646E65;
CDC_Transmit_FS(buffer, SIZE*sizeof(unsigned int));
}
}// while
}// main
this code doesn't wait for DMA filling first half of buffer, It's just fire up immediately. And what I have:
values in buffer was preinitialized for debug purposes from 0 to 61439,
DMA circular buffer mode OFF - when dma fill up buffer it stops
what do i have in my first file -> CDC_Transmit_FS just transfer full buffer without waiting
dma_buffer[0] = 145
dma_buffer[1] = 604
dma_buffer[2] = 2
dma_buffer[3] = 3
.....
dma_buffer[61439] = 61439
but then it transfer this buffer again (filled in DMA) and I have this
dma_buffer[0] = 145
dma_buffer[1] = 604
dma_buffer[2] = 10354526
dma_buffer[3] = 10354672