Need to flip order of bits MSB to LSB re: MCP23S17


Closed Thread
Results 1 to 9 of 9
  1. #1
    Join Date
    Sep 2006
    Location
    Indiana, USA
    Posts
    72

    Default Need to flip order of bits MSB to LSB re: MCP23S17

    Hello all!

    I am using a couple of MCP23S17's with a PIC18F2320 in order to communicate with a circuit that converts a 24 bit parallel output from the MCP23S17's to a fiber optic signal.

    The fiber signal requires timing that the PIC just cannot do, unfortunately, so a bunch of standard logic does the fast stuff, and the PIC handles feeding values in parallel via the port expanders (MCP23S17's)

    I'm using some code that I borrowed from here: http://www.picbasic.co.uk/forum/cont...P-PBP-MSSP-ASM

    The first variation to be exact. I've modified it to work with my circuit, as it includes two MCP23S17's, one of them only using 8 bits and the other using all 16 bits

    The MCP23S17 that handles 8 bit's of the full 24 bit packet is easy to deal with because the data is pretty much static and each of the 8 bits is handled as an individual, so no problem there.

    The problem is that the other 16 bits need to be handled as a singular WORD for a 16 bit numerical value. It's nice and easy doing math on an integer, etc.

    The way the code example works is that it sends everything to the MCP23S17 MSB first. My value has to be transmitted LSB first!

    So to the code %1000000000000000 looks like "32768" but if I send that, my circuit thinks it's "1"!!!

    So how do I go about reversing the bit order just before I send it on its way to the MCP23S17?

    I already have the PCB made, so I can't simply change my bit order by wiring or I would just do that. Trust me, I already have a "blue wire" or two "fixing" a bug or two, one you'll notice with PORTA.4, so I just shared a line with the other chip select, since the MCP's are hardware addressed anyway.

    The following is test code, far from complete and fraught with other issues to work through.

    Code:
    ' --------------------CHIP FUSES-------------------------------
    
    @ __CONFIG    _CONFIG1H, _HS_OSC_1H & _FSCM_OFF_1H & _IESO_OFF_1H
    @ __CONFIG    _CONFIG2L, _PWRT_OFF_2L & _BOR_OFF_2L
    @ __CONFIG    _CONFIG2H, _WDT_OFF_2H & _WDTPS_1_2H
    @ __CONFIG    _CONFIG4L, _STVR_OFF_4L & _LVP_OFF_4L & _DEBUG_OFF_4L
    @ __CONFIG    _CONFIG3H, _CCP2MX_OFF_3H & _PBAD_DIG_3H & _MCLRE_ON_3H
    
    DEFINE OSC 40
    INTCON = 0
    ADCON1.0 = 1                                     ' Turn off analog inputs
    ADCON1.1 = 1 
    ADCON1.2 = 1 
    ADCON1.3 = 1 
    ADCON0.0 = 0				                   ' Turn off analog converter
    CMCON.0 = 1
    CMCON.1 = 1
    CMCON.2 = 1
    
    
    
    
    
    
    
    
    ' --------------------Ports---------------------------------------
              '76543210          '76543210
     TRISA   = %00000000: PORTA = %00000000 
     TRISB   = %00000011: PORTB = %00000000
     TRISC   = %00000000: PORTC = %00000000
    
    '                         ALIAS & MODIFIERS
    ' ================================================================
      nCSA VAR PORTA.3                                                        
      nCSB var PORTA.4 '- BAD - OPEN COLLECTOR! DO NOT USE
      nRST VAR PORTA.2
      SCLK VAR PORTA.1
      SDO VAR PORTA.0
      xmit Var PORTA.5 
      UPbtn VAR PORTB.0
      DWNbtn VAR PORTB.1
    
    '                        VARIABLES & COSTANTS
    ' ================================================================
     MCP23A CON $42    'Register address to MCP23S17 Config
     MCP23B CON $40    'Register address to MCP23S17 PortA(1)
     IOCON  CON $0A    'Register address to MCP23S17 Config
     IODIRA CON $00    'Register address to MCP23S17 PortA(1)
     IODIRB CON $01    'Register address to MCP23S17 PortB(2)
     GPIOA  CON $12    'Register address to MCP23S17 GPIOA(1)
     GPIOB  CON $13    'Register address to MCP23S17 GPIOB(2)
     OLATA  CON $14    'Register address to MCP23S17 LATA(1)
     OLATB  CON $15    'Register address to MCP23S17 LATB(2)
     
      
     DataOut var BYTE
     Voltage VAR WORD   'Variable for manipulating Voltage as full 16 bit word
     VoltageFst VAR Voltage.BYTE0 'Variable for Voltage Byte 0 to Send to MCP23S17A-A
     VoltageSec VAR Voltage.BYTE1 'Variable for Voltage Byte 1 to Send to MCP23S17A-B
     Param Var BYTE     'Variable for Parameters Byte to Send to MCP23S17B-A
     RD VAR Param.0     'Varible to set read bit on IP Board - 0 = Read
     WR VAR Param.1     'Varible to set write bit on IP Board - 1 = Write
     O4 VAR Param.2     'Varible unused 4
     RY VAR Param.3     'Varible to set Relay bit on IP Board - 1 = Relay Pulled
     O3 VAR Param.4     'Varible unused 3
     O2 VAR Param.5     'Varible unused 2
     CH1 VAR Param.6    'Varible bit 0 of ADC channel select 
     CH0 VAR Param.7    'Varible bit 1 of ADC channel select
     AuxPort Var BYTE   'Variable for Aux Port Byte to Send to the MCP23S17B-B 
     UPbtnvar Var BYTE  'Variable for UP Button
     DWNbtnvar VAR BYTE 'Variable for DOWN Button
     MCPReg  VAR BYTE   'Variable for the Register to Send to the MCP23S17
     MCPWRT var BYTE   'Command o write in MCP23S17 Address $00
     MCPRED var BYTE   'Command o read from MCP23S17 Address $00 
    '                             INIT  
    ' ================================================================
        UPbtnvar = 0
        DWNbtnvar = 0 
        
        ncsa = 1
        'ncsb = 1
        nRST = 0                'Reset the port expanders
        PAUSE 1
        nRST = 1
        
        MCPReg = IOCON          'Configures MCP23S17-A
        DataOut = $28
        nCSA = 0                'Enable MCP23S17-A
        SHIFTOUT SDO, SCLK, 1, [MCP23A,MCPReg,DataOut]        
        nCSA = 1                'Disable MCP23S17-A
        
        MCPReg = IODIRA         'Configures PortA(1) All Output
        DataOut = $00
        nCSA = 0                'Enable MCP23S17-A
        SHIFTOUT SDO, SCLK, 1, [MCP23A,MCPReg,DataOut]        
        nCSA = 1                'Disable MCP23S17-A
        
        MCPReg = IODIRB         'Configures PortB(2) All Output
        DataOut = $00
        nCSA = 0                'Enable MCP23S17-A
        SHIFTOUT SDO, SCLK, 1, [MCP23A,MCPReg,DataOut]        
        nCSA = 1                'Disable MCP23S17-A 
        
        MCPReg = IOCON          'Configures the MCP23S17
        DataOut = $28
        nCSA = 0                'Enable MCP23S17-B
        SHIFTOUT SDO, SCLK, 1, [MCP23B,MCPReg,DataOut]        
        nCSA = 1                'Disable the MCP23S17
        
        MCPReg = IODIRA         'Configures PortA(1) All Output
        DataOut = $00
        nCSA = 0                'Enable MCP23S17-B
        SHIFTOUT SDO, SCLK, 1, [MCP23B,MCPReg,DataOut]        
        nCSA = 1                'Disable the MCP23S17
        
        MCPReg = IODIRB         'Configures PortB(2) All Output
        DataOut = $00
        nCSA = 0                'Enable MCP23S17-B
        SHIFTOUT SDO, SCLK, 1, [MCP23B,MCPReg,DataOut]        
        nCSA = 1                'Disable the MCP23S17      
    
        AuxPort = %00000000 
        GOSUB SEND_AuxPort              
    
                          '               _
                          ' |CH|--|RY|-|W|R
        Param = %00001010 '  00 00  1 0 1 0
        GOSUB SEND_Param
        
        Voltage = 0
        GOSUB SEND_Voltage
    '                            MAIN LOOP
    ' ===============================================================
    
    MAIN:
    
    BUTTON DWNbtn,1,255,255,DWNbtnvar,1,BtnDwn
    
    BUTTON UPbtn,1,255,255,UPbtnvar,1,BtnUp
    
    GOSUB Transmit
        
    GOTO MAIN
    
    '                              SUB - ROTINES
    ' ================================================================    
    BtnUp:
        
        IF Voltage >= 65535 THEN
        gOTO MAIN
        ENDIF
        Voltage = (Voltage + 1)
        GOSUB SEND_Voltage
       'pause 50
    GOTO MAIN
    
    BtnDwn:
    
        IF Voltage = 0 THEN
        GOTO MAIN
        ENDIF
        Voltage = (Voltage - 1)
        GOSUB SEND_Voltage
       'pause 50
    GOTO MAIN
    
    Transmit:
        xmit = 1
        PAUSEUS 1
        xmit = 0
    pause 50
    RETURN
    
    SEND_Voltage:
    
         Voltage = Voltage REV 16
    
        nCSA = 0                'Enable MCP23S17-A
        SHIFTOUT SDO, SCLK, 1, [MCP23A,OLATA,VoltageFst]        
        nCSA = 1                'Disable the MCP23S17
        pause 1
        nCSA = 0                'Enable MCP23S17-A
        SHIFTOUT SDO, SCLK, 1, [MCP23A,OLATB,VoltageSec]        
        nCSA = 1                'Disable the MCP23S17
    RETURN
    
    SEND_Param:
        nCSA = 0                'Enable MCP23S17-B
        SHIFTOUT SDO, SCLK, 1, [MCP23B,OLATA,Param]        
        nCSA = 1                'Disable the MCP23S17
    RETURN
    
    SEND_AuxPort:
        nCSA = 0                'Enable MCP23S17-B
        SHIFTOUT SDO, SCLK, 1, [MCP23B,OLATB,Auxport]        
        nCSA = 1                'Disable the MCP23S17
    RETURN
    
    goto main
    
    END

  2. #2
    Join Date
    Aug 2003
    Posts
    985


    Did you find this post helpful? Yes | No

    Default Re: Need to flip order of bits MSB to LSB re: MCP23S17

    Can’t you reverse the same 16 bits again to look at the correct value?

  3. #3
    Join Date
    Aug 2003
    Posts
    985


    Did you find this post helpful? Yes | No

    Default Re: Need to flip order of bits MSB to LSB re: MCP23S17

    I see.. you don’t know if it’s reversed because you aren’t tracking if it’s been reversed or not.
    It would only take one more bit as a flag for if reversed or not, but I would copy to useless variable to send.
    Code:
    useless var word ‘ don’t use for anything other than sending
    
        IF Voltage = 0 THEN
        GOTO MAIN
        ENDIF
        Voltage = (Voltage - 1)
    
        useless = Voltage REV 16
        GOSUB SEND_useless
    
       'pause 50
    GOTO MAIN

  4. #4
    Join Date
    Sep 2006
    Location
    Indiana, USA
    Posts
    72


    Did you find this post helpful? Yes | No

    Default Re: Need to flip order of bits MSB to LSB re: MCP23S17

    I have an o'scope on the fiber transmitter and say I want the fiber signal to look like this (in ones and zeros, the fiber signal is actually two different widths to represent 1 or 0):

    000000000000000101010000 - that is 24 bits, the last eight to the right are OK because they are the 8 from the MCP23S17 that is just static setup data and I can handle those... and they are on the proper side of the string and in the proper order. so no problem with those. BUT....

    The first 16 bits are: 0000000000000001 - Decimal "1"

    Well, if I use my code to send those 16 bits - the fiber output ends up looking more like this: 100000000000000001010000 - The first 16 bits are opposite of what I need! They equal decimal "32768"

    Far from the "1" I was expecting!

    It's actually worse than that, because the MCP23S17 is not acting like a 16 bit device, but rather as two 8 bit devices... hence the splitting of "Voltage" into two bytes. But I think I just need to configure the MCP23S17 correctly for 16 bit mode, as soon as I wrap my brain around its datasheet.

    But I still need to know how to send just the 16 bit WORD "Voltage" in my code LSB first, without having to do crazy math every time I work with the variable in my MAIN loop

    I tried the operator "REV" and it doesn't seem to work as expected.

    I think the MCP23S17 must have it's data fed to it MSB first, but my variable has to go LSB first!

    I wonder if I could just get away with this? :

    Code:
    nCSA = 0                'Enable MCP23S17-A
        SHIFTOUT SDO, SCLK, 1, [MCP23A,OLATA]   ' i.e. SHIFTOUT SDO, SCLK, MSB,[MCP23A,OLATA]    
        SHIFTOUT SDO, SCLK, 0, [VoltageFst]     ' i.e. SHIFTOUT SDO, SCLK, LSB,[VoltageFst]    
        nCSA = 1                'Disable the MCP23S17
        pause 1
        nCSA = 0                'Enable MCP23S17-A
        SHIFTOUT SDO, SCLK, 1, [MCP23A,OLATB]   ' i.e. SHIFTOUT SDO, SCLK, MSB,[MCP23A,OLATB]
        SHIFTOUT SDO, SCLK, 0, [VoltageSec]     ' i.e. SHIFTOUT SDO, SCLK, LSB,[VoltageSec]         
        nCSA = 1                'Disable the MCP23S17
    RETURN

  5. #5
    Join Date
    Aug 2003
    Posts
    985


    Did you find this post helpful? Yes | No

    Default Re: Need to flip order of bits MSB to LSB re: MCP23S17

    Using two bytes (PBP alias) I don’t think costs you any time even behind the scenes,
    and then just addressing them in the order you want would be the next best thing to swapping the hardware.
    I’m not familiar with the device, but if REV didn’t work as you expected, it sound like swapping bytes was the solution?

    If that’s wrong, and it’s back to reversing bits, there’s no math to do it,
    it’s always whacky procedural code emulating what a Human would do.
    You can use the above method first (almost free), and then logical operators,
    but it’s essentially the same goal as moving a ball around a table with paper cups.

  6. #6
    Join Date
    Aug 2003
    Posts
    985


    Did you find this post helpful? Yes | No

    Default Re: Need to flip order of bits MSB to LSB re: MCP23S17

    I’ve got to do it this weekend, and don’t get to use REV, so this is what I came up with (untested).
    There’s another thread about REV somewhere.. it was decompiled to find out instruction time,
    and I don’t know right now If I’m beating it.

    Code:
    sixteenbit var word
    revsixteen var word
    
    leasteight var sixteenbit.byte0
    mosteight var sixteenbit.byte1
    leastrev var revsixteen.byte0
    mostrev var revsixteen.byte1
    
    count var byte
    
    
    reversesixteen:
    
    for count = 0 to 7
    
    leastrev.bit7 = mosteight.bit0
    mosteight << 1
    leastrev >> 1
    
    mostrev.bit7 = leasteight.bit0
    leasteight << 1
    mostrev >> 1
    
    next count
    
    return

  7. #7
    Join Date
    Jan 2013
    Location
    Texas USA
    Posts
    229


    Did you find this post helpful? Yes | No

    Default Re: Need to flip order of bits MSB to LSB re: MCP23S17

    I tried the operator "REV" and it doesn't seem to work as expected.
    The following snippit displays what I would expect.

    Code:
    myWord var word
    myTest var word
    
    
        Low PORTE.2       ' LCD R/W low = write
        Pause 10         ' Wait for LCD to startup
    
    main:
       lcdout $fe, 1
       pause 1000
       myWord = $1
       myTest = myWord rev 16
    
       lcdout $fe, $80, ihex4 myWord, ":",ihex4 myTest," ","W:T"    'Store reversed value in separate var
       
       myWord = $8000
       myTest = myWord rev 16
       
       lcdout $fe, $c0, ihex4 myWord,":",ihex4 myTest," ","W:T"    'Store reversed value in separate var
       
       pause 1000
       lcdout $fe, 1
      
       myWord = $1
       lcdout $fe, $80, ihex4 myWord, ":"
       myWord = myWord rev 16
       lcdout $fe, $80+6, ihex4 myWord, " ", "W:W"    'Store reversed value in same var
    
       pause 1000
       myWord = $8000
       lcdout $fe, $c0, ihex4 myWord, ":"
       myWord = myWord rev 16
       lcdout $fe, $c0+6, ihex4 myWord, " ", "W:W"    'Store reversed value in same var
       
       pause 1000
        goto main
    Display
    Name:  Screen1.png
Views: 534
Size:  10.4 KB
    Name:  Screen2.png
Views: 506
Size:  12.4 KB

    Also, I think you are right in that you should be able to use the " SHIFTOUT SDO, SCLK, 0, [VoltageFst]"
    Regards,
    TABSoft

  8. #8
    Join Date
    Aug 2011
    Posts
    408


    Did you find this post helpful? Yes | No

    Default Re: Need to flip order of bits MSB to LSB re: MCP23S17

    Here's a few tips

    First off, don't REV anything. That's only going to confuse the issue.

    The MCP23S17 expects the bytes to be sent MSB first, that is the first bit clocked out appears at GPx7 and the last bit appears at GPx0.
    That's what you should get if you specify MSBFIRST in the SHIFTOUT instruction
    Code:
    SHIFTOUT SDO, SCLK, 1, [databyte]
    If you need to reverse the bits at the output port, then specify LSBFIRST in the SHIFTOUT instruction
    Code:
    SHIFTOUT SDO, SCLK, 0, [databyte]

    Now, on to the ordering of bytes. When you have a word declaration like
    Code:
     Voltage VAR WORD
     VoltageFst VAR Voltage.BYTE0 'this is the lower byte of the word
     VoltageSec VAR Voltage.BYTE1 'this is the upper byte of the word
    
     Voltage = $8001
    That would give you VoltageFst = $01, and VoltageSec = $80


    So, if you used your send routine with those values
    Code:
    nCSA = 0                'Enable MCP23S17-A
        SHIFTOUT SDO, SCLK, 1, [MCP23A,OLATA]   ' i.e. SHIFTOUT SDO, SCLK, MSB,[MCP23A,OLATA]    
        SHIFTOUT SDO, SCLK, 0, [VoltageFst]     ' i.e. SHIFTOUT SDO, SCLK, LSB,[VoltageFst]    
        nCSA = 1                'Disable the MCP23S17
        pause 1
        nCSA = 0                'Enable MCP23S17-A
        SHIFTOUT SDO, SCLK, 1, [MCP23A,OLATB]   ' i.e. SHIFTOUT SDO, SCLK, MSB,[MCP23A,OLATB]
        SHIFTOUT SDO, SCLK, 0, [VoltageSec]     ' i.e. SHIFTOUT SDO, SCLK, LSB,[VoltageSec]         
        nCSA = 1                'Disable the MCP23S17
    RETURN
    You end up with:
    OLATA7:OLATA0 = $80 ' VoltageFst is $01, but was sent out LSB first so it swapped order
    OLATB7:OLATB0 = $01 ' VoltageSec is $80, but was sent out LSB first so it swapped order

    If that's not what you need then you'll either have to send VoltageFst to OLATB/VoltageSec to OLATA to swap the bytes,
    and/or use MSB in the SHIFTOUT instruction, but that depends on exactly how the output ports are connected to the fiber interface.

    In your case I wouldn't bother with trying to using 16-bit mode with the MCP23S17, at least not right now. That'll change all of the
    register mapping addresses and likely confuse things even more. 16-bit mode can be faster, but since you're using SHIFTOUT instead
    of the hardware MSSP it's already slow.

  9. #9
    Join Date
    Sep 2006
    Location
    Indiana, USA
    Posts
    72


    Did you find this post helpful? Yes | No

    Default Re: Need to flip order of bits MSB to LSB re: MCP23S17

    Awesome stuff guys!

    Yes, when I got in and tried the thought that I had of just clocking in the set up register stuff first:

    Code:
    nCSA = 0                'Enable MCP23S17-A
        SHIFTOUT SDO, SCLK, 1, [MCP23A,OLATA]   ' i.e. SHIFTOUT SDO, SCLK, MSB,[MCP23A,OLATA]    
        SHIFTOUT SDO, SCLK, 0, [VoltageFst]     ' i.e. SHIFTOUT SDO, SCLK, LSB,[VoltageFst]    
        nCSA = 1                'Disable the MCP23S17
    It worked just like Tabsoft and Tumbleweed both surmised (or tested!) and yes, the byte order was wrong as well, so I just swapped the two alias bytes:

    Code:
        nCSA = 0                'Enable MCP23S17-A
        SHIFTOUT SDO, SCLK, 1, [MCP23A,OLATA]
        SHIFTOUT SDO, SCLK, 0, [VoltageSec]
        nCSA = 1                'Disable the MCP23S17
        pause 1
        nCSA = 0                'Enable MCP23S17-A
        SHIFTOUT SDO, SCLK, 1, [MCP23A,OLATB]
        SHIFTOUT SDO, SCLK, 0, [VoltageFst]        
        nCSA = 1                'Disable the MCP23S17
    And that gave me the full picture!

    So yay for my tired little brain at least showing some spark of life there with my hunch! Sometimes it's just good to put stuff up here to get the right thought patterns going.

    And thank all of you for helping to fill in the blanks! You guys rock!

    Now to get to tackling all the other stuff this thing needs to do.

    Like I posted above, the PIC is handling a setup byte and then a 16 bit value that ends up setting a 16 bit DAC at the other end of a fiber optic link. The card my circuit is talking to is an OEM ADC/DAC card that uses two pulse widths to represent a one or zero. The widths are tight and the entire pulse train is pretty narrow, so the PIC couldn't begin to help with that. So its a mess of shift registers and one-shot chips that do the critical timing, the PIC presents the full 24 bits to a string of parallel shift registers via the MCP23S17's and sends an enable pulse to transmit when everything is set.

    I'm working on another card that does the RX side by turning the pulse widths back into parallel data, and then I'll read them with a MCP23S17 again. Just 16 bits on the return.

    I'll likely end up redoing the board for the send side since it's got some "blue wires" going on, and the fact it requires some trickery in code to map everything just right. But at least I can do some more debugging with it now.

    My major mistake was the fact that I breadboarded the digital logic circuitry to figure that all out and never bothered to do the PIC stuff on there as well!!!

    I've learned my lesson!

    Thanks again guys! You are a wealth of knowledge and way more help than anyone could hope for!

Similar Threads

  1. shiftin with \bits - What order do they come?
    By tbarania in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 3rd April 2015, 05:39
  2. MSB Compile error
    By RFEFX in forum PBP3
    Replies: 2
    Last Post: - 26th January 2015, 07:32
  3. Replies: 2
    Last Post: - 23rd April 2013, 17:34
  4. Toggled Pic flip flop Help Please
    By g7jiq in forum General
    Replies: 2
    Last Post: - 22nd March 2009, 11:09
  5. Flip Flop
    By tazntex in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 13th November 2008, 21:53

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts