Ethercat学习-从站FOE固件更新(TwinCAT主站)

这篇具有很好参考价值的文章主要介绍了Ethercat学习-从站FOE固件更新(TwinCAT主站)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介

FOE(File Access over Ethercat),用于节点之间的文件传输。协议类似于TFTP协议,感觉和TFTP协议没有太大的区别,只是一个是UDP传输,一个是Ethercat传输。从机在通过FOE进行固件更新的时候,作为服务端,主机作为客户端,有主机发起固件的上传和下载

协议说明

FOE帧格式:

目标地址 源地址 类型 Frame Header Datagram Header Mailbox Header FOE Header data FCS
6 bytes 6 bytes 2 bytes (0x88A4) 2 bytes 10 bytes 6 bytes 6 bytes N bytes 4bytes

FOE 的帧格式与COE的帧格式差不多,也是邮箱数据。FOE Header6个字节,第一个字节是opcode,第二个字节为预留。opcode的取值范围是1~6,表示数据包的不同功能。

1.读请求
opcode reserved password file name
1byte (0x01) 1byte 4byte n byte

opcode为0x01的时候表示读请求,password可以作为一个判断,只有当密钥正确的时候才进行操作。file name 表示待读取文件的名字

2.写请求
opcode reserved password file name
1byte (0x02) 1byte 4byte n byte

opcode为0x02的时候表示写请求,password可以作为一个判断,只有当密钥正确的时候才进行操作。file name 表示待写入文件的名字。

3.数据
opcode reserved PacketNumber data
1byte (0x03) 1byte 4byte n byte

opcode为0x03的时候表示数据包,PacketNumber表示包计数,每次发送加1。

4.应答
opcode reserved PacketNumber
1byte (0x04) 1byte 4byte

opcode为0x04的时候表示数据包,PacketNumber表示所接收数据包的中的PacketNumber。

5.错误码
opcode reserved ErrorCode Error Text
1byte (0x05) 1byte 4byte n byte

opcode为0x05的时候表示错误码,ErrorCode表示所接收数据包的中的ErrorCode。Error Text对错误的描述,也可以不写。

6.忙
opcode reserved Done Entire Busy Text
1byte (0x06) 1byte 2byte 2 byte n byte

opcode为0x06这个在网上看,有的朋友说是表示传输百分比内容的,但是根据源码还是官方文档分析,感觉是重传请求。

数据传输流程

1.读流程

ethercat foe,Ethercat,学习,嵌入式硬件,单片机,c语言

如图所示,是一个成功读写的流程,客户机发起读请求;服务器在接收到读请求后经过password、文件名等判断后,开始返回第一个数据包,数据包的包计数为1;客户机在接收到数据包的时候,返回应答包,packetno等于接收到的数据包的packetno 。当服务端接收到最后一包数据的应答包的时候结束发送数据。

关于数据传输过程中的包数据长度,图中给出的是Full Maibox;在从站源码中有一个变量 u16FoeMaxSendBlockSize;当剩余数据大于等于u16FoeMaxSendBlockSize时传输的包长度为u16FoeMaxSendBlockSize,当剩余数据小于u16FoeMaxSendBlockSize时传输的数据长度等于剩余数据的长度。所以当客户机接收到数据后发现数据长度小于u16FoeMaxSendBlockSize时就职到当前数据时最后一包数据了。

/*  u16SendMbxSize: 主站配置的邮箱的大小 
    SIZEOF(TFOEHEADER) FOE 头的大小  6
    MBX_HEADER_SIZE: 邮箱头的大小  6 byte
*/
u16FoeMaxSendBlockSize = (u16SendMbxSize - SIZEOF(TFOEHEADER) - MBX_HEADER_SIZE);

ethercat foe,Ethercat,学习,嵌入式硬件,单片机,c语言

如图所示,是一个读请求操作失败的流程,客户机发出读请求,服务器在接收到读请求后对密钥、文件名进行判断,如果不正确,则直接返回错误码终止传输。另外在数据传输的过程中也如果出现问题,也可以发送错误码终止传输。

2.写流程

ethercat foe,Ethercat,学习,嵌入式硬件,单片机,c语言

如图所示,客户机发出写请求,服务器在接收到写请求后,判断密钥是否符合要求,如果符合,直接返回应答包,应答包的PacketNo等于0。客户机在收到应答包之后就会继续发送数据,当服务端接收的数据小于u16FoeMaxSendBlockSize时,就知道当前包时最后一包数据了,返回应答包,然后结束传输。

ethercat foe,Ethercat,学习,嵌入式硬件,单片机,c语言

如图所示,是一个写请求失败的流程,服务器在收到写请求后,对密钥进行判断,如果不符合要求,直接回复错误码终止传输。

3.忙操作

ethercat foe,Ethercat,学习,嵌入式硬件,单片机,c语言

如图所示,是一个在写流程的过程收到一个重传请求的操作。客户机发起写请求,服务器收到后回复应答包,然后开始写流程。中间服务器在收到一包数据后,因为一些状况(例如发现数据错误、数据保存文件失败)没有返回应答包,而是返回了Busy请求,客户端在接收到请求后,将上一包数据重新发送,然后继续传输。

代码实现

1.源码生成与移植

从站源码创建和移植部分不说了,重点是在SSC中勾选BOOTSTRAPMODE_SUPPORTED和FOE_SUPPORTED。FOE 进行固件更新可以再OP模式下进行,但是最好是在BootStrap模式下进行,在该状态下只能进行FOE通信,更安全一些。生成的文件中有几个文件bootloaderappl.c、bootloaderappl.h、bootmode.c、bootmode.h。我主要对bootloaderappl.c中的函数进行修改,bootmode中的函数我没有去做修改。

2.代码解析
1.FOE_ServiceInd

FOE_ServiceInd在接收到FOE数据的时候会调用,输入参数为接收到的数据包。

UINT8 FOE_ServiceInd(TFOEMBX MBXMEM * pFoeInd)
{
  ...
  初始化状态,计算接收的FOE数的长度
  ...
    switch ( SWAPWORD(pFoeInd->FoeHeader.OpCode) )
    {
    case ECAT_FOE_OPCODE_RRQ:
         如果是读请求,调用FOE_Read处理,返回状态值。
    case ECAT_FOE_OPCODE_WRQ:
         如果是写请求,调用FOE_Write处理,返回状态值。
    case ECAT_FOE_OPCODE_DATA:
        如果是数据包,调用FOE_Data处理,返回状态值
    case ECAT_FOE_OPCODE_ACK:
        如果是应答包,调用FOE_Ack处理,返回状态值
    case ECAT_FOE_OPCODE_ERR:
       如果是错误码,调用FOE_Error处理,返回状态值
    case ECAT_FOE_OPCODE_BUSY:
      如果是重发请求,调用FOE_Busy处理,返回状态值
    if ( nextState <= FOE_MAXDATA )
    {
       
    }
    else if ( nextState <= FOE_MAXBUSY )
    {
      ...
         根据状态值,对数据进行填充,然后发送
      ....

    return 0;
}

因此我们需要实现的就是FOE_Read、FOE_Write、FOE_Data、FOE_Ack、FOE_Error、FOE_Busy这几个函数。

2.FOE_Read

FOE_Read调用的pAPPL_FoeRead函数;FOE_Read里面主要就是判断一下文件名和密钥,然后读取第一包数据包

/**
 * @******************************************************************************: 
 * @func: [recv_RRQ]
 * @description: 接收到读请求信号调用函数
 * @note: 
 * @author: gxf
 * @param [UINT16 MBXMEM *] pName 请求的文件名
 * @param [UINT16] nameSize 请求的文件名长度
 * @param [UINT32] password 密钥
 * @param [UINT16] maxBlockSize 读取数据长度
 * @param [UINT16] *pData 读取数据的存储地址
 * @return [UINT16] 返回读取的数据的长度
 * @==============================================================================: 
 */
UINT16 recv_RRQ(UINT16 MBXMEM * pName, UINT16 nameSize, UINT32 password, UINT16 maxBlockSize, UINT16 *pData)
{
    UINT16 i = 0;
    UINT16 readsize = 0;
    CHAR aReadFileName[MAX_FILE_NAME_SIZE];

    /* 判断文件名长度 */
    if ((nameSize + 1) > MAX_FILE_NAME_SIZE)
    {
        return ECAT_FOE_ERRCODE_DISKFULL;
    }
    if(password != PSWD)
    {   
        /* 密钥无效 */
        return ECAT_FOE_ERRCODE_NORIGHTS;
    }
    /* 拷贝文件名到数组中 */
    MBXSTRCPY(aReadFileName, pName, nameSize);
    aReadFileName[nameSize] = '\0';
    /* 判断文件名 获取文件地址 文件长度 */
    if(strcmp("app1",aReadFileName) == 0)
    {
        u32Appaddr = APP1_ADDR;
        u32FileSize = flash_read32(APP1_LEN_ADDR);
        if(u32FileSize>196608) u32FileSize = 196608;
    }else if(strcmp("app2",aReadFileName) == 0){
        u32Appaddr = APP2_ADDR;
        u32FileSize = flash_read32(APP2_LEN_ADDR);
        if(u32FileSize>196608) u32FileSize = 196608;
    }else{
        /* 文件未找到 */
        return ECAT_FOE_ERRCODE_NOTFOUND;
    }
    /* 判断文件大小 */
    if (u32FileSize == 0)
    {
        return ECAT_FOE_ERRCODE_NOTFOUND;
    }
    readsize = maxBlockSize;
    if (u32FileSize < readsize)
    {
        readsize = (UINT16)u32FileSize;
    }
    flash_read8_multiple(u32Appaddr, (uint8_t *)pData, readsize);
    return readsize;
}

3.FOE_Write

FOE_Write调用的pAPPL_FoeWrite函数;FOE_Write主要就是判断一下文件名和密钥;然后做一些文件写入的准备比如打开文件,我这里是操作flash,所以是擦除flash。如果没有错误,在FOE_ServiceInd函数中会自动帮我们返回第一包ACK。

/**
 * @******************************************************************************: 
 * @func: [recv_WRQ]
 * @description: 接收到写请求的调用函数
 * @note: 
 * @author: gxf
 * @param [UINT16 MBXMEM *] pName 待写文件的名字
 * @param [UINT16] nameSize 名字长度
 * @param [UINT32] password 密钥
 * @return [*] 0:正确;其他:错误
 * @==============================================================================: 
 */
UINT16 recv_WRQ(UINT16 MBXMEM * pName, UINT16 nameSize, UINT32 password)
{
    if(password != PSWD)
    {   
        /* 密钥无效 */
        return ECAT_FOE_ERRCODE_NORIGHTS;
    }
    /* 如果当前运行的是APP2 ,则更新APP1 所在的位置 */
    if(flash_read32(APP_FLAG) ==  APP2_ADDR)
    {
        u32Appaddr = APP1_ADDR;
    }else{
        u32Appaddr = APP2_ADDR;
    }
    /* 擦除flash等待写入 */
    if(u32Appaddr == APP1_ADDR)
    {
        if(flash_erase_sector_multiple(4,5) != 0)
            return ECAT_FOE_ERRCODE_FLASH_ERROR;
    }else{
        if(flash_erase_sector_multiple(6,7) != 0)
            return ECAT_FOE_ERRCODE_FLASH_ERROR;        
    }
    nFileWriteOffset = 0;
    u32FileSize = 0;
    return 0;

}
4.FOE_Ack

FOE_Ack调用的是pAPPL_FoeReadData,它主要就是读取数据,然后存到指定的地址中

/**
 * @******************************************************************************: 
 * @func: [recv_ACK]
 * @description: 接收到应答信号的调用函数
 * @note: 
 * @author: gxf
 * @param [UINT32] offset 读取的地址的偏移量(相对于首次读取)
 * @param [UINT16] maxBlockSize 读取的数据长度
 * @param [UINT16] *pData 读取数据的存储地址
 * @return [UINT16] 返回读取的数据的长度
 * @==============================================================================: 
 */
UINT16 recv_ACK(UINT32 offset, UINT16 maxBlockSize, UINT16 *pData)
{
    UINT16 readsize = 0;
    
    /* 如果文件大小小于指针的偏移量,说明文件已经读完了*/
    if (u32FileSize < offset)
    {
        return 0;
    }

    /* 剩余未读取 */
    readsize = (UINT16)(u32FileSize - offset);
    /* 读取大小 */
    if (readsize > maxBlockSize)
    {
        readsize = maxBlockSize;
    }
    /* 读取文件大小 */
    flash_read8_multiple(u32Appaddr+offset, (uint8_t *)pData, readsize);
    return readsize;
}
5.FOE_Data

FOE_Data调用的pAPPL_FoeWriteData,主要就是向文件中写入数据

/**
 * @******************************************************************************: 
 * @func: [recv_DATA]
 * @description: 接收到数据包的调用函数
 * @note: 
 * @author: gxf
 * @param [UINT16 MBXMEM *] pData 带写入数据的地址
 * @param [UINT16] Size 写入数据的长度
 * @param [BOOL] bDataFollowing 是否还有数据数据
 * @return [*] 0:正确;其他:错误
 * @==============================================================================: 
 */
UINT16 recv_DATA(UINT16 MBXMEM * pData, UINT16 Size, BOOL bDataFollowing)
{

    if ((nFileWriteOffset + Size) > MAX_FILE_SIZE)
    {
        return ECAT_FOE_ERRCODE_DISKFULL;
    }

    if (Size)
    {
        /* 写flash */
        if(flash_write8_multiple(u32Appaddr+nFileWriteOffset,(uint8_t *)pData,Size)!=0)
            return ECAT_FOE_ERRCODE_FLASH_ERROR;
    }
    /* 后面是否还有数据 */
    if (bDataFollowing)
    {
        nFileWriteOffset += Size;
    }
    else
    {
        /* 最后一包数据 计算总的接收文件长度 */
        u32FileSize = nFileWriteOffset + Size;
        nFileWriteOffset = 0;
        /* 保存下次上电运行的APP地址 和 APP的长度*/
        UINT32 app1length = flash_read32(APP1_LEN_ADDR);
        UINT32 app2length = flash_read32(APP2_LEN_ADDR);
        UINT32 appflag    = flash_read32(APP_FLAG);
        if(u32Appaddr == APP1_ADDR) 
            app1length = u32FileSize;
        else
            app2length = u32FileSize;
        if(flash_erase_sector(2) != 0)
            return ECAT_FOE_ERRCODE_FLASH_ERROR;  
        if(flash_write32(APP_FLAG,appflag) != 0)
            return ECAT_FOE_ERRCODE_FLASH_ERROR;
        if(flash_write32(APP1_LEN_ADDR,app1length) != 0)
            return ECAT_FOE_ERRCODE_FLASH_ERROR;
        if(flash_write32(APP2_LEN_ADDR,app2length) != 0)
            return ECAT_FOE_ERRCODE_FLASH_ERROR;
        if(flash_write32(UPDATE_APP_FLAG,u32Appaddr) != 0)
            return ECAT_FOE_ERRCODE_FLASH_ERROR;
            
    }

    return 0;
}
6.FOE_Error

FOE_Error调用了pAPPL_FoeError,由于是测试程序,所以这个函数我没有去修改,当接收到错误包的时候,我们可以进行一些关闭文件等操作。

7.FOE_Busy

FOE_Busy调用了FOE_Ack,重新发送上一包数据。

UINT16 FOE_Busy(UINT16 done, UINT32 fileOffset, UINT16 MBXMEM * pData)
{
    return FOE_Ack(fileOffset, pData);
}
其他

上面的几个函数都是bootloaderappl.c中的,只是函数名字我改了。在MainInit函数中做一下赋值,如下:

UINT16 MainInit(void)
{
   ...
    pAPPL_FoeRead = recv_RRQ;
    pAPPL_FoeReadData = recv_ACK;
    pAPPL_FoeError = NULL;
    pAPPL_FoeWrite = recv_WRQ;
    pAPPL_FoeWriteData = recv_DATA;

    pAPPL_MainLoop = NULL;
/*ECATCHANGE_END(V5.12) ECAT8*/
    ...
}

TwinCAT测试

ethercat foe,Ethercat,学习,嵌入式硬件,单片机,c语言

测试很简单,我是使用TwinCAT作为主机进行测试的。OP模式下和Bootstrap模式下都可以进行上传和下载。图中标记的Download是将PC端的文件写入从站的。Upload是将从站中的文件读取到PC端。文章来源地址https://www.toymoban.com/news/detail-686127.html

到了这里,关于Ethercat学习-从站FOE固件更新(TwinCAT主站)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【】浅谈EtherCAT主站EOE(上)-EOE网络

    版权声明:本文为本文为博主原创文章,未经本人同意,禁止转载。如有问题,欢迎指正。博客地址:https://www.cnblogs.com/wsg1100/ 目录 一、EoE ethercat工作图示 二、EoE服务规范 EtherCAT主站如何提供EoE服务? 三、EoE网络 EOE网络 这篇文章的标题虽然是关于EtherCAT EOE,但其实主要内

    2024年02月06日
    浏览(52)
  • EtherCAT主站源码 基于STM32F407和STM32H743两款芯片 通过移植开源SOME主站代码,使两款芯片具有EtherCAT主站功能,支持DC同步功能

    EtherCAT主站源码基于STM32F407和STM32H743两款芯片,通过移植开源SOME主站代码,使两款芯片具有EtherCAT主站功能,支持DC同步功能。可支持汇川IS620N、松下A5B/A6B、欧姆龙G5系列、埃斯顿ProNet、迈信EP3E、台达A2-E,伟创SD700这几款EtherCAT总线伺服。支持的这些驱动器可以混用,主站自动

    2024年02月04日
    浏览(48)
  • EtherCat--主站开源的C语言库SOEM-环境搭建

    (一)安装VS; (二)下载SOEM 1.3.1 源代码:链接地址 http://openethercatsociety.github.io/ (三)安装WinPcap_4_1_3.exe:链接地址 https://www.winpcap.org/install/default.htm (一)soem目录:实现主从站功能的主要文件和源文件(头文件和源文件) ethercatbase.c : 基于ether功能函数,将数据封装成

    2024年02月05日
    浏览(39)
  • 十四.EtherCAT开发之ST MCU STM32F407ZGt6+ AX58100的开发FOE应用

    STM32F407ZGt6与AX58100是 SPI连接,工作在SPI模式。 FoE(File Access over EtherCAT)可实现EtherCAT节点之间的文件传输。 boot mode与FOE支持 FOE 说是要在状态机的boot mode下运行,实际测试了在OP模式也能收数据。可能是为了稳定,减少出错把,毕竟是升级固件。 14.1.1 XML支持字段 XML名称—AX58

    2024年02月10日
    浏览(41)
  • NXP对于Ethercat部署与支持(主站篇IGH与SOEM)

    EtherCAT的主站开发是基于EtherCAT 控制系统的开发中非常重要的环节。目前常见开源的主站代码为的RT-LAB开发的SOEM (Simple OpenSource EtherCAT Master)和EtherLab的the IgH EtherCAT® Master。使用起来SOEM的简单一些,而the IgH EtherCAT® Master更复杂一些,但对EtherCAT的实现更为完整。 具体比较如下

    2024年02月15日
    浏览(32)
  • Ubuntu 22.04下以SOEM为EtherCAT主站的驱动电机例子

    这篇文章是笔者的第一篇文章,笔者作为一个机器人从业者,经常要接触到EtherCAT与ROS等相关内容。目前市面上有的开源EtherCAT系统有Igh以及SOEM两种,Igh在多年前已经停止维护,而截至日前SOEM依然维持更新,且SOEM已经集成到ROS生态中,故笔者选择SOEM进行研究。 苦于网上资料

    2024年02月12日
    浏览(58)
  • 基于STM32F407-LAN9252的EtherCAT从站协议移植过程

    EtherCAT移植过程 前言:刚拿到一个EtherCAT的开发需求,本来想安心当个CV战士的,结果在网上找了一圈,只有https://www.hexcode.cn/article/5e3ee9a835616641b2daef97 这篇写的相对详细,看来偷不了懒了,只有自己重新整理开发了。 1 、需求 基于STM32F407芯片、LAN9253芯片(自带PHY芯片),验

    2024年02月09日
    浏览(34)
  • EtherCAT 开源主站 IGH 在 linux 开发板的移植和伺服通信测试

    手边有一套正点原子linux开发板imax6ul,一直在吃灰,周末业余时间无聊,把EtherCAT的开源IGH主站移植到开发板上玩玩儿,搞点事情做。顺便学习研究下EtherCAT总线协议及其对伺服驱动器的运动控制过程。实验很有意思,这里总结下实验过程,分享给有需要的小伙伴。 igh EtherC

    2024年04月29日
    浏览(117)
  • IGH(EtherCAT开源主站)移植到beaglebone black(AM3358)开发板上

    本文是在已经打上xenomai补丁的linux-3.8.13-bone86内核源码上进行的,参看使用xenomai与linux内核源码交叉编译,移植到beaglebone black(AM3358)开发板上 igh软件下载地址: IgH EtherCAT Master for Linux (etherlab.org) 将打入xenomai补丁,写入sd卡的系统的sd卡挂载(插入电脑,自动挂载)到ubuntu系统

    2024年02月11日
    浏览(45)
  • [工业互联-9]:EtherCAT(以太网控制自动化技术)+TwinCAT 在生产自动化控制中的应用 、

    EtherCAT ( 以太网控制自动化技术 )是一个开放架构,以以太网为基础的现场总线系统,其名称的CAT为 控制自动化技术 ( C ontrol  A utomation  T echnology)字首的缩写。EtherCAT是确定性的工业以太网, 最早是由德国的Beckhoff公司研发。 自动化对通讯一般会要求较短的信息 更新时

    2024年02月08日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包