DynamicConfig
Methods for dynamic configuration of slaves:
In the device tree of the projekt is just the PLC and the EtherCAT master. Slaves are scanned and added inside the application.
Example:
Program for dynamic configuration of slaves:
PROGRAM PLC_PRG
// required configuration:
// EK1100
// EL2008
// EL1008
// EL3142
// EL4132
VAR
config : dynamicConfig;
dwOffset : DWORD;
dwSize : DWORD;
pbyOutData : POINTER TO BYTE;
pbyInData : POINTER TO BYTE;
byIn : BYTE;
END_VAR
Ethercat_Master(); // call the instance to get the outputs
IF Ethercat_master.ConfigRead THEN
// If Ethercat master configuration is read then start the dynamic configuration of the slaves
config();
END_IF;
// Wait until söave configuration is done and master has finished the startup with the new configuration
IF config.xDone AND config.pSlaves <> 0 AND Ethercat_master.xConfigFinished THEN
// sample code for process data
dwOffset := config.pSlaves[1].OutputBitOffset;
dwSize := config.pSlaves[1].OutputBitSize;
pbyOutData := config.pSlaves[1].OutputData;
// Write to the outputs to EL2008
IF pbyOutData <> 0 AND dwSize >= 8 THEN
pbyOutData^ := pbyOutData^ + 1;
END_IF
// Read the inputs of EL1008
dwOffset := config.pSlaves[2].InputBitOffset;
dwSize := config.pSlaves[2].InputBitSize;
pbyInData := config.pSlaves[2].InputData;
IF pbyInData <> 0 AND dwSize >= 8 THEN
byIn := pbyOutData^;
END_IF
END_IF
FUNCTION_BLOCK DynamicConfig
VAR_INPUT
END_VAR
VAR_OUTPUT
xDone : BOOL;
xBusy : BOOL;
xError : BOOL;
pSlaves : POINTER TO ETCSlave;
wNumberOfSlaves : WORD;
END_VAR
VAR
readnbr : ReadNbrSlaves; // for reading number of connected slaves
readeeprom : ReadEEpromData; // for reading identification data
wSlaveIndex : WORD;
uiStep : UINT := 0;
pSlave : POINTER TO ETCSlave;
stAllocString : STRING := 'DynamicTest'; // For dynamic memory allocation
Result : UDINT;
xKnown : BOOL;
masterState : ETC_MASTER_STATE := ETC_MASTER_STATE.ETC_MASTER_OPERATIONAL;
END_VAR
CASE uiStep OF
0..5:
xError := FALSE;
xDone := FALSE;
xBusy := TRUE;
uiStep := uiStep + 1; // Wait some cycles
6:
IF Ethercat_master.FirstSlave = 0 THEN
Ethercat_master.Master^.ResetConfiguration();
Ethercat_master.Master^.EnableDynamicConfig := TRUE; // switch stack to dynamic config -> Reset does not remove configured slaves
uiStep := 8;
ELSE
// Already slave connected -> do nothing
uiStep := 1000;
END_IF
8:
IF NOT readnbr.xBusy THEN
readnbr.usiCom := DWORD_TO_USINT(Ethercat_Master.InstanceNumber);
readnbr.xExecute := TRUE;
readnbr.udiTimeOut := 1000;
END_IF
readnbr();
IF readnbr.xDone THEN
wNumberOfSlaves := readnbr.wNumberSlaves;
IF wNumberOfSlaves > 0 THEN
pSlaves := SysMemAllocData(stAllocString ,wNumberOfSlaves * DINT_TO_UDINT(SIZEOF(ETCSlave)),ADR(Result));
// allocate memory for slave instances
pSlave := pSlaves;
uiStep := 10;
wSlaveIndex := 0;
ELSE
uiStep := 99;
END_IF
END_IF
IF readnbr.xError THEN
uiStep := 1000;
END_IF
IF readnbr.xError OR readnbr.xDone THEN
readnbr.xExecute := FALSE;
readnbr();
END_IF
10:
IF NOT readeeprom.xBusy THEN
readeeprom.usiCom := DWORD_TO_USINT(Ethercat_Master.InstanceNumber);
readeeprom.wSlaveIndex := wSlaveIndex;
readeeprom.udiTimeOut := 1000;
readeeprom.xExecute := TRUE;
END_IF
readeeprom();
IF readeeprom.xDone THEN
// device found
{implicit on}
// important: initialize the fb instances
pSlave^.__vfinit();
pSlave^.FB_Init(FALSE, FALSE); // call the constructor
{implicit off}
pSlave^.AutoIncAddr := INT_TO_WORD(-WORD_TO_INT(wSlaveIndex));
pSlave^.PhysSlaveAddr := 1001 + wSlaveIndex;
pSlave^.SetConfigData(readeeprom.wAliasAddress, readeeprom.dwVendorID, readeeprom.dwProductID, readeeprom.dwRevisionID, readeeprom.dwSerialNo, 0,0);
pSlave^.SetOptional(FALSE);
pSlave^.SetStartupChecks(TRUE,TRUE,FALSE,0);
xKnown := FALSE;
CASE readeeprom.dwVendorID OF
2: // Beckhoff
CASE readeeprom.dwProductID OF
72100946: // EK1100 -> nothing to add
xKnown := TRUE;
131608658: // EL2008
pSlave^.AddSyncManager(16#0F00, 1,16#44, TRUE, 1);
pSlave^.AddFMMU(0, 1, 0, 7, 16#0F00, 0, 2, 1);
xKnown := TRUE;
66072658: // EL1008;
pSlave^.AddSyncManager(16#1000, 1,16#0, TRUE, 1);
pSlave^.AddFMMU(0, 1, 0, 7, 16#1000, 0, 1, 1);
xKnown := TRUE;
270807122: // EL4132
pSlave^.AddSyncManager(16#1800, 246,16#26, TRUE, 3);
pSlave^.AddSyncManager(16#18F6, 246,16#22, TRUE, 2);
pSlave^.AddSyncManager(16#1000, 4,16#24, TRUE, 1);
pSlave^.AddSyncManager(16#1100, 0,16#20, TRUE, 0);
pSlave^.AddFMMU(0, 4, 0, 7, 16#1000, 0, 2, 1);
pSlave^.AddFMMU(0, 1, 0, 0, 16#80D, 0, 1, 1);
xKnown := TRUE;
205926482: // EL3142
IF readeeprom.byMailboxProtocol > 0 THEN
// mailbox from eeprom
pSlave^.AddSyncManager(readeeprom.wRcvMbxOffset, readeeprom.wRcvMbxSize,16#26, TRUE, 3);
pSlave^.AddSyncManager(readeeprom.wSndMbxOffset, readeeprom.wSndMbxSize,16#22, TRUE, 2);
END_IF
pSlave^.AddSyncManager(16#1100, 0,16#4, TRUE, 1);
pSlave^.AddSyncManager(16#1180, 6,16#20, TRUE, 0);
pSlave^.AddFMMU(0, 6, 0, 7, 16#1180, 0, 1, 1);
pSlave^.AddFMMU(0, 1, 0, 0, 16#80D, 0, 1, 1);
IF pSlave^.NbrFMMU <> 2 THEN
xError := TRUE;
uiStep := 1000;
END_IF
IF pSlave^.NbrSyncManager <> 4 THEN
xError := TRUE;
uiStep := 1000;
END_IF
xKnown := TRUE;
END_CASE
END_CASE
IF xKnown = TRUE THEN
uiStep := 16; // Slave is known -> continue with next slave
ELSE
uiStep := 1000; // Slave not known -> error
END_IF
END_IF
IF readeeprom.xError THEN
uiStep := 1000;
END_IF
16:
pSlave := pSlave + SIZEOF(etcslave);
// pointer to next slave
readeeprom(xExecute := FALSE);
IF NOT readeeprom.xDone AND NOT readeeprom.xError THEN
IF wSlaveIndex < (wNumberOfSlaves - 1) THEN
wSlaveIndex := wSlaveIndex + 1;
uiStep := 10; // next slave
ELSE
uiStep := 99; // last slave done
END_IF
END_IF
99:
// add the slaves to ethercat master and restart the new configuration
pSlave := pSlaves;
IF pSlave <> 0 THEN
FOR wSlaveIndex := 1 TO wNumberOfSlaves DO
Ethercat_master.Master^.AddSlave(pSlave);
pSlave := pSlave + SIZEOF(etcslave);
END_FOR
Ethercat_master.MasterState := masterState;
Ethercat_master.Master^.RestartMaster();
END_IF
uiStep := 100;
100:
xDone := TRUE;
xBusy := FALSE;
1000: // error occurred
readeeprom(xExecute := FALSE);
xError := TRUE;
xBusy := FALSE;
END_CASE
readnbr();
readeeprom();