cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F407 DMA2 Repeated Disable and Enable Fails

Josh Yu
Associate II
Posted on April 12, 2018 at 03:22

Hi,

I'm using STM32F407 in my project and I use DMA2 on USART1 RX/TX. Since my TX packet length changes almost every time, I'd have to disable DMA, reconfigure it to the correct data length, and enable DMA. I'm doing this at least 100Hz if not more. And I don't know if it's because of that, the DMA would fail to enable after random periods of time. I write 1 to the EN bit in the control register and poll it to make sure it actually becomes 1, but it never does. I'm not sure what the problem is, since it always works for a few minutes then stops working. Another interesting point is that the DMA2 RX doesn't stop working at all. If anyone has any pointers I highly appreciate it. Thanks!

Here's my USART1 TX and DMA reconfigure code: (by the way, the printf statements printed out the same values when the DMA is working and when it's not)

void USART1_DMA2_Send_Array(u8 * data_to_send_addr, u16 send_length)
{
static int i = 0;
// Make sure that the UART TX DMA is disabled (which should already be disabled by hardware if
// the previous transfer is completed)
uint16_t remaining = DMA_GetCurrDataCounter(DMA2_Stream7);
if (remaining != 0) {
printf('Remaining DMA transfer = %u', remaining);
}
i = 0;
DMA_Cmd(DMA2_Stream7,DISABLE);
while(DMA_GetCmdStatus(DMA2_Stream7) != DISABLE) {
DMA_Cmd(DMA2_Stream7,DISABLE);
printf('Disabling DMA... %d\n', i);
i++;
if (i > 1000) {
System_Failure();
}
}
DMA_ClearFlag(DMA2_Stream7, DMA_FLAG_TCIF7|DMA_FLAG_HTIF7|DMA_FLAG_TEIF7|DMA_FLAG_DMEIF7|DMA_FLAG_FEIF7);
USART_ClearFlag(USART1, USART_FLAG_TC);
DMA_InitTypeDef DMA_InitStructure;
 // common configuration
 DMA_StructInit(&DMA_InitStructure);
 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
 DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
 DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
 DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
 DMA_InitStructure.DMA_Priority = DMA_Priority_High;
 // Configure TX DMA: DMA2_Stream7 Channel 4
 DMA_InitStructure.DMA_Channel = DMA_Channel_4;
 DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(USART1->DR);
 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
 DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
 DMA_InitStructure.DMA_BufferSize = send_length;
 DMA_InitStructure.DMA_Memory0BaseAddr = (u32)data_to_send_addr;
 DMA_Init(DMA2_Stream7,&DMA_InitStructure);
//DMA_SetCurrDataCounter(DMA2_Stream7, send_length);
// printf('Enabling DMA... %d\n', i);
//printf('Buffer size = %u\n', send_length);
//printf('USART1->SR = 0x%x\n', USART1->SR);
//printf('USART1->CR1 = 0x%x\n', USART1->CR1);
//printf('USART1->CR3 = 0x%x\n', USART1->CR3);
//printf('DMA2->HISR = 0x%x\n', DMA2->HISR);
//printf('DMA2->S7CR = 0x%x\n\n', DMA2_Stream7->CR);
 // started to transmit
 i = 0;
 DMA_Cmd(DMA2_Stream7,ENABLE);
 while(DMA_GetCmdStatus(DMA2_Stream7) != ENABLE) {
 DMA_Cmd(DMA2_Stream7,ENABLE);
//printf('Enabling DMA... %d\n', i);
//printf('Buffer size = %u\n', send_length);
//printf('USART1->SR = 0x%x\n', USART1->SR);
//printf('USART1->CR1 = 0x%x\n', USART1->CR1);
//printf('USART1->CR3 = 0x%x\n', USART1->CR3);
//printf('DMA2->HISR = 0x%x\n', DMA2->HISR);
//printf('DMA2->S7CR = 0x%x\n', DMA2_Stream7->CR);
i++;
vTaskDelay(pdMS_TO_TICKS(1));
if (i > 1000) {
System_Failure();
}
 }
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

#stm32f4 #dma #usart #usart-tx-issue
11 REPLIES 11
Posted on April 12, 2018 at 10:11

Have you consulted the errata?

Does this run in some multitasking environment? If so, can't there be hazards from other threads? Do other thread access DMA2 registers (including clearing the DMA2 status register)?

I see printouts at the disable stage. When the problem occurs, do you receive some of those printouts?

So the Rx DMA remains working and data *are* arriving while you are waiting for the Tx channel to be enabled? Any other DMA2 channels enabled and active? I am asking because IMO there may be interactions between the DMA channels.

Can you read out the DMA status register and the relevant DMA channel registers' content, when the problem happens, and post here?

JW

AvaTar
Lead
Posted on April 12, 2018 at 10:16

Since my TX packet length changes almost every time, I'd have to disable DMA, reconfigure it to the correct data length, and enable DMA. I'm doing this at least 100Hz if not more.

Doesn't this imply that DMA is not a good design approach in this case ?

An interrupt based handling would IMHO be much more appropriate in this case.

Posted on April 12, 2018 at 10:21

For Tx it's IMO appropriate.

As the code itself says, there's no real need for disabling the DMA, it's just a safety measure.

JW

Posted on April 12, 2018 at 11:30

For Tx it's IMO appropriate.

I agree.

As long as the send length is not variable, and one has to reconfigure DMA each time...

Asynchronous communication interfaces and DMA are not a good couple in all cases.

Other vendors (I'd like to name TI here) have FIFOs for their UARTs, which seem much more appropriate in this case.

Posted on April 12, 2018 at 21:25

> As long as the send length is not variable

What's the deal? The 'reconfiguration' is writing into two or three registers (flags clear, NDTR, CR/enable; and perhaps the memory pointer register if that is to change). Piece of cake.

Jan

Posted on April 13, 2018 at 04:29

Hi JW,

Those are really good questions! I know this might be a very rare case, so I'm just trying to put as much information out there as possible, in case anyone else has the same problem.

The errata didn't mention anything about DMA failing to enable or USART failing to request DMA transactions. There are other DMA and USART defects but I don't think they are applicable to my situation (for DMA, I didn't use peripherals described in the errata; for USART, the only flag I used were the TC flag but the errata says it only happens if CTS hardware flow control is enabled, which I don't have).

I'm indeed using FreeRTOS. I only have one task handling USART TX. It basically goes like this:

Get item in queue -> configure DMA and enable DMA -> task waits for DMA TC to be set (unblocked by IRQ) -> task waits for USART TC to be set (unblocked by IRQ) -> get next item in queue.

Now the interesting thing is that the RX is at DMA2_Stream2, and TX is at DMA2_Stream7. They should generate interrupts independently, and the status flags can only be cleared by writing 1 to the same bit position in a different register.

RX DMA indeed remains working and data keeps coming in, even when I'm waiting for TX enable. No other DMA2 (and DMA1 for that matter) channels are enabled. If there are interactions between DMA channels I'm not sure if that's a bug or a feature...

Another data point: at the beginning of the function I posted, DMA TX never fails to disable. I have only seen DMA TX failing to enable.

The DMA registers, when the problem happens, read like this:

0690X0000060AZUQA2.png

Sorry that the information I have doesn't directly solve the problem. But if anyone else has the same problem this could be helpful to them.

waclawek.jan wrote:

Have you consulted the errata?

Does this run in some multitasking environment? If so, can't there be hazards from other threads? Do other thread access DMA2 registers (including clearing the DMA2 status register)?

I see printouts at the disable stage. When the problem occurs, do you receive some of those printouts?

So the Rx DMA remains working and data *are* arriving while you are waiting for the Tx channel to be enabled? Any other DMA2 channels enabled and active? I am asking because IMO there may be interactions between the DMA channels.

Can you read out the DMA status register and the relevant DMA channel registers' content, when the problem happens, and post here?

JW

Posted on April 13, 2018 at 04:35

Hi AvaTar,

Being able to use DMA would free up quite a bit of MCU cycles. You are right that using interrupts could achieve the same functionality. If this turns out to be a hardware limitation, I would have no other choice but to use interrupts and MCU processing. Or if this turns out to be a software misconfiguration, then I can continue using DMA and get the benefits.

Posted on April 13, 2018 at 09:01

At some point, you spend at least as much time in reconfiguring DMA as you would in an interrupt handler.

Not even closely. As I've said, it's three register writes, or maybe four. The interrupt takes more than that just to enter and exit, and that's done for every single byte.

And the greatest weakness of DMA is IMHO reception error handling.

That we all agree upon. It's just too sad that it would have taken only a very little step to do this properly, by combining the data and status register together it would provide the FIFO experience of the venerable 16x50. This is just another example where the lack of real-world experience of the IP designers shows.

JW

Posted on April 13, 2018 at 07:24

At some point, you spend at least as much time in reconfiguring DMA as you would in an interrupt handler.

And the greatest weakness of DMA is IMHO reception error handling.