Cannot convert type 'UDINT' to type 'POINTER TO BOOL' Error in Beckhoff. FB Used to work in Codesys (IFM) for years

434 Views Asked by At

I am trying to reuse a FB in Beckhoff that I used in Codesys for years. Beckhoff is based on Codesys, therefore I did not expect any problems. I think the error has something to do with a type conversion that is possible in Codesys but not in Beckhoff. Error: Cannot convert type 'UDINT' to type 'POINTER TO BOOL'.

Underneath my code can be found. This FB has worked for 5+ years in multiple projects already with PLC's from IFM.


FUNCTION_BLOCK FC_AlarmsHandler
VAR_INPUT
    LI_bIN: BOOL;
    /// Reset Alarms bits - only Alarms that are acknowledged 
    LI_bReset: BOOL;
    /// Acknowledge all active Alarms bits at once 
    LI_bAckAll: BOOL;
    /// Hold time of new alarm 
    LI_rHoldTimeNewAlarms: REAL;
    /// Base address of Alarms group struct 
    LI_adrAlarmsGroup: DWORD;
    /// Number of Alarms group elements 
    LI_sizeofAlarmsGroup: UINT;
    /// Base address of Alarms struct 
    LI_adrAlarms: DWORD;
    /// Base address of Alarms old array of bool 
    LI_adrAlarmsOld: DWORD;
    /// Base address of Alarms hold array of bool 
    LI_adrAlarmsHold: DWORD;
    /// Base address of Alarms acknowledge array of bool 
    LI_adrAlarmsAck: DWORD;
    LI_adrAlarmsText: POINTER TO STRING(64);
END_VAR
VAR_OUTPUT
    LQ_bOUT: BOOL;
    /// New Alarm -> this output is one cycle high 
    LQ_bNewAlarm: BOOL;
    /// When an alarm is active, this output is high 
    LQ_bAlarmActive: BOOL;
    /// Alarm gone -> this output is one cycle high 
    LQ_bAlarmGone: BOOL;
END_VAR
VAR
    LT_bInit: BOOL;
    /// offset for group address 
    LT_adrOffsetGroup: DWORD;
    LT_iNumberOfAlarmGroupElements: UINT;
    /// Number of lines for alarm visualization table in Hmi 
    LT_iNumberOfHmiLines: INT;
    /// Number of lines for alarm history visualization table in Hmi 
    LT_iNumberOfHmiHistoryLines: INT;
    LT_ptAlarms: POINTER TO BOOL;
    LT_ptAlarmsOld: POINTER TO BOOL;
    LT_ptAlarmsHold: POINTER TO BOOL;
    LT_ptAlarmsAck: POINTER TO BOOL;
    LT_ptAlarmsText: POINTER TO STRING(64);
    LT_iCounterAlarmsElements: INT;
    /// Timer for holding new alarm 
    fbTofNewAlarm: TOF;
END_VAR
LQ_bOUT:=LI_bIN;
// Init 
IF LT_bInit = FALSE THEN
    LT_adrOffsetGroup := LI_adrAlarmsGroup - LI_adrAlarms;
    LT_iNumberOfAlarmGroupElements := LI_sizeofAlarmsGroup / SIZEOF(LT_ptAlarms^); 
    // Alarm array for HMI
    LT_iNumberOfHmiLines := GDI_Alarms.iNumberOfHmiLines;
    // Alarm history array for HMI
    LT_iNumberOfHmiHistoryLines := GDI_Alarms.iNumberOfHmiHistoryLines;
    LT_bInit := TRUE;
END_IF

(***************************************************************************)
(* Alarm handling *)
(***************************************************************************)

[HERE I AM HAVING MY PROBLEMS] 
// Init new scan cycle
LT_ptAlarms := LI_adrAlarms + (LT_adrOffsetGroup * SIZEOF(LT_ptAlarms^));
LT_ptAlarmsText := LI_adrAlarmsText + (LT_adrOffsetGroup * SIZEOF(LT_ptAlarmsText^));
LT_ptAlarmsOld := LI_adrAlarmsOld + (LT_adrOffsetGroup * SIZEOF(LT_ptAlarmsOld^));
LT_ptAlarmsHold := LI_adrAlarmsHold + (LT_adrOffsetGroup * SIZEOF(LT_ptAlarmsHold^));
LT_ptAlarmsAck := LI_adrAlarmsAck + (LT_adrOffsetGroup * SIZEOF(LT_ptAlarmsAck^));


LQ_bNewAlarm:= FALSE;
LQ_bAlarmActive := FALSE;
LQ_bAlarmGone := FALSE;

FOR LT_iCounterAlarmsElements := 1 TO LT_iNumberOfAlarmGroupElements DO // Scan all data of group
    // Check for new alarms 
    IF LT_ptAlarms^ AND NOT LT_ptAlarmsOld^ THEN
        LQ_bNewAlarm:= TRUE;
    END_IF

    // Reset current alarms 
    IF LI_bReset AND LT_ptAlarmsAck^ AND NOT LT_ptAlarms^ THEN
        LT_ptAlarms^ := FALSE;
    ELSE
        LT_ptAlarms^ := LT_ptAlarms^ OR LT_ptAlarmsOld^; (* keep alarms true *)
    END_IF

    // Hold new alarms 
    IF fbTofNewAlarm.Q = TRUE THEN
        LT_ptAlarmsHold^ := LT_ptAlarms^ OR LT_ptAlarmsHold^;
    ELSE
        LT_ptAlarmsHold^ := LT_ptAlarms^;
    END_IF

    // Acknowlegde current alarms
    IF LI_bAckAll THEN
        LT_ptAlarmsAck^ := LT_ptAlarms^;
    END_IF

    // check if alarm is gone 
    IF NOT LT_ptAlarms^ AND LT_ptAlarmsOld^ THEN
        LQ_bAlarmGone := TRUE;
    END_IF
    
    // Alarms active
    IF LT_ptAlarms^ THEN
        LQ_bAlarmActive:= TRUE;
    END_IF

    // Save old value 
    LT_ptAlarmsOld^ := LT_ptAlarms^;

    // Next element 
    LT_ptAlarms := LT_ptAlarms + SIZEOF(LT_ptAlarms^); // Pointer to next element
    LT_ptAlarmsText := LT_ptAlarmsText + SIZEOF(LT_ptAlarmsText^); // Pointer to next element
    LT_ptAlarmsOld := LT_ptAlarmsOld + SIZEOF(LT_ptAlarmsOld^); // Pointer to next element
    LT_ptAlarmsHold := LT_ptAlarmsHold + SIZEOF(LT_ptAlarmsHold^); // Pointer to next element
    LT_ptAlarmsAck := LT_ptAlarmsAck + SIZEOF(LT_ptAlarmsAck^); // Pointer to next element

END_FOR
fbTofNewAlarm(in:= LQ_bNewAlarm, PT:= REAL_TO_TIME(LI_rHoldTimeNewAlarms), Q=> ,    ET=> );

I already tried to add a conversion UDINT_TOPBOOL, UDINT_TODWORD (because of standard pointer datatype) but this did not work.

1

There are 1 best solutions below

3
Fred On

I strongly suspect you have been using a 32-bit version of CODESYS for all these years, and are now moving to a 64-bit Beckhoff PLC.

If so, your problem is not caused by moving from CODESYS to TwinCAT, but moving from 32 bits to 64 bits. Try it for yourself : go back to CODESYS, and choose any 64-bit runtime. You will get the same error as in TwinCAT when you compile.

  • You probably should not use DWORD variables to pass addresses around. Use "POINTER TO". Better yet, use "REFERENCE TO". This will compile and work across different CPU architectures.

  • You seem to be calculating the addresses of many variables that are found in a single structure using offsets, rather than having one single pointer (or reference) to the structure and using "." to access its fields. I have not fully analyzed your code, but it seems to me it would greatly simplify it as you would get rid of all pointer calculations and offload this work to the compiler.