代码基于xenomai2和qt
我igh修改了的源码
把ecrt_master_reference_clock_time(ighMaster,(uint64_t*)&refTime) 函数返回的refTime改成了uint64_t
#include "IghEthercatMaster.h"
#include "EthercatDevice.h"
#include "GlobalFunction.h"
#include "RtThread.h"
#include "RtMaster.h"
#include
#include
//#define Q_OS_LINUX
#if defined(Q_OS_LINUX)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct IghEthercatMaster::Pimp{
ec_master_state_t masterState;
ec_master_t* ighMaster=nullptr;
int64_t refTime=0;
int64_t freqShift=0;
int64_t dcDiffNs=0;
int64_t refDiffNs=0;
bool dcErrored=false;
bool stateErrored=false;
};
IghEthercatMaster::IghEthercatMaster(){
pimp.reset(new Pimp);
}
IghEthercatMaster::~IghEthercatMaster(){
}
bool IghEthercatMaster::init(){
ec_master_state_t& masterState = pimp->masterState;
ec_master_t*& ighMaster = pimp->ighMaster;
for(int i=0;i<5;i++){
if(ighMaster){
ecrt_release_master(ighMaster);
ighMaster=nullptr;
QThread::msleep(5000);
}
ighMaster = ecrt_request_master(0);
if(ighMaster==nullptr){
printf("Ethercat master request failed, no network card for ethercat");
return false;
}
ecrt_master_state(ighMaster,&masterState);
if(masterState.slaves_responding!=devices.size()){
printf("mismatch slave count=%d,expected=%d\r\n",masterState.slaves_responding,devices.size());
continue;
}
ec_slave_info_t slaveInfo;
for(uint32_t i=0; iethercatMaster=this;
dev->ighMaster=ighMaster;
if(slaveInfo.vendor_id!=dev->VID || slaveInfo.product_code!=dev->PID){
printf("%s: configure:%X,%X , but device:%X,%X\r\n",__FUNCTION__,dev->VID,dev->PID,slaveInfo.vendor_id,slaveInfo.product_code);
continue;
}
dev->slaveConfig=ecrt_master_slave_config(ighMaster, 0, slaveInfo.position, slaveInfo.vendor_id, slaveInfo.product_code);
if(dev->slaveConfig==nullptr){
printf("ecrt_master_slave_config failed,device=%d\r\n",i);
continue;
}
dev->config();
//printf("ec:device%d domainOffset=%d\r\n",i,dev->pdoDomainOffset);
}
ecrt_master_setup_domain_memory(ighMaster);
//rt_printf("ec:totalDomainSize=%u\r\n",pdoDomainSize);
for(size_t i=0; iactiveDomain();
}
int ret=ecrt_master_activate(pimp->ighMaster);
if(ret!=0){
return false;
}
state = State::SYNCING;
return true;
}
return false;
}
int64_t IghEthercatMaster::process(){
if(state==State::INITING || state==State::ERROR){
return 0;
}
ec_master_state_t& masterState = pimp->masterState;
ec_master_t* ighMaster = pimp->ighMaster;
int64_t phaseOffset=0;
int64_t cycleCount=getCycleCount();
ecrt_master_receive(ighMaster);
for(size_t i=0;iprocessRx();
}
for(size_t i=0;iprocessTx();
}
{// process dc distribute clock
if(cycleCount%200==50){
ecrt_master_sync_monitor_queue(ighMaster);
}else if(cycleCount%200==51){
pimp->dcDiffNs=ecrt_master_sync_monitor_process(ighMaster);
}
if(cycleCount>=32){
phaseOffset=getPhaseOffsetNs();
}
ecrt_master_application_time(ighMaster, rtMaster->getNextWakeupNs());
}
ecrt_master_sync_slave_clocks(ighMaster); //set slaves_timer to ref_timer
ecrt_master_send(ighMaster);
if(cycleCount % 2000==0){ //check error
ecrt_master_state(ighMaster,&masterState);
if((masterState.al_states&0x07)==0){
if(state == State::SYNCING){
state=State::OPERATING;
}
pimp->stateErrored=false;
}else if(cycleCount%40000==38000 && (( state > SYNCING && ( masterState.link_up==0) ) || state==SYNCING)){
if(!pimp->stateErrored){
pimp->stateErrored=true;
rtdebug(__FUNCTION__,QString("check master warning: link:%1, num:%2 expected:%3, al_state:0x%4").arg(masterState.link_up).arg(masterState.slaves_responding).arg(devices.size()).arg(masterState.al_states,2,16,QChar('0')).toLocal8Bit().constData());
}else{
rtdebug(__FUNCTION__,QString("check master failed: link:%1, num:%2 expected:%3, al_state:0x%4").arg(masterState.link_up).arg(masterState.slaves_responding).arg(devices.size()).arg(masterState.al_states,2,16,QChar('0')).toLocal8Bit().constData());
state=ERROR;
}
}
}
traceStatus->freqShift = pimp->freqShift;
traceStatus->dcDiff = pimp->dcDiffNs;
traceStatus->slaveNum = pimp->masterState.slaves_responding;
traceStatus->alStatus = pimp->masterState.al_states;
traceStatus->inited = state > State::INITING;
traceStatus->linkup = pimp->masterState.link_up;
traceStatus->synced = state==State::OPERATING;
traceStatus->error = state==State::ERROR;
return phaseOffset;
}
void IghEthercatMaster::onExit(){
/*for(size_t i=0;islaveConfig){
ecrt_slave_config_dc(devices[i]->slaveConfig, 0, 0, 0, 0, 0);
}
}*/
ecrt_master_deactivate_slaves(pimp->ighMaster);
/*for(int i=0;i<10;i++){
RtThread::sleepNs(getCycleNs());
process();
}*/
if(pimp->ighMaster){
ecrt_release_master(pimp->ighMaster);
pimp->ighMaster=nullptr;
}
}
int64_t IghEthercatMaster::getPhaseOffsetNs(){
ec_master_t* ighMaster = pimp->ighMaster;
int64_t& refTime=pimp->refTime;
int64_t& freqShift=pimp->freqShift;
int64_t cycleNs=getCycleNs();
int64_t cycleCount=getCycleCount();
bool& dcErrored=pimp->dcErrored;
int ret=ecrt_master_reference_clock_time(ighMaster,(uint64_t*)&refTime);
int64_t errorNs=0;
int64_t limit=cycleNs/10;
if(ret==0){
errorNs = (pimp->refTime + cycleNs/2)%cycleNs - cycleNs/2;
pimp->refDiffNs = errorNs;
if(errorNs > limit){
rt_printf("IghEthercatMaster:bigError refTime=%lld,errUs=%lld,freqShift=%lld,dcDiff=%lld @ %lld\r\n",refTime/1000,errorNs/1000,freqShift/1000,pimp->dcDiffNs,cycleCount);
errorNs = limit;
}else if(errorNs < -limit){
rt_printf("IghEthercatMaster:bigError refTime=%lld,errUs=%lld,freqShift=%lld,dcDiff=%lld @ %lld\r\n",refTime/1000,errorNs/1000,freqShift/1000,pimp->dcDiffNs,cycleCount);
errorNs = -limit;
}
freqShift+=errorNs/100;
if(freqShift > limit){
freqShift = limit;
}else if(freqShift < -limit){
freqShift = -limit;
}
if( (cycleCount%3000==0 && cycleCount<30000) || (cycleCount<100 && cycleCount%3==0)){
rt_printf("IghEthercatMaster:log refTime=%lld,currentTime=%lld,errUs=%lld,freqShift=%lld,dcDiff=%lld @ %lld\r\n",refTime/1000,rtMaster->getNextWakeupNs()/1000,errorNs/1000,freqShift/1000,pimp->dcDiffNs,cycleCount);
}
if(dcErrored){
dcErrored=false;
rt_printf("ecrt_master_reference_clock_time resumed @ tick:",cycleCount);
}
}else{
if(!dcErrored){
dcErrored=true;
rt_printf("ecrt_master_reference_clock_time return err @ tick:%2",cycleCount);
}
}
return -(errorNs/10 + freqShift);
}
#endif
外部的实时线程会以1ms为周期调用 int64_t IghEthercatMaster::process() 这个函数,并根据这个函数的返回值在下一周期额外的延时ns时间
void RtMaster::threadEntry(){
pimp->wakeupTime=RtThread::getTimeNs();
pimp->wakeupTime += 2*pimp->cycleNs - pimp->wakeupTime%pimp->cycleNs + 30*1000;
while(pimp->exitRequest==0){
RtThread::sleepUntilNs(pimp->wakeupTime);
tracer.reset(pimp->wakeupTime/1000);
recordTrace(rtStatus->avgWake,rtStatus->maxWake,tracer.trace(RtThread::getTimeUs(),"wakeup"));
if(ethercatMaster){
int64_t phaseShift=ethercatMaster->process();
pimp->wakeupTime+=phaseShift;
}
pimp->wakeupTime+=pimp->cycleNs;
tracer.trace(RtThread::getTimeUs(),"ethercat");
for(size_t i=0;iprocessRx();
}
for(size_t i=0;iprocessRx();
}
recordTrace(rtStatus->avgRx,rtStatus->maxRx,tracer.trace(RtThread::getTimeUs(),"processRx"));
for(size_t i=0;iprocessRx();
}
for(size_t i=0;iprocessTx();
}
for(size_t i=0;iprocessTx();
}
for(size_t i=0;iprocessTx();
}
for(size_t i=0;iprocessRx();
}
for(size_t i=0;iprocessTx();
}
recordTrace(rtStatus->avgTx,rtStatus->maxTx,tracer.trace(RtThread::getTimeUs(),"processTx"));
pimp->cycleCount++;
rtStatus->cycleCount=pimp->cycleCount;
if(rtStatus->resetTrace){
memset(rtStatus,0,sizeof(RT_STATUS));
}
}
for(size_t i=0;ionExit();
}
for(size_t i=0;ionExit();
}
for(size_t i=0;ionExit();
}
for(size_t i=0;ionExit();
}
if(ethercatMaster){
ethercatMaster->onExit();
}
pimp->exitRequest=2;
}
还有一点是dev->config()函数
void EthercatCoolDriveR4::config(){
domain = ecrt_master_create_domain(ighMaster);
if ( ecrt_slave_config_pdos( slaveConfig, ARRAY_SIZE(syncs), syncs ) ) {
rtdebug(__FUNCTION__,"error: ecrt_slave_config_pdos failed");
return;
}
for(size_t i=0;igetCycleNs(), ethercatMaster->getCycleNs()*100 + ethercatMaster->getCycleNs()/2, 0, 0);
}
ecrt_slave_config_dc的shift参数被设置成cycle/2,这和getPhaseOffsetNs里的cycle/2是一样的