Shop OBEX P1 Docs P2 Docs Learn Events
mcp23017 (i2c) example code? — Parallax Forums

mcp23017 (i2c) example code?

mparkmpark Posts: 1,305
edited 2013-07-26 09:11 in Propeller 1
Does anyone have some mcp23017 code I can look at? It's getting late and the datasheet is becoming blurry.
Maybe tomorrow I'll wake up and find that some kind soul has posted some code to get me started.
Being inexperienced in the ways of i2c, I just need to be pointed in the right direction.

Comments

  • nutsonnutson Posts: 242
    edited 2008-11-12 15:15
    There is MCP23016 code included in one of the OBEX modules, one of the early IIC drivers had a demo program with coding examples for several different devices. Don't remember which one though....
  • dMajodMajo Posts: 855
    edited 2008-11-12 15:44
    nutson said...
    There is MCP23016 code included in one of the OBEX modules, one of the early IIC drivers had a demo program with coding examples for several different devices. Don't remember which one though....
    I2CObject V2.1
  • mparkmpark Posts: 1,305
    edited 2008-11-12 16:01
    Thanks, I did look at that, but from the datasheets I got the impression that the 016 and 017 were quite different. The 016 datasheet talks about "command bytes" and the 017 says "register addresses". Are they just different names for the same thing??
  • dMajodMajo Posts: 855
    edited 2008-11-12 18:19
    mpark said...
    Thanks, I did look at that, but from the datasheets I got the impression that the 016 and 017 were quite different.············································· YES
    The 016 datasheet talks about "command bytes" and the 017 says "register addresses". Are they just different names for the same thing??········ YES
    I have given a glance to the datasheets and you are right. The 17 is and "advanced" version ?!? You have the same registers than on 16 (and some others more) but with different addresses so you will need to adapt the 16 driver for 17 operation. The ones with the same name (table 1.5 on both) have the same function.
  • mparkmpark Posts: 1,305
    edited 2008-11-12 19:10
    Thank you!
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-11-02 05:28
    Sorry to resurrect an old thread, but I am also wondering if there is any code for the MCP23017 (I2C) chip?

    A search in the Obex search for MCP23017 comes up blank, as does a number of other searches for chips like this (including the SPI variants).

    Spin or Pasm or both would be fine. Searches on Google come up with Duane Johnson's Femtobasic driver but Spin/Pasm would be better!

    mpark - did you end up getting some code working?

    I'm not looking to use every feature on these chips - in fact all I really want to do is either output some bytes, or input some bytes. I'm intrigued by this chip as it can share the I2C bus which is already used by the eeprom, and hence effectively it can give you more I/O pins on the propeller without actually using any more propeller pins. Cunning!

    Any help would be most appreciated.
  • Ron CzapalaRon Czapala Posts: 2,418
    edited 2011-11-02 06:38
    I don't have any Propeller code but I do have some BS2px code which should be pretty simple to convert to SPIN...
  • JonnyMacJonnyMac Posts: 9,107
    edited 2011-11-02 10:55
    I'm using that chip in a project now; this should help.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-11-02 23:53
    Thanks guys. Just what I need!
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2013-07-26 05:43
    A very belated second thankyou to JonnyMac here - I have just got his code working and it is perfect. I initially was using some MCP23106 code and MCP23017 chips and there is a subtle difference between the chips as they have different registers. So if you use MCP23016 code on MCP23017 chips and try to output some bits, the logic Low's are correct, and the logic High's come out as HiZ. Confusing.

    Simple answer - use Jonny Mac's code which works perfectly. Is this one maybe for the Obex?

    Addit - a little demo using two MCP23017 chips. These are $1.20 each at Futurlec, so for $2.40 you can have another 32 I/O pins for the propeller chip.
    PUB MCP23017_Out_Long(n) ' send out a long to two MCP23017 chips
    ' chips share the I2c bus with the eeprom. Pin 18 reset high, pin 19 and 20 = NC, A0-1-2 on first chip all low
    ' and on second chip A0 is high. The chips can be run from 3 or 5V (useful for level translation)
    ' gives a propeller another 32 input and output pins. Futurlec sell these chips for $1.20. DIP28 narrow package.
    ' if using sockets and can't source 28 pin sockets, use two 14 pin ones. 
    ' use johnny macs code, the io codes are different for the 23016 and 23017
      mcp23017.start(i2cSCL,i2cSDA,%000)                    ' clock, data, address of chip (2 chips, either 000 or 001)   
      mcp23017.cfg_dira(%00000000)                          ' 0 = output, 1=input
      mcp23017.wr_gpioa(n & %11111111)                      ' output low byte 
      mcp23017.cfg_dirb(%00000000)                          ' 0 = output, 1=input
      mcp23017.wr_gpiob(n >> 8)                             ' second lowest byte
      mcp23017.stop                                         ' stop this chip
      mcp23017.start(i2cSCL,i2cSDA,%001)                    ' clock, data, address of second chip   
      mcp23017.cfg_dira(%00000000)                          ' 0 = output, 1=input
      mcp23017.wr_gpioa(n >> 16)                            ' output second high byte
      mcp23017.cfg_dirb(%00000000)                          ' 0 = output, 1=input
      mcp23017.wr_gpiob(n >> 24)                            ' output high byte
      mcp23017.stop 
    
  • fixmaxfixmax Posts: 91
    edited 2013-07-26 07:08
    This was a big help to me also. Thanks for the object. One thing I would suggest if this object is posted to the OBEX, is to include additional PUBs for some of the other features of the chip that may be desired in a project. I used interrupt on change and added some of these missing items to his existing object. I have attached the extra code I added below:

    the object itself:
    pub cfg_iocon(outbits)
    
    '' Write value to IOCON
    
      i2c.start
      i2c.write(slaveid)
      i2c.write(IOCON)
      i2c.write(outbits)
      i2c.stop
    
    pub cfg_gpinta(outbits)
    
    '' Write value to GPINTENA
    
      i2c.start
      i2c.write(slaveid)
      i2c.write(GPINTENA)
      i2c.write(outbits)
      i2c.stop
    
    pub cfg_gpintb(outbits)
    
    '' Write value to GPINTENB
    
      i2c.start
      i2c.write(slaveid)
      i2c.write(GPINTENB)
      i2c.write(outbits)
      i2c.stop
    

    Here is my test code to run it with int on change.
    ''This code block uses a modified version of Jon "JonnyMac" McPhalen's MCP23017 object
        -added cfg_iocon, cfg_gpinta and cfg_gpintb
    
    OBJ
    
      mcp1 : "jm_mcp23017_2"
      mcp2 : "jm_mcp23017_2"
    
    CON
    
      _clkmode        = xtal1 + pll16x           ' Feedback and PLL multiplier
      _xinfreq        = 5_000_000                ' External oscillator = 5 MHz
    
    VAR
      long temp
    
    PUB Main                                      ' Main method
      dira[2]:=0                                  'set address port to input
      dira[3]:=1                                  'set address port to output
    
    ' Setup Chip 1
      mcp1.start(0,1,0)                           ' scl=0, sda=1, address=0
      mcp1.cfg_iocon(%0100_0100)                  ' turn on open drain ints, and mirroring
      mcp1.cfg_gpintb(%1111_1111)                 ' turn on int on change for pina 0-7 on portb
    
      mcp1.cfg_dira(0)                            ' group a configure for outputs
      mcp1.cfg_pola(0)                            ' group a normal polarity
      mcp1.cfg_pua(1)                             ' group a pullup enabled
      mcp1.cfg_dirb(1)                            ' group b configure for inputs
      mcp1.cfg_polb(1)                            ' group b normal polarity 0=normal, 1=inverted
      mcp1.cfg_pub(1)                             ' group b pullup enabled
      
    ' Setup Chip 2
      mcp2.start(0,1,1)                           ' scl=0, sda=1, address=0
      mcp2.cfg_iocon(%0100_0100)                  ' turn on open drain ints, and mirroring
      mcp2.cfg_gpintb(%1111_1111)                 ' turn on int on change for pina 0-7 on portb
    
      mcp2.cfg_dira(0)                            ' group a configure for outputs
      mcp2.cfg_pola(0)                            ' group a normal polarity
      mcp2.cfg_pua(1)                             ' group a pullup enabled
      mcp2.cfg_dirb(1)                            ' group b configure for inputs
      mcp2.cfg_polb(1)                            ' group b normal polarity 0=normal, 1=inverted
      mcp2.cfg_pub(1)                             ' group b pullup enabled
       
     repeat                                       ' Endless loop
        temp:=ina[2]
        if temp==0
           mcp1.wr_gpioa(mcp1.rd_gpiob)              ' read input and send to output
           mcp2.wr_gpioa(mcp2.rd_gpiob)              ' read input and send to output
           outa[3]:=1
           waitcnt(clkfreq / 10 + cnt)   
        else
           outa[3]:=0
    

    The test code used a circuit with two MCP23017's on a PPDB. Each MCP23017 had port B set up as in input with port A set up as an output. I used a pushbutton switch on the board for the input, and a LED on the board for the output. I used the interrupt pin bussed off of both MCP23017's to trigger the reads and writes to the chips. This keeps from having to poll continuously and tie up the I2C port with messages. Finally, I just had an LED to turn on with the interrupt so that I could see that. This circuit is not really practical (although it may be), but I wanted to use all the features of the chips. It also may be handy to have each chip capable of 8 inputs and 8 outputs, versus having to have one chip as an input and one as an output.

    Again, thanks for the object, this was a great help. Hopefully this code may help someone else use them as well.
  • TtailspinTtailspin Posts: 1,326
    edited 2013-07-26 09:11
    Jon "JonnyMac" McPhalen (aka Jon Williams) and Spin make it easy...:thumb:
    {MCP23017 16bit general purpose I/O expander                             
                                ┌──────┬┬─────┐
                        GPB0─[│1          28│]─GPA7
                        GPB1─[│2          27│]─GPA6
                        GPB2─[│3          26│]─GPA5
                        GPB3─[│4     M    25│]─GPA4
                        GPB4─[│5     C    24│]─GPA3
                        GPB5─[│6     P    23│]─GPA2
                        GPB6─[│7     2    22│]─GPA1
                        GPB7─[│8     3    21│]─GPA0
                         VDD──[│9     0    20│]──INTA
                         VSS──[│10    1    19│]──INTB
                          NC───[│11    7    18│]──RESET (active low)
                         SCL──[│12         17│]──A2 
                         SDA─[│13         16│]──A1 ─(I2C address pins)
                          NC───[│14         15│]──A0 
                                └─────────────┘     
    
    
    }
    CON
    
    
            _clkmode = xtal1 + pll16x                     'Standard clock mode * crystal frequency = 80 MHz
            _xinfreq = 5_000_000
    
    
    
    
      SCL = 0                                             ' Connect to propeller pin 0
      SDA = 1                                             ' Connect to propeller pin 1
    
    
    '               A2 A1 A0<<<(I2C address pins)must be Biased to VSS="0" or VDD="1"
    '                &#9492;&#9488;&#9474;&#9484;&#9496;
      MCP_ID = 00_0011                                ' I2C address for MCP23017 
                      
             
    VAR
      
      byte  Abits
      byte  Ainbits
      byte  Bbits
      byte  Binbits
      
    OBJ
    
    
            GPIO : "jm_mcp23017"
      
    PUB Init | counter, count
    
    
        GPIO.start(SCL,SDA,MCP_ID)    
        waitcnt(clkfreq / 2 + cnt)
    
    
        'All_Output
        HalfIn_HalfOut
        
    PUB All_Output
         
        GPIO.cfg_dira(00_0000)        ' Configure all eight pins of PortA to output.
        GPIO.cfg_dirb(00_0000)        ' Configure all eight pins of PortB to output. 
        
        Abits := 01_0101              ' Set PortA bit pattern
        Bbits := 01_0101              ' Set PortB bit pattern
        
      repeat    
        GPIO.wr_gpioa(Abits)             ' Write eight bits to PortA
        GPIO.wr_gpiob(Bbits)             ' Write eight bits to PortB
    
    
        waitcnt(clkfreq / 2 + cnt)
    
    
        GPIO.wr_gpioa(!Abits)            ' Flip bits with Not(!)
        GPIO.wr_gpiob(!Bbits)
        
        waitcnt(clkfreq / 2 + cnt)
    
    
    PUB HalfIn_HalfOut
    
    
        GPIO.cfg_dira(11_1111)        ' Configure all eight pins of PortA to inputs.
        GPIO.cfg_dirb(00_0000)        ' Configure all eight pins of PortB to output.
         
        GPIO.cfg_pola(11_1111)        ' Invert Polarity of all eight pins of PortA  
                                         ' ( for Pull_up resistors on PPDB push buttons.)
                                         
      repeat
        Ainbits := GPIO.rd_gpioa         ' Read the eight bits from PortA into the Ainbits variable
        GPIO.wr_gpiob(Ainbits)           ' Write the eight bit Ainbits variable to PortB
        
        waitcnt(clkfreq / 16 + cnt)
    
    
    
    EDIT: it's amazing what the forum software can do to code...don't cut and paste the above, unless you add the percent signs and missing zeros.. sigh...
    I like the MCP23017, seems like it will be handy for reading switches and such.
    Purchased from the 'OldBitCollector'( http://www.propellerpowered.us/) himself.

    They are large, and do take some real estate investment...:smile:
    MCP23017_setup.jpg


    Thanks for sharing your code fixmax,

    MCP23017_Demo_MyWay - Archive [Date 2013.07.26 Time 09.34].zip

    -Tommy
Sign In or Register to comment.