streaming of buffer that fills with DMA over USB_FS
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2018-09-11 8: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:
- USB transfer can't share memory area with DMA that writing to that memory
- DMA halting until USB finish it transfer and but in that time CCR1 register is still getting new values so and after USB finish DMA starts writing that value to my buffer and that causes data incoherence
- Somewhat cause data corruption in dma_buffer but only highest bits not lowest
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.
- Labels:
-
DMA
-
STM32H7 series
-
USB
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2018-09-11 8:41 AM
The USB transmission lasts too long, so the buffer gets overwritten by DMA while transmitted.
JW
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎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
