Shop OBEX P1 Docs P2 Docs Learn Events
Give me a sign — Parallax Forums

Give me a sign

I've been playing with this so long... it has become a blur.

I have a nifty BNO055 absolute position sensor with sensor fusion. It reports linear acceleration as signed 16bit integers.
When I display these values over serial, the signs are lost. Actual negative values are reported as the two's complement form... and appear as positive values. And if I do arithmetic on these values, the result appears as though the two's complement form of the negative values is actually a positive integer being operated upon.

What to do?

Comments

  • sounds like your prpgram is interpreting the values as 32-bit or 16-bit unsigned. can we see your code?
  • Yeah it might be a sign extension issue. A negative number would need the upper 16 bits set to $FF. I'm pretty new to Prop, but something like:

    NegMask = $0080

    if ReadValue AND NegMask = $0080
    then OR ReadValue, $FF00

    should work. You know what I'm saying :P
  • JonnyMacJonnyMac Posts: 9,105
    edited 2016-01-08 01:31
    Make sure your variables are longs, then do this:
    ~~sensorvalue
    
    Yep, that's it. The ~~ at the front of a variable extends the sign from bit 15 (a single ~ extends from bit 7).
  • rjo__rjo__ Posts: 2,114
    David,

    I had trouble figuring out which version to show you... but your question got me looking and Iit turns out that I was declaring a long but bit shifting it as though it were a word... duh.

    I also discovered that if I declare a variable as a word and then assign a -1 to it, what comes back is the two's complement form... but for as a long it comes back as -1... who would have figured?

    I don't have it completely sorted yet, but this appears to be my first mistake.

    Thanks,

    Rich
  • JonnyMacJonnyMac Posts: 9,105
    edited 2016-01-08 01:39
    gis667en11 wrote: »
    Yeah it might be a sign extension issue. A negative number would need the upper 16 bits set to $FF. I'm pretty new to Prop, but something like:

    NegMask = $0080

    if ReadValue AND NegMask = $0080
    then OR ReadValue, $FF00

    should work. You know what I'm saying :P

    Your example is actually showing extension to a 16-bit value from a signed 8-bit number. In Spin you need to use longs for correct results with signed operations. Here's a way to do what you're suggesting if the special operator is not your cup of tea.
      if (sensorvalue & $8000)
        sensorvalue |= $FFFF_0000
    

    Another what to so this in Spin -- if the sign is not in in bit 15 or bit 7 -- is like this:
    (sensorvalue << (31 - SIGN_BIT)) ~> (31 - SIGN_BIT)
    
    The ~> (SAR, shift arithmetic right) works like a right shift but fills bit 31 with the previous contents of bit31 (instead of 0 as a standard shift does).



  • rjo__rjo__ Posts: 2,114
    This is what I ended up with... all variables are long. The signs and magnitudes seem reasonable. Still seems blurry:)
    PRI Get_Acceleration_Data
          accxi:=i2c.readByte(BNO055,LIA_DATA_x_MSB)
          accxi:=accxi<<8
          mydata:= i2c.readByte(BNO055,LIA_DATA_x_LSB)
          accxi:=accxi+mydata
          mydata:=accxi
           
          tester:=1
          mydata:=mydata<<17
          mydata:=mydata>>17
           
          if mydata<accxi
             accxi:=1+ not(accxi) 
             tester:=-1
           
          accx :=tester*accxi
    
  • The ">>" operator is an unsigned shift. You should use "~>" to do a signed shift. So your "mydata:=mydata>>17" should be "mydata:=mydata>>17". Or you could write it as "mydata ~>>= 17".

    The shift by 17 assumes that the data is only 15 bits. If you really have 16 bits of data you could shift by 16, or you could use the "~~" sign extension operator.
  • rjo__rjo__ Posts: 2,114
    Took a nap... things always look better after a nice little nap.

    Thanks guys
  • JonnyMacJonnyMac Posts: 9,105
    edited 2016-01-08 06:15
    If the two-byte value is a signed word, you could do this:
    pri get_accel_x_data | tacc
    
      tacc := i2c.readbyte(BNO055, LIA_DATA_X_MSB) << 8
      tacc |= i2c.readbyte(BNO055, LIA_DATA_X_LSB)
    
      return ~~tacc
    
  • rjo__rjo__ Posts: 2,114
    hmmm.... and just when things seemed so clear:)
    I'll tell you what though, even with my miserable programming... this little package is looking just fine:)
    I'm going to look at this again in the AM

    Thanks
  • gis667en11gis667en11 Posts: 73
    edited 2016-01-08 14:56
    JonnyMac wrote: »
    gis667en11 wrote: »

    Your example is actually showing extension to a 16-bit value from a signed 8-bit number. In Spin you need to use longs for correct results with signed operations. Here's a way to do what you're suggesting if the special operator is not your cup of tea.
      if (sensorvalue & $8000)
        sensorvalue |= $FFFF_0000
    

    Another what to so this in Spin -- if the sign is not in in bit 15 or bit 7 -- is like this:
    (sensorvalue << (31 - SIGN_BIT)) ~> (31 - SIGN_BIT)
    
    The ~> (SAR, shift arithmetic right) works like a right shift but fills bit 31 with the previous contents of bit31 (instead of 0 as a standard shift does).



    Oh. Duh. The cogs all use longs for everything, so of course it'd have to be signed to a long. Thanks JM
  • Would you mind posting the code you're using to interface to the sensor? I've been having difficulty with getting any data out of mine at all.
Sign In or Register to comment.