Hello again,
I'm continuing my work on a proof of concept application using the IgH
EtherCAT master however I'm having more problems. Specifically I'm
seeing warnings and errors when trying to setup a Beckhoff EL2252 module:
====================================================
Dec 15 08:49:31 lyot kernel: [90434.144520] EtherCAT ERROR 0-2: Slave
does not support CoE!
Dec 15 08:49:31 lyot kernel: [90434.244602] EtherCAT ERROR 0-2: Failed
to read number of mapped PDO entries.
Dec 15 08:49:31 lyot kernel: [90434.244605] EtherCAT WARNING 0-2: Failed
to read PDO entries for PDO 0x1604.
====================================================
I see the above errors both when using my code (attached but not yet
functioning) as well as using a working example program that I found on
the mailing list [1] (much thanks Philippe).
WRT the warnings/errors above:
Do I need to be concerned about the errors/warnings that I see in the log?
If they aren't of concern is there any way to silence them?
Thanks in advance
[1] http://lists.etherlab.org/pipermail/etherlab-users/2013/002134.html
--
-john
To be or not to be, that is the question
2b || !2b
(0b10)*(0b1100010) || !(0b10)*(0b1100010)
0b11000100 || !0b11000100
0b11000100 || 0b00111011
0b11111111
255, that is the answer.
#include <sstream>
#include <bitset>
#include "OutputModule.h"
OutputModule::OutputModule(uint16_t position) :
EtherCatSlave(OutputModule::BECKHOFF_ID, OutputModule::EL2252_ID,
position) {
int i = 0;
pdoRegs[i++] = { 0, position, BECKHOFF_ID, EL2252_ID, 0x1d09, 0x81,
&offsetActivate, NULL};
pdoRegs[i++] = { 0, position, BECKHOFF_ID, EL2252_ID, 0x1d09, 0x90,
&offsetStartTime, NULL};
pdoRegs[i++] = { 0, position, BECKHOFF_ID, EL2252_ID, 0x7000, 0x01,
&offsetOutput[0], &bitPosOutput[0]};
pdoRegs[i++] = { 0, position, BECKHOFF_ID, EL2252_ID, 0x7000, 0x02,
&offsetTriState[0], &bitPosTriState[0]};
pdoRegs[i++] = { 0, position, BECKHOFF_ID, EL2252_ID, 0x7010, 0x01,
&offsetOutput[1], &bitPosOutput[1]};
pdoRegs[i++] = { 0, position, BECKHOFF_ID, EL2252_ID, 0x7010, 0x02,
&offsetTriState[1], &bitPosTriState[1]};
//pdoRegs[i++] = { 0, position, BECKHOFF_ID, EL2252_ID, 0x1d09, 0x10,
//&offsetSysTime, NULL};
//pdoRegs[i++] = { 0, position, BECKHOFF_ID, EL2252_ID, 0x1d09, 0x11,
//&offsetFeedback, NULL};
pdoRegs[i++] = { };
state = IDLE;
}
const ec_sync_info_t* OutputModule::getSyncs() const {
return syncs;
}
const ec_pdo_entry_reg_t* OutputModule::getPdoEntryRegs() const {
return pdoRegs;
}
void OutputModule::readProcessData(uint8_t* processData) { }
void OutputModule::writeProcessData(uint8_t* processData) {
switch (state) {
case IDLE:
break;
case WRITE_READY:
EC_WRITE_U64(processData + offsetStartTime, time);
for (int i = 0; i < 2; i++) {
EC_WRITE_BIT(processData + offsetOutput[i], offsetOutput[i], output[i]);
EC_WRITE_BIT(processData + offsetTriState[i], offsetTriState[i], 0);
}
EC_WRITE_U8(processData + offsetActivate, 0);
std::cout << "State transitioned from WRITE_READY --> WRITE_STARTED";
std::cout << std::endl;
state = WRITE_STARTED;
break;
case WRITE_STARTED:
std::cout << "State transitioned from WRITE_STARTED --> IDLE";
std::cout << std::endl;
EC_WRITE_U8(processData + offsetActivate, 3);
state = IDLE;
break;
}
}
void OutputModule::schedule(uint64_t startTime, bool output0, bool output1) {
std::cout << "@ " << startTime << " El2252[0] will become " << output0;
std::cout << " and El2252[1] will become " << output1 << std::endl;
this->startTime = startTime;
this->output[0] = output0;
this->output[1] = output1;
this->state = WRITE_READY;
}
OutputModule::~OutputModule() { }
const ec_pdo_entry_info_t OutputModule::pdoEntries[] = {
{0x1d09, 0x81, 8}, /* Activate */
{0x1d09, 0x90, 64}, /* StartTime */
{0x7000, 0x01, 1}, /* Output */
{0x7000, 0x02, 1}, /* TriState */
{0x7010, 0x01, 1}, /* Output */
{0x7010, 0x02, 1}, /* TriState */
{0x0000, 0x00, 4}, /* Reserved */
//{0x1d09, 0x10, 64}, /* SysTime */
//{0x1d09, 0x11, 8}, /* Feedback */
};
const ec_pdo_info_t OutputModule::pdos[] = {
/* from original slaves.h */
{0x1602, 1, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 0)}, //Activate
{0x1603, 1, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 1)}, //StartTime
{0x1600, 2, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 2)}, //Channel 1
{0x1601, 3, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 4)}, //Channel 2
{0x1604, 0, NULL}, //Reserved
/*
{0x1602, 0, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 0)}, //Activate
{0x1603, 0, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 1)}, //StartTime
{0x1600, 0, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 2)}, //Channel 1
{0x1601, 0, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 4)}, //Channel 2
{0x1604, 0, NULL}, //Reserved
*/
/* from mailing list slaves.h
{0x1602, 1, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 0)}, //Activate
{0x1603, 1, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 1)}, //StartTime
{0x1600, 2, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 2)}, //Channel 1
{0x1601, 3, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 4)}, //Channel 2
{0x1604, 0, NULL}, //Reserved
{0x1a00, 1, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 7)}, //SysTime
{0x1a01, 1, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 8)}, //Feedback
*/
};
const ec_sync_info_t OutputModule::syncs[] = {
/* from original slaves.h */
{0, EC_DIR_INPUT, 1, const_cast<ec_pdo_info_t*>(pdos + 0), EC_WD_DISABLE},
{1, EC_DIR_INPUT, 1, const_cast<ec_pdo_info_t*>(pdos + 1), EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 3, const_cast<ec_pdo_info_t*>(pdos + 2), EC_WD_ENABLE},
{3, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{4, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{0xff}
/* from mailing list slaves.h
{0, EC_DIR_OUTPUT, 1, const_cast<ec_pdo_info_t*>(pdos + 0), EC_WD_DISABLE},
{1, EC_DIR_OUTPUT, 1, const_cast<ec_pdo_info_t*>(pdos + 1), EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 2, const_cast<ec_pdo_info_t*>(pdos + 2), EC_WD_ENABLE},
{3, EC_DIR_INPUT, 1, const_cast<ec_pdo_info_t*>(pdos + 4), EC_WD_DISABLE},
{4, EC_DIR_INPUT, 1, const_cast<ec_pdo_info_t*>(pdos + 5), EC_WD_DISABLE},
{4, EC_DIR_INPUT, 1, const_cast<ec_pdo_info_t*>(pdos + 6), EC_WD_DISABLE},
{0xff}
*/
};
std::string OutputModule::toString() const {
std::stringstream os;
for (int i = 0; i < 2; i++) {
if (0 == i) os << "el2252 ";
else os << " ";
os << i << " : ";
//os << "in=" << input[i] ? std::string("true"): std::string("false");
//std::bitset<8> statusBits(status[i]);
//os << "\tstatus=" << statusBits;
//os << "\tnegLatch=" << negLatch[i];
//os << "\tposLatch=" << posLatch[i];
if (i == 0) os << std::endl;
}
return os.str();
}
void OutputModule::printPdoEntryInfo() const {
std::cout << "========== output module ==========" << std::endl;
std::cout << "offsetActivate: " << offsetActivate << std::endl;
std::cout << "offsetStartTime: " << offsetStartTime << std::endl;
for (int i = 0; i < 2; i++) {
std::cout << "offsetOutput["<<i<<"]: " << offsetOutput[i] << std::endl;
std::cout << "bitPosOutput["<<i<<"]: " << bitPosOutput[i] << std::endl;
std::cout << "offsetTriState["<<i<<"]: " << offsetTriState[i] << std::endl;
std::cout << "bitPosTriState["<<i<<"]: " << bitPosTriState[i] << std::endl;
}
for (int i = 0; i < 2; i++) {
}
//for (int i = 0; i < 2; i++)
// std::cout << "offsetPosLatch["<<i<<"]: " << offsetPosLatch[i] << std::endl;
std::cout << "===================================" << std::endl;
}
std::ostream& operator<<(std::ostream & os, OutputModule& x) {
os << x.toString();
return os;
}
#include <iostream>
#include <chrono>
#include <thread>
#include "EtherCat.h"
#include "Timer.h"
#define BECKHOFF 0x00000002
EtherCat::EtherCat(const unsigned short& masterNum) {
master = ecrt_request_master(masterNum);
if (NULL == master) {
std::cerr << "ERROR:\tFailed to obtain master" << std::endl;
exit(-1);
} else {
std::cout << "OK:\tMaster obtained" << std::endl;
}
domain = ecrt_master_create_domain(master);
if (NULL == domain) {
std::cerr << "ERROR:\tFailed to obtain domain" << std::endl;
exit(-1);
} else {
std::cout << "OK:\tDomain obtained" << std::endl;
}
}
EtherCat::~EtherCat() {
}
ec_master_t* EtherCat::getMaster() {
return master;
}
ec_domain_t* EtherCat::getDomain() {
return domain;
}
void EtherCat::start(void (*f)(EtherCat* ec), const unsigned int& micros) {
unsigned int error = ecrt_master_activate(master);
if (error) {
std::cerr << "ERROR:\tFailed to activate master" << std::endl;
exit(-1);
} else std::cout << "OK:\tMaster activated" << std::endl;
auto delayTime = std::chrono::microseconds(micros);
auto nextTick = std::chrono::high_resolution_clock::now() + delayTime;
Timer timer = Timer();
while (!done) {
ecrt_master_receive(getMaster());
ecrt_domain_process(getDomain());
uint8_t* pd = getProcessData();
for (auto &slaveEntry: slaves)
slaveEntry.second->readProcessData(pd);
f(this);
for (auto &slaveEntry: slaves)
slaveEntry.second->writeProcessData(pd);
ecrt_domain_queue(getDomain());
ecrt_master_send(getMaster());
std::this_thread::sleep_until(nextTick);
timer.tick();
nextTick += delayTime;
}
timer.printStats();
ecrt_master_deactivate(master);
std::cout << "OK:\tMaster deactivated" << std::endl;
}
void EtherCat::stop() {
done = true;
}
void EtherCat::configureSlave(const std::string& name,
EtherCatSlave& slave) {
std::cout << "DEBUG:\tPreparing to configure slave '" << name;
auto vid = slave.getVendorId();
auto pid = slave.getProductId();
auto pos = slave.getPositionId();
std::cout << "' in position " << pos << std::endl;
ec_slave_config_t* cfg = ecrt_master_slave_config(master, 0, pos, vid, pid);
if (NULL == cfg) {
std::cerr << "ERROR:\tFailed to obtain slave config " << name << std::endl;
exit(-1);
} else {
std::cout << "OK:\tConfig obtained for slave '" << name << "'" << std::endl;
slaveCfgs[name] = cfg;
}
{
ec_slave_config_state_t state;
ecrt_slave_config_state(cfg, &state);
std::string opState;
switch (state.al_state) {
case 1: opState = "INITIALISED";
case 2: opState = "PRE-OPERATIONAL";
case 4: opState = "SAFE-OPERATIONAL";
case 8: opState = "OPERATIONAL";
}
std::cout << "\tstate is " << opState << std::endl;
//std::cout << "\t\t\tconfig obtained" << std::endl;
}
int error;
error = ecrt_slave_config_pdos(cfg, EC_END, slave.getSyncs());
if (error) {
std::cerr << "ERROR:\tFailed to configure slave PDOs" << std::endl;
exit(-1);
} else {
std::cout << "OK:\tSlave '" << name << "' pdos configured" << std::endl;
}
auto pdos = slave.getPdoEntryRegs();
error = ecrt_domain_reg_pdo_entry_list(domain, pdos);
if (error) {
std::cerr << "ERROR:\tFailed to register PDOs with domain";
std::cerr << " Error code: " << error << std::endl;
exit(-1);
} else {
std::cout << "OK:\tPDOs registered with domain" << std::endl;
}
slaves[name] = &slave;
slave.printPdoEntryInfo();
}
EtherCatSlave* EtherCat::getSlave(const std::string& name) {
return slaves[name];
}
uint8_t* EtherCat::getProcessData() {
return ecrt_domain_data(domain);
}
#include <unistd.h>
#include <signal.h>
#include <iostream>
#include <bitset>
#include <chrono>
#include <thread>
#include <string.h>
#include "ecrt.h"
#include "EtherCat.h"
#include "InputModule.h"
#include "OutputModule.h"
static EtherCat* ec;
static void checkMasterStatus(ec_master_t* master);
static void checkDomainStatus(ec_domain_t* domain);
static void doCyclicTask(EtherCat* ec);
static void term(int sigNum);
static const std::string INPUT_MODULE = "input";
static const std::string OUTPUT_MODULE = "output";
//unsigned int micros = 5000000; // 5 s ==> 0.2 Hz
//unsigned int micros = 500000; // 0.5 s ==> 2 Hz
unsigned int micros = 50000; // 50 ms ==> 20 Hz
//unsigned int micros = 5000; // 5 ms ==> 200 Hz
//unsigned int micros = 500; // 0.5ms ==> 2 KHz
static InputModule inputModule(1);
static OutputModule outputModule(2);
int main(int argc, char** argv) {
std::cout << "Starting main..." << std::endl;
//sleep(5);
//EtherCat* ec = new EtherCat();
ec = new EtherCat();
ec_master_t* master = ec->getMaster();
ec_domain_t* domain = ec->getDomain();
//InputModule inputModule = InputModule(1);
//OutputModule outputModule = OutputModule(2);
ec->configureSlave(INPUT_MODULE, inputModule);
ec->configureSlave(OUTPUT_MODULE, outputModule);
checkMasterStatus(master);
checkDomainStatus(domain);
signal(SIGABRT, &term);
signal(SIGTERM, &term);
signal(SIGINT, &term);
ec->start(doCyclicTask, micros);
// stop will from from a ctrl+c signal
delete ec;
ec = NULL;
std::cout << "Leaving main..." << std::endl;
return 0;
}
static void doBlink();
static void doPrintInputInfo();
static void periodic();
static void doCyclicTask(EtherCat* ec) {
doBlink();
//doPrintInputInfo();
//periodic();
}
static void periodic() {
static uint64_t counter = 0;
static unsigned int x = (10 * 1000 * 1000) / micros;
if (counter++ % x == 0) {
std::cout << inputModule.toString() << std::endl;
}
}
static void doBlink() {
static bool lastInput[2] = {false, false};
static uint64_t lastPosLatch[2] = {0, 0};
static unsigned int blink = false;
unsigned short channel = 1;
bool input1 = inputModule.getInput(channel);
if (input1 && (input1 != lastInput[channel])) {
uint64_t time = inputModule.getPosLatch(channel);
std::cout << "button press detected @ ";
std::cout << time << std::endl;
// add 1 second
time += 1000000000;
outputModule.schedule(time, blink, !blink);
blink = !blink;
}
for (unsigned short i = 0; i < 2; i++) {
lastInput[i] = inputModule.getInput(i);
lastPosLatch[i] = inputModule.getPosLatch(i);
}
}
static void doPrintInputInfo() {
static bool lastInput[2] = {false, false};
static uint64_t lastPosLatch[2] = {0, 0};
for (unsigned short i = 0; i < 2; i++) {
bool input = inputModule.getInput(i);
if (input != lastInput[i])
std::cout << inputModule.toString() << std::endl;
lastInput[i] = inputModule.getInput(i);
lastPosLatch[i] = inputModule.getPosLatch(i);
}
}
static void term(int signum) {
std::cerr << "Received sig: " << signum << std::endl;
if (NULL != ec) ec->stop();
}
static void checkMasterStatus(ec_master_t* master) {
ec_master_state_t ms;
ecrt_master_state(master, &ms);
std::bitset<4> states(ms.al_states);
std::cout << "Master:\tlink is " << (ms.link_up ? "up" : "down");
std::cout << " with " << ms.slaves_responding << " slave(s)." << std::endl;
std::cout << " \tapplication layer states: 0b" << states << std::endl;
}
static void checkDomainStatus(ec_domain_t* domain) {
ec_domain_state_t ds;
ecrt_domain_state(domain, &ds);
std::cout << "Domain:\tWC " << ds.working_counter << std::endl;
std::cout << " \tState " << ds.wc_state << std::endl;
}
static void parseProcessData(uint8_t* data) {
int i;
for (i = 0; i < 2; i++) {
//unsigned int in = EC_READ_BIT(data + el1252.offset_in[i],
//el1252.offset_in[i]);
//unsigned int status = EC_READ_BIT(data + el1252.offset_status[i],
//el1252.offset_status[i]);
//unsigned int poslatch= EC_READ_BIT(data + el1252.offset_latch_pos[i],
//el1252.offset_latch_pos[i]);
//unsigned int neglatch= EC_READ_BIT(data + el1252.offset_latch_neg[i],
//el1252.offset_latch_neg[i]);
//printf("el1252[%i]: in=%s\tstatus=%s\tlatchpos=%s\tlatchneg=%s\n", i,
//in ? "true": "false",
//status ? "true": "false",
//poslatch? "true": "false",
//neglatch? "true": "false");
}
}
_______________________________________________
etherlab-users mailing list
etherlab-users@etherlab.org
http://lists.etherlab.org/mailman/listinfo/etherlab-users