Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
CANopen_canfestival
canfestival从站测试NMT节点切换状态功能时遇到问题
发布于 2025-01-15 16:27:29 浏览:241
订阅该版
[tocm] 在用canfestival做从节点NMT状态切换时遇到了问题,请教各位大佬。 # 大致背景说明: 1、参考canfestival包里的例程master402源码,修改成从站TestSlave。  2、测试板卡芯片STM32F407作为从站,NodeID = 2。为了最大程度简化功能目前从站只配置了心跳报文,5秒一次心跳(0x1388 = 5000 ms)。  3、PC作为主站,使用CANPro软件收发报文,并且板卡上电运行后可以正常收到每隔5秒的心跳报文。 **(顺便请教,下图中打印信息中间夹杂了一些不完整的字符是什么原因?)**   4、部分切换功能可以成功(如下图从Pre-Operational切至Stop):   5、rt-thread版本:4.1.0  6、之前开启了硬件滤波器HDR测试遇到了其他问题,目前暂时关闭了HDR。 # 问题: **其他大部分的状态切换都会报不一样的错误,最常见的错误为以下两种。** 1、从Stop状态切到preOperational状态时,报错:(obj != object) assertion failed at function:rt_object_init, line number:358   2、从preOperational状态切到Operational状态时,报错:thread: stack overflow  
查看更多
2
个回答
默认排序
按发布时间排序
NoneKnowsMe
2025-01-15
这家伙很懒,什么也没写!
# 补充: 打印信息都是在canopen_callback.c里实现的,根据打印信息可以看到从节点已经收到报文并调用了canDispatch,跳转到了指定的callback函数成功执行了打印代码。callback函数已经执行成功了为什么还会出现其他报错? ```c /* This file is part of CanFestival, a library implementing CanOpen Stack. Copyright (C): Edouard TISSERANT and Francis DUPIN See COPYING file for copyrights details. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include
#include "canfestival.h" #include "TestSlave_od.h" #include "canopen_callback.h" #include "TestSlave_canopen.h" /*****************************************************************************/ void TestSlave_heartbeatError(CO_Data* d, UNS8 heartbeatID) { rt_kprintf("heartbeatError %d\n", heartbeatID); } void TestSlave_initialisation(CO_Data* d) { rt_kprintf("canfestival enter initialisation state\n"); } void TestSlave_preOperational(CO_Data* d) { rt_thread_t tid; rt_kprintf("canfestival enter preOperational state\n"); tid = rt_thread_create("co_cfg", canopen_start_thread_entry, RT_NULL, 1024, 12, 2); if(tid == RT_NULL) { rt_kprintf("canfestival config thread start failed!\n"); } else { rt_thread_startup(tid); } } void TestSlave_operational(CO_Data* d) { rt_kprintf("canfestival enter operational state\n"); } void TestSlave_stopped(CO_Data* d) { rt_kprintf("canfestival enter stop state\n"); } void TestSlave_post_sync(CO_Data* d) { } void TestSlave_post_TPDO(CO_Data* d) { } void TestSlave_storeODSubIndex(CO_Data* d, UNS16 wIndex, UNS8 bSubindex) { /*TODO : * - call getODEntry for index and subindex, * - save content to file, database, flash, nvram, ... * * To ease flash organisation, index of variable to store * can be established by scanning d->objdict[d->ObjdictSize] * for variables to store. * * */ rt_kprintf("storeODSubIndex : %4.4x %2.2x\n", wIndex, bSubindex); } void TestSlave_post_emcy(CO_Data* d, UNS8 nodeID, UNS16 errCode, UNS8 errReg, const UNS8 errSpec[5]) { rt_kprintf("received EMCY message. Node: %2.2x ErrorCode: %4.4x ErrorRegister: %2.2x\n", nodeID, errCode, errReg); } ``` # 补充2 通过进一步简化程序,目前已将所有回调函数简化为只执行一条打印语句: ```c void TestSlave_heartbeatError(CO_Data* d, UNS8 heartbeatID) { rt_kprintf("heartbeatError %d\n", heartbeatID); } void TestSlave_initialisation(CO_Data* d) { rt_kprintf("canfestival enter initialisation state\n"); } void TestSlave_preOperational(CO_Data* d) { // rt_thread_t tid; rt_kprintf("canfestival enter preOperational state\n"); // tid = rt_thread_create("co_cfg", canopen_start_thread_entry, RT_NULL, 1024, 12, 2); // if (tid == RT_NULL) // { // rt_kprintf("canfestival config thread start failed! \n"); // } // else // { // rt_thread_startup(tid); // } } void TestSlave_operational(CO_Data* d) { rt_kprintf("canfestival enter operational state\n"); } void TestSlave_stopped(CO_Data* d) { rt_kprintf("canfestival enter stop state\n"); // if(rt_thread_delete(tid) != RT_EOK) // { // rt_kprintf("canfestival config thread stop failed!\n"); // } } void TestSlave_post_sync(CO_Data* d) { } void TestSlave_post_TPDO(CO_Data* d) { } void TestSlave_storeODSubIndex(CO_Data* d, UNS16 wIndex, UNS8 bSubindex) { /*TODO : * - call getODEntry for index and subindex, * - save content to file, database, flash, nvram, ... * * To ease flash organisation, index of variable to store * can be established by scanning d->objdict[d->ObjdictSize] * for variables to store. * * */ rt_kprintf("storeODSubIndex : %4.4x %2.2x\n", wIndex, bSubindex); } void TestSlave_post_emcy(CO_Data* d, UNS8 nodeID, UNS16 errCode, UNS8 errReg, const UNS8 errSpec[5]) { rt_kprintf("received EMCY message. Node: %2.2x ErrorCode: %4.4x ErrorRegister: %2.2x\n", nodeID, errCode, errReg); } ``` 这样改了之后暂时不会出现上面提到的问题1:从Stop状态切到preOperational状态时,报错:(obj != object) assertion failed at function:rt_object_init, line number:358 问题2仍然存在:从preOperational状态切到Operational状态时,报错:thread: stack overflow 通过debug排查目前定位到是在can_rtthread.c里的canopen_recv_thread_entry()函数,这个线程函数里用了一个while(1)循环专门接收报文: ```c void canopen_recv_thread_entry(void* parameter) { struct can_app_struct *canpara = (struct can_app_struct *) parameter; struct rt_can_msg msg; Message co_msg; candev = rt_device_find(canpara->name); RT_ASSERT(candev); rt_sem_init(&can_data.sem, "co-rx", 0, RT_IPC_FLAG_PRIO); rt_err_t err = rt_device_open(candev, (RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX)); if( err != RT_EOK) { LOG_E("canfestival open device %s failed, err = %d", canpara->name, err); return; } err = rt_device_set_rx_indicate(candev, can1ind); if( err != RT_EOK) { LOG_E("canfestival set rx indicate failed, err = %d", err); return; } rt_size_t read_size = 0; while (1) { err = rt_sem_take(&can_data.sem, MAX_SEM_WAIT_TIME); if ( err != RT_EOK) { if(getState(OD_Data) == Operational) { LOG_W("canfestival wait receive timeout, err = %d", err); } } else { read_size = rt_device_read(candev, 0, &msg, sizeof(msg)); if( read_size == sizeof(msg)) { co_msg.cob_id = msg.id; co_msg.len = msg.len; co_msg.rtr = msg.rtr; memcpy(co_msg.data, msg.data, msg.len); EnterMutex(); canDispatch(OD_Data, &co_msg); LeaveMutex(); } else if (read_size == 0){ LOG_W("canfestival receive faild, err = %d", rt_get_errno()); } else { LOG_W("canfestival receive size wrong, size = %u", read_size); } } } } ``` 当测试板卡(Slave)接收到PC测试软件(Master)发送的Start切换报文时,已确实被canopen_recv_thread_entry线程函数捕捉到并成功通过canDispatch函数调用了回调函数TestSlave_operational(),打印出了信息:canfestival enter operational state。 问题出在之后,while(1)开始下一轮循环后执行err = rt_sem_take(&can_data.sem, MAX_SEM_WAIT_TIME),然后执行到rt_sem_take()函数里的rt_schedule(),之后就发生了栈溢出现象。 尝试了将线程的栈大小改大(由原本的1024提高到4096),或者将rt_sem_take()的等待时间由原本的5000改为RT_WAITING_FOREVER,没有用。 思路卡在了这里,为什么设备上电初始化时执行while(1)里的rt_sem_take()没有问题,但是在收到一次报文执行过一次while(1)里的操作后,进入下一轮循环时却会出现问题呢?
用户名由3_15位
2025-01-16
这家伙很懒,什么也没写!
- 打印混乱是线程间都要同时打印造成的;在打印前后加中断屏蔽可以解决(不完美) -
撰写答案
登录
注册新账号
关注者
0
被浏览
241
关于作者
NoneKnowsMe
这家伙很懒,什么也没写!
提问
8
回答
5
被采纳
0
关注TA
发私信
相关问题
1
canfestival怎么实现单独对每个从机进行配置
2
bootloader 里面不能运行 canfestiavl
3
CanFestvial(CanOpen)调试时遇到问题
4
移植CAN festival相关问题?
5
菜鸟也出把力 RT-Thread+CanOpen(开源的CanFestival)
6
最好的开源PLC/HMI开发平台(Beremiz软件平台)
7
CANfestival_Canopen 协议问题
8
drv_can.c 和can_rtthread.c啥关系
9
canfestival跑起来后提示驱动器心跳包超时!
10
CANFestival使用困扰
推荐文章
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
RTT串口查找函数使用过程中遇到的问题。
2
RT-Thread CI编译产物artifacts自动上传功能介绍
3
STM32G030移植RT-Thread
4
CubeMX & RT-Thread Studio 联合开发说明
5
RT-Thread项目助手v0.3 | Ubuntu与MacOS平台的RT-Thread Env
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
rt-smart
RTC
FAL
I2C_IIC
cubemx
ESP8266
UART
WIZnet_W5500
ota在线升级
PWM
BSP
flash
freemodbus
packages_软件包
潘多拉开发板_Pandora
GD32
定时器
ADC
flashDB
编译报错
socket
中断
rt_mq_消息队列_msg_queue
keil_MDK
Debug
SFUD
ulog
msh
C++_cpp
MicroPython
本月问答贡献
出出啊
1522
个答案
343
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
814
个答案
179
次被采纳
crystal266
555
个答案
162
次被采纳
whj467467222
1222
个答案
149
次被采纳
本月文章贡献
出出啊
1
篇文章
6
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
3
次点赞
crystal266
2
篇文章
1
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部