文章

CAN-EtherCAT使用快速指南

refer to EtherCAT MainDevice Application Developers Manual and CAN-EtherCAT/2(-FD)

Demo 系统的搭建

使用esd EtherCAT Workbench 配置 CAN-EtherCAT (obj 6000 and 7000, baudrate 1000k bps)

  1. PreOP 状态下, 点击 "Slave -> Process Data -> Assignment -> Recreate PDO lists -> Online by SDO Info Service". 在"All PDOs:"框内,生成了 0x1600 in outputs 和 0x1a00 0x1a85 in inputs。

  2. 双击 0x1600 可以看到 0x7000 被配置进了 RxPDO 内。双击 0x1a00和 0x1a85,依次可以看到 0x6000 和 0xf108 被配置进了TxPDO。

  3. 点击 "Sync Manager: -> 2. Outputs 198",查看 "SM2 PDOs:" 中 Assigned 0x1600(Assigned含义为将 0x1600 内包含的 OD entries assign到Process Image中)。 点击 "Sync Manager: -> 3. Inputs 168",查看 "SM3 PDOs:" 中 Assigned 0x1a00,而 Not Assigned 0x1a85,继续双击 0x1a85 将其 Assigned 到 Process Image内。

  4. 点击 "Process Data/Image" 标签,查看目前加入的Output 和 Input 变量以及其对应的 Offset 和 Logical Address。

  5. PreOP 状态下,点击 "Slave -> Mailbox -> CoE", 点击鼠标右键选择 "Append new item",依次填入以下内容来配置 CAN-EtherCAT装置的CAN端口的波特率,将其设置成1000k bit/s。(Index: F800, Sub Index: 2, Data: 00, Transitions: PS)

  6. 点击 "Export ENI",输入文件名如 eni_only_can-ethercat_11bit_1mbps.xml。

  7. 使用文本编辑器,打开 eni_only_can-ethercat_11bit_1mbps.xml,将网卡 MAC 地址改为运行 EtherCAT Master 的电脑的MAC地址,修改的位置如下。 <Info><source>...</source></Info>

(Rx) 利用Object 6000h CAN Rx Message Queue 接收11-bit CAN消息

ecmC2EReadCANMsg.c , eni_only_can-ethercat_11bit_1mbps.xml:此程序运行在esd EtherCAT Master端,展示了如何透过 CAN-EtherCAT 装置把其接收到的所有 11 bit CAN消息读取到 Master 端,且展示了如何解析消息中的CAN ID,Length 和 rtr。

程序编译后,将eni_only_can-ethercat_11bit_1mbps.xml放在执行文件的同一目录中。运行程序时,通过esd CANreal或者cantest软件,任意发送11 bit CAN ID的 CAN消息,查看master端的程序output,output中会打印相关解码后的CAN信息。

static int CycleHandler(){
    uint8_t * pTemp = pucRxMsg;
    uint16_t numOfRxMsgs = *pucNumOfRxMsgs;
    uint8_t byteStream[10];
    uint16_t id;
    uint8_t rtr;
    uint8_t len;

    if(*pucRxCountGateway == *pucRxCountApp) 
        return 0;
    printf("----------------------------------\n");
    printf("Rx Count App: %d \n", *pucRxCountApp);
    printf("Rx Count Gateway: %d \n", *pucRxCountGateway);
    printf("Number of Rx Msg: %d \n\n", numOfRxMsgs);
    for(int i=0;i<numOfRxMsgs;){
        printf("Rx Msg No.%d octets (HEX): ", ++i);
        for(int j=0;j<10;j++){
            byteStream[j] = *pTemp++;
            printf("%02x ",  byteStream[j]);
        }
        printf("\n");

        id = 0;
        id |= (byteStream[1]<<3);
        id |= (byteStream[0]&0xf0)>>5;
        printf("CAN ID (HEX): %03x \n",id);
        
        len = byteStream[0]&0xf;
        printf("CAN Msg Len: %d \n",len);

        rtr = (byteStream[0]>>4)&0x1;
        printf("RTR: %d \n",rtr);
        
        if(!rtr){
            printf("CAN Msg Content: ");
            for(int k=0;k<len;k++)
                printf("%02x ", byteStream[k+2]);
        }

        printf("\n\n");
    }
    printf("\n");
    *pucRxCountApp = *pucRxCountApp + 1;
}

使用cantest 工具连续发送7条11 bit CAN-ID的CAN消息。Sample 程序接收到的 Output 如下

cantest 50 3 0x1 0x7 7 10 100 50 5000 0 1 0x22 0x33


ECM_EVENT_STATE_CHANGE: Master state change to OP
----------------------------------
Rx Count App: 3 
Rx Count Gateway: 4 
Number of Rx Msg: 7 

Rx Msg No.1 octets (HEX): 22 00 22 33 00 00 00 00 00 00 
CAN ID (HEX): 001 
CAN Msg Len: 2 
RTR: 0 
CAN Msg Content: 22 33 

Rx Msg No.2 octets (HEX): 42 00 22 33 00 00 00 00 00 00 
CAN ID (HEX): 002 
CAN Msg Len: 2 
RTR: 0 
CAN Msg Content: 22 33 

Rx Msg No.3 octets (HEX): 62 00 22 33 00 00 00 00 00 00 
CAN ID (HEX): 003 
CAN Msg Len: 2 
RTR: 0 
CAN Msg Content: 22 33 

Rx Msg No.4 octets (HEX): 82 00 22 33 00 00 00 00 00 00 
CAN ID (HEX): 004 
CAN Msg Len: 2 
RTR: 0 
CAN Msg Content: 22 33 

Rx Msg No.5 octets (HEX): a2 00 22 33 00 00 00 00 00 00 
CAN ID (HEX): 005 
CAN Msg Len: 2 
RTR: 0 
CAN Msg Content: 22 33 

Rx Msg No.6 octets (HEX): c2 00 22 33 00 00 00 00 00 00 
CAN ID (HEX): 006 
CAN Msg Len: 2 
RTR: 0 
CAN Msg Content: 22 33 

Rx Msg No.7 octets (HEX): e2 00 22 33 00 00 00 00 00 00 
CAN ID (HEX): 007 
CAN Msg Len: 2 
RTR: 0 
CAN Msg Content: 22 33 

(Rx) 利用 Object 6001h CAN Rx Extended Message Queue 既能接收 29-bit CAN消息,也能接收11-bit CAN消息

  1. 使用esd EtherCAT Workbench 配置 CAN-EtherCAT。 1.1 进入PreOP状态,进入"Slave - Device Specific",点击"Set to 29 bit mode",可以自动配置,修改内容如下。 a. 双击 0x1600,其中所有的Index 都为 0x7001,且 0x7001.04 - 0x7001.13(共16项)的长度都为 16 bytes。 b. 双击 0x1a00,其中所有的Index 都为 0x6001,且 0x6001.05 - 0x6001.14(共16项)的长度都为 14 bytes。 c. 查看 "Slave - Mailbox - CoE",添加了 0x8000.20 (Set CAN queues to 29-Bit-Mode), value 为 (Hex) 08 00, Transition: PS。

    1.2 进入"Slave - Mailbox - CoE, Append new item",设置波特率为 1000k bit/s,具体参数请参见以上章节。 1.3 Export ENI,name: eni_only_can-ethercat_29bit_1mbps.xml 1.4 用文本编辑器修改eni_only_can-ethercat_29bit_1mbps.xml。将网卡 MAC 地址改为运行 EtherCAT Master 的电脑的 MAC地址,修改的位置如下。 <Info><source>...</source></Info>

ecmC2EReadCANMsg29bit.c , eni_only_can-ethercat_29bit_1mbps.xml:此程序运行在esd EtherCAT Master端,展示了如何透过 CAN-EtherCAT 装置把其接收到的所有 29 bit CAN消息以及所有11 bit CAN消息读取到 Master 端,且展示了如何解析消息中的CAN ID,Length 和 rtr。

static int CycleHandler(){
    uint8_t * pTemp = pucRxMsg;
    uint16_t numOfRxMsgs = *pucNumOfRxMsgs;
    uint8_t byteStream[14];
    uint32_t id;
    uint8_t rtr;
    uint8_t len;
    uint8_t is29bit;

    if(*pucRxCountGateway == *pucRxCountApp) 
        return 0;
    printf("----------------------------------\n");
    printf("Rx Count App: %d \n", *pucRxCountApp);
    printf("Rx Count Gateway: %d \n", *pucRxCountGateway);
    printf("Number of Rx Msg: %d \n\n", numOfRxMsgs);
    for(int i=0;i<numOfRxMsgs;){
        printf("Rx Msg No.%d octets (HEX): ", ++i);
        for(int j=0;j<14;j++){
            byteStream[j] = *pTemp++;
            printf("%02x ",  byteStream[j]);
        }
        printf("\n");

        id = 0;
        id |= byteStream[2];
        id |= (byteStream[3]<<8);
        id |= (byteStream[4]<<16);
        id |= (byteStream[5]&0x1f)<<24;
        
        printf("CAN ID ");
        is29bit = (byteStream[5]>>7)&0x1;
        if(is29bit)
            printf("29-Bit (HEX): %08x \n",id);
        else
            printf("11-Bit (HEX): %03x \n",id);
  
        len = byteStream[0]&0xf;
        printf("CAN Msg Len: %d \n",len);

        rtr = (byteStream[5]>>6)&0x1;
        printf("RTR: %d \n",rtr);
        
        if(!rtr){
            printf("CAN Msg Content (HEX): ");
            for(int k=0;k<len;k++)
                printf("%02x ", byteStream[k+6]);
        }

        printf("\n\n");
    }
    printf("\n");

    *pucRxCountApp = *pucRxCountApp + 1;
}
----------------------------------
Rx Count App: 560 
Rx Count Gateway: 561 
Number of Rx Msg: 1 

Rx Msg No.1 octets (HEX): 08 00 45 32 fd 9f 78 89 90 00 33 22 34 21 
CAN ID 29-Bit (HEX): 1ffd3245 
CAN Msg Len: 8 
RTR: 0 
CAN Msg Content (HEX): 78 89 90 00 33 22 34 21 

(Tx) 利用Object 7001h CAN Tx Extended Message Queue 既能发送 29-bit CAN消息,也能发送11-bit CAN消息

利用上一章节使用过的,一样的 ENI 文件 eni_only_can-ethercat_29bit_1mbps.xml

参考ecmC2ESendCANMsg.c,运行此程序将先发送所有11-bit CAN-ID的消息,再发送所有11-bit CAN-ID的消息。

    int8_t byteStream[16];
    uint32_t canid = 0;
    uint8_t len = 8;
    uint8_t content[8] = {0x1f,0x2e,0x3d,0x4c,0x5b,0x6a,0x79,0x88};
    uint8_t rtr = 0;
    uint8_t is29bit = 0;

    // Send all 11-bit CAN-ID (0-7ff) msg
    while (1)
    {   
        ECM_INIT(byteStream);
        printf("can-id 11-bit (Hex): %03x \n", canid);
        printf("len: %d \n", len);
        printf("rtr: %d \n", rtr);

        byteStream[0] = 0;
        byteStream[1] = 0;
        byteStream[2] |= len;
        byteStream[3] = 0;
        byteStream[4] = (canid & 0xff);
        byteStream[5] = ((canid & 0xff00) >> 8);
        byteStream[6] = ((canid & 0xff0000) >> 16);
        byteStream[7] = ((canid & 0x1f000000) >> 24);
        byteStream[7] |= (rtr<<6);
        byteStream[7] |= (is29bit<<7);

        for (int i=0;i<len;i++)
            byteStream[i+8] = content[i];
        
        for (int k=0;k<16;k++)
            printf("%02x ", byteStream[k]);
        printf("\n\n");

        for (int j=0;j<16;j++){
            *pucTxMsg = byteStream[j];
            pucTxMsg++;
        }

        *pusTxTransNum = 0;
        *pusNumOfTxMsgs = 1;
        *pusTxCountApp = *pusTxCountApp + 1;
        pucTxMsg=pucTxMsg-16;
        ecmSleep(10); 
        
        canid++;
        if (canid==0x800) 
        {   
            canid = 0;
            is29bit=1;
            break;
        }
    }

    // Send all 29-bit CAN-ID (0-1fffffff) msg
    while (1)
    {   
        ECM_INIT(byteStream);
        printf("can-id 29-bit (Hex): %08x \n", canid);
        printf("len: %d \n", len);
        printf("rtr: %d \n", rtr);

        byteStream[0] = 0;
        byteStream[1] = 0;
        byteStream[2] |= len;
        byteStream[3] = 0;
        byteStream[4] = (canid & 0xff);
        byteStream[5] = ((canid & 0xff00) >> 8);
        byteStream[6] = ((canid & 0xff0000) >> 16);
        byteStream[7] = ((canid & 0x1f000000) >> 24);
        byteStream[7] |= (rtr<<6);
        byteStream[7] |= (is29bit<<7);

        for (int i=0;i<len;i++)
            byteStream[i+8] = content[i];
        
        for (int k=0;k<16;k++)
            printf("%02x ", byteStream[k]);
        printf("\n\n");

        for (int j=0;j<16;j++){
            *pucTxMsg = byteStream[j];
            pucTxMsg++;
        }

        *pusTxTransNum = 0;
        *pusNumOfTxMsgs = 1;
        *pusTxCountApp = *pusTxCountApp + 1;
        pucTxMsg=pucTxMsg-16;
        ecmSleep(10); 
        
        canid++;
        if (canid==0x20000000) 
        {   
            break;
        }
    }