2020-08-18 03:33 PM
Hi,
I am using 2 DMA transfers (DMA2) in the following configuration. The basic project is generated with cubeMX. Mostly clocking and USB parts are done in cubeMX, everything else is done "by hand".
The first DMA2 transfer uses stream0 and is transferring data from SPI to my buffer and that is done 8 times for a 16 bit value. This transfer is repeated every time new data is available. You can also look at this as one 128 bit data burst with clock period of 4 MHz. The burst period is about 64 us so there is about 50% dead time once the data transfer is completed (32 us to transfer the data and 32 us when no transfer is made). This part is working fine and as expected so no problem here.
The second DMA2 transfer uses stream1 in memory to memory mode. It is triggered when the first DMA transfer is complete inside stream0 interrupt handler. In addition I use an external trigger (command string sent over USB) to set a flag. Only when the flag is set the DMA transfer is actually enabled and in turn started from the stream0 interrupt handler (transfer complete) by enabling the stream1 DMA.
Once the second (strream1) DMA transfer is done the DMA is disabled in the stream1 interrupt handler (transfer complete).
Looking at the array values when debugging or if I send them over USB the second array has data shifted by 1 bit to left.
For example in [0] of the first array (stream0) the data is 0x100C which is the expected value. And in [0] of the second array (stream1) the data is 0x2019. This also means that the bit 0 is actually bit 15 from [1].
What is going on here and how can I solve the problem?
I also noticed that if I disable the first DMA transfer (stream0) once the transfer is done (inside stream0 interrupt handler) the data is also shifted left for 1 bit.
Again I am confused what is going on here.
This is the initialisation for the DMA2 stream0 part:
DMA2_Stream0->CR |= (4UL << 25)|(3UL << 16)|(1UL << 13)|(1UL << 11)|(1UL << 10)|(1UL << 8)|(1UL << 4);
DMA2_Stream0->NDTR = 8;
DMA2_Stream0->PAR = (uint32_t)(&(SPI4->DR));
DMA2_Stream0->M0AR = (uint32_t)adcData;
DMA2->LIFCR |= DMA_LIFCR_CTCIF0;
NVIC_SetPriority(DMA2_Stream0_IRQn, 0);
NVIC_ClearPendingIRQ(DMA2_Stream0_IRQn);
NVIC_EnableIRQ(DMA2_Stream0_IRQn);
DMA2_Stream0->CR |= (1UL << 0);
This is the initialisation for the DMA2 stream1 part:
DMA2_Stream1->CR |= (3UL << 16)|(1UL << 13)|(1UL << 11)|(1UL << 10)|(1UL << 9)|(1UL << 8)|(2UL << 6)|(1UL << 4);
DMA2_Stream1->NDTR = 8;
DMA2_Stream1->PAR = (uint32_t)adcData;
DMA2_Stream1->M0AR = (uint32_t)adcDataBuffered;
DMA2->LIFCR |= DMA_LIFCR_CTCIF1;
NVIC_SetPriority(DMA2_Stream1_IRQn, 0);
NVIC_ClearPendingIRQ(DMA2_Stream1_IRQn);
NVIC_EnableIRQ(DMA2_Stream1_IRQn);
And I enable/disable the DMA2 stream1 inside the interrupt handlers like:
DMA2_Stream1->CR |= (1UL << 0);
DMA2_Stream1->CR &= ~(1UL << 0);
Hopefully someone will help me resolve both problems.
2020-08-19 12:55 PM
So it looks like uVision automatically enabled FPU which I disabled now. But the major factor was strcmp() function. With this function removed I can now sometimes get the correct data. So the interrupt handler is triggered right on the edge and sometimes the delay is just a bit too high and the data is shiftet.
I plan to use the FPU so I enabled that back again and the result was about the same. So the delay comes from the strcmp function which I guess I just won't use now.
2020-08-19 01:03 PM
A small intentional delay after comparison of the command seems to solve the problem:
if(usbReceiveBuf[0] == 'M'){
HAL_Delay(1);
measure = 1;
}
And now even the strcmp function that was used before is not causing any problems.
I am at a loss what is happening here. I will need to decrease the delay as I would like to get at lease 500 Hz update rate, so I will use a timer for that and get it as low as possible. If I take in to account the time it will take to gather all of the data and recalculate it the 1ms delay will be too much.
Can anyone help explain why the delay solved the problem? I am happy that it is working now but I would like to understand why.
2020-08-19 01:19 PM
1us delay (actually about 925.9 ns as I can't set the timer to a good value) seems to also work fine. My guess is that something is happening in the MCU that prevents the EXTI1 interrupt from being executed. But I don't know why the intentional delay then resolves this.