mirror of
https://github.com/PX4/PX4-Autopilot.git
synced 2026-09-24 19:08:21 +08:00
fix(uavcan): keep the configured CAN bitrate on FlexCAN controllers
The SIOCSCANBITRATE path in CanIface::setBitRate() was gated on SIOCGCANERRORS, which the NuttX submodule bump now defines. That turned on a retune sequence that had never been compiled or run in this tree: it takes the interface down, sets the bitrate and brings it back up. Two problems surfaced on a Pixhawk v6XRT. The path did not build, because it still used IFF_DOWN, which NuttX removed; SIOCSIFFLAGS now acts on the IFF_UP request bit, so clearing it is what takes an interface down. Once it built, the board booted and then crashed a few seconds later, when uavcan started and retuned the interfaces. The driver ioctl itself is harmless and only stores the timings, so the fault is in bringing a FlexCAN interface down and back up at runtime, where ECC RAM initialisation runs again on a controller that has already been started. SIOCGCANERRORS reports whether a driver can read error counters, which says nothing about whether it can be retuned; the two capabilities only happened to arrive in the same commit. Gate on the capability that is actually meant, and keep the configured rate on the FlexCAN chips. Every board in the tree that enables SocketCAN today is FlexCAN, so this restores the behaviour those boards already had before the bump. Verified on px4_fmu-v6xrt: crashes with the retune path active, stable with the configured rate kept. Assisted-by: Claude:claude-opus-5 Signed-off-by: Julian Oes <julian@oes.ch>
This commit is contained in:
@@ -361,6 +361,25 @@ int CanIface::pollErrors() const
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Retuning through SIOCSCANBITRATE takes the interface down and brings it back
|
||||
* up again. The FlexCAN drivers (i.MX RT, S32K, Kinetis) re-run their ECC RAM
|
||||
* initialisation on ifup, which faults once the controller has been started, so
|
||||
* the rate the driver was configured with is kept on those chips instead.
|
||||
*
|
||||
* SIOCGCANERRORS only says that the driver can report error counters, which is
|
||||
* a separate capability from being able to retune, so it cannot gate this on
|
||||
* its own.
|
||||
*/
|
||||
#if defined(SIOCGCANERRORS) && \
|
||||
!defined(CONFIG_ARCH_CHIP_IMXRT) && \
|
||||
!defined(CONFIG_ARCH_CHIP_S32K1XX) && \
|
||||
!defined(CONFIG_ARCH_CHIP_S32K3XX) && \
|
||||
!defined(CONFIG_ARCH_CHIP_KINETIS)
|
||||
# define PX4_SOCKETCAN_SAFE_RETUNE 1
|
||||
#else
|
||||
# define PX4_SOCKETCAN_SAFE_RETUNE 0
|
||||
#endif
|
||||
|
||||
int CanIface::setBitRate(uint32_t bitrate)
|
||||
{
|
||||
if (_fd < 0 || bitrate == 0) {
|
||||
@@ -382,12 +401,8 @@ int CanIface::setBitRate(uint32_t bitrate)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef SIOCGCANERRORS
|
||||
/* Before the PX4/NuttX change that added SIOCGCANERRORS, SIOCSCANBITRATE
|
||||
* restarted a running controller from inside the driver, which on FlexCAN
|
||||
* with ECC RAM initialisation is a bus fault. Keep the configured rate.
|
||||
*/
|
||||
PX4_WARN("can%" PRIu32 ": UAVCAN_BITRATE %u kbit/s needs a newer NuttX, staying at %" PRIu32 " kbit/s",
|
||||
#if !PX4_SOCKETCAN_SAFE_RETUNE
|
||||
PX4_WARN("can%" PRIu32 ": UAVCAN_BITRATE %u kbit/s not applied, staying at %" PRIu32 " kbit/s",
|
||||
_index, kbps, ifr.ifr_ifru.ifru_can_data.arbi_bitrate);
|
||||
return 0;
|
||||
#else
|
||||
@@ -409,9 +424,11 @@ int CanIface::setBitRate(uint32_t bitrate)
|
||||
|
||||
const bool was_up = flags.ifr_flags & IFF_UP;
|
||||
|
||||
/* NuttX takes IFF_DOWN / IFF_UP as requests, not as a state mask */
|
||||
/* NuttX acts on the IFF_UP request bit: setting it brings the interface up,
|
||||
* clearing it takes the interface down. IFF_DOWN was removed in NuttX 12.
|
||||
*/
|
||||
if (was_up) {
|
||||
flags.ifr_flags = IFF_DOWN;
|
||||
IFF_CLR_UP(flags.ifr_flags);
|
||||
|
||||
if (ioctl(_fd, SIOCSIFFLAGS, &flags) < 0) {
|
||||
PX4_ERR("can%" PRIu32 ": cannot take the interface down (%d)", _index, errno);
|
||||
|
||||
Reference in New Issue
Block a user