RT-Thread / RT-Thread/rt-thread
[Feature] 自动配置can波特率的可行性
Open
Nobody has claimed this yet.
- Dominant language
- C
- Stars
- 12.2k
- Forks
- 5.4k
- Avg merge
- 4d 12h
- Merged PRs (30d)
- 40
Description
Describe problem solved by the proposed feature
目前的bsp配置CAN通信波特率时使用了大量预定义的表格 不同的芯片如果当前不支持 就要新增宏定义
是否可以考虑实现一个函数自动计算适配的波特率参数呢 例如
#include <math.h>
#include <float.h>
#include <stdint.h>
#include <stdio.h>
typedef struct
{
uint32_t prescaler;
uint8_t bs1;
uint8_t bs2;
float baud_error;
float sample_point;
} CAN_TimingConfig;
/**
* @brief
*
* @param F_pclk CAN的APB1时钟
* @param target_baudrate 目标波特率
* @return CAN_TimingConfig
*/
CAN_TimingConfig calculate_can_timing(uint32_t F_pclk,
uint32_t target_baudrate)
{
CAN_TimingConfig best = {0};
float min_error = FLT_MAX;
float target_sample_point = 0.8f;
const uint8_t tq_min = 8, tq_max = 25;
const uint8_t bs1_max = 16, bs2_max = 8;
// 扩展分频范围避免遗漏
uint32_t prescale_max = (F_pclk + target_baudrate * tq_min - 1) / (target_baudrate * tq_min);
uint32_t prescale_min = F_pclk / (target_baudrate * tq_max);
prescale_min = prescale_min > 0 ? prescale_min : 1;
prescale_max = prescale_max > 1024 ? 1024 : prescale_max;
// 逆序循环优先大分频值
for (uint32_t prescale = prescale_max; prescale >= prescale_min; --prescale)
{
float total_tq = (float)F_pclk / (target_baudrate * prescale);
uint8_t tq = (uint8_t)(total_tq + 0.5f);
if (tq < tq_min || tq > tq_max) continue;
uint8_t bs1 = (uint8_t)(target_sample_point * tq - 1 + 0.5f);
uint8_t bs2 = tq - 1 - bs1;
if (bs1 < 1 || bs1 > bs1_max || bs2 < 1 || bs2 > bs2_max) continue;
float actual_baud = (float)F_pclk / (prescale * (1 + bs1 + bs2));
float baud_err = fabsf(actual_baud - target_baudrate) / target_baudrate;
float sample_point = (1.0f + bs1) / (1 + bs1 + bs2);
float sample_err = fabsf(sample_point - target_sample_point);
float total_err = 0.6f * baud_err + 0.4f * sample_err;
// 误差更小 或 误差相同但分频更大 或 分频相同但TQ更小
if ((total_err < min_error) || (total_err == min_error && ((prescale > best.prescaler) || (prescale == best.prescaler && tq < (best.bs1 + best.bs2 + 1)))))
{
min_error = total_err;
best.prescaler = prescale;
best.bs1 = bs1;
best.bs2 = bs2;
best.baud_error = baud_err;
best.sample_point = sample_point;
}
}
return best;
}
int main()
{
CAN_TimingConfig cfg = calculate_can_timing(36000000, 500 * 1000);
printf("Prescaler: %u\nBS1: %u\nBS2: %u\nSample: %.1f%%\nBaud error: %.4f%%\n",
cfg.prescaler, cfg.bs1, cfg.bs2,
cfg.sample_point * 100, cfg.baud_error * 100);
}
这个函数可以考虑放在dev_can.c中 给drv_can.c传参时只需要相应的分频值和两个bs的TQ数(默认SWJ 1TQ)
Describe your preferred solution
No response
Describe possible alternatives
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the existing CAN baud-rate tables and the CAN configuration flow in dev_can.c and drv_can.c. Check how prescaler, BS1, and BS2 values are passed to the driver, then define how the proposed calculation should work across supported chips. Done means a validated approach replaces or supplements the duplicated predefined parameters without breaking existing CAN configurations.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- embedded-iot
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100