Shop OBEX P1 Docs P2 Docs Learn Events
The most elegant MSB LSB swap? — Parallax Forums

The most elegant MSB LSB swap?

Is there a more elegant/efficient/legible way to do a swap of MSB and LSB. In this case I need it to communicate with a chip that reads and writes in the "reverse" order. (please do not start an 'endian war in this thread).
value.BYTE[0]<< 8 + value>> 8

Erlend

Comments

  • That looks pretty good. The following might be a hair better:
    value.BYTE[0] << 8 + value.BYTE[1]
    

    ... or not. Dunno.

    -Phil
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2017-03-16 22:28
    Isn't this what we use the REV instruction for in PASM and bitwise reverse operator >< or ><= for in Spin? However your code is about swapping bytes not "Most Significant Bit" with "Least Significant Bit". Some chips require this MSB to be sent first, some require LSB, regardless of the number of bits, but (with chips) it's about bits , not bytes. Besides, why swap bytes if you can just as easily send one or the other first?
  • Isn't this what we use the REV instruction for in PASM and bitwise reverse operator >< or ><= for in Spin?
    Actually, no. Anyway, if he's sending one byte at a time or the data in serial, none of this would be necessary. I think we have to assume the communication is 16-bit parallel, or he wouldn't be asking.

    -Phil
  • evanhevanh Posts: 15,126
    It does very much depend on what the transmission format actually is. If it's serial Big-Endian then the bit order, rather than the byte order, is where he needs to be focusing.
  • ErlendErlend Posts: 612
    edited 2017-03-18 17:16
    The chip expects to receive a word, so I'd like to send a word. Spin puts an (16 bit) integer in a word (actually long) with the MSB in bits 8-15, and the LSB in bits 0-7. My standard (serial) routine transmits the 8-15 first, then the 0-7. The chip wants to receive the LSB first. That is why I need to swap them so that the LSB goes into 8-15, and the MSB goes into 0-7.

    Erlend
  • So, as I understand it, you already have a serial routine that works with words instead of bytes?

    -Phil
  • If your serial routine has a method for counted strings, you might be able to use,
    serial.Nstring(@wordValue,2)
    That would point to the low byte and send it first.
  • So much unnecessary mystery in some of these posts. Why say "the chip" when you can say which chip it is. Is this an issue with the order that bytes are read rather actually having to swap bytes? However when talking about communicating with chips and swapping MSB and LSB I naturally think of reversing bits.
  • Tracy AllenTracy Allen Posts: 6,656
    edited 2017-03-19 00:53
    The following method to swap bytes is maybe elegant but more suited to a pasm implementation.
    x and y are bytes, ^ is the bitwise XOR operator.
    x := x ^ y
    y := y ^ x
    x := x ^ y
    now the bytes are swapped.

  • ErlendErlend Posts: 612
    edited 2017-03-19 16:16
    So much unnecessary mystery in some of these posts. ...

    No mystery intended. I was just curious to learn if there were a simpler way. The 'chip' is the IR sensor MLX90614. My curiousity was with regards to Spin and swapping byte order in general - interfacing to this chip just triggered me to ask the question.
    value.BYTE[0] << 8 | value.BYTE[1]
    
    appears to be the best answer.

    Erlend

  • Tracy AllenTracy Allen Posts: 6,656
    edited 2017-03-19 19:10
    The MLX60915 sends and receives its words least significant byte first, which is the same as the natural order in the Propeller. It is the order used by common i2c objects such as Basic_I2C_Driver:
    ReadPage(SCL, devSel, addrReg, @data, 2) . ' to read a word
    WritePage(SCL, devSel, addrReg, @data, 2) . ' to write a word
    Isn't that what you want, no byte swap required?

    That said, the order of bytes presented by different i2c devices is all over the place. Many do send most significant first, or have data like time strings in an order opposite of what you'd like. I posit that the order should be handled as an option within any full-featured i2c object, a choice of most or least significant byte first. I'd write it to interpret a negative byte count as an endedness swap.

    p.s. I'm not trying to start an endedness war -- we have to work with it however it is.
  • Erlend wrote: »
    So much unnecessary mystery in some of these posts. ...

    No mystery intended. I was just curious to learn if there were a simpler way. The 'chip' is the IR sensor MLX90614. My curiousity was with regards to Spin and swapping byte order in general - interfacing to this chip just triggered me to ask the question.
    value.BYTE[0] << 8 | value.BYTE[1]
    
    appears to be the best answer.

    Erlend

    Thanks for that info. As Tracy mentioned that chip send its words in the same order as the Propeller handles it in memory so there isn't any need for byte swapping in this and most cases, although not all cases.

  • AribaAriba Posts: 2,682
    Erlend wrote: »
    Is there a more elegant/efficient/legible way to do a swap of MSB and LSB. ...

    More legible:
       txword.byte[0] := value.byte[1]
       txword.byte[1] := value.byte[0]
    
    compiles to the same amount of bytes as your code

    More efficient:
       txword := value>>8 | value<<8
    
    Is 2 bytes shorter

    Elegance is a matter of taste, so no proposal for that...

    Andy
  • Ariba wrote: »
    Erlend wrote: »
    Is there a more elegant/efficient/legible way to do a swap of MSB and LSB. ...

       txword := value>>8 | value<<8
    

    I like this one. Elegant, compact, and efficient.

    Erlend
  • -but I have to make sure there are no bits set in byte three of a long holding this value, right - because they would be shifted right, into byte two, and then be or'ed with the result of 'value<<8' - am I right?
    (this is just for my curiosity and learning, I can easily do a &FF first to clean it)

    Erlend
  • I would use:
     txword := (value>>8) | (value<<8)
    

    It's probably not necessary, but it ensures the order of operations.

    As for making sure that the upper-word bits are set / not set, it depends on how the values are used. Ultimately some code somewhere is sending bits out to a device. If that code only deals with the lower 16 bits then no, you don't need to worry.
  • I think the name of the assigned variable, txword, is a hint that only 16 bits will be stored.

    -Phil
  • I think the name of the assigned variable, txword, is a hint that only 16 bits will be stored.

    -Phil

    Yes, the result only needs the 16 bits, but when I tested in my particular code, as I feared, the 'value' variable had 'trash' in it's upper word bits, so I had to do a & $FF on it, so that that trash did not get shifted into the lower word - which I guess is only good coding practise anyway.

    Erlend
  • evanhevanh Posts: 15,126
    edited 2017-03-28 09:25
    It's unlikely you'll need to swap bytes for serial data.

    Transmitting LittleEndian serial data is a simple case of transmitting from the lsb and shifting right, then repeat until the word is all shifted out. As opposed to BigEndian where you transmit the msb and shift left instead.

    To receive, input bits at the opposite end to transmitting: LE receives at msb and shifts right, while BE receives at lsb and shifts left.

    If not doing the above then you'll be up for bit swapping the whole word, but that's still not a byte swap.
  • I read this stuff because I'm still trying to learn as much as I can. Is this more than a bitwise byte reversal?
    CON
      _clkmode = xtal1 + pll16x                           
      _xinfreq = 5_000_000
    
    OBJ   
    
      Debug : "FullDuplexSerialPlus"
       
    PUB Main  | value
    
        Debug.start(31, 30, 0, 57600)
        waitcnt(clkfreq * 2 + cnt)
        
        value := 85
    
        Debug.tx(13)
        Debug.bin(value, 8)
        Debug.tx(13)
        Debug.dec(value)
    
        value := value  >< 8
        
        Debug.tx(13)
        Debug.bin(value, 8)
        Debug.tx(13)
        Debug.dec(value)
    
        waitcnt(clkfreq + cnt)
    

    I got "85" and "170"
  • evanhevanh Posts: 15,126
    Yep, that's it. And good use of debug there.
  • evanh wrote: »
    It's unlikely you'll need to swap bytes for serial data.
    ...

    The situation is pretty simple; I have a (library) method that puts out MSB first, then LSB. The receiver wants LSB first, then MSB. How to fix this? Either write a new method that does LSB-MSB - or - swap the bytes before transmitting. I chose the latter, and I have asked for advice on how to do that in the best way. I did not expect to get so much good answers, and I still think
    txword := value>>8 | value<<8
    
    is the best answer. A valuable side effect is all the stuff I learn from this thread.

    Erlend
  • evanhevanh Posts: 15,126
    Maybe fix the library. It must be going out of it's way to swap things itself. The library author had some hardware that used mixed Endianess or just assumed that was the normal way.
Sign In or Register to comment.