CAN系列芯片全面技术分析
SJA1000: 经典独立CAN控制器,支持CAN 2.0A/BTJA1040/1050: 高速CAN收发器TJA1145: 高速CAN FD收发器MCP2515: SPI接口CAN控制器,支持CAN 2.0BMCP25625: CAN FD控制器ATA6560/ATA6561: CAN收发器SN65HVD23x: 3.3V CAN收发器TCAN33x: CAN FD收发器系列CC770: 早期C
CAN系列芯片全面技术分析
一、CAN控制器芯片历程与规格
国外主要CAN控制器系列
NXP (Philips) 系列
-
SJA1000: 经典独立CAN控制器,支持CAN 2.0A/B
-
TJA1040/1050: 高速CAN收发器
-
TJA1145: 高速CAN FD收发器
Microchip (Atmel) 系列
-
MCP2515: SPI接口CAN控制器,支持CAN 2.0B
-
MCP25625: CAN FD控制器
-
ATA6560/ATA6561: CAN收发器
Texas Instruments 系列
-
SN65HVD23x: 3.3V CAN收发器
-
TCAN33x: CAN FD收发器系列
Bosch 系列
-
CC770: 早期CAN控制器
-
C_CAN: 集成在微控制器中的CAN模块
STMicroelectronics 系列
-
STM32 CAN: 集成在STM32微控制器中
-
VN360/VN7610: 系统基础芯片(SBC)
国内主要CAN控制器系列
芯旺微电子 (ChipON)
-
KF8A系列: 集成CAN控制器的8位MCU
-
KF32A系列: 32位汽车级MCU with CAN FD
华大半导体 (HDSC)
-
HC32F4A0: 高性能MCU with CAN FD
兆易创新 (GigaDevice)
-
GD32F4xx: ARM Cortex-M4 MCU with CAN
北京君正 (Ingenic)
-
X系列: 车载SoC with CAN接口
技术参数对比
| 芯片型号 | CAN标准 | 接口 | 最高速率 | 特性 | Linux内核支持 |
|---|---|---|---|---|---|
| SJA1000 | CAN 2.0B | 并行 | 1 Mbps | 经典控制器 | 2.6+ |
| MCP2515 | CAN 2.0B | SPI | 1 Mbps | 低成本SPI方案 | 2.6.33+ |
| MCP25625 | CAN FD | SPI | 5 Mbps | CAN FD支持 | 4.14+ |
| TJA1042 | CAN 2.0B | PHY | 1 Mbps | 低功耗模式 | 驱动支持 |
| GD32F4xx | CAN FD | MCU | 5 Mbps | 集成MCU方案 | 4.19+ |
二、Linux内核CAN子系统架构分析
CAN核心子系统架构
// net/can/af_can.c - CAN协议族实现
static const struct proto_ops can_ops = {
.family = PF_CAN,
.owner = THIS_MODULE,
.release = can_release,
.bind = can_bind,
.connect = sock_no_connect,
.socketpair = sock_no_socketpair,
.accept = sock_no_accept,
.getname = sock_no_getname,
.poll = datagram_poll,
.ioctl = can_ioctl,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown,
.setsockopt = can_setsockopt,
.getsockopt = can_getsockopt,
.sendmsg = can_sendmsg,
.recvmsg = can_recvmsg,
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage,
};
// CAN设备框架
struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max)
{
struct net_device *dev;
struct can_priv *priv;
dev = alloc_netdev(sizeof_priv, "can%d", NET_NAME_UNKNOWN, can_setup);
if (!dev)
return NULL;
priv = netdev_priv(dev);
priv->dev = dev;
priv->echo_skb_max = echo_skb_max;
return dev;
}
CAN总线驱动框架
// drivers/net/can/dev/can-dev.c
struct can_priv {
struct can_device_stats can_stats;
struct can_bittiming bittiming;
struct can_bittiming_const bittiming_const;
const struct can_ctrlmode *ctrlmode;
enum can_state state;
u32 ctrlmode_supported;
int (*do_set_bittiming)(struct net_device *dev);
int (*do_set_mode)(struct net_device *dev, enum can_mode mode);
int (*do_get_berr_counter)(const struct net_device *dev,
struct can_berr_counter *bec);
unsigned int echo_skb_max;
struct sk_buff **echo_skb;
};
// 标准CAN操作
static const struct net_device_ops can_netdev_ops = {
.ndo_open = can_open,
.ndo_stop = can_close,
.ndo_start_xmit = can_start_xmit,
.ndo_change_mtu = can_change_mtu,
};
三、USB CAN适配器技术演进
USB CAN适配器发展历程
早期USB CAN适配器
-
EMS CPC-USB: 基于SJA1000的USB转CAN
-
Kvaser USBcan: 商业级USB CAN适配器
-
PCAN-USB: PEAK-System的经典产品
现代USB CAN适配器
-
CANable: 开源USB转CAN适配器
-
USB2CAN: 低成本解决方案
-
CANtact: 开源硬件项目
Linux USB CAN驱动架构
// drivers/net/can/usb/usb_8dev.c
struct usb_8dev_priv {
struct can_priv can; /* must be the first member */
struct usb_device *udev;
struct usb_interface *intf;
struct net_device *netdev;
struct usb_anchor rx_submitted;
struct usb_anchor tx_submitted;
/* CAN frame buffer */
struct usb_8dev_tx_urb_context tx_contexts[MAX_TX_URBS];
struct usb_8dev_netdev_priv_stats stats;
};
// USB设备表
static const struct usb_device_id usb_8dev_table[] = {
{ USB_DEVICE(0x0483, 0x1234) }, /* 8devices USB2CAN */
{ USB_DEVICE(0x1d50, 0x606f) }, /* CANtact */
{ } /* Terminating entry */
};
// USB批量传输处理
static void usb_8dev_read_bulk_callback(struct urb *urb)
{
struct usb_8dev_priv *priv = urb->context;
struct net_device *netdev = priv->netdev;
int ret;
if (!netif_device_present(netdev))
return;
switch (urb->status) {
case 0: /* success */
usb_8dev_rx_can_msg(priv, urb->transfer_buffer, urb->actual_length);
break;
case -ENOENT:
case -ESHUTDOWN:
return;
default:
break;
}
/* Resubmit URB */
usb_fill_bulk_urb(urb, priv->udev,
usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_RX),
urb->transfer_buffer, RX_BUFFER_SIZE,
usb_8dev_read_bulk_callback, priv);
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret == -ENODEV)
netif_device_detach(netdev);
}
CAN FD USB适配器支持
// drivers/net/can/usb/gs_usb.c
struct gs_can {
struct can_priv can; /* must be the first member */
struct can_berr_counter bec;
struct usb_device *udev;
struct usb_interface *iface;
struct gs_host_frame *hf; /* host frame buffer */
dma_addr_t hf_dma;
struct gs_device_bt_const bt_const;
u32 feature;
unsigned int channel; /* channel number */
/* CAN FD support */
bool canfd;
u8 tdc_max;
u32 data_bittiming_const_max;
};
// CAN FD帧处理
static void gs_usb_receive_bulk_callback(struct urb *urb)
{
struct gs_can *dev = urb->context;
struct net_device *netdev = dev->netdev;
struct gs_host_frame *hf = urb->transfer_buffer;
struct canfd_frame *cf;
struct sk_buff *skb;
if (!netif_device_present(netdev))
return;
/* Create skb */
if (hf->can_id & GS_CAN_FLAG_FD)
skb = alloc_canfd_skb(netdev, &cf);
else
skb = alloc_can_skb(netdev, (struct can_frame **)&cf);
if (!skb)
return;
/* Copy frame data */
if (hf->can_id & GS_CAN_FLAG_FD) {
cf->len = can_dlc2len(hf->can_dlc);
memcpy(cf->data, hf->data, cf->len);
} else {
cf->can_dlc = hf->can_dlc;
memcpy(cf->data, hf->data, cf->can_dlc);
}
cf->can_id = hf->can_id & GS_CAN_ID_MASK;
/* Pass to network stack */
netif_rx(skb);
/* Update statistics */
dev->can.can_stats.rx_packets++;
dev->can.can_stats.rx_bytes += cf->len;
}
四、CAN物理接口技术分析
高速CAN (ISO 11898-2)
// CAN物理层配置
struct can_bittiming {
u32 bitrate; /* Bitrate in bits/second */
u32 sample_point; /* Sample point in one-tenth of a percent */
u32 tq; /* Time quanta (TQ) in nanoseconds */
u32 prop_seg; /* Propagation segment in TQs */
u32 phase_seg1; /* Phase buffer segment 1 in TQs */
u32 phase_seg2; /* Phase buffer segment 2 in TQs */
u32 sjw; /* Synchronisation jump width in TQs */
u32 brp; /* Bitrate prescaler */
};
// 位时间约束
struct can_bittiming_const {
char name[16]; /* Name of the CAN controller hardware */
u32 tseg1_min; /* Time segment 1 = prop_seg + phase_seg1 */
u32 tseg1_max;
u32 tseg2_min; /* Time segment 2 = phase_seg2 */
u32 tseg2_max;
u32 sjw_max; /* Synchronisation jump width */
u32 brp_min; /* Bit-rate prescaler */
u32 brp_max;
u32 brp_inc;
};
CAN FD物理层 (ISO 11898-1)
// CAN FD数据相位配置
struct can_data_bittiming {
u32 bitrate; /* Bitrate in bits/second */
u32 sample_point; /* Sample point in one-tenth of a percent */
u32 tq; /* Time quanta (TQ) in nanoseconds */
u32 prop_seg; /* Propagation segment in TQs */
u32 phase_seg1; /* Phase buffer segment 1 in TQs */
u32 phase_seg2; /* Phase buffer segment 2 in TQs */
u32 sjw; /* Synchronisation jump width in TQs */
u32 brp; /* Bitrate prescaler */
};
// CAN FD控制器模式
#define CAN_CTRLMODE_LOOPBACK 0x01 /* Loopback mode */
#define CAN_CTRLMODE_LISTENONLY 0x02 /* Listen-only mode */
#define CAN_CTRLMODE_3_SAMPLES 0x04 /* Triple sampling */
#define CAN_CTRLMODE_ONE_SHOT 0x08 /* One-Shot mode */
#define CAN_CTRLMODE_BERR_REPORTING 0x10 /* Bus-error reporting */
#define CAN_CTRLMODE_FD 0x20 /* CAN FD mode */
#define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */
#define CAN_CTRLMODE_FD_NON_ISO 0x80 /* CAN FD in non-ISO mode */
五、SPI接口CAN控制器驱动分析
MCP2515驱动架构
// drivers/net/can/spi/mcp251x.c
struct mcp251x_priv {
struct can_priv can;
struct spi_device *spi;
struct clk *clk;
/* Message buffer */
struct mcp251x_tx_buf tx_buf[MCP251X_MAX_TX_QUEUES];
struct mcp251x_rx_buf rx_buf[MCP251X_MAX_RX_QUEUES];
/* SPI transfer buffers */
u8 *spi_tx_buf;
u8 *spi_rx_buf;
/* IRQ handling */
struct workqueue_struct *wq;
struct work_struct tx_work;
struct work_struct restart_work;
};
static const struct can_bittiming_const mcp251x_bittiming_const = {
.name = "mcp2515",
.tseg1_min = 3,
.tseg1_max = 16,
.tseg2_min = 2,
.tseg2_max = 8,
.sjw_max = 4,
.brp_min = 1,
.brp_max = 64,
.brp_inc = 1,
};
// SPI传输函数
static int mcp251x_spi_trans(struct spi_device *spi, int len)
{
struct spi_transfer t = {
.tx_buf = priv->spi_tx_buf,
.rx_buf = priv->spi_rx_buf,
.len = len,
.cs_change = 0,
};
struct spi_message m;
int ret;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
ret = spi_sync(spi, &m);
if (ret)
dev_err(&spi->dev, "spi transfer failed: ret = %d\n", ret);
return ret;
}
MCP25625 CAN FD驱动
// CAN FD支持扩展
static int mcp25625_set_data_bittiming(struct net_device *net)
{
struct mcp251x_priv *priv = netdev_priv(net);
struct can_bittiming *bt = &priv->can.data_bittiming;
u8 dbtcfg1, dbtcfg2, dbtcfg3;
/* Calculate data bit timing parameters */
dbtcfg1 = ((bt->sjw - 1) << 6) | (bt->brp - 1);
dbtcfg2 = ((bt->phase_seg1 - 1) << 3) | (bt->prop_seg - 1);
dbtcfg3 = bt->phase_seg2 - 1;
/* Write to data bit timing registers */
mcp251x_write_reg(priv->spi, DBTCFG1, dbtcfg1);
mcp251x_write_reg(priv->spi, DBTCFG2, dbtcfg2);
mcp251x_write_reg(priv->spi, DBTCFG3, dbtcfg3);
return 0;
}
六、授时技术与时间同步支持
CAN总线时间戳支持
// CAN帧时间戳处理
struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
{
struct sk_buff *skb;
skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
sizeof(struct can_frame));
if (unlikely(!skb))
return NULL;
skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;
*cf = skb_put(skb, sizeof(struct can_frame));
/* Set CAN frame attributes */
memset(*cf, 0, sizeof(struct can_frame));
/* Setup skb for hardware timestamping */
if (dev->flags & IFF_ECHO)
skb->pkt_type = PACKET_LOOPBACK;
return skb;
}
// 硬件时间戳获取
static void can_get_echo_skb(struct net_device *dev, unsigned int idx)
{
struct can_priv *priv = netdev_priv(dev);
if (!priv->echo_skb[idx]) {
netdev_dbg(dev, "BUG: echo_skb is empty\n");
return;
}
if (dev->flags & IFF_ECHO) {
struct sk_buff *skb = priv->echo_skb[idx];
struct can_frame *cf = (struct can_frame *)skb->data;
u8 dlc = cf->can_dlc;
/* Get hardware timestamp */
skb->tstamp = ktime_get_real();
netif_rx(skb);
priv->echo_skb[idx] = NULL;
priv->can.can_stats.tx_frames++;
priv->can.can_stats.tx_bytes += dlc;
} else {
kfree_skb(priv->echo_skb[idx]);
priv->echo_skb[idx] = NULL;
}
}
PTP over CAN支持
#ifdef CONFIG_CAN_PTP
// CAN总线PTP时钟支持
struct can_ptp_clock {
struct ptp_clock_info info;
struct can_priv *priv;
spinlock_t lock;
};
static const struct ptp_clock_info can_ptp_clock_ops = {
.owner = THIS_MODULE,
.name = "CAN PTP",
.max_adj = 1000000,
.n_alarm = 0,
.n_ext_ts = 0,
.n_per_out = 0,
.pps = 0,
.adjfine = can_ptp_adjfine,
.adjtime = can_ptp_adjtime,
.gettime64 = can_ptp_gettime,
.settime64 = can_ptp_settime,
.enable = can_ptp_enable,
};
// CAN时间同步帧处理
static int can_ptp_rx_handler(struct sk_buff *skb, struct net_device *dev)
{
struct can_frame *cf = (struct can_frame *)skb->data;
struct can_priv *priv = netdev_priv(dev);
struct can_ptp_clock *ptp_clock;
u64 timestamp;
if (!priv->ptp_clock)
return 0;
ptp_clock = priv->ptp_clock;
/* Check if this is a PTP sync frame */
if (cf->can_id == CAN_PTP_SYNC_ID) {
timestamp = ktime_to_ns(skb->tstamp);
spin_lock(&ptp_clock->lock);
/* Update PTP clock */
ptp_clock_update(ptp_clock, timestamp);
spin_unlock(&ptp_clock->lock);
}
return 0;
}
#endif
七、网络驱动架构软件设计模式演进
第一代:字符设备驱动 (Linux 2.4)
// 早期CAN驱动设计
static struct file_operations can_fops = {
.owner = THIS_MODULE,
.read = can_read,
.write = can_write,
.ioctl = can_ioctl,
.open = can_open,
.release = can_release,
};
static int can_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case CAN_SET_BITTIMING:
return can_set_bittiming(can_dev, (struct can_bittiming *)arg);
case CAN_SET_MODE:
return can_set_mode(can_dev, arg);
default:
return -ENOTTY;
}
}
第二代:网络设备驱动 (Linux 2.6)
// 网络设备CAN驱动
static const struct net_device_ops can_netdev_ops = {
.ndo_open = can_open,
.ndo_stop = can_close,
.ndo_start_xmit = can_start_xmit,
.ndo_change_mtu = can_change_mtu,
.ndo_do_ioctl = can_ioctl,
};
static netdev_tx_t can_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
struct can_frame *cf = (struct can_frame *)skb->data;
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
/* Hardware transmission */
priv->do_start_xmit(priv, cf);
/* Save for echo */
can_put_echo_skb(skb, dev, priv->echo_skb_idx);
priv->echo_skb_idx = (priv->echo_skb_idx + 1) % priv->echo_skb_max;
return NETDEV_TX_OK;
}
第三代:模块化CAN框架 (Linux 3.x+)
// 现代CAN驱动框架
struct can_dev_rcv_lists {
struct hlist_head rx[0x800]; /* 2048 CAN IDs */
struct hlist_head rx_sff[0x800]; /* 2048 CAN SFF IDs */
struct hlist_head rx_eff[0x200000]; /* 2^21 CAN EFF IDs */
};
// CAN协议处理
static const struct can_proto can_raw_proto = {
.type = SOCK_RAW,
.protocol = CAN_RAW,
.ops = &can_raw_ops,
.prot = &can_raw_proto_ops,
.prot_size = sizeof(struct raw_sock),
};
// CAN总线错误处理
static void can_bus_off(struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
netdev_dbg(dev, "bus-off\n");
priv->can.state = CAN_STATE_BUS_OFF;
/* Schedule bus-off recovery */
if (priv->restart_ms)
schedule_delayed_work(&priv->restart_work,
msecs_to_jiffies(priv->restart_ms));
}
八、数据上传实时技术演进
实时传输技术发展
1. 简单轮询传输
// 早期轮询传输
static int can_poll_transmit(struct net_device *dev, struct can_frame *cf)
{
struct can_priv *priv = netdev_priv(dev);
unsigned long flags;
int ret;
spin_lock_irqsave(&priv->tx_lock, flags);
/* Wait for transmit buffer to be free */
while (priv->tx_head - priv->tx_tail >= priv->echo_skb_max) {
spin_unlock_irqrestore(&priv->tx_lock, flags);
schedule();
spin_lock_irqsave(&priv->tx_lock, flags);
}
/* Transmit frame */
ret = priv->write_reg(priv, CAN_TXBUF, cf);
spin_unlock_irqrestore(&priv->tx_lock, flags);
return ret;
}
2. 中断驱动传输
// 中断驱动传输
static irqreturn_t can_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct can_priv *priv = netdev_priv(dev);
struct can_frame *cf;
struct sk_buff *skb;
/* Check interrupt source */
if (priv->check_int(priv) & CAN_INT_TX) {
/* Transmission complete */
can_get_echo_skb(dev, priv->echo_skb_idx);
netif_wake_queue(dev);
}
if (priv->check_int(priv) & CAN_INT_RX) {
/* Receive frame */
skb = alloc_can_skb(dev, &cf);
if (!skb)
return IRQ_NONE;
priv->read_reg(priv, CAN_RXBUF, cf);
netif_rx(skb);
priv->can.can_stats.rx_frames++;
priv->can.can_stats.rx_bytes += cf->can_dlc;
}
return IRQ_HANDLED;
}
3. 高精度时间戳传输
// 高精度时间戳支持
static int can_start_xmit_timestamp(struct sk_buff *skb, struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
struct can_frame *cf = (struct can_frame *)skb->data;
ktime_t timestamp;
/* Get hardware timestamp if available */
if (priv->get_timestamp)
timestamp = priv->get_timestamp(priv);
else
timestamp = ktime_get_real();
/* Store timestamp in skb */
skb->tstamp = timestamp;
/* Transmit frame */
return can_start_xmit(skb, dev);
}
// CAN FD高性能传输
static netdev_tx_t canfd_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
/* Check for CAN FD support */
if (!(priv->ctrlmode & CAN_CTRLMODE_FD)) {
kfree_skb(skb);
return NETDEV_TX_OK;
}
/* Hardware transmission with CAN FD */
priv->do_start_xmit_fd(priv, cfd);
can_put_echo_skb(skb, dev, 0);
return NETDEV_TX_OK;
}
性能对比分析
| 技术阶段 | 传输方式 | 延迟水平 | 吞吐量 | 时间精度 | Linux版本 |
|---|---|---|---|---|---|
| 轮询传输 | 软件轮询 | 1-10ms | 低 | 1ms | 2.4-2.6 |
| 中断驱动 | 硬件中断 | 100-500μs | 中 | 100μs | 2.6+ |
| DMA传输 | 直接内存访问 | 50-200μs | 高 | 10μs | 3.x+ |
| CAN FD | 高速数据 | 20-100μs | 很高 | 1μs | 4.14+ |
| 时间戳 | 硬件同步 | 10-50μs | 极高 | 100ns | 4.19+ |
九、内核源码树形结构分析
CAN子系统源码组织
net/can/ ├── af_can.c # CAN协议族实现 ├── proc.c # /proc接口 ├── gw.c # CAN网关 ├── bcm.c # 广播管理器 ├── raw.c # RAW套接字 ├── isotp.c # ISO-TP传输协议 └── j1939/ # J1939协议 ├── j1939-priv.h ├── j1939-core.c └── j1939-socket.c drivers/net/can/ ├── can-dev.c # CAN设备框架 ├── can-led.c # LED支持 ├── spi/ # SPI CAN控制器 │ ├── mcp251x.c # MCP2515/MCP25625 │ └── hi311x.c # HI311x ├── usb/ # USB CAN适配器 │ ├── usb_8dev.c # 8devices │ ├── gs_usb.c # Geschwister Schneider │ ├── ems_usb.c # EMS │ └── kvaser_usb.c # Kvaser ├── c_can/ # Bosch C_CAN ├── sja1000/ # NXP SJA1000 │ ├── sja1000.c │ └── sja1000_platform.c └── flexcan/ # NXP FlexCAN └── flexcan.c
关键函数调用树
// CAN子系统初始化 can_init() → sock_register(&can_family_ops) → register_pernet_subsys(&can_pernet_ops) → can_proto_init() // 设备驱动注册 mcp251x_can_driver_init() → spi_register_driver(&mcp251x_can_driver) → mcp251x_probe() → alloc_candev() → register_candev() // 数据发送路径 can_send() → dev_queue_xmit() → can_start_xmit() → priv->do_start_xmit() // 数据接收路径 can_rx_handler() → can_receive() → can_rcv_filter() → can_rcv()
十、未来发展趋势
技术发展方向
-
CAN FD全面普及
-
更高数据速率(8-16 Mbps)
-
更大数据负载(64字节)
-
向后兼容CAN 2.0
-
-
CAN XL开发
-
最高20 Mbps速率
-
2048字节数据负载
-
改进的仲裁机制
-
-
时间敏感网络(TSN)集成
-
IEEE 802.1AS时间同步
-
确定性通信保障
-
与以太网TSN桥接
-
-
安全增强
-
CAN FD安全协议
-
消息认证
-
加密传输
-
-
车载以太网融合
-
CAN到以太网网关
-
混合网络架构
-
服务导向通信
-
这个全面的分析展示了CAN总线技术在汽车和工业领域的发展历程,从经典的CAN 2.0到现代的CAN FD,以及在Linux内核中的完整支持架构。CAN技术继续在实时性、可靠性和性能方面不断演进。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)