Shop OBEX P1 Docs P2 Docs Learn Events
Trouble shifting bits — Parallax Forums

Trouble shifting bits

I've been trying to write a method for SPI and what I thought would work doesn't. The code I've written will read the bits right to left but I had to add another zero to the right. I'm testing it with leds. The line I commented out works the same as the binary line.
PUB  READ_BYTE   | idx

   dira[1]~~
   dira[2]~~

  Test_Byte := %1110010110
     
  repeat idx from 1 to 9   
    outa[2] := %1110010110 >> (idx) 
    'outa[2] := Test_Byte >> (idx)
    waitcnt(clkfreq/4 + cnt)
    outa[2]~     
    waitcnt(clkfreq/4 + cnt)

Comments

  • You have idx start at 1 and go to 9. Do you want it to start at 0 and go to 9?
  • lardomlardom Posts: 1,659
    edited 2015-11-16 23:04
    It didn't make a difference in my tests. Leds didn't make that clear. My next step would be check the numbers on the PST.
    Only Shift right worked though and I'm hoping someone can tell me why.
  • how about this?
    PUB  READ_BYTE   | idx
    
       dira[1]~~
       dira[2]~~
    
      Test_Byte := %1110010110
         
      repeat idx from 1 to 9   
        outa[2] := (%1110010110 >> idx) 
        'outa[2] := (Test_Byte >> idx)
        waitcnt(clkfreq/4 + cnt)
        outa[2]~     
        waitcnt(clkfreq/4 + cnt)
    

    Enjoy!

    Mike
  • kwinnkwinn Posts: 8,697
    I suspect it is only outputting the lsb in both outa statements. Only by shifting the data will each bit be output.
  • JonnyMacJonnyMac Posts: 9,105
    edited 2015-11-16 23:51
    As they say here in Hollywood... for your consideration:
    pub shift_out(value, bits, mode)
    
    '' Shift value out via DPIN using SCLK
    '' -- bits is # of bits to shift out
    '' -- mode is 0 for LSBFIRST, !0 for MSBFIRST
    
      if (mode == 0)
        value ><= bits                                               ' reverse bits for LSBFIRST output
    
      value <<= 32 - bits                                            ' move first bit to bit31
    
      repeat bits
        outa[DPIN] := (value <-= 1)                                  ' rotate output bit to bit0
        outa[SCLK] := 1                                              ' clock it
        outa[SCLK] := 0
    
    IMHO, using numbers for pins and the post ~ and ~~ is a recipe for bug generation. I've used the code above in a number of apps. It's flexible, which makes it easy to use, and readable, which makes it easy to debug. "Quick and dirty" is never quick, but always dirty.
  • JonnyMac wrote: »
    As they say here in Hollywood... for your consideration:
    pub shift_out(value, bits, mode)
    
    '' Shift value out via DPIN using SCLK
    '' -- bits is # of bits to shift out
    '' -- mode is 0 for LSBFIRST, !0 for MSBFIRST
    
      if (mode == 0)
        value ><= bits                                               ' reverse bits for LSBFIRST output
    
      value <<= 32 - bits                                            ' move first bit to bit31
    
      repeat bits
        outa[DPIN] := (value <-= 1)                                  ' rotate output bit to bit0
        outa[SCLK] := 1                                              ' clock it
        outa[SCLK] := 0
    

    Thanks JonnyMac, I'll run this on the PST. I did want to make 'sure' the bits were shifting before started thinking about clocking data.
  • Okay, that's easy to check using one extra line of code -- to be removed later. BTW... I ran this with PST and it does in fact work in both modes.
    pub shift_out(value, bits, mode)
    
    '' Shift value out via DPIN using SCLK
    '' -- bits is # of bits to shift out
    '' -- mode is 0 for LSBFIRST, !0 for MSBFIRST
    
      if (mode == 0)
        value ><= bits                                               ' reverse bits for LSBFIRST output
    
      value <<= 32 - bits                                            ' move first bit to bit31
    
      repeat bits
        outa[DPIN] := (value <-= 1)                                  ' rotate output bit to bit0
    
        term.tx("0" + outa[DPIN])                                    ' verification only (remove)
    
        outa[SCLK] := 1                                              ' clock it
        outa[SCLK] := 0
    
  • I think the only issue with your first version is that you're counting from 1 to 9 instead of 0 to 8.

    Counting from 1 to 9 means that you're not getting the lowest bit value, because the smallest shift you use is 1, not 0.
    PUB  READ_BYTE   | idx, bit
    
       dira[1]~~
       dira[2]~~
    
      Test_Byte := %1110010110
         
      repeat idx from 0 to 8
    
        bit := (%1110010110 >> idx) & 1    'the & 1 is used to mask off all bits but the lowest one, just for terminal output
    
        outa[2] := bit
        term.tx( "0" + bit )               'stolen from JonnyMac to help you debug it
    
        waitcnt(clkfreq/4 + cnt)
        outa[2]~     
        waitcnt(clkfreq/4 + cnt)
    
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2015-11-17 01:49
    JasonDorie wrote:
    I think the only issue with your first version is that you're counting from 1 to 9 instead of 0 to 8.
    Jason,

    I think you missed this from lardom's post:

    "The code I've written will read the bits right to left but I had to add another zero to the right."

    I looked at his code and didn't see any major issues, which made me wonder if he had his LED wired correctly.

    -Phil
  • Removing that extra zero and changing the indexing from 0 to 8 instead of 1 to 9 would fix it - that's what I was getting at, though I probably should've changed the example to remove the extra zero on the right. :)
  • This code displays:

    110100111
    110100111

    Mine is the first one, iterating the bits from 0 to 8, without the extra zero on the value. His is the 2nd one, with the extra zero, iterating the bits from 1 to 9.

    PUB  READ_BYTE   | idx, bit, Test_byte
    
      Test_Byte := %111001011
         
      repeat idx from 0 to 8
    
        bit := (Test_Byte >> idx) & 1    'the & 1 is used to mask off all bits but the lowest one, just for terminal output
        dbg.tx( "0" + bit )               'stolen from JonnyMac to help you debug it
    
    
      dbg.tx( 13 )
    
    
      Test_Byte := %1110010110
         
      repeat idx from 1 to 9
    
        bit := (Test_Byte >> idx) & 1    'the & 1 is used to mask off all bits but the lowest one, just for terminal output
        dbg.tx( "0" + bit )               'stolen from JonnyMac to help you debug it
    
  • I hope you guys don't mind me still asking questions eventhough I've been at this for several years. There is still a ton of stuff to learn. Had I known how much fun programming is I would have majored in it.
  • JasonDorie, In this thread I've learned a number of things: I'll consult the Propeller manual tomorrow to read about the ampersand operator. I assumed it was a form of "+".
    I also learned the purpose of 'rotate bits' 'reverse bits' and 'shift bits'. BTW, thanks for the tips on hexadecimal and binary numbers. I'm using both in building the code for my current project.
    One of my questions is does a 32-bit-shift move those bits to a different register?
  • ElectrodudeElectrodude Posts: 1,657
    edited 2015-11-17 05:49
    lardom wrote: »
    One of my questions is does a 32-bit-shift move those bits to a different register?

    In Spin, unless you use an assignment operator (e.g. "x := 2" or "x += 2" or "x >>= 2", as opposed to "x >> 2", which is not an assignment operation), it will never overwrite a value. Shifting a value with the normal ">>" right shift will not overwrite the old value but will only return the shifted result, while the ">>=" right shift will overwrite your value.

    I'm sorry if I misunderstood your question or if I confused you even more with my answer.
  • fridafrida Posts: 155
    edited 2015-11-17 12:49
    My simple solution
    PUB spiOut(out) : in | y
    
        out ><= 8               ' reverse byte
        repeat y from 0 to 7
            outa[clkPin]~~      ' clk pin high
            outa[mosiPin]:= out ' data bit out
            out /= 2            ' rotate right 1
            'waitcnt(cnt + 1000)
            outa[clkPin]~       ' clk pin low
            in *= 2             ' rotate left 1
            in |= ina[misoPin]  ' data bit in
    
  • ErlendErlend Posts: 612
    edited 2015-11-17 13:01
    @lardom
    Before you freak out - bits/2 has the same effect as bits >>1 because we are in the binary system. To compare, in decimal system say 200>>1 has the same effect as 200/10, 10 being the base of decimal, while 2 is being the base of binary.


    Erlend
  • AribaAriba Posts: 2,690
    edited 2015-11-17 14:40
    Erlend wrote: »
    @lardom
    Before you freak out - bits/2 has the same effect as bits >>1 because we are in the binary system. To compare, in decimal system say 200>>1 has the same effect as 200/10, 10 being the base of decimal, while 2 is being the base of binary

    Erlend

    Yes /2 and >>1 are the same, only that a division takes about thousand clock cycles, while the shift takes 4 clock cycles.
    So never do shifts with multiply and division in Spin. C may optimize that to a shift, but Spin does not.

    Andy

    Edit: As I rethink it: /2 and >>1 is not exactly the same, one works with signed numbers the other with unsigned, so /2 and ~>1 is the same.
  • In Spin, unless you use an assignment operator (e.g. "x := 2" or "x += 2" or "x >>= 2", as opposed to "x >> 2", which is not an assignment operation), it will never overwrite a value. Shifting a value with the normal ">>" right shift will not overwrite the old value but will only return the shifted result, while the ">>=" right shift will overwrite your value.
    My reaction to learning that bit of info would be to insert a smiley. I've been reading up on digital flip flops, transistor logic gates etc. Thanks.
    Erlend wrote: »
    @lardom
    Before you freak out - bits/2 has the same effect as bits >>1 because we are in the binary system. To compare, in decimal system say 200>>1 has the same effect as 200/10, 10 being the base of decimal, while 2 is being the base of binary.
    I think >> or << must be faster than division. With this knowledge there will be times when I can avoid having to use a float object. Thank you.

    frida, I'll copy and paste. Thanks.
  • JonnyMacJonnyMac Posts: 9,105
    edited 2015-11-17 19:01
    I think >> or << must be faster than division.

    >> can be used in place of division when divisor is power of 2 (2, 4, 8 16...).

    << can be used in place of multiplication when multiplier is power of 2.

    Instead of
    x := y * 8
    
    you can use:
    x := y << 3
    
    because 8 is 2^3. Same rules apply for dividing by right shifting.

    Additional tip: If you're dividing a signed number that can be negative, there is an operator called SAR that looks like this ~>. This operator will preserve the sign of the value value being divided (>> pads the sign bit end with zeroes for each bit shifted). As Andy pointed out, using shifts for multiplication and division where possible are faster than * and / operators.

  • There's a subtle difference that's typically overlooked:

    1 / 2 = 0 (in integer math)
    -1 / 2 = 0
    1 ~> 1 = 0
    BUT
    -1 ~> 1 = -1

    So, in very specific cases, signed right shift is not the same as divide by two.
  • lardomlardom Posts: 1,659
    edited 2015-11-20 22:23
    JonnyMac and JasonDorie, SAR is not clear to me yet. I need to further study computer architecture as well as transistor representations of logic gates before a lot of stuff makes sense to me. I will learn "~>". It'll require a little work on my part.
    I do now have a working SPI method, mode 0, msb 1st. Thanks to everybody.
  • The difference is actually pretty simple. SHR moves all bits down by N bit positions, shifting in a zero for the vacated top bits. SAR moves all bits down by N bit positions, replicating the current upper-most bit for the vacated top bit positions. If the number is negative, the top bit (bit 31) is 1. If the number is positive (or 0) the upper bit will be 0. For positive numbers, SAR and SHR function identically.
  • JasonDorie wrote:
    For positive numbers, SAR and SHR function identically.
    Just to clarify: For positive signed numbers, SAR and SHR function identically. $ffff_0000 is a positive unsigned number and can be treated as such in Spin, albeit not without going to some trouble.

    My apologies in advance if that seems nitpicky ... :)
    -Phil
  • My apologies in advance if that seems nitpicky ... :)
    -Phil

    'Apologies' from the guy who used Goertzel's algorithm to program the Propeller to respond to spoken words???
Sign In or Register to comment.