Commit fba27b4b authored by Henrik Brix Andersen's avatar Henrik Brix Andersen Committed by Martí Bolívar
Browse files

drivers: can: change sample point for can_set_bitrate() at high bitrates



CAN in Automation (CiA) 301 v4.2.0 recommends a sample point location of
87.5% percent for all bitrates. However, some CAN controllers have
difficulties meeting this for higher bitrates.

Change can_set_bitrate() to use a sample point of 75.0% for bitrates
over 800 kbit/s, 80.0% for bitrates over 500 kbit/s, and 87.5% for all
other bitrates. This is in line with the sample point locations used by
the Linux kernel.

Regard a sample point error of more than +/- 5.0% as an error in setting
the bitrate. Previously, any sample rate error was accepted without
providing any feedback to the caller. This is in line with the CAN
sample point calculation criteria used by the Linux kernel.

Signed-off-by: default avatarHenrik Brix Andersen <hebad@vestas.com>
parent 3b1527a8
Loading
Loading
Loading
Loading
+40 −2
Original line number Diff line number Diff line
@@ -11,6 +11,9 @@

LOG_MODULE_REGISTER(can_common, CONFIG_CAN_LOG_LEVEL);

/* Maximum acceptable deviation in sample point location (permille) */
#define SAMPLE_POINT_MARGIN 50

/* CAN sync segment is always one time quantum */
#define CAN_SYNC_SEG 1

@@ -180,6 +183,30 @@ int can_calc_prescaler(const struct device *dev, struct can_timing *timing,
	return core_clock % (ts * timing->prescaler);
}

/**
 * @brief Get the sample point location for a given bitrate
 *
 * @param  bitrate The bitrate in bits/second.
 * @return The sample point in permille.
 */
uint16_t sample_point_for_bitrate(uint32_t bitrate)
{
	uint16_t sample_pnt;

	if (bitrate > 800000) {
		/* 75.0% */
		sample_pnt = 750;
	} else if (bitrate > 500000) {
		/* 80.0% */
		sample_pnt = 800;
	} else {
		/* 87.5% */
		sample_pnt = 875;
	}

	return sample_pnt;
}

int can_set_bitrate(const struct device *dev, uint32_t bitrate, uint32_t bitrate_data)
{
	struct can_timing timing;
@@ -187,6 +214,7 @@ int can_set_bitrate(const struct device *dev, uint32_t bitrate, uint32_t bitrate
	struct can_timing timing_data;
#endif /* CONFIG_CAN_FD_MODE */
	uint32_t max_bitrate;
	uint16_t sample_pnt;
	int ret;

	ret = can_get_max_bitrate(dev, &max_bitrate);
@@ -201,11 +229,16 @@ int can_set_bitrate(const struct device *dev, uint32_t bitrate, uint32_t bitrate
		return -ENOTSUP;
	}

	ret = can_calc_timing(dev, &timing, bitrate, 875);
	sample_pnt = sample_point_for_bitrate(bitrate);
	ret = can_calc_timing(dev, &timing, bitrate, sample_pnt);
	if (ret < 0) {
		return -EINVAL;
	}

	if (ret > SAMPLE_POINT_MARGIN) {
		return -EINVAL;
	}

	timing.sjw = CAN_SJW_NO_CHANGE;

#ifdef CONFIG_CAN_FD_MODE
@@ -213,11 +246,16 @@ int can_set_bitrate(const struct device *dev, uint32_t bitrate, uint32_t bitrate
		return -ENOTSUP;
	}

	ret = can_calc_timing_data(dev, &timing_data, bitrate_data, 875);
	sample_pnt = sample_point_for_bitrate(bitrate_data);
	ret = can_calc_timing_data(dev, &timing_data, bitrate_data, sample_pnt);
	if (ret < 0) {
		return -EINVAL;
	}

	if (ret > SAMPLE_POINT_MARGIN) {
		return -EINVAL;
	}

	timing_data.sjw = CAN_SJW_NO_CHANGE;

	return can_set_timing(dev, &timing, &timing_data);
+9 −2
Original line number Diff line number Diff line
@@ -845,7 +845,14 @@ static inline int z_impl_can_set_mode(const struct device *dev, enum can_mode mo
/**
 * @brief Set the bitrate of the CAN controller
 *
 * The sample point is set to the CiA DS 301 recommended value of 87.5%.
 * CAN in Automation (CiA) 301 v4.2.0 recommends a sample point location of
 * 87.5% percent for all bitrates. However, some CAN controllers have
 * difficulties meeting this for higher bitrates.
 *
 * This function defaults to using a sample point of 75.0% for bitrates over 800
 * kbit/s, 80.0% for bitrates over 500 kbit/s, and 87.5% for all other
 * bitrates. This is in line with the sample point locations used by the Linux
 * kernel.
 *
 * @note The parameter ``bitrate_data`` is only relevant for CAN-FD. If the
 * controller does not support CAN-FD or if @kconfig{CONFIG_CAN_FD_MODE} is not
@@ -857,7 +864,7 @@ static inline int z_impl_can_set_mode(const struct device *dev, enum can_mode mo
 *
 * @retval 0 If successful.
 * @retval -ENOTSUP bitrate not supported by CAN controller/transceiver combination
 * @retval -EINVAL bitrate cannot be met.
 * @retval -EINVAL bitrate/sample point cannot be met.
 * @retval -EIO General input/output error, failed to set bitrate.
 */
int can_set_bitrate(const struct device *dev, uint32_t bitrate, uint32_t bitrate_data);