mirror of
https://github.com/PX4/PX4-Autopilot.git
synced 2026-10-06 09:02:52 +08:00
* feat(dshot): EDT and BDShot HAL contract on i.MX RT The FlexIO driver ignored edt_enable and only marked a channel ready after a CRC-good post-training frame, so one missing ESC blocked telemetry for every motor. Match the STM32 consumer contract: ready every cycle, consecutive CRC hysteresis, train on any valid GCR, and gate FlexIO output from up_dshot_arm. Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com> * fix(dshot): keep the trained BDShot offset across an i.MX RT dropout Going offline restarted baud training from BDSHOT_TCMP_MIN_OFFSET. The offset tracks the ESC oscillator, not the link, so a transient dropout threw away a still-valid result and pinned the channel offline for the whole re-sweep, starving the ESC RPM notch. Train once on first connect and let the success hysteresis handle recovery. Also close three smaller gaps: the sweep stopped one round early and never evaluated BDSHOT_TCMP_MAX_OFFSET, up_bdshot_get_erpm carried a bound check the next line subsumes, and re-arming left a stale channel state that latched a garbage SHIFTBUFBIS read as a response. Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com> * fix(dshot): harvest i.MX RT BDShot RX before the next TX dshot_motor_data_set flipped state to DSHOT_START and cleared SHIFTSTAT before the frame was consumed, so a delayed FlexIO IRQ transmitted irq_data instead of latching telemetry. Harvest under a critical section and skip the burst while the receive window is still open. Zero driver state in up_dshot_init so a module restart cannot keep a stale online bit through retraining. After a second offline period, restart the TCMP sweep so a wrong baud can recover. Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com> * fix(dshot): guard the whole i.MX RT DShot cycle, not just the receive The busy window started at the IRQ's receive timestamp, so a trigger landing during the frame itself reconfigured the shifter mid-transmit, and up_dshot_arm enabled the shifter interrupt with nothing queued. The first trigger after arming also counted a missing response, and the trained TCMP was updated outside the critical section the IRQ reads it in. Stamp the cycle at transmit and size the window for frame, ESC turnaround and response. Latch, decode and reconfigure in one critical section, mask the IRQ by the enable registers instead of a channel mask, and leave the timer interrupt off while receiving. Warn for outputs the FlexIO cannot serve instead of dropping them silently. Assisted-by: Claude:claude-fable-5 Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com> * fix(dshot): keep the i.MX RT DShot trigger out of a critical section up_dshot_trigger runs at the output rate, so masking every interrupt on the MCU for the whole latch, decode and reconfigure pass was far too long. The IRQ only acts on a channel whose interrupt is enabled and the trigger only touches a channel whose cycle is over, so the two contexts never own the same channel at once and none of that needed a lock. What does: the SHIFTBUF write and the interrupt enable must not be separated by preemption, since the IRQ has to queue the second word within 20 us at DShot1200, and SHIFTSIEN/TIMIEN have no set/clear aliases, so the thread's read-modify-write must be atomic against the IRQ's. That is a dozen register accesses. Assisted-by: Claude:claude-fable-5 Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com> * fix(dshot): do not clear SSF after re-enabling the i.MX RT transmit shifter In transmit mode SSF sets on enable and is the timer's active-low trigger. Clearing it before SHIFTBUF is written asserts the trigger, so the timer shifts an empty shifter for one compare and the real word lands late: 14 garbage sub-bits, a truncated frame, no ESC response. Only the SHIFTBUF write may clear it. Assisted-by: Claude:claude-fable-5 Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com> * fix(dshot): resynchronise the i.MX RT BDShot receive timer on the channel pin The receive timer was set to reset on its timer pin's rising edge, but the timer pin was left at FXIO_D0, so the baud counter never resynchronised; and with the timer output starting high the first shift came a full period after the start edge, so every sample sat on a bit boundary. Only a baud 2-3 % faster than the ESC's pulled the samples inside the bits, which is why training found a three-count window and why channels fell off it per run. Point the timer pin at the channel pin so a baud-mode reset reloads the divider on every falling edge of the response, and start the output low so the shift lands mid-bit. On an ARK 4in1 at DShot300 every offset from -10 to +15 now decodes 198/200, all four channels train on the first sweep, and the CRC error rate matches the previous driver. The status output shows the training mask. Assisted-by: Claude:claude-fable-5 Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com> * perf(dshot): run the i.MX RT DShot cycle from ITCM up_dshot_trigger executed from the NOR over XIP, so its ~1 µs critical section measured 5.6 µs worst case on instruction cache misses at 800 Hz. Map the per-cycle path — the trigger, its FlexIO callees, the HAL getters and the DShot module's Run/updateOutputs/telemetry — into ITCM on fmu-v6xrt, about 3 KB. decode_gcr_payload is inlined so the list needs no compiler-named partial section. Assisted-by: Claude:claude-fable-5 Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com> * fix(dshot): keep the i.MX RT BDShot offset across a dropout A missing response counted toward the re-sweep, so any dropout over 0.5 s — a wire, an ESC power cycle — cost a full seven-second sweep after the ESC came back although its oscillator had not changed. Only frames that arrive and fail to decode restart training now; a dropout just takes the channel offline and it is back 200 good frames after the ESC returns. Assisted-by: Claude:claude-fable-5 Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com> * perf(dshot): sweep the i.MX RT BDShot baud in 25-frame rounds With the receive timer resynchronising, every offset is either clean or fails outright, so 200 frames per offset only stretched the sweep to eight seconds at 800 Hz once the whole window started passing. 25 frames with one allowed miss give the same mask in a second, well inside the five seconds DShot.cpp ignores telemetry after boot. Assisted-by: Claude:claude-fable-5 Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com> * docs(dshot): restore the i.MX RT FlexIO register comments The rewrite dropped the comments naming what each shifter and timer register write configures. They are the only prose map of the FlexIO setup, so keep them wherever the code they describe survives. Assisted-by: Claude:claude-fable-5 Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com> --------- Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>