Hi, this is my first time posting in the mailing list. I'm an embedded
software engineer and I primarily work on the PX4-Autopilot project. I
recently implemented Bidirectional DShot in PX4 which uses Timer Burst with
DMA to simultaneously update channels 1 - 4 to send data to the ESCs
(electronic speed controllers) to control the RPM of the motors. The
Bidirectional DShot protocol uses a single wire for both RX and TX. So
after the Timer Burst is complete I am reusing the same DMA stream to then
perform a Capture Compare on one timer channel at a time in a round-robin
fashion (to receive ESC telemetry). When I implemented and tested the
feature it worked and we merged it in. Fast forward to now, a user reported
that one of their serial devices wasn't working when Bidirectional Dshot
was enabled. Upon investigation I confirmed this, one of the serial devices
also using DMA on DMA1 stopped receiving data when bidirectional dshot was
enabled. I instrumented the NuttX driver code and verified that I was using
the exact number of DMA streams as I was expecting, none of the streams
were in conflict. In total I am using 7 streams -- 2 for SPI, 4 for two
UARTs, and 1 for the Timer. The SPI and first UART devices work properly,
only the second UART is affected.

My working theory is that the high frequency allocation/freeing of the DMA
stream (re-assinging from Burst to CaptureCompare at 800Hz) is
interfering with the other streams on that DMA controller. I looked through
the NuttX code and saw that most drivers use stm32_dmachannel() during
initialization and stm32_dmafree() during cleanup, so my use case seems
unique. Can anyone shed some light on this and help me determine the best
path forward? For now I've moved the Timer DMA stream to DMA2 to avoid
conflicts with my other peripherals, but I would like to solve this issue
so that I am not limiting my available DMA streams. The code is here, I've
highlighted the relevant sections:
https://github.com/PX4/PX4-Autopilot/blob/main/platforms/nuttx/src/px4/stm/stm32_common/dshot/dshot.c#L330-L537
The flow is as such:
up_dshot_trigger --> dma_burst_finished_callback
--> capture_complete_callback

Thank you for your time,
Jake

Reply via email to