软件包

构建顺序

  1. epics-base
  2. asyn
  3. motor
  4. etherlab
  5. ruckig
  6. ecmc

epics-base

正常交叉编译。

asyn

正常交叉编译。

motor

配置如下:

configure/CONFIG_SITE.local
1
2
# Uncomment the following line to build iocs in motor/modules/motorVendor/iocs
BUILD_IOCS = YES
configure/RELEASE.local
1
2
3
EPICS_BASE=/path/to/epics/base-7.0.10
SUPPORT=$(EPICS_BASE)/../epics-modules
ASYN=$(SUPPORT)/asyn

etherlab

需要内核源码头文件才能编译,和EPICS不相关。

ruckig 编译

机器人运动控制库,版本:0.15.3

配置交叉编译工具链

toolchain.cmake
1
2
set(CMAKE_C_COMPILER "loongarch64-linux-gnu-gcc")
set(CMAKE_CXX_COMPILER "loongarch64-linux-gnu-g++")

编译步骤

shell
1
2
3
4
5
6
# 新建编译目录
mkdir build
cd build
# 交叉编译
cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake -DCMAKE_BUILD_TYPE=Release ..
make

ecmc

把下载的exprtk解压到exprtkSupport目录下(也可以用git pull下来)。

配置如下:

configure/RELEASE.local
1
2
3
4
5
6
7
EPICS_BASE=/path/to/epics/base-7.0.10
SUPPORT=$(EPICS_BASE)/../epics-modules
ASYN=$(SUPPORT)/asyn
MOTOR=$(SUPPORT)/motor
RUCKIG=$(SUPPORT)/ruckig
# 指定交叉编译架构
EPICS_HOST_ARCH=linux-loong64

修改devEcmcSup/Makefile

devEcmcSup/Makefile
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#************************************************************************
# Copyright (c) 2019 European Spallation Source ERIC
# ecmc is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#
# Author: Jeong Han Lee <jeonghan.lee@gmail.com>
#
#*************************************************************************

TOP=..
include $(TOP)/configure/CONFIG
#----------------------------------------
#  ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================


ECMC = $(TOP)/devEcmcSup

LIBRARY_IOC += ecmc

# Ubuntu needs the following ldflags
USR_LDFLAGS += -Wl,--no-as-needed
USR_LDFLAGS += -lstdc++

ifeq ($(T_A),linux-x86_64)
# Assume that the etherlab user library is done via
# https://github.com/icshwi/etherlabmaster
USR_INCLUDES += -I/opt/etherlab/include
USR_CFLAGS += -fPIC
USR_LDFLAGS += -L /opt/etherlab/lib
USR_LDFLAGS += -lethercat
USR_LDFLAGS += -Wl,-rpath=/opt/etherlab/lib
else
# Assume that the etherlab user library is done via
# Yocto ESS Linux bb recipe
USR_INCLUDES += -I$(SDKTARGETSYSROOT)/usr/include/etherlab
USR_CFLAGS   += -fPIC
USR_LDFLAGS  += -L $(SDKTARGETSYSROOT)/usr/lib/etherlab
USR_LDFLAGS  += -lethercat
USR_LDFLAGS  += -Wl,-rpath=$(SDKTARGETSYSROOT)/usr/lib/etherlab
endif

+ USR_CXXFLAGS += -std=c++17
+ USR_INCLUDES += -I$(RUCKIG)/include/ruckig
USR_LDFLAGS += -L$(RUCKIG)/build/ -lruckig
USR_LDFLAGS += -Wl,-rpath,'$(RUCKIG)/build/'

SRC_DIRS += ${ECMC}/main
SRC_DIRS += ${ECMC}/ethercat
SRC_DIRS += ${ECMC}/com
SRC_DIRS += ${ECMC}/motion
SRC_DIRS += ${ECMC}/motor
SRC_DIRS += ${ECMC}/plc
SRC_DIRS += ${ECMC}/plugin
SRC_DIRS += ${ECMC}/misc
ecmc_SRCS += $(notdir $(foreach d,$(SRC_DIRS),$(wildcard $d/*.c)))
ecmc_SRCS += $(notdir $(foreach d,$(SRC_DIRS),$(wildcard $d/*.cpp)))
DBD += $(notdir $(foreach d,$(SRC_DIRS),$(wildcard $d/*.dbd)))

$(info ===== ECMC_SRCS =====)
$(info $(ecmc_SRCS))
$(info =====================)

ecmc_LIBS += exprtkSupport
ecmc_LIBS += $(EPICS_BASE_IOC_LIBS)

include $(TOP)/configure/RULES
#----------------------------------------
#  ADD RULES AFTER THIS LINE

gitversion.c:
        @$(RM) $@
        @sh $(TOP)/tools/gitversion.sh $@

修改ecmcExampleTop/configure/RELEASE.local

ecmcExampleTop/configure/RELEASE.local
1
2
3
4
5
6
7
8
9
EPICS_BASE=/path/to/epics/base-7.0.10
SUPPORT=$(EPICS_BASE)/../epics-modules
ASYN=$(SUPPORT)/asyn
MOTOR=$(SUPPORT)/motor
RUCKIG=$(SUPPORT)/ruckig
# 添加QSRV2支持
PVXS=$(SUPPORT)/pvxs
# 指定交叉编译架构
EPICS_HOST_ARCH=linux-loong64

修改ecmcExampleTop/ecmcIocApp/src/Makefile

diff
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
TOP=../..

include $(TOP)/configure/CONFIG
#----------------------------------------
#  ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================

#=============================
# Build the IOC application

PROD_IOC = ecmcIoc

# Ubuntu needs the following ldflags
USR_LDFLAGS_Linux += -Wl,--no-as-needed

+ ifeq ($(T_A),linux-x86_64)
+ # Assume that the etherlab user library is done via
+ # https://github.com/icshwi/etherlabmaster
+ USR_INCLUDES += -I/opt/etherlab/include
+ USR_CFLAGS += -fPIC
+ USR_LDFLAGS += -L /opt/etherlab/lib
+ USR_LDFLAGS += -lethercat
+ USR_LDFLAGS += -Wl,-rpath=/opt/etherlab/lib
+ else
+ # Assume that the etherlab user library is done via
+ # Yocto ESS Linux bb recipe
+ # 这里注意etherlab的路径
+ USR_INCLUDES += -I$(SDKTARGETSYSROOT)/usr/include/etherlab
+ USR_CFLAGS   += -fPIC
+ USR_LDFLAGS  += -L $(SDKTARGETSYSROOT)/usr/lib/etherlab
+ USR_LDFLAGS  += -lethercat
+ USR_LDFLAGS  += -Wl,-rpath=$(SDKTARGETSYSROOT)/usr/lib/etherlab
+ endif

+ # ruckig路径
+ USR_INCLUDES += -I$(RUCKIG)/include/ruckig
+ USR_LDFLAGS  += -L$(RUCKIG)/build -lruckig

# ecmcioc.dbd will be created and installed
DBD += ecmcIoc.dbd

# opcuaIoc.dbd will be made up from these files:
ecmcIoc_DBD += base.dbd
+ ecmcIoc_DBD += system.dbd
ecmcIoc_DBD += ecmcController.dbd
ecmcIoc_DBD += ecmcMotorRecordSupport.dbd

+ ecmcIoc_DBD += asyn.dbd
+ ecmcIoc_DBD += motorSupport.dbd

# Add all the support libraries needed by this IOC
ecmcIoc_LIBS += asyn
ecmcIoc_LIBS += ecmc
+ ecmcIoc_LIBS += motor
ecmcIoc_LIBS += exprtkSupport

ecmcIoc_SRCS += ecmcIoc_registerRecordDeviceDriver.cpp

# Build the main IOC entry point on workstation OSs.
ecmcIoc_SRCS_DEFAULT += ecmcIocMain.cpp
ecmcIoc_SRCS_vxWorks += -nil-

+ # Link PVXS if available
+ ifdef PVXS_MAJOR_VERSION
+     ecmcIoc_LIBS += pvxsIoc pvxs
+     ecmcIoc_DBD += pvxsIoc.dbd
+ else
+ # Link QSRV (pvAccess Server) if available
+ ifdef EPICS_QSRV_MAJOR_VERSION
+     ecmcIoc_LIBS += qsrv
+     ecmcIoc_LIBS += $(EPICS_BASE_PVA_CORE_LIBS)
+     ecmcIoc_DBD += PVAServerRegister.dbd
+     ecmcIoc_DBD += qsrv.dbd
+ endif
+ endif

# Finally link to the EPICS Base libraries
ecmcIoc_LIBS += $(EPICS_BASE_IOC_LIBS)

#===========================
include $(TOP)/configure/RULES
#----------------------------------------
#  ADD RULES AFTER THIS LINE

编译的时候需要指定使用c++17的标准,不然有一些语法不支持,应该是ruckig库比较新。

添加CXXFLAGS=-std=c++17

shell
1
2
3
4
5
# 执行交叉编译
make \
LD=loongarch64-linux-gnu-ld \
CC=loongarch64-linux-gnu-gcc \
CCC=loongarch64-linux-gnu-g++ -j8

使用方法

主要使用ecmccfg软件包提供的预编写脚本进行EtherCAT主站、从站配置。

修改IOC环境变量配置iocBoot/iocExample/envPaths

envPaths
1
2
3
4
5
epicsEnvSet("IOC", "iocExample")
epicsEnvSet("TOP", "../..")
epicsEnvSet("SUPPORT", "/path/to/epics-modules")
epicsEnvSet("ASYN", "${SUPPORT}/asyn")
epicsEnvSet("ECMC", "${SUPPORT}/ecmc")

修改启动脚本iocBoot/iocExample/st.cmd

st.cmd
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#!../../bin/linux-loong64/ecmcIoc

< envPaths

cd "${TOP}"

## Register all support components
dbLoadDatabase "dbd/ecmcIoc.dbd"
ecmcIoc_registerRecordDeviceDriver pdbbase

## Load record instances
#dbLoadRecords("db/xxx.db","user=${USER}")

# ecmccfg路径配置
epicsEnvSet "ecmccfg_DIR", "${ECMC}/scripts/"
epicsEnvSet "ecmccfg_DB", "${ECMC}/db/"
epicsEnvSet "ECMC_CONFIG_ROOT", "${ecmccfg_DIR}"
epicsEnvSet "ECMC_CONFIG_DB", "${ecmccfg_DB}"
epicsEnvSet "SCRIPTEXEC", "iocshLoad"

# EPICS 7.0.10 支持
epicsEnvSet "EPICS_DB_INCLUDE_PATH", "${ECMC_CONFIG_DB}"

#- 初始化
${SCRIPTEXEC} "${ECMC_CONFIG_ROOT}initAll.cmd", "SM_MOTOR_PORT=MCU1,SM_ASYN_PORT=MC_CPU1,SM_PREFIX=${IOC}:"
# EtherCAT主站号
epicsEnvSet "MASTER_ID", 0
# 扫描频率,默认 1000
epicsEnvSet "EC_RATE", 100
# 工作模式,默认 FULL,可选 FULL/DAQ/NO_MR
epicsEnvSet "ECMC_MODE", "DAQ"
epicsEnvSet "ECMC_PVA", "NO"
epicsEnvSet "ECMC_EC_TOOL_PATH", "/usr/bin/ethercat"

#-
#-------------------------------------------------------------------------------
# Set EtherCAT frequency (defaults to 1000)
ecmcConfigOrDie "Cfg.SetSampleRate(${EC_RATE=1000})"
#-
#- Set current EtherCAT sample rate
#- Note: Not the same as ECMC_SAMPLE_RATE_MS which is for record update
epicsEnvSet "ECMC_EC_SAMPLE_RATE", ${EC_RATE=1000}
ecmcEpicsEnvSetCalc("ECMC_EC_SAMPLE_RATE_MS", 1000/${ECMC_EC_SAMPLE_RATE=1000})

# Update records in 10ms (100Hz) for FULL MODE and in EC_RATE for DAQ mode
ecmcEpicsEnvSetCalcTernary(ECMC_SAMPLE_RATE_MS, "'${ECMC_MODE=FULL}'=='DAQ'","${ECMC_EC_SAMPLE_RATE_MS}","10")
epicsEnvSet(ECMC_SAMPLE_RATE_MS_ORIGINAL, ${ECMC_SAMPLE_RATE_MS})

#- define naming convention script
epicsEnvSet "ECMC_P_SCRIPT", "${NAMING=mXsXXX}"

#- Set master
${SCRIPTEXEC} "${ECMC_CONFIG_ROOT}addMaster.cmd", "MASTER_ID=${MASTER_ID=0}"
epicsEnvSet "ECMC_EC_MASTER_ID", ${MASTER_ID=0}

#- Add slaves
${SCRIPTEXEC} "${ECMC_CONFIG_ROOT}addSlave.cmd", "SLAVE_ID=0, HW_DESC=EK1100"
${SCRIPTEXEC} "${ECMC_CONFIG_ROOT}addSlave.cmd", "SLAVE_ID=1, HW_DESC=EL4024"
${SCRIPTEXEC} "${ECMC_CONFIG_ROOT}addSlave.cmd", "SLAVE_ID=2, HW_DESC=EL2624"
${SCRIPTEXEC} "${ECMC_CONFIG_ROOT}addSlave.cmd", "SLAVE_ID=3, HW_DESC=EL3742, NELM=10"
${SCRIPTEXEC} "${ECMC_CONFIG_ROOT}addSlave.cmd", "SLAVE_ID=4, HW_DESC=EK1110"

#- Apply hardware configuration
${SCRIPTEXEC} "${ECMC_CONFIG_ROOT}applyConfig.cmd"

#- Load PLCs
#${SCRIPTEXEC} "${ecmccfg_DIR}loadPLCFile.cmd", "FILE=${TOP}/iocBoot/${IOC}/test1.plc, ECMC_TMP_FILE=/tmp/PLC1.plc, DESC=test, SAMPLE_RATE_MS=125"

#- Configure diagnostics:
ecmcConfigOrDie "Cfg.EcSetDiagnostics(1)"
ecmcConfigOrDie "Cfg.EcEnablePrintouts(0)"
ecmcConfigOrDie "Cfg.EcSetDomainFailedCyclesLimit(100)"

#- Activate
${SCRIPTEXEC} "${ECMC_CONFIG_ROOT}setAppMode.cmd"

#Set Affinity of ecmc_rt (core 1)
epicsThreadSetAffinity ecmc_rt 1

cd "${TOP}/iocBoot/${IOC}"
iocInit

## Start any sequence programs
#seq sncxxx,"user=${USER}"
#seq procServControl, "P=${IOC}"
  • ecmcXXxxxx.cmd:从站配置脚本
  • ecmcXXxxxx.substitutions:EPICS数据库文件(DB records)

参考链接