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
- 1.在板级文件
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 = 0x123
和mask_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_CNT
和IOCTL_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
总线错误中断
-
enumerator CAN_EVENT_CLEAR_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
总线空闲状态
-
enumerator CAN_EVENT_RXFIFO_HAVE_DATA_STATUS
CAN mode
CAN filter mode
CAN data format
CAN frame format
CAN irq callback
-
const struct device_operations can_dev_ops
rate = (lsb_clk)/((TSEG1+TSEG2+3)*(brp+1)*2) ///
-
struct can_baudrate_t
-
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的屏蔽位
-
can_filter_t filter_mode
-
struct can_data_t
-
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设置
-
int rx_pin
-
struct can_cb_t