2.29. CAN

Overview

CAN分有基础模式与增强模式,基础模式阉割的功能较多,建议使用增强模式。例如基础模式只能接收发送标准帧,过滤器只能设置过滤ID高8位,不能设置过滤的帧类型,局限较大,建议使用增强模式。

提供CAN应用示例、配置介绍、常用相关API介绍和常见问题。

2.29.1. 配置说明

  • 1.在板级文件 apps/.../board.h 中打开宏 TCFG_CAN_ENABLE 并进行对应配置
    #define TCFG_CAN_ENABLE                     1
    #define TCFG_CAN_MODE                       1//0标准模式;1增强模式
    #define TCFG_CAN_RX_IO                      IO_PORTC_01
    #define TCFG_CAN_TX_IO                      IO_PORTC_02
    #define TCFG_CAN_STM_ENABLE                 0
    #define TCFG_CAN_LOM_ENABLE                 0
    #define TCFG_CAN_BAUD_BRP                   3
    #define TCFG_CAN_BAUD_SJW                   3
    #define TCFG_CAN_BAUD_SAM                   1
    #define TCFG_CAN_BAUD_PTS_PBS1              2
    #define TCFG_CAN_BAUD_PBS2                  1
    #if TCFG_CAN_MODE
    #define TCFG_CAN_FILTER_MODE                1//0双接收滤波器标准帧模式;1双接收滤波器扩展帧模式;2单接收滤波器标准帧模式;3单接收滤波器扩展帧模式
    #define TCFG_CAN_FILTER_ACC_ID0             0x1FFFFFFF
    #define TCFG_CAN_FILTER_ACC_ID1             0x10FFFFFF
    #define TCFG_CAN_FILTER_ACC_RTR0            1
    #define TCFG_CAN_FILTER_ACC_RTR1            0
    #define TCFG_CAN_FILTER_MASK_ID0            0xFFFFFFFF
    #define TCFG_CAN_FILTER_MASK_ID1            0xFFFFFFFF
    #define TCFG_CAN_FILTER_MASK_RTR0           1
    #define TCFG_CAN_FILTER_MASK_RTR1           1
    #else
    #define TCFG_CAN_FILTER_MODE                2//基础模式下可以不设置
    #define TCFG_CAN_FILTER_ACC_ID0             0x654
    #define TCFG_CAN_FILTER_MASK_ID0            0xFF
    #endif
    

  • 2.在板级文件 apps/.../board.c 中增加CAN配置如下

    CAN_PLATFORM_DATA_BEGIN(can_data)
    ......
    CAN_PLATFORM_DATA_END()
    
    ......
    
    REGISTER_DEVICES(device_table) = {
    ......
    { "can", &can_dev_ops, (void *)&can_data },
    ......
    };
    

  • 3.也可以不使用板级文件的配置进行初始化,在自定义的初始化文件中,定义结构体can_platform_data并赋值,然后通过dev_open传参即可。

    static const struct can_platform_data can_user_data = {
    .rx_pin                 = TCFG_CAN_RX_IO,
    .tx_pin                 = TCFG_CAN_TX_IO,
    //如板级文件添加各个参数即可
    ....
    };
    main()
    {
        void *can_hdl = NULL;
        can_hdl = dev_open("can", &can_user_data);
        dev_ioctl(can_hdl, IOCTL_CAN_SET_DMA_FRAMES, CAN_RX_CNT);
        dev_ioctl(can_hdl, IOCTL_CAN_SET_RECV_WAIT_SEM, 0);
        //自行添加应用代码
    }
    

2.29.2. 应用实例

示例演示:

  • 演示阻塞式接收、非阻塞式接收、多帧发送与接收、二次修改相关配置等。

example: 具体示例代码详见 apps/common/example/peripheral/can/can_test.c ,示例工程实现需自行定义 USE_CAN_TEST_DEMO

2.29.3. 常见问题

  • 申请中断异常、没有进入中断、配置接收中断后一直在中断?

    答:留意基本配置中调用的API dev_ioctl() ,部分IOCTL形参会占用中断或内部清除中断,如 IOCTL_CAN_SET_RECV_WAIT_WHILE 内部会清除中断,如需申请外部中断请在调用该接口后申请。详情查看API接口说明。

    在中断函数中需要执行 dev_ioctl(can_hdl, IOCTL_CAN_SET_INTERRUPT_DISABLE, CAN_EVENT_CLEAR_INTERRUPT); 清除本次接收中断产生的标志位。

  • CAN每次接收发送都会打印log,能否关闭?

    答:可以,在 apps/common/config/log_config/lib_driver_config.c 中找到CAN的debug开关,将TRUE修改为FALSE。

    const char log_tag_const_v_CAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
    const char log_tag_const_d_CAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
    const char log_tag_const_i_CAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
    const char log_tag_const_w_CAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
    const char log_tag_const_e_CAN AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(FALSE);
    
  • CAN的滤波器异常、没有正确过滤设置的ID?

    答:① accept_id(x)mask_id(x) 是对应关系,accept_id(x)配置过滤器的ID,mask_id(x)是将accept_id(x)对应bit忽略,例如配置 accept_id0 = 0x123mask_id0 = 0x03 `` 最终过滤器配置的id为0x120。 ``accept_rtr(x) 指示的是只接受 0数据帧``或 ``1远程帧 ,并非0/1使能关系。

    ② CAN的基础模式下只有单滤波器并且只能设置标准帧ID的高8位,对应mask_id同样是高8位,且无法设置rtr位。增强模式下分单滤波器与双滤波器、标准帧与扩展帧的配置差异,单滤波器下无论是标准帧还是扩展帧都能配置全ID的bit;双滤波器下仅支持高16bit。标准帧id只有11bit,所以是全bit匹配且支持rtr位。扩展帧id有29bit,仅支持高16bit且不支持rtr位。

  • CAN的总线一直在报错,如何解决?

    答:① 优先排查波特率是否正确设置。波特率计算公式: baudrate = (lsb_clk)/((tseg1+tseg2+3)*(brp+1)*2) 其中tseg1 = pts+pbs2,tseg2 = pbs2。

    ② 在增强模式下,可以调用 dev_ioctl(can_Hdl, IOCTL_CAN_GET_ERROR_CAPTURE, (int *)arg) 根据返回的arg或者debug的log,查询错误表格获取错误位置和错误原因。表格如下;

  • 两个792同时挂载在CAN总线上时,出现接收异常,无法正常接收数据?

    答:实际上接收数据没有异常,只是接收次数debug异常。三种解决方式:1、降低波特率;2、使用ioctl命令 IOCTL_CAN_SET_RECV_WAIT_WHILE ,更换使用轮询状态位的方式,但是会额外增加cpu占用;3、使用ioctl命令 IOCTL_CAN_SET_RECV_NON_BLOCK_ENABLE ,更换使用非阻塞式接收方式,在中断回调中自行获取数据后自行处理。

  • CAN在发送数据的时候,通过逻辑分析仪或示波器抓取信号存在部分BIT异常置位?

    答:这是CAN协议的填充错误判断,在需要位填充的段内,连续检测到6位相同的电平时,会把末位电平翻转。但不影响CAN设备通信。

Note

说明:

  • 错误信息查询表格

arg的bit6-bit7:00-位错误;01-格式错误;10-填充错误;11其他错误

arg的bit5:0-发送时发生的错误;1-接收时发生的错误

arg的bit0-bit4:查看下表

二进制

十六进制

错误信息

0b00011

0x03

帧起始

0b00010

0x02

ID BIT 28-21

0b00110

0x06

ID BIT 20-18

0b00100

0x04

SRTR位

0b00101

0x05

IDE位

0b00111

0x07

ID BIT 17-13

0b01111

0x0F

ID BIT 12-5

0b01110

0x0E

ID BIT 4-0

0b01100

0x0C

RTR位

0b01101

0x0D

保留位1

0b01001

0x09

保留位0

0b01011

0x0B

数据长度代码

0b01010

0x0A

数据区

0b01000

0x08

CRC序列

0b11000

0x18

CRC界定符

0b11001

0x19

应答

0b11011

0x1B

应答界定

0b11010

0x1A

帧结束

0b10010

0x12

中止

0b10001

0x11

活动错误标志

0b10110

0x16

消极错误标志

0b10011

0x13

控制位误差

0b10111

0x17

错误定义符

0b11100

0x1C

溢出标志

  • 各个IOCTL_CAN_GET形参返回的arg对应信息是什么?

    答:① IOCTL_CAN_GET_INTERRUPT_SOURCE :BIT0-接收中断;BIT1-发送中断;BIT2-错误中断;BIT3-数据溢出中断;BIT5-被动错误中断;BIT6-仲裁丢失中断,当该bit返回为1时可调用 IOCTL_CAN_GET_ARBITRATION_LOSS 获取仲裁丢失位置;BIT7-总线错误中断。各个错误BIT置1后可调用 IOCTL_CAN_GET_ERROR_CAPTURE 获取详细错误信息。

    IOCTL_CAN_GET_STATUS_CALLBACK :对应BIT置1为以下状态,置0则为相反状态;BIT0-接收缓冲器中存在数据;BIT1-接收数据已溢出;BIT2-发送缓冲器已释放;BIT3-发送请求处理完毕;BIT4-正在接收信息;BIT5-正在发送信息;BIT6-已超过设置的报警限制值,当该BIT置1,说明达到 IOCTL_CAN_SET_ERROR_ALARM_CNT 中预设的报警值,可以通过调用 IOCTL_CAN_GET_RX_ERROR_CNTIOCTL_CAN_GET_TX_ERROR_CNT 查看发送或者接收时产生的错误次数;BIT7-CAN总线处于工作状态。

    IOCTL_CAN_GET_ARBITRATION_LOSS :返回数值为11-仲裁丢失在SRTR;返回数值为12-仲裁丢失在IDE;返回数值为32-仲裁丢失在RTR;返回数值0~10-仲裁丢失在ID的BIT0~BIT10;返回数值13~30-仲裁丢失在ID的BIT11~BIT28。

  • CAN一运行就出现空指针访问?

    答:检查代码流程,是否在打开CAN外设后先执行 IOCTL_CAN_SET_DMA_FRAMES 设置最大单次接收帧数以及接收方式(阻塞式接收-使用信号量/使用死等;非阻塞式接收方式),如果配置为非阻塞式接收,是否配置了回调函数。

2.29.4. API参考

CAN dev_ioctl funciton selest

CAN_MAGIC
IOCTL_CAN_SET_DMA_FRAMES

设置can-dma缓存数据

IOCTL_CAN_SET_INTERRUPT_ENABLE

中断使能

IOCTL_CAN_SET_INTERRUPT_DISABLE

中断失能

IOCTL_CAN_SET_MODE

修改can参数

IOCTL_CAN_SET_FILTER

修改can参数

IOCTL_CAN_SET_RATE

修改can参数

IOCTL_CAN_SET_RECV_WAIT_SEM

阻塞式接收-使用信号量,占用中断

IOCTL_CAN_SET_RECV_WAIT_WHILE

阻塞式接收-使用查询中断标志位,内部会清除中断

IOCTL_CAN_SET_RECV_NON_BLOCK_ENABLE

非阻塞式接收-使用中断接收,需要配置IOCTL_CAN_SET_IRQ_CB

IOCTL_CAN_SET_RECV_NON_BLOCK_DISABLE

非阻塞式接收-使用中断接收,需要配置IOCTL_CAN_SET_IRQ_CB

IOCTL_CAN_SET_IRQ_CB

非阻塞式接收会占用一个can接收中断,需要配置回调函数进行接收数据获取

IOCTL_CAN_SET_ERROR_ALARM_CNT

设置错误报警计数值,当达到预设值后会给STATUS_CALLBACKE的bit6置1

IOCTL_CAN_GET_INTERRUPT_SOURCE

获取中断源

IOCTL_CAN_GET_STATUS_CALLBACK

获取当前状态

IOCTL_CAN_GET_ARBITRATION_LOSS

获取仲裁丢失位

IOCTL_CAN_GET_ERROR_CAPTURE

错误捕获

IOCTL_CAN_GET_RX_ERROR_CNT

获取接收错误计数

IOCTL_CAN_GET_TX_ERROR_CNT

获取发送错误计数

IOCTL_CAN_GET_PUT_REGISTER_INFO

寄存器参数读取

CAN event interrupt

enum can_event_isr_t

Values:

enumerator CAN_EVENT_CLEAR_INTERRUPT

清除中断标志位

enumerator CAN_EVENT_RECEIVE_INTERRUPT

接收中断

enumerator CAN_EVENT_TRANSMIT_INTERRUPT

发送中断

enumerator CAN_EVENT_ERROR_INTERRUPT

错误中断

enumerator CAN_EVENT_DATA_OVERFLOW_INTERRUPT

数据溢出中断

enumerator CAN_EVENT_ALL_INTERRUPT_DISABLE

关闭所有中断

enumerator CAN_EVENT_ERROR_PASSIVE_INTERRUPT

被动错误中断

enumerator CAN_EVENT_ARBITRATION_LOST_INTERRUPT

仲裁丢失中断

enumerator CAN_EVENT_BUS_ERROR_INTERRUPT

总线错误中断

CAN event status

enum can_event_status_t

Values:

enumerator CAN_EVENT_RXFIFO_HAVE_DATA_STATUS

接收缓冲器中有数据

enumerator CAN_EVENT_RECEIVE_DATA_OVERFLOW_STATUS

接收数据已溢出

enumerator CAN_EVENT_TRANSMISSION_BUFFER_RELEASE_STATUS

发送缓冲器已释放

enumerator CAN_EVENT_TRANSMIT_END_STATUS

发送请求已处理完毕

enumerator CAN_EVENT_RECEIVING_DATA_STATUS

正在接收数据

enumerator CAN_EVENT_SENDING_DATA_STATUS

正在发送数据

enumerator CAN_EVENT_ERROR_OVERFLOW_STATUS

错误计数器达到设置的报警限制值

enumerator CAN_EVENT_BUS_IS_IDLE_STATUS

总线空闲状态

CAN mode

enum can_mode_t

Values:

enumerator CAN_MODE_BASICCAN

标准模式

enumerator CAN_MODE_ENHANCED

增强模式

enumerator CAN_MODE_MAX

CAN filter mode

enum can_filter_t

Values:

enumerator CAN_FILTER_DOUBLE_STAND

2 x 16bit filters

enumerator CAN_FILTER_DOUBLE_EXTEND

2 x 16bit filters

enumerator CAN_FILTER_SINGLE_STAND

1 x 32bit filter

enumerator CAN_FILTER_SINGLE_EXTEND

1 x 32bit filter

enumerator CAN_FILTER_MAX

CAN data format

enum can_request_type_t

Values:

enumerator CAN_REQUEST_DATA_TYPE

数据帧

enumerator CAN_REQUEST_REMOTE_TYPE

远程帧

enumerator CAN_REQUEST_MAX

CAN frame format

enum can_frame_format_t

Values:

enumerator CAN_FRAME_STANDARD_FORMAT

标准帧

enumerator CAN_FRAME_EXTENDED_FORMAT

扩展帧

enumerator CAN_FRAME_MAX

CAN irq callback

const struct device_operations can_dev_ops

rate = (lsb_clk)/((TSEG1+TSEG2+3)*(brp+1)*2) ///

struct can_baudrate_t

Public Members

u16 brp

分频系数

u16 sjw

再同步补偿最大宽度,节点与总线再同步每一bit最多允许的补偿偏差

u16 aligned0

仅对齐作用

u8 sam

采样次数:0-采样1次;1-采样3次

u8 tseg2

PBS2

u8 tseg1

PBS1+PTS

struct can_rx_filter_t

Public Members

can_filter_t filter_mode

ecan 双接收滤波器模/

u8 accept_rtr0

接收的rtr0

u8 accept_rtr1

接收的rtr1

u8 mask_rtr0

接收rtr0的屏蔽位

u8 mask_rtr1

接收rtr1的屏蔽位

u8 aligned

仅对齐作用

u32 accept_id0

接收的id0;扩展帧在双滤波器开启的状态下仅支持ID的高16位,即bit 28-bit 13

u32 accept_id1

接收的id1;扩展帧在双滤波器开启的状态下仅支持ID的高16位,即bit 28-bit 13

u32 mask_id0

接收id0的屏蔽位

u32 mask_id1

接收id1的屏蔽位

struct can_data_t

Public Members

u32 id
u8 dlc
u8 data_format

标准帧/扩展帧标记位

u8 rtr
u8 aligned
u8 data[8]
struct can_platform_data

Public Members

int rx_pin
int tx_pin
u8 stm

增强型can自检测模式使能

u8 lom

增强型can监听模式使能

u8 priority

can中断优先级-用于阻塞式接收-信号量/非阻塞式接收

u8 cpu_id

can中断注册cpu-用于阻塞式接收-信号量/非阻塞式接收

can_mode_t can_mode

can 模式

can_baudrate_t baudrate

波特率设置

can_rx_filter_t filter

滤波器ID设置

struct can_cb_t

Public Members

int (*cb_func)(void *priv, can_data_t *data)
void *cb_priv