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: Henrik Brix Andersen <hebad@vestas.com>
This commit is contained in:
parent
3b1527a8f9
commit
fba27b4bde
2 changed files with 49 additions and 4 deletions
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue