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();