EhterCAT_SOEM

文章目录

  • EhterCAT_SOEM
  • 前言
  • 一、eepromtool.c的作用
  • 二、读写EEPROM步骤
    • 1.读取EEPROM数据
    • 2.写入EEPROM数据
      • 2.1 写入从站别名
      • 2.2 读取0-6字数据
      • 2.3 计算校验和
      • 2.4 写入校验和
  • 总结

前言

SOEM简单开放式ETherCAT主站,支持Linux,Windows双系统,这里讲解是SOEM 1.3.1版本基于Windows平台编译后的源码eepromtool.c,在SOEM-1.3.1\test\win32\eepromtool文件夹中。
源码可以到这里下载:百度网盘,提取码:5679


一、eepromtool.c的作用

就如其名字一样,作用就是实现对ESC SII的读写,这里主要就是讲解源码中读写函数应该怎么使用,但是大家应该知道EEPROM数据不能随便更改,很有可能更改后就不能与从站通讯了,需要重新烧写EEPROM,大家谨慎操作,本文章主要讲解对0-7字的读写。

二、读写EEPROM步骤

根据倍福官网 手册 描述操作EEPROM步骤如下:

  1. 检查 EEPROM 状态寄存器的 Busy 位是否清零(0x0502[15]=0)和 EEPROM接口不忙,否则等到 EEPROM 接口不忙。
  2. 检查 EEPROM 状态寄存器的错误位是否被清除。如果没有,请写入“000”到命令寄存器(寄存器 0x​​0502 位 [10:8])。
  3. 将 EEPROM 字地址写入 EEPROM 地址寄存器。
  4. 只写命令:将写入数据放入 EEPROM 数据寄存器(仅 1 个字/2 个字节)。
  5. 通过写入控制寄存器发出命令。
    a) 对于读取命令,将 001 写入命令寄存器 0x​​0502[10:8]。
    b) 对于写入命令,将 1 写入写入启用位 0x0502[0] 并将 010 写入命令寄存器0x0502[10:8]。两个位都必须写在一帧中。写使能位实现写保护机制。对同一帧下发的后续 EEPROM 命令有效并在之后自行清理。写使能位不需要从 PDI 写入,如果它控制EEPROM接口。
    c) 对于重载命令,将 100 写入命令寄存器 0x​​0502[10:8]。
  6. 如果 EtherCAT 帧没有错误,则在 EOF 之后执行该命令。通过 PDI 控制,命令立即执行。
  7. 等到 EEPROM 状态寄存器的 Busy 位被清除。
  8. 检查 EEPROM 状态寄存器的错误位。错误位通过清除清除命令寄存器。如果缺少 EEPROM 确认,则重试命令(返回步骤 5)。如果必要时,在重试之前等待一些时间,让慢速 EEPROM 在内部存储数据。
  9. a) 对于读取命令:读取数据在 EEPROM 数据寄存器中可用(2 或 4 个字,取决于 ESC 检查寄存器 0x​​0502[6])。
    b) 对于重载命令:ESC 配置被重载到适当的寄存器中。
    注意:命令寄存器位是自清零的。手动清除命令寄存器也将清除状态信息。

使用VS的命令行工具 x86 Nactive Tools Command Prompt for VC2019进入eepromtool文件夹之后,输入eepromtool可以看到如下提示:

使用方法: eepromtool 网卡ID 从站索引 操作 文件地址
如使用我的电脑读取1号站的EEPROM数保存为16进制数据到read.txt中:
eepromtool \Device\NPF_{36CBEDF6-B690-4C67-8C8B-9A2D1811234E} 1 ri read.txt
写入数据同理就不讲解了。使用eepromtool.exe直接读写EEPROM较简单就不说了,直接开始讲解源码。

1.读取EEPROM数据

eepromtool.c中关于读取的函数如下:
1.首先是主站夺回控制权,eeprom_read函数

/// <summary>
/// 夺回主站控制权
/// </summary>
/// <param name="slave">从站索引</param>
/// <param name="start">开始读取地址,这里是字地址,如从站别名字地址:4</param>
/// <param name="length">读取长度</param>
/// <returns>0:读取失败,1:读取成功</returns>
int eeprom_read(int slave, int start, int length)
{int i, wkc, ainc = 4;uint16 estat, aiadr;uint32 b4;uint64 b8;uint8 eepctl;//源码中限制了读取的大小MAXBUF=32768,也就是只读取32kb数据if((ec_slavecount >= slave) && (slave > 0) && ((start + length) <= MAXBUF)){aiadr = 1 - slave;eepctl = 2;//二进制10 //ECT_REG_EEPCFG地址0x0500,顺序寻址写0x500.1 == 1,强制清除0x501.0,主站从PDI夺回EEPROM控制权wkc = ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET3); /* force Eeprom from PDI */eepctl = 0;//0x500.0 == 0,主站接管EEPROM控制权wkc = ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET3); /* set Eeprom to master */estat = 0x0000;aiadr = 1 - slave;//ECT_REG_EEPSTAT地址0x0502,读取EEPRO状态wkc=ec_APRD(aiadr, ECT_REG_EEPSTAT, sizeof(estat), &estat, EC_TIMEOUTRET3); /* read eeprom status */estat = etohs(estat);//EC_ESTAT_R64 0x0040 二进制 0100 0000,跟读取的estat进行与操作,及可得知EEPROM支持读取的字节数,ET1100和ET1200支持8字节,其他ESC芯片为4字节。if (estat & EC_ESTAT_R64){ainc = 8;for (i = start ; i < (start + length) ; i+=ainc){//读取EEPROM数据b8 = ec_readeepromAP(aiadr, i >> 1 , EC_TIMEOUTEEP);ebuf[i] = (uint8) b8;ebuf[i+1] = (uint8) (b8 >> 8);ebuf[i+2] = (uint8) (b8 >> 16);ebuf[i+3] = (uint8) (b8 >> 24);ebuf[i+4] = (uint8) (b8 >> 32);ebuf[i+5] = (uint8) (b8 >> 40);ebuf[i+6] = (uint8) (b8 >> 48);ebuf[i+7] = (uint8) (b8 >> 56);}}else{for (i = start ; i < (start + length) ; i+=ainc){b4 = (uint32)ec_readeepromAP(aiadr, i >> 1 , EC_TIMEOUTEEP);ebuf[i] = (uint8) b4;ebuf[i+1] = (uint8) (b4 >> 8);ebuf[i+2] = (uint8) (b4 >> 16);ebuf[i+3] = (uint8) (b4 >> 24);}}return 1;}return 0;
}

2.读取EEPROM数据,ec_readeepromAP函数

/** Read EEPROM from slave bypassing cache. APRD method.* @param[in] context     = context struct* @param[in] aiadr       = auto increment address of slave* @param[in] eeproma     = (WORD) Address in the EEPROM* @param[in] timeout     = Timeout in us.* @return EEPROM data 64bit or 32bit*/
uint64 ecx_readeepromAP(ecx_contextt *context, uint16 aiadr, uint16 eeproma, int timeout)
{uint16 estat;uint32 edat32;uint64 edat64;ec_eepromt ed;int wkc, cnt, nackcnt = 0;edat64 = 0;edat32 = 0;//对应上述读写EEPRO步骤1,读取0x502,检查EEPROM是否繁忙if (ecx_eeprom_waitnotbusyAP(context, aiadr, &estat, timeout)){//EC_ESTAT_EMASK 0x7800 二进制0111 1000 0000 0000 对应步骤2检查错误位是否被清除if (estat & EC_ESTAT_EMASK) /* error bits are set */{//EC_ECMD_NOP 0x0000estat = htoes(EC_ECMD_NOP); /* clear error bits *///对应步骤2,清除错误位,写000到0x​​0502 位 [10:8]wkc = ecx_APWR(context->port, aiadr, ECT_REG_EEPCTL, sizeof(estat), &estat, EC_TIMEOUTRET3);}do{//EC_ECMD_READ 0x0100 二进制 0000 0001 0000 0000 将001写入命令寄存器 0x​​0502[10:8],读取EEPROM命令ed.comm = htoes(EC_ECMD_READ);//读取地址,字地址ed.addr = htoes(eeproma);//这里我还没搞懂是什么ed.d2   = 0x0000;cnt = 0;do{//ECT_REG_EEPCTL 0x502 ,写入读取命令wkc = ecx_APWR(context->port, aiadr, ECT_REG_EEPCTL, sizeof(ed), &ed, EC_TIMEOUTRET);}while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));if (wkc){//延时osal_usleep(EC_LOCALDELAY);estat = 0x0000;//读取0x502.15 等待EEPOM繁忙位清除,0x502.15 == 0;if (ecx_eeprom_waitnotbusyAP(context, aiadr, &estat, timeout)){         //EC_ESTAT_NACK 0x2000 二进制 0010 0000 0000 0000检查EEPROM应答位0x502.13,是否应答丢失    if (estat & EC_ESTAT_NACK){//EEPROM无应答或命令无效nackcnt++;osal_usleep(EC_LOCALDELAY * 5);}else{//无错误nackcnt = 0;//EEPROM支持读取的字节数if (estat & EC_ESTAT_R64){//8字节cnt = 0;do{//读取EEPROM数据wkc = ecx_APRD(context->port, aiadr, ECT_REG_EEPDAT, sizeof(edat64), &edat64, EC_TIMEOUTRET);}while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));}else{//4字节cnt = 0;do{//读取EEPROM数据wkc = ecx_APRD(context->port, aiadr, ECT_REG_EEPDAT, sizeof(edat32), &edat32, EC_TIMEOUTRET);}while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));edat64=(uint64)edat32;}}}}}while ((nackcnt > 0) && (nackcnt < 3));}return edat64;
}

这里举两个例子,比如
1.使用eeprom_read函数读取从站1别名:
eeprom_read(1,8,2);

2.直接使用ec_readeepromAP函数读取从站1别名:
ec_readeepromAP(1,4, EC_TIMEOUTEEP);
但是需要注意的是直接使用ec_readeepromAP函数时,要先让主站夺回控制权。

2.写入EEPROM数据

查看源码中eeprom_write和ec_writeeepromAP函数就会发现,其作用与对应的eeprom_read和ec_readeepromAP一模一样。但是写入EEPROM步骤可不是直接写入那么简单。这里还是以写入从站别名为例。

2.1 写入从站别名

同样举两个例子,比如
1.使用eeprom_write函数读取从站1别名:
//赋值
ebuf[8] = 0x04;//写入别名0x04
eeprom_read(1,8,2);

2.直接使用ec_readeepromAP函数读取从站1别名:
//写入别名
ec_writeeepromAP(1, 4, 0x04, EC_TIMEOUTEEP);
同样需要注意的是直接使用ec_writeeepromAP函数时,要先让主站夺回控制权。

2.2 读取0-6字数据

读取0-6字数据,用于计算校验和

2.3 计算校验和

计算0-6字的校验和在写入EEPROM数据的步骤中最为关键,能不能写入成功最后就是看校验和是否正确,ESC在上电或是复位后会自动读取0-7字数据(ESC寄存器配置区)并装入相应的寄存器,并检查校验和,校验和如果不正确则写入不成功。
倍福官网介绍的校验和计算方式为:
Low byte contains remainder of division of word 0 to word 6 as unsigned number divided by the polynomial x8+x2+x+1(initial value0xFF).
NOTE: For debugging purposes it is possible to disable the checksum validation with a checksum value of 0x88A4. Never use this for production!
低字节包含字 0 到字 6 的除以无符号数除以多项式 x8+x2+x+1(初始值 0xFF)的余数。
注意:出于调试目的,可以使用校验和值 0x88A4 禁用校验和验证。切勿将其用于生产!
这里可以百度一下CRC8计算器,给大家推荐一个CRC8计算器
计算器设置:

或者使用代码

unsigned char crc_high_first(unsigned char* ptr, unsigned char len)
{unsigned char i;unsigned char crc = 0xff;/* 计算的初始crc值 */while (len--){crc ^= *ptr++;  /* 每次先与需要计算的数据异或,计算完指向下一数据 */for (i = 8; i > 0; --i)   /* 下面这段计算过程与计算一个字节crc一样 */{if (crc & 0x80)crc = (crc << 1) ^ 0x07;//多项式elsecrc = (crc << 1);}}return (crc);
}

2.4 写入校验和

与2.2节一样,写入校验和到字地址7即可。


总结

有什么理解的不正确或是写错的地方,大家可以讨论,另外有不理解的也可以评论,再提供一个简单的读写EEPROM项目,提取码:5679

详解EtherCAT主站SOEM源码_eepromtool.c相关推荐

  1. EtherCAT主站SOEM源码解析----分布时钟DC

    分布时钟(DC,Dsitributed Clock)可以使所有EtherCAT设备使用相同的系统时间,从而控制各设备任务的同步执行. 1.DC从站 支持分布式时钟的从站称为DC从站,同步原理如下所示: ...

  2. EtherCAT主站SOEM源码解析----ecx_siiPDO()

    1.从站EEPROM的PDO信息 从站EEPROM存储的PDO信息如下如所示: TxPDO的类型名为50(0x0032),RxPDO的类型名为51(0x0033). 每个PDO占用的EEPROM字节数 ...

  3. Android高级开发之【RxJava】详解(附项目源码)

    文章大纲 一.什么是RxJava 二.为什么要用RxJava 三.RxJava使用详解 四.项目源码下载 一.什么是RxJava Rx(Reactive Extensions)是一个库,用来处理事件和 ...

  4. 写给小白的机器学习之决策树算法详解(附实战源码)

    这里是实战源码,里面算法参数解释和数据可视化详解 GitHub慢的话看码云 具体ppt也已上传至csdn和GitHub 可以做分类树和回归树 现在是一个多分类任务 PPT讲解 强壮性是对若有缺失值等其 ...

  5. Java源码详解六:ConcurrentHashMap源码分析--openjdk java 11源码

    文章目录 注释 类的继承与实现 数据的存储 构造函数 哈希 put get 扩容 本系列是Java详解,专栏地址:Java源码分析 ConcurrentHashMap 官方文档:ConcurrentH ...

  6. Java源码详解四:String源码分析--openjdk java 11源码

    文章目录 注释 类的继承 数据的存储 构造函数 charAt函数 equals函数 hashCode函数 indexOf函数 intern函数 本系列是Java详解,专栏地址:Java源码分析 Str ...

  7. Java源码详解五:ArrayList源码分析--openjdk java 11源码

    文章目录 注释 类的继承与实现 构造函数 add操作 扩容函数 remove函数 subList函数 总结 本系列是Java详解,专栏地址:Java源码分析 ArrayList 官方文档:ArrayL ...

  8. Java源码详解三:Hashtable源码分析--openjdk java 11源码

    文章目录 注释 哈希算法与映射 线程安全的实现方法 put 操作 get操作 本系列是Java详解,专栏地址:Java源码分析 Hashtable官方文档:Hashtable (Java Platfo ...

  9. Java源码详解二:HashMap源码分析--openjdk java 11源码

    文章目录 HashMap.java介绍 1.HashMap的get和put操作平均时间复杂度和最坏时间复杂度 2.为什么链表长度超过8才转换为红黑树 3.红黑树中的节点如何排序 本系列是Java详解, ...

  10. ext4 extent详解2之内核源码详解

    在查看本文前,希望先查看<ext4 extent详解1之示意图演示>这篇文章,有助于理解本文.本文内核源码版本3.10.96,详细内核详细源码注释见https://github.com/d ...

最新文章

  1. 2022-2028年中国场景金融行业深度调研及投资前景预测报告
  2. CICC《城市大脑建设规范》标准建设启动会在京召开
  3. 解读网络“攻城狮”的发展---老赵带你铺一段路
  4. 计算机与音乐课题,泉州实验小学《小学音乐学科教学与信息技术整合的研究》结题报告...
  5. oracle冷备份/恢复
  6. python模块之 paramiko(转载)
  7. 孙宇晨凌晨发致歉信:为过度营销、热衷炒作的行为深感愧疚
  8. hive中导入csv,本地CSV导入hive表
  9. 解决微信0day上线CobaltStike的几个问题
  10. 向程序发送命令失败_Word提示:“向程序发送命令时出现问题”重装软件也没用?...
  11. linux删除文件后不释放磁盘的问题
  12. 【优化调度】基于matlab遗传算法求解孤岛型微电网(成本最低) 调度优化问题【含Matlab源码 1163期】
  13. python赋值与c语言区别,运算符-赋值运算符和逻辑运算符
  14. 分解gif动图如何操作?手把手教你动图分解方法
  15. Google Code的简单使用
  16. C程序实例1--个人通讯录管理系统
  17. word顶部有一道线_word文档上方总有一条线怎样去掉?
  18. SAP采购定价过程-条件技术介绍
  19. python-图像边缘化处理
  20. 摩天轮社区_摩天轮:基于真实地理位置游戏

热门文章

  1. html里的音频插件,html5音频播放插件
  2. 注意,Windows7只能安装Python 3.8以下的版本
  3. 手把手教你开发-滚动效果号码抽奖(QT)
  4. 1. Windows网络编程(C++ Socket编程)
  5. 怎样让手机打电话显示不在服务器,要怎样设置才让对方打电话进来是空号?
  6. Flowable官方指定中国社区成立了
  7. 网络爬虫:中国大学排名定向爬虫
  8. lg2用计算机怎么算,lg计算器(log计算器在线)
  9. DB2数据库的备份还原详解
  10. JLU数据结构第七次上机实验解题报告