cancel
Showing results for 
Search instead for 
Did you mean: 

USART Receive to Idle DMA callbacks

PCamp.2
Associate III

I got this working, then it stopped working.

I finally figured out after about 3 hours what is wrong.

Situation. I am making a "Serial tap" for debugging. The STM32F411CE on the Black Pill board. 2xUSARTs Rx only and the CDC Virtual COM port device on USB.

It "did" work, however when I brought in the second USART I needed a state machine so I didn't have to handle the sending in the interrupts and could handle one UART being active and the other idle.

However, I think what I missed is that if I call

HAL_UARTEx_ReceiveToIdle_DMA(&huart1, buffer1, READ_SIZE );

and the UART is sitting idle, then the DMA will transfer nothing. The interupts will fire, but it will not fire the Tx complete (TC) interupt. It appears to fire another one. Maybe Abort?

I struggle tracking down those call backs, they are _weak externs buried in the library files, they are lots of them and they are confusing with combining DMA and UART.

Before I go guessing as to which call backs I need to handle to not dead lock my state machine when the line is idle and DMA fails.

Would it just be the DMA abort call back?

Could you suggest another way to poll the uart DMA transfer to see if the UART has gone back to READY maybe?

Basically my code just needs to read a burst of data on a UART and send that on the VCOM port as a single line. Ideally not mixing the lines up.

The other less important issue I have seen is that the CDC Transmit function is too smart for it's own good and has a tendency to return "BSY" when it's absolutely not busy, it's just that nothing is consuming the data on the other end of the wire (no app on the PC is using the COM port), so it keeps returning busy, probably because it's waiting on an application emptying it's buffer.

3 REPLIES 3
Piranha
Chief II

Stop wasting a time on a broken bloatware and implement something usable...

https://github.com/MaJerle/stm32-usart-uart-dma-rx-tx

If by bloatware you mean the HAL libraries. Sure. I can spent 3 weeks in the data sheet to write something that, if it worked, would take 30 mins with HAL.

Sure it covers cases I don't need, but the thing is, the code is in my project, if I don't like part of it I can remove it.

Also, don't be so sure. That code, you posted would not help. It makes the same mistake I made. All of about a dozen examples make the same mistake and will deadlock on any unexpected or erroneous condition.

A UART Break Condition on the wire will abort a DMA transfer and reset the receiving UART. It will NOT fire the idle interrupt, it will not call the HAL call back and as the code you posted doesn't handle the failure condition, the lovely ring buffer stuff will simply deadlock.

If you simply ignore that flag, then what is in the DMA buffer is very likely just garbage.

I believe my issue was that I was testing with an IC. It mostly sat silent with nothing to say, so to test my STM code I was resetting that IC and expecting to see the boot spam come through. It never did.

Looking at what happens when I reset the IC on the logic analyser and I figured it out.

The IC pulls the line low and holds it low until it initialises it's UART. This is interpreted as a "BREAK" condition. The STM32 Uart fires it's interrupt handler, but it's for the "reset" condition. It (HAL) eventually calls the UARTEx_RxAborted call back.

As I was setting buffer flags and restarting the transfer in the RxEvent ... it never got called and dead locked the buffers.

I will have to resume tomorrow evening. By the time I had figured this out I had ripped half my test rig apart checking and double checking connections and eventually getting the logic analyser out.

An observation. Powering Nucleo boards from a PC power supply produces a FIERCE amount of noise on the ground rail. We are talking 800mV p2p of noise! All of it is coming from the PC's noise earth and USB isolators are expensive, but it makes scoping the UARTs very difficult to get the triggers working right (On a cheap scope).

Pavel A.
Evangelist III

> CDC Transmit function is too smart for it's own good and has a tendency to return "BSY" when it's absolutely not busy .... probably because it's waiting on an application emptying it's buffer

Yes, USB has its own way to apply back-pressure, even when the virtual COM port has flow control = none. But more likely there's some problem at the STM32 firmware side. Interaction of USB code with UART is a suspicious spot.