Opinion time again. Which do you prefer?

Which method of sign extending would you prefer?

  • MyVarOut := ASHR(MyVarIn*65536),16)

    Votes: 1 7.1%
  • MyVarOut := ((MyVarIn*65536)/65536);

    Votes: 2 14.3%
  • MyVarOut := ASHR(ASHL(MyVarIn,16),16);

    Votes: 4 28.6%
  • MyVarOut := ASH(ASH(MyVarIn,16),-16);

    Votes: 0 0.0%
  • MyVarOut := SEXT(MyVarIn,16);

    Votes: 6 42.9%
  • MyVarOut := ASHR(DWORD_TO_DINT(SHL(DINT_TO_DWORD(MyVarIn),16)),16);

    Votes: 1 7.1%

  • Total voters
    14
  • Poll closed .
Join Date
Apr 2002
Location
No income tax, no capital gains tax. Freedom!
Posts
8,389
Which method do you prefer for taking the difference between two encoder counts and sign extending the difference into a DINT.

MyVarIn:=CurrentEnoderCounts-PreviousEncoderCounts;
1) MyVarOut := ((MyVarIn*65536)/65536);
The MyVarIn*65536 may cause an overflow but that is not a problem with our product.

2) MyVarOut := ASHR(MyVarIn*65536),16);
The ASHR ( arithmetic shift right ) instruction shift right DINTs the number of bits specified. Bit 31 used to fill the most significant bits. Not the ASHR would be an extension to the IEC specification. It is standard to have a ASHR instruction on a microcontroller. It is a flaw not to have a ASHR instruction.

3) MyVarOut := ASHR(ASHL(MyVarIn,16),16);
This is similar to the above only the ASHL instruction replaces the multiply. The ASHL may potentionaly be faster on a small microcontroller but it does make any difference on our product. The advantage is consistency.

4) MyVarOut := ASH(ASH(MyVarIn,16),-16);
This is how our TI DSP do it. The sign of the shift number determines the direction. This reduces the number of instructions to implement.

5) MyVarOut := SEXT(MyVarIn,16);
This is the simplest. Just provide a sign extend instruction.

6) MyVarOut := ASHR(DWORD_TO_DINT(SHL(DINT_TO_DWORD(MyVarIn),16)),16)
Yuk, the IECE spec makes you type cast all the conversions. Originally the MyVarIn is signed and it must be type cast to an DWORD. Then it can be shifted left. Then it must be type cast to a DINT so it can be shifted right and sign extended. Those IEC guy really want to make life easy for you don't they?

7) Another option is to not to follow the IECs in the area of type casting. In this case option 6 would be.
MyVarOut := ASHR(SHL(MyVarIn,16)),16)
Rockwell converts the types for you whereas IEC and Siemens don't. This would be a more 'Rockwell' approach to the problem. Unfortunately I can't update my poll.

This is my first poll.

BTW, one of our tech support guys said the number of people that would care about this in the next two years is 0 and that is an over estimate. We will see.
 
Last edited:
We are a little short on opinions

I expected more options but I did expect the simplest solution to win however, since no one will ask for this feature in the next two years we have decided this is a low priority. We implemented the ASHR because it does fill a whole in the incomplete IEC instruction set but we won't do any more because other things have higher priority.

What is funny is that no one picked the two choice that were closest to the IEC specification. What is interesting is that no one picked the two options that are closest to the IEC spec.
 
Peter Nachtwey said:
I expected more options

I think you are a little impatient. It's only been a day. I just got time to look and already it's called closed.

I'm confused, Based on your IEC choice 6) it looks like MyVarIn is a DINT already, why do you have to sign extend it? Is the assumption that PreviousCnt and CurrentCnt are 16 bit values? Since they are just counts could they be UINT values (unsigned integers)? Then how about:

MyVarOut:=UINT_TO_DINT(CurrentEnoderCounts)-UINT_TO_DINT(PreviousEncoderCounts);

Since we're in a pseudo-IEC mode here, I don't think the question can be answered without knowing the type of CurrentEncoderCounts and PreviousEncoderCounts...

If they are type WORD, then no conversion function is necessary (at Least in CoDeSys based languages)... This compiles and runs fine...


VAR
Prev: WORD;
Curr: WORD;
MyOut: DINT;
END_VAR

MyOut := Curr - Prev;

 
There was a thread a week or two ago where I suggested a way to sign extend the difference between two 16 bit encoder readings on a Control Logix. In this particular case the problem was avoiding over flow faults.
http://www.plctalk.net/qanda/showthread.php?t=41175&highlight=overflow
Just about a day before someone asked how to simulated a multi turn encoder using a single turn encoder. The math is basically the same but I had to suggest using version 1. I don't like this because the divides take a long time compare to a simple shift left and shift right.

In C I would

DifCounts = (((CurCount-PrevCounts) << 16) >> 16;

The DSP compiler compiles this down to a
Load
subtract
shift Left
shift right
which takes just 4 clock cycles and is very efficient and simple.

The closest thing to this in the something that looks like IEC is option 3 or 4. Option 5 is the easiest but it is very specific and there would still be a need for an ASHR instruction. Perhaps having two added instructions would be best. We will see.

I just shake my head when I see the **** we manufacturers force on you guys in the name of 'standards' like IEC type conversions and overflow faults to make sure you don't miss over flow errors. I am giving you all a chance to have a say so my stuff does stink as bad as all the others.

ndzied1 said:
I think you are a little impatient. It's only been a day. I just got time to look and already it's called closed.
It closes 30 Aug.

I'm confused, Based on your IEC choice 6) it looks like MyVarIn is a DINT already, why do you have to sign extend it?
MyVarin is just the difference between the current and previous count which can be assumed to be 16 bit values. Therefore the upper 16 bits of MyVarIn may not be right.

Is the assumption that PreviousCnt and CurrentCnt are 16 bit values? Since they are just counts could they be UINT values (unsigned integers)? Then how about:

MyVarOut:=UINT_TO_DINT(CurrentEnoderCounts)-UINT_TO_DINT(PreviousEncoderCounts);
That doesn't work if the previous count is 65535 and the current count is 0.

Since we're in a pseudo-IEC mode here, I don't think the question can be answered without knowing the type of CurrentEncoderCounts and PreviousEncoderCounts...
It doesn't make any difference until the shift right 16 or divide by 65536.

If they are type WORD, then no conversion function is necessary (at Least in CoDeSys based languages)... This compiles and runs fine...


VAR
Prev: WORD;
Curr: WORD;
MyOut: DINT;
END_VAR

MyOut := Curr - Prev;

What happens when Curr = 0 and Prev = 65535 ?
This same case was cover in the thread two weeks ago.

BTW, we do all this math for the user inside the controller. Quadrature encoder are always extended to 32 bit values. Normally this isn't sign extending exercise isn't required.
 
I misunderstood the term "sign extension"

I mistakenly thought "sign extension" just meant to extend every negative INT to a negative DINT...

I haven't been following much recently. Too busy.

Didn't this encoder roll over thingy come up a year or so ago (every thing is a cycle they say...).

So if I understand it right, when a negative has a magnitude less than 0x8000 then we assume that encoder moved backwards and it really is a negative displacement. When a negative number has a magnitude greater than 0x8000 then we assume we rolled over 0 and the displacement is really positive.

Then instead of doing a check for this condition and maybe another add or subtract you came up with the Rocky Horror Time Warp method:
It's just a jump to the left
And then a step to the right...

Clever. I say use all 32 bit registers and forget about it. I know it's not always possible with the hardware you get with high speed counters but it should be.
 
ndzied1 said:
Not clever, any assembly language programmer would know this trick.

I say use all 32 bit registers and forget about it.
Me too. In fact we have no choice. Our 32 bit DSP only understands 32 bit values. No 8bit or 16bit variables. Bytes, words, dwords, dints and reals are all 32 bit values.

I know it's not always possible with the hardware you get with high speed counters but it should be.
The size of the counters only affects how many counts you can get between readings. 8 bit counters will work just as well as 16 bit counters IF the difference between two counts always less than 2^(n-1) where n is the number of bits the counter has. If I have an 8 bit counter, so MyVarIn is 8 bits, then I would do this:

MyVarOut:=ASHR(ASHL(MyVarIn,24),24); /* IN ST */
MyVarOut = (( MyVarIn << 24 ) >> 24 ); // IN C

MyVarOut will still be a DINT with the difference between two counts. MyVarOut can be added to a DINT software counter. This is how you make 32 bit counters out of 8 bit or 16 bit counters.

kamenges said:
I personally like #3 but I have to use #2 since my processor of choice is 'flawed'. Keith
:( If there was a smiley with a tear I would have used it.

There still aren't enough votes to be statistically significant.
 
Last edited:
kamenges said:
I personally like #3 but I have to use #2 since my processor of choice is 'flawed'.


Keith

I voted for three, but I fail to see how you can use 2 if your processor is "flawed" since 2 also needs an ASHR.

I imagined for just a minute that I was needing to do this on a Microillogix brick, then I decided that imagination was best used for for pleasant thoughts.
 
Alaric said:
I voted for three, but I fail to see how you can use 2 if your processor is "flawed" since 2 also needs an ASHR.
You can't. Overflows will occur. #3 will not work if your processor faults on overflows. Ours does not so all the example will work on our controller. It is just a matter of making it simple.

I imagined for just a minute that I was needing to do this on a Microillogix brick, then I decided that imagination was best used for for pleasant thoughts.
Wouldn't the technique discussed in the thread above work for a Micrologix? It isn't pretty but it should sour your thoughts too much.

What I don't like about #3 is that we must add YAI ( yet another instruction ) to make it work. I prefer option #3A

MyVarOut := ASHR(SHL(MyVarIn,16),16);

In this case the data type of MyVarIn is ignored so that SHL can shift left either DINTs or DWORDs. This 'extends' the IEC standard though.
 
My bad, Alaric. Peter swapped his methods in the poll list relative to the descrtiptions in his post. I was going by the numbering in the poll list, not the descriptions. As I suspect you guessed I need to do the multiply then the divide in ladder on the AB Logix family of processor. I still don't have the FBD adder so I don't know if the have anything in there to do this.


Keith
 

Similar Topics

I'm looking forward Iconics. I had previously extensive experience with Citect and little bit less experience with Wonderware. Pros and cons with...
Replies
0
Views
837
It is rare that I ask for opinions. But here goes. Currently using a low cost NUC for an hmi. Looking for a low cost NUC or similar. thoughts
Replies
1
Views
1,164
In my project, I have created a UDT for VFD driven motor. The UDT has elements of .SpdCmd, .ManSpdCmd, .MinLim, .MaxLim among others. The idea...
Replies
1
Views
1,251
We are in a mechatronics class currently learning the beginnings of PLCs. There are a few things I think we are being misinformed on and I'd like...
Replies
56
Views
22,562
What on earth is wrong with them? a) Some in imperial, some in metric b) Some in imperial or metric, undefined, at 1:2 scale c) Have fun with...
Replies
14
Views
4,134
Back
Top Bottom