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