HAL_ChibiOS: fixed CANFD timings
our CANFD timings were resulting in a lot of busoff errors. Here is an example of master at 1Mbit/5MBit: Getting @SYS/can0_stats.txt as - ------- Clock Config ------- CAN_CLK_FREQ: 80MHz Std Timings: bitrate=1000000 presc=7 sjw=0 bs1=7 bs2=0 sample_point=90.00000% FD Timings: bitrate=5000000 presc=1 sjw=0 bs1=5 bs2=0 sample_point=90.00000% ------- CAN Interface Stats ------- tx_requests: 2689 tx_rejected: 0 tx_overflow: 443 tx_success: 7 tx_timedout: 2232 tx_abort: 0 rx_received: 18470 rx_overflow: 0 rx_errors: 0 num_busoff_err: 34439 num_events: 18477 ECR: F8 fdf_rx: 18467 fdf_tx_req: 2182 fdf_tx: 0 here is an example with the new timings: ------- Clock Config ------- CAN_CLK_FREQ: 80MHz Std Timings: bitrate=1000000 presc=8 sjw=1 bs1=8 bs2=1 sample_point=90.00000% FD Timings: bitrate=8000000 presc=2 sjw=3 bs1=8 bs2=3 sample_point=80.00000% ------- CAN Interface Stats ------- tx_requests: 3023 tx_rejected: 0 tx_overflow: 0 tx_success: 3023 tx_timedout: 0 tx_abort: 0 rx_received: 27865 rx_overflow: 0 rx_errors: 0 num_busoff_err: 0 num_events: 30888 ECR: 0 fdf_rx: 27862 fdf_tx_req: 3016 fdf_tx: 3016 I am testing between a CubeOrange and a Pixhawk6X. I tested 1, 2, 4, 5 and 8 MBit (which are the only valid FD bitrates in our parameters) Many thanks to Kai from Salient Motion for finding this issue and providing the corrected timing table
This commit is contained in:
parent
52468f0238
commit
1c8048df8f
@ -190,7 +190,7 @@ void CANIface::handleBusOffInterrupt()
|
||||
_detected_bus_off = true;
|
||||
}
|
||||
|
||||
bool CANIface::computeTimings(const uint32_t target_bitrate, Timings& out_timings)
|
||||
bool CANIface::computeTimings(const uint32_t target_bitrate, Timings& out_timings) const
|
||||
{
|
||||
if (target_bitrate < 1) {
|
||||
return false;
|
||||
@ -316,13 +316,46 @@ bool CANIface::computeTimings(const uint32_t target_bitrate, Timings& out_timing
|
||||
}
|
||||
|
||||
out_timings.sample_point_permill = solution.sample_point_permill;
|
||||
out_timings.prescaler = uint16_t(prescaler - 1U);
|
||||
out_timings.sjw = 0; // Which means one
|
||||
out_timings.bs1 = uint8_t(solution.bs1 - 1);
|
||||
out_timings.bs2 = uint8_t(solution.bs2 - 1);
|
||||
out_timings.prescaler = uint16_t(prescaler);
|
||||
out_timings.sjw = 1;
|
||||
out_timings.bs1 = uint8_t(solution.bs1);
|
||||
out_timings.bs2 = uint8_t(solution.bs2);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
table driven timings for CANFD
|
||||
*/
|
||||
bool CANIface::computeFDTimings(const uint32_t target_bitrate, Timings& out_timings) const
|
||||
{
|
||||
static const struct {
|
||||
uint8_t bitrate_mbaud;
|
||||
uint8_t prescaler;
|
||||
uint8_t bs1;
|
||||
uint8_t bs2;
|
||||
uint8_t sjw;
|
||||
uint8_t sample_point_pct;
|
||||
} CANFD_timings[] {
|
||||
{ 1, 5, 15, 6, 6, 75},
|
||||
{ 2, 3, 15, 6, 6, 75},
|
||||
{ 4, 2, 15, 6, 6, 75},
|
||||
{ 5, 2, 12, 5, 5, 75},
|
||||
{ 8, 2, 8, 3, 3, 80},
|
||||
};
|
||||
for (const auto &t : CANFD_timings) {
|
||||
if (t.bitrate_mbaud*1000U*1000U == target_bitrate) {
|
||||
// out_timings has the register bits, which are the actual value minus 1
|
||||
out_timings.prescaler = t.prescaler;
|
||||
out_timings.bs1 = t.bs1;
|
||||
out_timings.bs2 = t.bs2;
|
||||
out_timings.sjw = t.sjw;
|
||||
out_timings.sample_point_permill = t.sample_point_pct*10;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int16_t CANIface::send(const AP_HAL::CANFrame& frame, uint64_t tx_deadline,
|
||||
CanIOFlags flags)
|
||||
{
|
||||
@ -666,13 +699,13 @@ bool CANIface::init(const uint32_t bitrate, const uint32_t fdbitrate, const Oper
|
||||
unsigned(timings.prescaler), unsigned(timings.sjw), unsigned(timings.bs1), unsigned(timings.bs2));
|
||||
|
||||
//setup timing register
|
||||
can_->NBTP = ((timings.sjw << FDCAN_NBTP_NSJW_Pos) |
|
||||
(timings.bs1 << FDCAN_NBTP_NTSEG1_Pos) |
|
||||
(timings.bs2 << FDCAN_NBTP_NTSEG2_Pos) |
|
||||
(timings.prescaler << FDCAN_NBTP_NBRP_Pos));
|
||||
can_->NBTP = (((timings.sjw-1) << FDCAN_NBTP_NSJW_Pos) |
|
||||
((timings.bs1-1) << FDCAN_NBTP_NTSEG1_Pos) |
|
||||
((timings.bs2-1) << FDCAN_NBTP_NTSEG2_Pos) |
|
||||
((timings.prescaler-1) << FDCAN_NBTP_NBRP_Pos));
|
||||
|
||||
if (fdbitrate) {
|
||||
if (!computeTimings(fdbitrate, fdtimings)) {
|
||||
if (!computeFDTimings(fdbitrate, fdtimings)) {
|
||||
can_->CCCR &= ~FDCAN_CCCR_INIT;
|
||||
uint32_t while_start_ms = AP_HAL::millis();
|
||||
while ((can_->CCCR & FDCAN_CCCR_INIT) == 1) {
|
||||
@ -685,9 +718,10 @@ bool CANIface::init(const uint32_t bitrate, const uint32_t fdbitrate, const Oper
|
||||
_fdbitrate = fdbitrate;
|
||||
Debug("CANFD Timings: presc=%u bs1=%u bs2=%u\n",
|
||||
unsigned(fdtimings.prescaler), unsigned(fdtimings.bs1), unsigned(fdtimings.bs2));
|
||||
can_->DBTP = ((fdtimings.bs1 << FDCAN_DBTP_DTSEG1_Pos) |
|
||||
(fdtimings.bs2 << FDCAN_DBTP_DTSEG2_Pos) |
|
||||
(fdtimings.prescaler << FDCAN_DBTP_DBRP_Pos));
|
||||
can_->DBTP = (((fdtimings.bs1-1) << FDCAN_DBTP_DTSEG1_Pos) |
|
||||
((fdtimings.bs2-1) << FDCAN_DBTP_DTSEG2_Pos) |
|
||||
((fdtimings.prescaler-1) << FDCAN_DBTP_DBRP_Pos) |
|
||||
((fdtimings.sjw-1) << FDCAN_DBTP_DSJW_Pos));
|
||||
}
|
||||
|
||||
//RX Config
|
||||
@ -1111,7 +1145,7 @@ void CANIface::get_stats(ExpandingString &str)
|
||||
unsigned(timings.bs2), timings.sample_point_permill/10.0f,
|
||||
_fdbitrate, unsigned(fdtimings.prescaler),
|
||||
unsigned(fdtimings.sjw), unsigned(fdtimings.bs1),
|
||||
unsigned(fdtimings.bs2), timings.sample_point_permill/10.0f,
|
||||
unsigned(fdtimings.bs2), fdtimings.sample_point_permill/10.0f,
|
||||
stats.tx_requests,
|
||||
stats.tx_rejected,
|
||||
stats.tx_overflow,
|
||||
|
@ -123,7 +123,8 @@ class ChibiOS::CANIface : public AP_HAL::CANIface
|
||||
|
||||
const uint8_t self_index_;
|
||||
|
||||
bool computeTimings(uint32_t target_bitrate, Timings& out_timings);
|
||||
bool computeTimings(uint32_t target_bitrate, Timings& out_timings) const;
|
||||
bool computeFDTimings(uint32_t target_bitrate, Timings& out_timings) const;
|
||||
|
||||
void setupMessageRam(void);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user