当前位置: 首页 > news >正文

Canfestival的移植思想

 

目录

1 序

2 移植

3 代码

4 字典


1 序

本文对Canfestival的移植核心点进行阐述;

阅读本文须先掌握CANopen基本理论,本文不再赘述。

 I.MX RT1176实现:https://github.com/CenwJen/i.mxrt1176.git


2 移植

软件准备

python-2.7.15.amd64.msi

wxPython2.8-win64-3.0.2.0-py27.exe

Gnosis_Utils-1.2.2.zip

CanFestival-3

对于CanFestival-3,包含1个官方源码与其3个分支,需要从中挑选支持自己平台的内核。常用的Cortex-M4/7,是Mongo-canfestival-3。

文件移植

Mongo-canfestival-3/src *.c

Mongo-canfestival-3/include *.h

Mongo-canfestival-3/include/(Platform Core)/ *.h

Mongo-canfestival-3\examples\AVR\Slave\config.h

 对于移植的文件,需要移植到工程文件里并包含,注意:

  1. 检查canfestival.h是否有条件编译防止头文件重复包含。
  2. 删除dcf.c的内联关键字。
  3. 对于config.h,以cm4/7为参考,更改为以下代码,请仔细阅读对比,其中
  • AVR为不需要的头文件;
  • SDO_BLOCK_SIZE为SDO块传输;
  • CAN_BAUDRATE为CAN波特率;
  • REPEAT_SDO_MAX_SIMULTANEOUS_TRANSFERTS_TIMES更改为REPEAT_SDO_MAX_SIMULTANEOUS_TRANSFERS_TIMES。
#ifndef _CONFIG_H_
#define _CONFIG_H_#ifdef  __IAR_SYSTEMS_ICC__
#include <ioavr.h>
#include <intrinsics.h>
#include "iar.h"
#else	// GCC
//#include <inttypes.h>
//#include <avr/io.h>
//#include <avr/interrupt.h>
//#include <avr/pgmspace.h>
//#include <avr/sleep.h>
//#include <avr/wdt.h>
#endif	// GCC//#define WD_SLEEP
// Needed defines by Atmel lib
#define FOSC           8000        // 16 MHz External cristal
#ifndef F_CPU
#define F_CPU          (1000UL*FOSC) // Need for AVR GCC
#endif
#define CAN_BAUDRATE    1000	//1000K, CAN BAUDRATE 1M// Needed defines by Canfestival lib
#define MAX_CAN_BUS_ID 1
#define SDO_MAX_LENGTH_TRANSFER 32
#define SDO_BLOCK_SIZE 16
#define SDO_MAX_SIMULTANEOUS_TRANSFERS 1
#define NMT_MAX_NODE_ID 128
#define SDO_TIMEOUT_MS 3000U
#define MAX_NB_TIMER 8// CANOPEN_BIG_ENDIAN is not defined
#define CANOPEN_LITTLE_ENDIAN 1#define US_TO_TIMEVAL_FACTOR 8#define REPEAT_SDO_MAX_SIMULTANEOUS_TRANSFERS_TIMES(repeat)\
repeat
#define REPEAT_NMT_MAX_NODE_ID_TIMES(repeat)\
repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat repeat#define EMCY_MAX_ERRORS 8
#define REPEAT_EMCY_MAX_ERRORS_TIMES(repeat)\
repeat repeat repeat repeat repeat repeat repeat repeat#endif /* _CONFIG_H_ */

applicfg.h提供调试输出宏在不需要使用时可以注释掉,因为串口速率远低于can速率,且其打印函数MSG(...)为阻塞函数,在can收发中等待打印会相当耗时,导致can速率大降。

另,留意其打印换行符为适应Linux。


3 代码

Canfestival的移植需要两个驱动:首先CANopen基于CAN,得实现平台的CAN驱动。其次,Canfestival协议是基于硬定时器的软定时,需要实现平台的硬定时中断驱动

在Canfestival协议栈中,TimeDispatch()canDispatch(&Master_Data, &rxMessage)是两个核心函数。

TimeDispatch()​用于​处理所有定时事件​​,调用频率至少应小于协议栈中最小时间事件间隔,在硬定时中断调用。其实现方式在timer.c,如下:

void TimeDispatch(void)
{TIMER_HANDLE i;TIMEVAL next_wakeup = TIMEVAL_MAX; /* used to compute when should normaly occur next wakeup *//* First run : change timer state depending on time *//* Get time since timer signal */UNS32 overrun = (UNS32)getElapsedTime();TIMEVAL real_total_sleep_time = total_sleep_time + overrun;s_timer_entry *row;for(i=0, row = timers; i <= last_timer_raw; i++, row++){if (row->state & TIMER_ARMED) /* if row is active */{if (row->val <= real_total_sleep_time) /* to be trigged */{if (!row->interval) /* if simply outdated */{row->state = TIMER_TRIG; /* ask for trig */}else /* or period have expired */{/* set val as interval, with 32 bit overrun correction, *//* modulo for 64 bit not available on all platforms     */row->val = row->interval - (overrun % (UNS32)row->interval);row->state = TIMER_TRIG_PERIOD; /* ask for trig, periodic *//* Check if this new timer value is the soonest */if(row->val < next_wakeup)next_wakeup = row->val;}}else{/* Each armed timer value in decremented. */row->val -= real_total_sleep_time;/* Check if this new timer value is the soonest */if(row->val < next_wakeup)next_wakeup = row->val;}}}/* Remember how much time we should sleep. */total_sleep_time = next_wakeup;/* Set timer to soonest occurence */setTimer(next_wakeup);/* Then trig them or not. */for(i=0, row = timers; i<=last_timer_raw; i++, row++){if (row->state & TIMER_TRIG){row->state &= ~TIMER_TRIG; /* reset trig state (will be free if not periodic) */if(row->callback)(*row->callback)(row->d, row->id); /* trig ! */}}
}

其中,调用了getElapsedTime()setTimer(next_wakeup)。这两个软定时函数本身在Canfestival并没有实现,需要配合硬定时器和源码注释提示来设计:

 //Set the timer for the next alarm.
void setTimer(TIMEVAL value)
{
}//Return the elapsed time to tell the Stack how much time is spent since last call.
TIMEVAL getElapsedTime(void)
{
}

canDispatch(&Master_Data, &rxMessage)​用于处理接收到的报文,调用时机为​每次接收到报文后,在CAN接收中断的下半部调用。其实现方式在states.c,如下:

void canDispatch(CO_Data* d, Message *m)
{UNS16 cob_id = UNS16_LE(m->cob_id);switch(cob_id >> 7){case SYNC:		/* can be a SYNC or a EMCY message */if(cob_id == 0x080)	/* SYNC */{if(d->CurrentCommunicationState.csSYNC)proceedSYNC(d);} else 		/* EMCY */if(d->CurrentCommunicationState.csEmergency)proceedEMCY(d,m);break;case TIME_STAMP:case PDO1tx:case PDO1rx:case PDO2tx:case PDO2rx:case PDO3tx:case PDO3rx:case PDO4tx:case PDO4rx:if (d->CurrentCommunicationState.csPDO)proceedPDO(d,m);break;case SDOtx:case SDOrx:if (d->CurrentCommunicationState.csSDO)proceedSDO(d,m);break;case NODE_GUARD:if (d->CurrentCommunicationState.csLifeGuard)proceedNODE_GUARD(d,m);break;case NMT:if (*(d->iam_a_slave)){proceedNMTstateChange(d,m);}break;
#ifdef CO_ENABLE_LSScase LSS:if (!d->CurrentCommunicationState.csLSS)break;if ((*(d->iam_a_slave)) && cob_id==MLSS_ADRESS){proceedLSS_Slave(d,m);}else if(!(*(d->iam_a_slave)) && cob_id==SLSS_ADRESS){proceedLSS_Master(d,m);}break;
#endif}
}

相对于发送报文,则需要封装:

// The driver send a CAN message passed from the CANopen stack
unsigned char canSend(CAN_PORT port, Message *message) 
{
}

其返回值应当判断报文发送是否成功:

unsigned char canSend(CAN_PORT port, Message *message) 
{status_t status;...return (status == kStatus_Success) ? 0 : 1;
}

status_t定义在fsl_common.h,如下:

enum
{kStatus_Success         = MAKE_STATUS(kStatusGroup_Generic, 0), /*!< Generic status for Success. */kStatus_Fail            = MAKE_STATUS(kStatusGroup_Generic, 1), /*!< Generic status for Fail. */kStatus_ReadOnly        = MAKE_STATUS(kStatusGroup_Generic, 2), /*!< Generic status for read only failure. */kStatus_OutOfRange      = MAKE_STATUS(kStatusGroup_Generic, 3), /*!< Generic status for out of range access. */kStatus_InvalidArgument = MAKE_STATUS(kStatusGroup_Generic, 4), /*!< Generic status for invalid argument check. */kStatus_Timeout         = MAKE_STATUS(kStatusGroup_Generic, 5), /*!< Generic status for timeout. */kStatus_NoTransferInProgress =MAKE_STATUS(kStatusGroup_Generic, 6),            /*!< Generic status for no transfer in progress. */kStatus_Busy = MAKE_STATUS(kStatusGroup_Generic, 7), /*!< Generic status for module is busy. */kStatus_NoData =MAKE_STATUS(kStatusGroup_Generic, 8), /*!< Generic status for no data is found for the operation. */
};/*! @brief Type used for all status and error return values. */
typedef int32_t status_t;

另外,timerscfg.h的宏MS_TO_TIMEVAL(ms)宏US_TO_TIMEVAL(us)需要根据当前硬定时中断的触发时间来更改,其参数应当被设置当前硬定时中断的触发时间通过计算而得。示例时间单位为1us,则如下:

// TIMEVAL is not at least on 32 bits
#define TIMEVAL UNS32// using 16 bits timer
#define TIMEVAL_MAX 0xFFFFFFFF// The timer is incrementing every 1 us.
#define MS_TO_TIMEVAL(ms) ((ms) * 1000)
#define US_TO_TIMEVAL(us) ((us) )

4 字典

首先安装前文的python2.7。

对于Gnosis_Utils-1.2.2,在目录下打开cmd,键入以下命令安装:

python setup.py install

然后将其目录下的gnosis文件复制到Mongo-canfestival-3\objdictgen目录下,然后通过python2.7打开方式打开Mongo-canfestival-3\objdictgen\objdictedit.py,即可配置字典。

Canfestival的字典索引配置皆由此配置:

通过[文件]选择[新建]可以创建一个新节点,创建后即可根据需求如PDO、SDO和心跳等配置。

通过[文件]选择[保存]可以生成.od文件保存当前词典配置。通过[文件]选择[建立词典]可以生成.c和.h的文件词典,该词典需要被canfestival调用。

http://www.xdnf.cn/news/964495.html

相关文章:

  • EndNote 21完整安装指南:从零开始的详细步骤(附EndNote下载安装包)
  • HTML 文本省略号
  • HTML 标签 综合案例
  • 在鸿蒙HarmonyOS 5中HarmonyOS应用开发实现QQ音乐风格的播放功能
  • CppCon 2015 学习:Improving the future<T> with monads
  • MinHook 对.NET底层的 SendMessage 拦截真实案例反思
  • PHP和Node.js哪个更爽?
  • 【论文阅读】多任务学习起源类论文《Multi-Task Feature Learning》
  • MyBatis注解开发的劣势与不足
  • LeetCode--27.移除元素
  • Leetcode 3578. Count Partitions With Max-Min Difference at Most K
  • HTML 列表、表格、表单
  • Docker-containerd-CRI-CRI-O-OCI-runc
  • 【kafka】Golang实现分布式Masscan任务调度系统
  • Python 自动化临时邮箱工具,轻松接收验证码,支持调用和交互模式(支持谷歌gmail/googlemail)
  • 【C++】26. 哈希扩展1—— 位图
  • 【PhysUnits】17.5 实现常量除法(div.rs)
  • Linux上并行打包压缩工具
  • Cryosparc: Local Motion Correction注意输出颗粒尺寸
  • 基于大模型的输尿管下段结石诊疗全流程预测与方案研究
  • 多场景 OkHttpClient 管理器 - Android 网络通信解决方案
  • 【AI study】ESMFold安装
  • Ribbon负载均衡实战指南:7种策略选择与生产避坑
  • 深度学习核心概念:优化器、模型可解释性与欠拟合
  • 【无标题新手学习期权从买入看涨期权开始】
  • OpenCV 图像像素值统计
  • Python入门手册:常用的Python标准库
  • C++初阶-list的模拟实现(难度较高)
  • C++学习-入门到精通【17】自定义的模板化数据结构
  • ParcelJS:零配置极速前端构建工具全解析