cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F091 UART Rx DMA failing at high speeds when talking to specific device

Luke Metro
Associate II
Posted on March 29, 2018 at 22:57

In my project, I'm using an STM32F091 MCU to communicate with another ARM processor via UART. The communication rate is 1 MBaud, and I'm using the STM32's DMA in circular mode to receive bytes.

I have been developing the STM32 firmware on a Nucleo board and using an FTDI USB-to-UART cable as a stand-in for the other processor. I have just recently begun to replace the FTDI cable with the other processor, and some transmission problems have arisen.

While the new processor is able to successfully communicate with the STM32 via basic polling (the proper bytes are appearing in RDR, and RXNE is being correctly flagged), the DMA is not activating at Baud rates over 900kBaud when communicating with this specific device.

I am convinced there are no problems with the other processor: Its output is properly decoded by a logic analyzer, and it is able to successfully communicate with the FTDI cable. It is only the DMA transfer that is not occuring: the bytes otherwise appear to be properly received, as the STM32 in polling mode is able to communicate with the new processor. The buffer in memory is not filling up, and the DMA channel's CNDTR register is keeping its initial value.

I have found a workaround: Switching the UART's oversampling from 8 to 16 does make the DMA work normally. I'm not sure why, as in theory the UART and DMA controllers are separate from one another. The DMA error register does not show any errors when I look at it with a debugger.

Even with the workaround, adding a small amount of series resistance (400 ohms total) to the TX and RX lines causes the DMA to stop working at higher frequencies. Both the UART and DMA are using the internal HSI48 clock with prescalers set to 1 (so both are using a 48MHz clock).

It seems like a timing bug to me, but has anyone encountered anything like this before?

#uart-dma #usart-rx
1 ACCEPTED SOLUTION

Accepted Solutions
Luke Metro
Associate II
Posted on March 31, 2018 at 02:35

Just solved the problem!

It turns out that the clock trees for the STM32 and the other computer did not agree -- there was a high skew, and increasing the frequency by a few dozen kiloBaud made it work.

The lack of DMA transfers can be explained by the DDRE bit in one of the DMA's control registers: since the clock skew caused framing errors, the bytes weren't being transferred (even though the correct values appeared in RDR, and RXNE was being set)

View solution in original post

11 REPLIES 11
Posted on March 30, 2018 at 13:19

It sounds you have a rather high error rate. With not using a precise enough clocks on both sides it's not a surprise; and the high baudrate together with probably problematic long transmission line may only worsen it.

The DMA should not be 'coupled' principially to the errors, but my crystal ball says that you may use some 'library' such as Cube/HAL, which enables interrupt upon errors and then disables the DMA when error occurs.

JW

Luke Metro
Associate II
Posted on March 30, 2018 at 21:52

I don't believe error rate is the problem: Using the same analog configuration, bytes can be properly read by the STM32 in polling mode - it is only the DMA that is problematic. Furthermore, a logic analyzer / FTDI cable placed at the location of the STM32 is able to read the bytes perfectly.

I tried changing the clock from the HSI48 to an external 24MHz oscillator, but that hasn't resolved the issue. I am not using an external library, I am writing to the control registers manually. When I investigate the STM32 with a debugger after sending it some bytes, the DMA is stilll enabled. No TEIF bits are set, and I don't have any transfer error interrupts enabled anyways. 

Luke Metro
Associate II
Posted on March 30, 2018 at 22:06

I have not been observing the USART registers. CNDTR does not change at all.

I just tested another transmission before inspecting the UART registers, and the FE (framing error) and NF (noise detected flag) bits were both set high. However, this doesn't happen when DMA is disabled. Either way, the RDR is changing to reflect the bytes sent.

Posted on March 30, 2018 at 22:21

However, this doesn't happen when DMA is disabled.

Humm..

Have you observed the data lines themselves, by an oscilloscope or logic analyzer?

What is the physical connection? Are grounds connected properly?

Is the communication continuous or are you trying just to send a few bytes at a time, with longer 'quiet' spaces in between?

Also, can you please read out and post the content of the USART and DMA registers, so that we have some fixed points to discuss further?

JW

PS. Comparing the registers content between the non-DMA and DMA version won't reveal any significant difference?

Luke Metro
Associate II
Posted on March 30, 2018 at 23:26

I have observed the data lines with an oscilloscope and analyzer. The signal quality is good, and the logic analyzer reads the incoming stream of bytes properly.

The STM32 and the other processor are on the same PCB, so they share the same ground.

I'm sending packets of around 10 bytes at a time. In my testing environment, packets are being sent manually (one every few seconds or so)

I'm using UART 4 with DMA1, channel 6. The registers are as such:

DMA1 ISR: All bits set to 0

DMA1 CCR6: EN=1, CIRC=1, MINC=1, PL=3, all others set to 0.

DMA1 CPAR6 & CMAR6 are set to the proper addresses, and CNDTR6 is equal to the initialized value.

USART4 CR1 has the UE, RE, TE, & OVER8 bits set to 1.

USART4 CR2 has all bits set to 0.

USART4 CR3: DMAR set to 1, all others set to 0.

UART4 ISR: FE, NF, TC, TXE, CMF, TEACK, and REACK set to 1. All others set to 0.

USART4 RDR contains the last byte of the packet.

USART4 BRR fraction set to 0, mantissa set to 0x6. (Whole register value is 0x60.) The math, as far as I can tell is correct, since system clock is 48 MHz.

The only difference in register content between DMA and non-DMA is that the DMA seems to be clearing the RXNE register (even though the transfer does not seem to be happening)

Thank you!

Posted on March 30, 2018 at 23:52

I'm using UART 4 with DMA1, channel 6.

So, what's in DMA_CSELR ?

And can't be some other channel, or DMA2, inadvertently enabled, picking up the received bytes?

DMA1 CPAR6 & CMAR6 are set to the proper addresses,

Are they? Aren't they swapped by any chance? (I now this shouldn't work but this situation all sounds crazy so maybe some crazy questions are permitted by now...)

Can you try to (manually) transmit from USART4 while it is in that problematic state, to double-check the baudrate is OK? And, when at it, could you perhaps also try setting the baudrate register to 0x30 and OVER8 to 0.

Running out of ideas.

JW

Posted on March 30, 2018 at 21:59

Humm. Sorry. Have to send in the crystal ball for repolish... 😉

You don't observe the USART registers by the debugger while running, do you? Reading the data by the debugger clears the RXNE flag, which then won't trigger the DMA.

Btw after that few bytes transferred, you say CNDTR does not change at all? And what's in the USART status register after that?

JW

PS. While at it, you might perhaps read out and post all the relevant USART and DMA registers, including those which steer the DMA requests (F09x may be different from other 'F0 in this regard if I remember correctly)

T J
Lead
Posted on March 31, 2018 at 02:30

at 1M baud the RS232 line drivers will be upset.

I am surprised it works at all.

I found some RS232 drive chips wont work above 115200, some work at 230400, never tried above that.

did you scope the lines ?  you need at least + 3V and - 3V on the serial wire.

Luke Metro
Associate II
Posted on March 31, 2018 at 02:35

Just solved the problem!

It turns out that the clock trees for the STM32 and the other computer did not agree -- there was a high skew, and increasing the frequency by a few dozen kiloBaud made it work.

The lack of DMA transfers can be explained by the DDRE bit in one of the DMA's control registers: since the clock skew caused framing errors, the bytes weren't being transferred (even though the correct values appeared in RDR, and RXNE was being set)