【前言】
之前的视频教程分享了两期CANopen的专题,配套的例子都是基于裸机的,为了方便大家在OS下使用,本期视频带OS下的支持。
CANopen协议栈专题,实战方式系统了解NMT,PDO,SDO,时间戳,同步报文,紧急报文等(2023-10-17)
https://www.armbbs.cn/forum.php?mod=viewthread&tid=121438
CANopen协议栈专题,CANopen主从机组网实战,CAN词典工具使用方法以及吃透PDO玩法(2023-11-01)
https://www.armbbs.cn/forum.php?mod=viewthread&tid=121619
【视频】
https://www.bilibili.com/video/BV1zHSaYQEYx/
【简介】
1、针对RTX5/FreeRTOS源码全家桶模板,已经更新了4期视频,这是第5期,来一期添加CANopen组件的视频教程。
第1期:RTX5全家桶源码综合模板发布,含FreeRTOS内核版本,将其打造成直接面向实际项目应用的综合框架
https://www.armbbs.cn/forum.php?mod=viewthread&tid=124516
第2期:RTX5源码全家桶集成emWin6.40, Modbus主从,含FreeRTOS版, 探讨一种移植第3方组件通用方法以及使用注意事项
https://www.armbbs.cn/forum.php?mod=viewthread&tid=125509
第3期:手把手AppWizard轻松制作一个emWin滑动主界面控制框架,任意跳转控制(2024-09-06)
https://www.armbbs.cn/forum.php?mod=viewthread&tid=125613
第4期:【授人以渔】CMSIS-RTOS V2封装层专题视频,一期视频将常用配置和用法梳理清楚,适用于RTX5和FreeRTOS(2024-09-28)
https://www.armbbs.cn/forum.php?mod=viewthread&tid=125907
2、CANopen常用的NMT,PDO,SDO,时间戳,同步报文,紧急报文都支持
3、移植CANopenNode协议栈到RTOS两个关键地方的处理
(1)开关中断的处理,裸机版的移植在开关中断的处理地方非常"暴力",直接就是大范围的全局开关中断处理,非常不合理
/* (un)lock critical section in CO_CANsend() */ #define CO_LOCK_CAN_SEND(CAN_MODULE) \ do { \ (CAN_MODULE)->primask_send = __get_PRIMASK(); \ __disable_irq(); \ } while (0) #define CO_UNLOCK_CAN_SEND(CAN_MODULE) __set_PRIMASK((CAN_MODULE)->primask_send) /* (un)lock critical section in CO_errorReport() or CO_errorReset() */ #define CO_LOCK_EMCY(CAN_MODULE) \ do { \ (CAN_MODULE)->primask_emcy = __get_PRIMASK(); \ __disable_irq(); \ } while (0) #define CO_UNLOCK_EMCY(CAN_MODULE) __set_PRIMASK((CAN_MODULE)->primask_emcy) /* (un)lock critical section when accessing Object Dictionary */ #define CO_LOCK_OD(CAN_MODULE) \ do { \ (CAN_MODULE)->primask_od = __get_PRIMASK(); \ __disable_irq(); \ } while (0) #define CO_UNLOCK_OD(CAN_MODULE) __set_PRIMASK((CAN_MODULE)->primask_od)
canopen_app_interrupt(void) { CO_LOCK_OD(CO->CANmodule); if (!CO->nodeIdUnconfigured && CO->CANmodule->CANnormal) { bool_t syncWas = false; /* get time difference since last function call */ uint32_t timeDifference_us = 1000; // 1ms second #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE syncWas = CO_process_SYNC(CO, timeDifference_us, NULL); #endif #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE CO_process_RPDO(CO, syncWas, timeDifference_us, NULL); #endif #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE CO_process_TPDO(CO, syncWas, timeDifference_us, NULL); #endif /* Further I/O or nonblocking application code may go here. */ } CO_UNLOCK_OD(CO->CANmodule); }
现在修改为采用仅开关CAN中断,且支持嵌套调用
/* (un)lock critical section in CO_CANsend() */ #define CO_LOCK_CAN_SEND(CAN_MODULE) \ do { \ HAL_NVIC_DisableIRQ(FDCAN1_IT0_IRQn); \ (CAN_MODULE)->CriticalNesting++; \ } while(0) #define CO_UNLOCK_CAN_SEND(CAN_MODULE) \ do { \ (CAN_MODULE)->CriticalNesting--; \ if((CAN_MODULE)->CriticalNesting == 0) \ { \ HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn); \ } \ } while(0) /* (un)lock critical section in CO_errorReport() or CO_errorReset() */ #define CO_LOCK_EMCY(CAN_MODULE) \ do { \ HAL_NVIC_DisableIRQ(FDCAN1_IT0_IRQn); \ (CAN_MODULE)->CriticalNesting++; \ } while(0) #define CO_UNLOCK_EMCY(CAN_MODULE) \ do { \ (CAN_MODULE)->CriticalNesting--; \ if((CAN_MODULE)->CriticalNesting == 0) \ { \ HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn); \ } \ } while(0) /* (un)lock critical section when accessing Object Dictionary */ #define CO_LOCK_OD(CAN_MODULE) \ do { \ HAL_NVIC_DisableIRQ(FDCAN1_IT0_IRQn); \ (CAN_MODULE)->CriticalNesting++; \ } while (0) #define CO_UNLOCK_OD(CAN_MODULE) \ do { \ (CAN_MODULE)->CriticalNesting--; \ if((CAN_MODULE)->CriticalNesting == 0) \ { \ HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn); \ } \ } while(0) #endif
(2)函数canopen_app_process和canopen_app_interrupt的调用处理,我们这里直接将其放在1ms执行一次的任务里面:
/* ********************************************************************************************************* * 函 数 名: AppTaskCANopen * 功能说明: CANopen处理任务。 * 形 参: 无 * 返 回 值: 无 * 优 先 级: osPriorityNormal6 ********************************************************************************************************* */ extern void DemoCANFD(void); void AppTaskCANopen(void *argument) { const uint16_t usFrequency = 1; /* 延迟周期 */ uint32_t tick; DemoCANFD(); /* 获取当前时间 */ tick = osKernelGetTickCount(); while(1) { /* CAN处理 */ canopen_app_process(); canopen_app_interrupt(); /* 相对延迟 */ tick += usFrequency; osDelayUntil(tick); } }
工程目录
1、集成了CMSIS6.10,CMSIS-Driver,CMSIS-DSP,CMSIS-Viwer,CMSIS-Compiler,CMSIS-RTOS
V2,CMSIS-FreeRTOS,CMSIS-RTX,CMSIS-MbedTLS等,全部采用的当前最新版。
2、网络协议栈,单网络协议栈同时管理DM9000和DM9162双网口。
3、文件系统,同时管理外挂U盘,NAND Flash和SD卡。
4、USB协议栈,RL-USB同时外挂USB FS和USB HS两个USB外设,USB FS接口用于外接电脑,实现SD卡和NAND模拟U盘,USB HS用于外挂U盘设备。
5、加密算法库使用的CMSIS-mbedTLS。
6、BSP外设驱动,部分是采用的CMSIS-Driver,其他都采用我们自己设计的。
7、Modbus RTU主从。
8、emWin6.46。
9、CANopen。
注意事项
使用的CANFD1,注意V7开发板上的跳线帽设置。另外就是如果使用了CANFD1引脚后,不能再使用MicroUSB的Device端口了
参考资料
1、案例下载,本次功能升级将emWin升级到最新的6.46版本。
FreeRTOS All In One(2024-10-30 V3.0).7z (30.53MB)
RTX5 All In One(2024-10-30 V3.0).7z (29.38MB)
2、RTX5全家桶源码综合模板发布V2.0,含FreeRTOS内核版本,将其打造成直接面向实际项目应用的综合框架(2024-08-30)
https://www.armbbs.cn/forum.php?mod=viewthread&tid=124516
3、H7-TOOL的CAN/CANFD助手CANopen协议解析操作说明V1.1,持续更新(2023-12-04)
https://www.armbbs.cn/forum.php?mod=viewthread&tid=120863