How to interpret two word (32-bit) data from a serial device?

Hi everyone,

I'm trying to figure how how to correctly display a two word (32 bit) parameter value from a serial device. The problem is that this register is sent by the device using the following order:  higher value word: first 16 bit, lower value: second 16 bit.

I've created a 32 bit unsigned data type dataset, as the device memory map establishes for the data type of the register. I'm reading the register this way and I've found out that what I'm displaying isn't the actual value of the register but an inverted value: because of the order that the device uses to send the data (16 bit with highest value first), I'm receiving the two words inverted!

To make thing more easy to understand I'm going to make some numbers: 

Say that actual register value is 227,149.... this in binary is interpreted as 0000 0000 0000 0011 0111 0111 0100 1101.... being the first 16 bits one word (0000 0000 0000 0011), and of course the other 16 bits the second word (0111 0111 0100 1101). Now, what the devices is doing is comparing both words (both 16 bit halves) and sending the second one first, as it has a higher value compared to the first word. This way, what I'm receiving is 0111 0111 0100 1101 0000 0000 0000 0011... that converted to decimal corresponds to the number 2,001,534,979!

Has anyone experience solving anything like this? I would appreciate any help.

Thanks in advance!.

  • Hi

    How the data field arrives to the "serial device" ?

    Because this kind of inverting order is not "programmaticaly" normal.

    If you cannot correct the data source format, you will have to proceed with bit inversion :

    - in a CALC block (using 2^^ and &), if the meaning of this value have to be used in a controller

    Example :

    The fifth bit of an Integer or Long value can be isolated like that : True If (Value & (2^^4)) = (2^^4)

    and you will have to create a While/End_While structure to enumerate bits 0 to 31

    - in a VBA, you can use this 'rotation' of bits :

    Private Function LongLeftRotate(ByVal value As Long) As Long

       Dim lngSign As Long, lngI As Long

       Dim Bits As Long

       Bits = 16

       For lngI = 1 To Bits

           lngSign = value And &HC0000000

           value = (value And &H3FFFFFFF) * 2

           value = value Or ((lngSign < 0) And 1) Or (CBool(lngSign And &H40000000) And &H80000000)

       Next

       LongLeftRotate = value

    End Function

    and use it like that :

       Dim LongInitial     As Long

       Dim LongModified    As Long

       LongInitial = 2001534979             ' 0111 0111 0100 1101 0000 0000 0000 0011

       LongModified = LongLeftRotate(LongInitial)

       MsgBox LongModified    ' give 227149 = 0000 0000 0000 0011 0111 0111 0100 1101

    Hope that will help

  • In reply to Jack_France:

    It´s the big/little endian problem: en.wikipedia.org/.../Endianness

    In the PLC world it would be really easy:

    you have 32 bit word. MD 100 (consistes of mb 100,101,102,103)

    then you just move the MB:s to a new MD (double)

    L MB100 to MB 113

    L MB101 to MB 112

    and so on... propably you could do the same inside VB code

    (depending are the words just swapped or also the Bytes inside the words)

    If the bytes are also swapped you can´t use rotate :p

    Niklas Flykt 

    Klinkmann Oy

    Key Account Manager safety products

    nikfly@gmail.com

  • I guess that using SHL or SHR in a calc block you can split the 32 bits in 2
    * 16 bit values. These values can be the input for a BFI to see the
    individual flags.

    -----Oorspronkelijk bericht-----
    Van: SMAQLL [mailto:bounce-SMAQLL@community.emerson.com]
    Verzonden: maandag 26 augustus 2013 00:45
    Aan: DeltaV@community.emerson.com
    Onderwerp: [EE365 DeltaV Track] How to interpret two word (32-bit) data from
    a serial device?

    Hi everyone,

    I'm trying to figure how how to correctly display a two word (32 bit)
    parameter value from a serial device. The problem is that this register is
    sent by the device using the following order: higher value word: first 16
    bit, lower value: second 16 bit.

    I've created a 32 bit unsigned data type dataset, as the device memory map
    establishes for the data type of the register. I'm reading the register this
    way and I've found out that what I'm displaying isn't the actual value of
    the register but an inverted value: because of the order that the device
    uses to send the data (16 bit with highest value first), I'm receiving the
    two words inverted!

    To make thing more easy to understand I'm going to make some numbers:

    Say that actual register value is 227,149.... this in binary is interpreted
    as 0000 0000 0000 0011 0111 0111 0100 1101.... being the first 16 bits one
    word (0000 0000 0000 0011), and of course the other 16 bits the second word
    (0111 0111 0100 1101). Now, what the devices is doing is comparing both
    words (both 16 bit halves) and sending the second one first, as it has a
    higher value compared to the first word. This way, what I'm receiving is
    0111 0111 0100 1101 0000 0000 0000 0011... that converted to decimal
    corresponds to the number 2,001,534,979!

    Has anyone experience solving anything like this? I would appreciate any
    help.

    Thanks in advance!.

  • In reply to Maarten van der Waal:

    @Niklas :

    I also thought about little/big endian, but, in that case, it would invert the bits order (0-15 -> 15-0), not inverting 2 blocks of 16 bits in which the order is not changed.

  • In reply to Jack_France:

    Seems to me the easiest is to simply read the registers as 16 Bit words and combine them in the right order in a CALC block.  

    Create a 32 Bit destination parameter in the module.  Read the MSW and write this to the 32 bit parameter.  Shift this left 16 bits.  Then bitwise OR  (|) this 32 Bit parameter with the LSW.

    Note that DeltaV CALC blocks use 32 Bit Floats for internal registers.  You need to use a defined 32 Bit parameter to "host" the data as you manipulate it.  Using two external reference parameters called 'MSW' and 'LSW'

    '^/32-BIT_PARAM.cv' :='^/MSW.CV';

    '^/32-BIT_PARAM.cv' := (SHL('^/32-BIT_PARAM.cv' , 16 ) );

    '^/32-BIT_PARAM.cv' := '^/32-BIT_PARAM.cv' | '^/LSW.CV';

    The above three lines can be condensed to the following:

    '^/32-BIT_PARAM.cv' := (SHL('^/MSW.CV', 16 ) | '^/LSW.CV';

    The Programmable serial card has 5 special data fields that can be used to 'adjust' the order of bytes and words so that the Dataset holds the converted value.  I think Special Data 2 will swap the two 16 bit registers and give you a 32 Bit word in the Data set without the need for the above expression.  This used to be a downloadable driver from Mynah.  I think the default for the serial card is this driver.  A quick check on my machine shows the Special Data fields available.  Mynah has a document called "Special Modbus Driver

    Programmable Serial Interface Card" that discusses this option.

    If you are using the MODBUS TCP driver for the VIM, it emulates the Programable card and can swap the word order using Special Data 2 set to "1".

    Andre Dicaire

  • In reply to Andre Dicaire:

    Thank you all guys. Problem solved.