Skip to main content
Josh Yu
Associate II
April 12, 2018
Question

STM32F407 DMA2 Repeated Disable and Enable Fails

  • April 12, 2018
  • 3 replies
  • 3239 views
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
This topic has been closed for replies.

3 replies

waclawek.jan
Super User
April 12, 2018
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

Josh Yu
Josh YuAuthor
Associate II
April 13, 2018
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

waclawek.jan
Super User
April 13, 2018
Posted on April 13, 2018 at 09:16

So the status flags are cleared, and still the EN bit won't be set... humm.

Can you please tell us about how do you handle the reception? Do you reconfigure its DMA?

I see you have transfer-error interrupt enabled. How is it handled? Does it happen? Doesn't it happen just before the problem?

Can you please make a copy of the HTIF before you clear it, into a local variable, and then print it out when the problem happens?

You don't enable/disable or reset the UART, do you?

You don't observe the USART and/or DMA registers in a debugger while the application is running, do you? If you do, please disconnect the debugger and try to run the application without it.

JW

AvaTar
Senior III
April 12, 2018
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.

waclawek.jan
Super User
April 12, 2018
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

AvaTar
Senior III
April 12, 2018
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.

waclawek.jan
Super User
April 13, 2018
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

AvaTar
Senior III
April 13, 2018
Posted on April 13, 2018 at 10:07

Not even closely. As I've said, it's three register writes, or maybe four.

For you, yes.

Pretty sure Cube generates much noise about those simple register writes...