Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
CAN总线
【BUG】CAN发送时拔插can总线,导致后续发送显示失败
发布于 2022-10-10 19:01:07 浏览:1183
订阅该版
[tocm] - 使用KEILV5 AC6编译器 优化等级-OZ - RTT使用V4.1.0 - 使用CAN驱动 - 芯片为STM32F429IGT6 # 问题描述 这些测试都没有使用自动重发功能,can部分代码都是最新从RTT源码拉下来的。 ### 先插上CAN总线,发送10次成功。 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221012/12d47769a47ae649d9c53fd785c81a39.png) ### 断开CAN总线,发送10次失败 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221012/91c75880ef4e7edecc43c800a58e4c50.png) ### 再次插上CAN总线,发送10次成功 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221012/163595c785cf7b4011073b7a64fdf872.png) ### 再次断开CAN总线,发送10次失败 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221012/955b28f82f532133a1ddef63847e7a5b.png) ### 再次插上CAN总线,发送10次 **失败** - 可以看出进入到被动恢复了 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221012/7a6044a2fc31d0224e9171ac9050d808.png) - 接上分析仪可以看出,发送是成功的。但是代码认为发送失败了 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221012/b83b8545eb509a0ed72eb609f0bf1dc9.png) ### 跟这个帖子一样,进入被动恢复后,没有解决这个问题。 > https://club.rt-thread.org/ask/question/d19dd32f398cc2a6.html ## 原来的测试 ### 正常发送,没有拔插can总线 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221010/48ec858a7927ea2acd535177b26e11b1.png) ### 拔出总线 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221010/b7c331f03e84590dea6eafc8d55a741b.png) ### 重新插回总线,显示失败。实际上发送出来了 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221010/19a6214240d860f65a1f2f76820ec808.png) - 逻辑分析仪显示由ACK回复 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221011/462d0bca7af047412e74e0619776c690.png.webp) ##代码如下 ```c /* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : * @brief : * @date : ****************************************************************************** * @attention * @author ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ /* Private includes ----------------------------------------------------------*/ #include
#include "rtdevice.h" #define CAN_DEV_NAME "can1" /* CAN 设备名称 */ /*ulog include*/ #define LOG_TAG CAN_DEV_NAME #define LOG_LVL DBG_INFO #include
/* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* 监控线程配置 */ #define THREAD_PRIORITY 12 //线程优先级 #define THREAD_TIMESLICE 10 //线程时间片 #define THREAD_STACK_SIZE 1024//栈大小 /* Private variables ---------------------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/ static struct rt_semaphore rx_sem; /* 用于接收消息的信号量 */ static rt_device_t can_dev; /* CAN 设备句柄 */ /** * @brief 接收数据回调函数 * @param None * @retval None * @note */ static rt_err_t can_rx_call(rt_device_t dev, rt_size_t size) { /* CAN 接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */ rt_sem_release(&rx_sem); return RT_EOK; } /** * @brief can接收线程 * @param None * @retval None * @note */ static void can_rx_thread(void *parameter) { int i; rt_err_t res; struct rt_can_msg rxmsg = {0}; /* 设置接收回调函数 */ rt_device_set_rx_indicate(can_dev, can_rx_call); #ifdef RT_CAN_USING_HDR struct rt_can_filter_item items[5] = { RT_CAN_FILTER_ITEM_INIT(0x100, 0, 0, 0, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x100~0x1ff,hdr 为 - 1,设置默认过滤表 */ RT_CAN_FILTER_ITEM_INIT(0x300, 0, 0, 0, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x300~0x3ff,hdr 为 - 1 */ RT_CAN_FILTER_ITEM_INIT(0x211, 0, 0, 0, 0x7ff, RT_NULL, RT_NULL), /* std,match ID:0x211,hdr 为 - 1 */ RT_CAN_FILTER_STD_INIT(0x486, RT_NULL, RT_NULL), /* std,match ID:0x486,hdr 为 - 1 */ {0x555, 0, 0, 0, 0x7ff, 7,} /* std,match ID:0x555,hdr 为 7,指定设置 7 号过滤表 */ }; struct rt_can_filter_config cfg = {5, 1, items}; /* 一共有 5 个过滤表 */ /* 设置硬件过滤表 */ res = rt_device_control(can_dev, RT_CAN_CMD_SET_FILTER, &cfg); RT_ASSERT(res == RT_EOK); #endif while (1) { /* hdr 值为 - 1,表示直接从 uselist 链表读取数据 */ rxmsg.hdr = -1; /* 阻塞等待接收信号量 */ rt_sem_take(&rx_sem, RT_WAITING_FOREVER); /* 从 CAN 读取一帧数据 */ rt_device_read(can_dev, 0, &rxmsg, sizeof(rxmsg)); /* 打印数据 ID 及内容 */ rt_kprintf("\n"); rt_kprintf("ID:%x:", rxmsg.id); for (i = 0; i < 8; i++) { rt_kprintf("%2x", rxmsg.data[i]); } rt_kprintf("\n"); } } /** * @brief CAN初始化函数 * @param None * @retval None * @note */ int can1_init(void) { struct rt_can_msg msg = {0}; rt_err_t res; rt_size_t size; /* 查找 CAN 设备 */ can_dev = rt_device_find(CAN_DEV_NAME); if (!can_dev) { LOG_E("find %s failed", CAN_DEV_NAME); return RT_ERROR; } /* 初始化 CAN 接收信号量 */ rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO); /* 以中断接收及发送方式打开 CAN 设备 */ res = rt_device_open(can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX); RT_ASSERT(res == RT_EOK); /* 创建线程 放在最后 避免定时器还为初始化*/ rt_thread_t thread = rt_thread_create( "can_rx", /* 线程名字 */ can_rx_thread, /* 线程入口函数 */ RT_NULL, /* 线程入口函数参数 */ THREAD_STACK_SIZE, /* 线程栈大小 */ THREAD_PRIORITY, /* 线程的优先级 */ THREAD_TIMESLICE); /* 线程时间片 */ /* 创建成功则启动线程 */ if (thread != RT_NULL) { rt_thread_startup(thread); } else { LOG_E("Monitor thread created failed."); res = RT_ERROR; } msg.id = 0x78; /* ID 为 0x78 */ msg.ide = RT_CAN_STDID; /* 标准格式 */ msg.rtr = RT_CAN_DTR; /* 数据帧 */ msg.len = 8; /* 数据长度为 8 */ /* 待发送的 8 字节数据 */ msg.data[0] = 0x00; msg.data[1] = 0x11; msg.data[2] = 0x22; msg.data[3] = 0x33; msg.data[4] = 0x44; msg.data[5] = 0x55; msg.data[6] = 0x66; msg.data[7] = 0x77; /* 发送一帧 CAN 数据 */ size = rt_device_write(can_dev, 0, &msg, sizeof(msg)); if (size == 0) { LOG_E("can dev write data failed!"); } return res; } INIT_APP_EXPORT(can1_init); /** * @brief CAN发送测试 * @param None * @retval None * @note */ void can_send_test(void) { struct rt_can_msg msg = {0}; rt_size_t size; static rt_uint8_t num = 0; /* 查找 CAN 设备 */ can_dev = rt_device_find(CAN_DEV_NAME); if (!can_dev) { LOG_E("find %s failed", CAN_DEV_NAME); } msg.id = 0x78; /* ID 为 0x78 */ msg.ide = RT_CAN_STDID; /* 标准格式 */ msg.rtr = RT_CAN_DTR; /* 数据帧 */ msg.len = 8; /* 数据长度为 8 */ /* 待发送的 8 字节数据 */ msg.data[0] = 0x00; msg.data[1] = num++; msg.data[2] = 0x22; msg.data[3] = 0x33; msg.data[4] = num++; msg.data[5] = 0x55; msg.data[6] = 0x66; msg.data[7] = 0x77; /* 发送一帧 CAN 数据 */ size = rt_device_write(can_dev, 0, &msg, sizeof(msg)); if (size == 0) { rt_kprintf("can dev write data failed!\n"); } } /* 导出到 msh 命令列表中 */ MSH_CMD_EXPORT(can_send_test, can send test); ``` # 解决办法 - 查找到这个帖子 https://club.rt-thread.org/ask/article/5cedb728813e6fd8.html - 发现主要问题在最新的RTT中已经解决了。 ## 但是断开总线再次插入发送失败的问题没有解决 - 查看帖子下面的评论 @mhxsoft 的回复 > 还发现一个地方,drv_can.c里,当CAN总线拔掉发送时,会进入ACK错误中断SCE,这时TSR的TXOK都是0,另CAN_FLAG_TXOK0/1/2值的定义,还要移位才能对应,READ_BIT没有进行移位,所以下面这三个条件并不会执行,改为下面方式就可以执行了,并且清理了发送请求位CAN_TSR_RQCP0/1/2 ```c CAN1_SCE_IRQHandler(void) { ...... case RT_CAN_BUS_ACK_ERR:/* attention !!! test ack err's unit is transmit unit */ drv_can1.device.status.ackerrcnt++; if (!READ_BIT(drv_can1.CanHandle.Instance->TSR, CAN_FLAG_TXOK0)) rt_hw_can_isr(&drv_can1.device, RT_CAN_EVENT_TX_FAIL | 0 << 8); else if (!READ_BIT(drv_can1.CanHandle.Instance->TSR, CAN_FLAG_TXOK1)) rt_hw_can_isr(&drv_can1.device, RT_CAN_EVENT_TX_FAIL | 1 << 8); else if (!READ_BIT(drv_can1.CanHandle.Instance->TSR, CAN_FLAG_TXOK2)) rt_hw_can_isr(&drv_can1.device, RT_CAN_EVENT_TX_FAIL | 2 << 8); break; ...... } ``` ———————-改为以下代码——————— ```c CAN1_SCE_IRQHandler(void) { ...... case RT_CAN_BUS_ACK_ERR:/* attention !!! test ack err's unit is transmit unit */ drv_can1.device.status.ackerrcnt++; if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP0)) { if (!__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK0)) { rt_hw_can_isr(&drv_can1.device, RT_CAN_EVENT_TX_FAIL | 0 << 8); } SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP0); } else if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP1)) { if (!__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK1)) { rt_hw_can_isr(&drv_can1.device, RT_CAN_EVENT_TX_FAIL | 1 << 8); } SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP1); } else if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP2)) { if (!__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK2)) { rt_hw_can_isr(&drv_can1.device, RT_CAN_EVENT_TX_FAIL | 2 << 8); } SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP2); } break; ...... } ``` # 修改结果 - **修改后,确实不会出现该情况,在没有开启自动重传的情况下** - **修改后,不能开启自动重传,开启自动重传后,不能有发送失败。 **如果造成发送失败,会阻塞当前发送线程。只要发送成功** **我用MSH命令发送,就把SHELL线程卡死了。** - 希望这个问题能够修复。由于不是我写的代码,不好意思pr。 - 另外一个就是关于can驱动部分的代码确实没看懂,所以自己并没有找到解决办法。还得搜索。
查看更多
mhxsoft
2022-10-11
这家伙很懒,什么也没写!
```c void CAN1_SCE_IRQHandler(void) { 。。。 //HAL_CAN_IRQHandler(hcan); //这里好像多调用了个CAN中断,我去掉了 。。。 } ```
3
个回答
默认排序
按发布时间排序
用户名由3_15位
2022-10-11
这家伙很懒,什么也没写!
@mhxsoft
胡图图
2022-10-12
这家伙很懒,什么也没写!
你不选重发应该就没事吧,重发拔了CAN线是阻塞在里面的
撰写答案
登录
注册新账号
关注者
0
被浏览
1.2k
关于作者
用户名由3_15位
这家伙很懒,什么也没写!
提问
62
回答
231
被采纳
32
关注TA
发私信
相关问题
1
我也来传一个CANOpen移植,RTT+STM32F107+CanOpenNode
2
谁有STM32裸跑的CANopen程序啊???
3
CAN驱动程序框架
4
CAN驱动接口如何规范一下
5
RTT无法进入线程.Cannot access Memory
6
编译提示arm-none-eabi/bin/ld: cannot find crt0.o: No such file o
7
rtt 2.1.0 正式版 mdk4 bsp/stm32 编译canapp.c错误
8
STM32F10XCAN驱动使用的问题
9
2.1版本stm32f10x分支bxcan驱动波特率设置的bug
10
rtthread2.1.0下,找不到can1设备
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
【24嵌入式设计大赛】基于RT-Thread星火一号的智慧家居系统
2
RT-Thread EtherKit开源以太网硬件正式发布
3
如何在master上的BSP中添加配置yml文件
4
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
5
RT-Thread 发布 EtherKit开源以太网硬件!
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
MicroPython
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
16
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
6
个答案
2
次被采纳
用户名由3_15位
13
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
5
次点赞
RTT_逍遥
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部