diff --git a/drivers/can/can_common.c b/drivers/can/can_common.c index f6c02ccedd0..c7902ee9d20 100644 --- a/drivers/can/can_common.c +++ b/drivers/can/can_common.c @@ -78,52 +78,86 @@ int z_impl_can_add_rx_filter_msgq(const struct device *dev, struct k_msgq *msgq, return api->add_rx_filter(dev, can_msgq_put, msgq, filter); } -static int update_sampling_pnt(uint32_t ts, uint32_t sp, struct can_timing *res, +/** + * @brief Update the timing given a total number of time quanta and a sample point. + * + * @code{.text} + * + * +---------------------------------------------------+ + * | Nominal bit time in time quanta (total_tq) | + * +--------------+----------+------------+------------+ + * | sync_seg | prop_seg | phase_seg1 | phase_seg2 | + * +--------------+----------+------------+------------+ + * | CAN_SYNG_SEG | tseg1 | tseg2 | + * +--------------+-----------------------+------------+ + * ^ + * sample_pnt + * @endcode + * + * @see @a can_timing + * + * @param total_tq Total number of time quanta. + * @param sample_pnt Sampling point in permill of the entire bit time. + * @param[out] res Result is written into the @a can_timing struct provided. + * @param max Maximum timing parameters values. + * @param min Minimum timing parameters values. + * @return Absolute sample point error. + */ +static int update_sampling_pnt(uint32_t total_tq, uint32_t sample_pnt, + struct can_timing *res, const struct can_timing *max, const struct can_timing *min) { - uint16_t ts1_max = max->phase_seg1 + max->prop_seg; - uint16_t ts1_min = min->phase_seg1 + min->prop_seg; - uint32_t sp_calc; - uint16_t ts1, ts2; + uint16_t tseg1_max = max->phase_seg1 + max->prop_seg; + uint16_t tseg1_min = min->phase_seg1 + min->prop_seg; + uint32_t sample_pnt_res; + uint16_t tseg1, tseg2; - ts2 = ts - (ts * sp) / 1000; - ts2 = CLAMP(ts2, min->phase_seg2, max->phase_seg2); - ts1 = ts - CAN_SYNC_SEG - ts2; + /* Calculate number of time quanta in tseg2 for given sample point */ + tseg2 = total_tq - (total_tq * sample_pnt) / 1000; + tseg2 = CLAMP(tseg2, min->phase_seg2, max->phase_seg2); - if (ts1 > ts1_max) { - ts1 = ts1_max; - ts2 = ts - CAN_SYNC_SEG - ts1; - if (ts2 > max->phase_seg2) { + /* Calculate number of time quanta in tseg1 */ + tseg1 = total_tq - CAN_SYNC_SEG - tseg2; + if (tseg1 > tseg1_max) { + /* Sample point location must be decreased */ + tseg1 = tseg1_max; + tseg2 = total_tq - CAN_SYNC_SEG - tseg1; + if (tseg2 > max->phase_seg2) { return -1; } - } else if (ts1 < ts1_min) { - ts1 = ts1_min; - ts2 = ts - CAN_SYNC_SEG - ts1; - if (ts2 < min->phase_seg2) { + } else if (tseg1 < tseg1_min) { + /* Sample point location must be increased */ + tseg1 = tseg1_min; + tseg2 = total_tq - CAN_SYNC_SEG - tseg1; + if (tseg2 < min->phase_seg2) { return -1; } } - res->phase_seg2 = ts2; + res->phase_seg2 = tseg2; - /* Attempt to distribute ts1 evenly between prop_seq and phase_seg1 */ - res->prop_seg = CLAMP(ts1 / 2, min->prop_seg, max->prop_seg); - res->phase_seg1 = ts1 - res->prop_seg; + /* Attempt to distribute tseg1 evenly between prop_seq and phase_seg1 */ + res->prop_seg = CLAMP(tseg1 / 2, min->prop_seg, max->prop_seg); + res->phase_seg1 = tseg1 - res->prop_seg; if (res->phase_seg1 > max->phase_seg1) { - /* Even ts1 distribution not possible, decrease phase_seg1 */ + /* Even tseg1 distribution not possible, decrease phase_seg1 */ res->phase_seg1 = max->phase_seg1; - res->prop_seg = ts1 - res->phase_seg1; + res->prop_seg = tseg1 - res->phase_seg1; } else if (res->phase_seg1 < min->phase_seg1) { - /* Even ts1 distribution not possible, increase phase_seg1 */ + /* Even tseg1 distribution not possible, increase phase_seg1 */ res->phase_seg1 = min->phase_seg1; - res->prop_seg = ts1 - res->phase_seg1; + res->prop_seg = tseg1 - res->phase_seg1; } - sp_calc = (CAN_SYNC_SEG + ts1) * 1000 / ts; + /* Calculate the resulting sample point */ + sample_pnt_res = (CAN_SYNC_SEG + tseg1) * 1000 / total_tq; - return sp_calc > sp ? sp_calc - sp : sp - sp_calc; + /* Return the absolute sample point error */ + return sample_pnt_res > sample_pnt ? + sample_pnt_res - sample_pnt : + sample_pnt - sample_pnt_res; } /* Internal function to do the actual calculation */