I2C and MCP23016


Closed Thread
Results 1 to 20 of 20
  1. #1

    Default I2C and MCP23016

    Hi!

    Searched around the forum but did not found a solution to my problem.

    This is what I have:
    One MCP23016 connected to PIC18F4550 via I2C.
    Pins A0,A1,A2,Vss1,Vss2 and Vss3 grounded, TP flouting...
    CLK connected to +5V with 3k9 resistor and 33pF to gnd.
    I2C pulled up with two 2k2 resistors.

    Can read and write a I2C EEPROM with I2CREAD and I2CWRITE without problems, so I think the problem is solely on the MPC23016 side.

    I'm first trying only to use half of it, that is only P1 now.
    The pins on P1 are pulled up with 10k each.

    The code is like this:
    1)
    DEFINE i2c_hold 1
    deviceIO con $40 ' MCP23016 address
    GP0 con $00 ' port GP0 all in
    GP1 con $01 ' port GP1 all in
    OLAT0 con $02 ' Output latch register
    OLAT1 con $03 '
    IPOL0 con $04 ' input polarity normal, not inverted
    IPOL1 con $05 '
    IODIR0 con $06 ' all in = 1
    IODIR1 con $07 ' 00111011 down=0,up=1,valoT=3,valoE=4,On/Off=5
    INTCAP1 con $09 ' read-only, Interrupt Captured Value
    INTCAPbyte var byte ' interrupt capture reg for buttons
    IOCON1 con $0b '
    I2Cbyte var byte
    IOEbyte var byte

    2)
    I2Creg = OLAT1 : I2Cbyte = $ff : gosub writeIOExtender: pause 20
    I2Creg = IODIR1 : I2Cbyte = $7f : gosub writeIOExtender: pause 20
    I2Creg = GP1 : I2Cbyte = $7f : gosub writeIOExtender: pause 20

    3)
    I2Creg = GP1 : gosub readIOExtender' to IOEbyte
    LCDOUT HEX2 IOEbyte

    4)
    writeIOExtender:
    i2cdevice = deviceIO
    I2CWrite SDA,SCL,i2cdevice,I2Creg,[i2cbyte],error
    return'from writeIOExtender
    '--------------------------------------------------
    readIOExtender: ' to IOEbyte
    i2cdevice = deviceIO
    I2Cread SDA,SCL, i2cdevice,I2Creg,[IOEbyte],error
    return'from readIOExtender

    You can read back every register except one (INTCAP). I do not know what fails, read or write or perhaps both, but I do not get back what I wrote, so I do not know which one fails, read or write?

    And as you can guess, buttons on GP1 does not com through

    It seems not to have any effect which one is first (2), OLAT1, IODIR1 or GP1?
    I have also the error trap if no ack received (NAK) but it jumps not there!

    Can anyone see what is wrong?... Thank you in advance ...

  2. #2
    Join Date
    Oct 2007
    Location
    The Netherlands
    Posts
    45


    Did you find this post helpful? Yes | No

    Default

    I could get the MCP23016 to work reliably only by removing the timing capacitor (33pF) all together.

  3. #3


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by eggman View Post
    I could get the MCP23016 to work reliably only by removing the timing capacitor (33pF) all together.
    Thanks Eggman!

    When I removed that capacitor the program goes to the error-label, so that does not solve my problem
    I soldered a new 33pF on the PCB and got rid of the error label jump but the original problem remains...

    I'm puzzled, I do not know what I should try next!

    Any other suggestions?

  4. #4
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Since you are using an 18F4550, it means you are using MPASM as the assembler.
    So, DEFINE i2c_hold 1 needs to be Uppercase.

    You can read back every register except one (INTCAP). I do not know what fails, read or write
    Not sure what you mean here. The INTCAP? registers are read-only.

    Also not sure what you are trying to do with the port.
    You write all 1's to the output latch OLAT1, then set all but 1 pin to input IODIR1, then write to GP1 which actually writes to OLAT1 again. Doesn't make sense.

    What is it you're trying to do, and what's not working.
    DT

  5. #5


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Darrel Taylor View Post
    Since you are using an 18F4550, it means you are using MPASM as the assembler.
    So, DEFINE i2c_hold 1 needs to be Uppercase.

    Not sure what you mean here. The INTCAP? registers are read-only.

    Also not sure what you are trying to do with the port.
    You write all 1's to the output latch OLAT1, then set all but 1 pin to input IODIR1, then write to GP1 which actually writes to OLAT1 again. Doesn't make sense.

    What is it you're trying to do, and what's not working.
    Thank you Darrel!

    I changed it, so now I have DEFINE I2C_HOLD 1...
    but that did not change anything.

    With INTCAP I just wanted to say that it is the only register that is read-only, besides it was kind of irrelevant from me to mention that in the first place

    The final goal is to use the device as an input extender, that is only inputs. However, one should also be able to read and write all registers, except one. Nothing seems to work, as earlier told, I can't tell if it is the write or read that fails. I have tried all kind of values and also changing the sequence of those three initializing lines but without any sign of life. Well, of course maybe some kind of quiet life when not the error label is activated.

    What values would you suggest to use in the initialization section and what sequence would you use for those three init lines?

  6. #6
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    I think it's probably working, but you don't realize it.

    In your code, the only thing you're reading is GP1, and prior to that it writes to GP1, so you're thinking you should read the same value back.

    But when you write to GP1, the value is actually written to OLAT1.
    Reading GP1 reads the state of the pins, not what was written to GP1.
    <br>
    DT

  7. #7


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Darrel Taylor View Post
    I think it's probably working, but you don't realize it.

    In your code, the only thing you're reading is GP1, and prior to that it writes to GP1, so you're thinking you should read the same value back.

    But when you write to GP1, the value is actually written to OLAT1.
    Reading GP1 reads the state of the pins, not what was written to GP1.
    <br>
    Thanks, I really hoped you were right, but sorry...
    I tested it with the following code:
    Loop:
    I2Creg = OLAT1 : I2Cbyte = $ff : gosub writeioextender: pause 20
    I2Creg = IODIR1 : I2Cbyte = $ff : gosub writeioextender: pause 20

    I2Creg = olat1 : gosub readioextender: pause 20
    LCDOUT hex2 ioebyte, " "
    I2Creg = gp1 : gosub readioextender: pause 20
    LCDOUT hex2 ioebyte, cmd,home1
    if onoffpressed = 1 then powerout = 0
    goto Loop

    I have a button on GP1.0 (pin 2) that is pressed or not, on the LCD one can only see 00 00, nothing else. I think this demonstrates that you can not write OLAT1 or read it, it also shows that a button press does not come through, or perhaps the GP1 is not initialized correctly. Tested also to write IODIR1 first but with the same result...

    How should one initialize the chip with all pins as inputs?

  8. #8
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    When you get all 0's, it usually means one of two things.

    1) The SDA,SCL pins still have the analog mode enabled.

    2) There aren't any pull-ups, or they pull-down.

    If you have a voltmeter, check the voltage on the SDA,SCL pins.
    They should be above 4V when no data is being transfered.

    But I'm betting on analog mode.
    <br>
    DT

  9. #9


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Darrel Taylor View Post
    When you get all 0's, it usually means one of two things.

    1) The SDA,SCL pins still have the analog mode enabled.

    2) There aren't any pull-ups, or they pull-down.

    If you have a voltmeter, check the voltage on the SDA,SCL pins.
    They should be above 4V when no data is being transfered.

    But I'm betting on analog mode.
    <br>
    As said in post 1#, both (SCL and SDA) are pulled up with 2 2k2 resistors, one for each. So when the lines are inactive you can measure 4,98V there, so that suggest also that the problem has to be somewhere else. I have also looked with an oscilloscope on the active signals, but being not so familiar with the inner live of the I2C protocol, can't tell if there would be something wrong, to me they look "normal". From the clock line I could calculate a clock frequency of something around 65kHz +/-20%. Is that OK?

  10. #10
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Then it must be 1).

    Put this line at the top of your program.

    ADCON1 = $F ; set all pins to digital
    <br>
    DT

  11. #11


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Darrel Taylor View Post
    Then it must be 1).

    Put this line at the top of your program.

    ADCON1 = $F ; set all pins to digital
    <br>
    Copy-Pasted that ADCON1... and that could have helped but unfortunately it did not help, nothing changed
    The problem is somewhere else, but where?

    Does that 65KHz sound correct? On what frequency should the clock run under those two I2C routines (I2CREAD I2CWRITE), where could one find any info on that. Tried also DEFINE I2C_SLOW, but again without success... What can I do? The expander is kind of alive because it does not throw you to the error label....

  12. #12
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    No 65khz does not sound right, and ...
    It doesn't throw you to the error label because it always reads 0's on the pin.

    An ack from the device is a low pulse. As long as it sees a low when it expects an ack, it will never jump to the label.

    OK, it's time for you to pony up some of the info you've been leaving out.

    What are your CONFIGs?
    What cyrstal are you using?
    What DEFINE OSC are you using?
    What pins are the SCL and SDA on?

    And the rest of the code.
    <br>
    DT

  13. #13


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Darrel Taylor View Post
    No 65khz does not sound right, and ...
    It doesn't throw you to the error label because it always reads 0's on the pin.

    An ack from the device is a low pulse. As long as it sees a low when it expects an ack, it will never jump to the label.

    OK, it's time for you to pony up some of the info you've been leaving out.

    What are your CONFIGs?
    What cyrstal are you using?
    What DEFINE OSC are you using?
    What pins are the SCL and SDA on?

    And the rest of the code.
    <br>
    So, back to the basics.
    If not 65kHz is correct, then what should it be?

    If I change the device address from $40 to something else for ex. $45 it will throw the program to the error label. That behavior sounds "healthy", doesn't it?

    By CONFIGs you mean? See post #1
    The crystal is 12MHz
    DEFINE OSC 48
    The SDA,SCL pins are connected correctly to pins 33,34 + 2x 2k2 pull-ups
    Using also Microchip USB HID bootloader v2.2

    I2Creg = OLAT1 : I2Cbyte = $ff : gosub writeioextender: pause 20
    I2Creg = IODIR1 : I2Cbyte = $ff : gosub writeioextender: pause 20
    The current test loop is here:
    Loop:
    gosub getbattery
    if onoffpressed = 1 then powerout = 0

    I2Creg = GP1 : gosub readioextender' to IOEbyte
    pause 20

    lcdout cmd,home3, dec battery/10, ".",dec battery//10,"V ", dec w/100," ", _
    dec onoffpressed,cmd,home4, hex2 IOEbyte," "
    goto Loop

  14. #14
    Join Date
    Aug 2006
    Location
    Look, behind you.
    Posts
    2,818


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by keymuu View Post

    By CONFIGs you mean? See post #1
    No look at this thread.
    http://www.picbasic.co.uk/forum/showthread.php?t=543
    If you do not believe in MAGIC, Consider how currency has value simply by printing it, and is then traded for real assets.
    .
    Gold is the money of kings, silver is the money of gentlemen, barter is the money of peasants - but debt is the money of slaves
    .
    There simply is no "Happy Spam" If you do it you will disappear from this forum.

  15. #15
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    A quick test here on a 4550 at 48mhz, shows ~250khz clk.

    For the configs, I didn't know you were using the USB bootloader. The configs will be whatever the bootloader was programmed with. You'd probably need to read back the chip to find out what configs are set.

    I was hoping for more of the program, there's a lot of stuff missing, and you never know, 1 statement could change everything.

    Since you are getting all 0's. Maybe you should just try to read the RB0 pin without I2C, as a test. There's a pull-up on it, if you only read a 0, then something's still not right.
    <br>
    DT

  16. #16


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Joe S. View Post
    Oops, sorry... the question was about all this here below

    Here are the configurations settings:
    DEFINE RESET_ORG 1000h ' Room for Microchip USB Bootloader
    define ADC_BITS 10 ' 10 bit A/D
    define ADC_CLOCK 3 ' 3=rc
    define ADC_SAMPLEUS 50 ' sampling time in us
    define I2C_HOLD 1 ' Can't read or write MCP23016 without i2c_hold = 1

    '**************** Define LCD registers and bits *********************
    DEFINE LCD_DREG PORTD ' Set LCD Data port
    DEFINE LCD_DBIT 4 ' Set starting Data bit (0 or 4 if 4-bit bus)
    DEFINE LCD_RSREG PORTC ' Set LCD Register Select port
    DEFINE LCD_RSBIT 2 ' Set LCD Register Select bit
    DEFINE LCD_EREG PORTC ' Set LCD Enable port
    DEFINE LCD_EBIT 1 ' Set LCD Enable bit
    DEFINE LCD_BITS 4 ' Set LCD bus size (4 or 8 bits)
    DEFINE LCD_LINES 4 ' Set number of lines on LCD
    DEFINE LCD_COMMANDUS 2000 ' Set command delay time in us, 2000 us
    DEFINE LCD_DATAUS 50 ' Set data delay time in us, 50 us

    sda var PORTB.0 ' i2c data pin 33
    scl var PORTB.1 ' i2c clock pin 34

    deviceIO con $40 ' MCP23016
    GP0 con $00 ' port GP0 all in
    GP1 con $01 ' port GP1 all in
    OLAT0 con $02 ' Output latch register 0
    OLAT1 con $03 ' 1
    IPOL0 con $04 ' input polarity normal, not inverted
    IPOL1 con $05 '
    IODIR0 con $06 ' all out = 0
    IODIR1 con $07 '
    INTCAP1 con $09
    INTCAPbyte var byte
    IOCON1 con $0b '

    cmd con $fe ' LCD command
    clr con 1 ' LCD clear display
    blink con $0f ' LCD blinkinking cursor on
    home1 con $80 ' LCD move cursor to beginning of first line
    home2 con $c0 ' LCD move cursor to beginning of second line
    home3 con $94 ' debug lines
    home4 con $d4 ' debug lines

  17. #17


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Darrel Taylor View Post
    A quick test here on a 4550 at 48mhz, shows ~250khz clk.

    For the configs, I didn't know you were using the USB bootloader. The configs will be whatever the bootloader was programmed with. You'd probably need to read back the chip to find out what configs are set.

    I was hoping for more of the program, there's a lot of stuff missing, and you never know, 1 statement could change everything.

    Since you are getting all 0's. Maybe you should just try to read the RB0 pin without I2C, as a test. There's a pull-up on it, if you only read a 0, then something's still not right.
    <br>
    I'm note anymore sure about anything...

    When I use the following code to show things:

    LCDOUT cmd,home3, dec battery/10, ".",dec battery//10,"V ",dec w/100," ", dec onoffpressed, _
    cmd,home4, hex2 portb.0, " ", hex2 IOEbyte," ",cmd,home1

    I can see on row 4 = 01 00, RB0=1 !! IOEbyte should show the button press on P1.0 but NO it does not come through
    Took PIC of the PCB and read it with meProg and attached it here.

    By the way, the ~250kHz that you got, are you absolutely sure that you communicated with the MPC23016 device? I'm just wondering because I have an impression from the datasheet of MCP23016 that it couldn't run that fast... Is my impression wrong?
    Attached Images Attached Images  

  18. #18
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    The configs look OK.

    The PORTB.0 read looks OK.

    In my test, I did not have an MCP23016 connected, I was just testing the clk frequency with I2CWRITE at 48mhz. The MCP23016 is a 400khz device, so 250khz should not be a problem.

    The i2cdevice and I2Creg variables weren't shown. Are they both BYTEs?
    I assume they are, just asking.

    The only other possibility I can see is that the registers are configured as "Pairs", and all examples in the datasheet show reading or writing 2-bytes of data at a time. I don't see anything that says you can't read only 1-byte at a time, but then there's nothing that says you can either.

    So this is my last best guess...
    Try doing everything with 2 data bytes.
    Code:
    I2CWrite SDA,SCL,i2cdevice,I2Creg,[i2cbyte1, i2cbyte2],error
    If the address is for GP0 ($0), then i2cbyte1 should have GP0 and i2cbyte2 should have GP1.

    If the address is for GP1 ($1), then they will be reversed. GP1 in i2cbyte1 and GP0 in i2cbyte2.

    Both write and reads would need 2-bytes.
    And be sure to cycle power after changing it, in case it's still locked up.

    hth
    DT

  19. #19


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Darrel Taylor View Post
    The configs look OK.

    The PORTB.0 read looks OK.

    In my test, I did not have an MCP23016 connected, I was just testing the clk frequency with I2CWRITE at 48mhz. The MCP23016 is a 400khz device, so 250khz should not be a problem.

    The i2cdevice and I2Creg variables weren't shown. Are they both BYTEs?
    I assume they are, just asking.

    The only other possibility I can see is that the registers are configured as "Pairs", and all examples in the datasheet show reading or writing 2-bytes of data at a time. I don't see anything that says you can't read only 1-byte at a time, but then there's nothing that says you can either.

    So this is my last best guess...
    Try doing everything with 2 data bytes.
    Code:
    I2CWrite SDA,SCL,i2cdevice,I2Creg,[i2cbyte1, i2cbyte2],error
    If the address is for GP0 ($0), then i2cbyte1 should have GP0 and i2cbyte2 should have GP1.

    If the address is for GP1 ($1), then they will be reversed. GP1 in i2cbyte1 and GP0 in i2cbyte2.

    Both write and reads would need 2-bytes.
    And be sure to cycle power after changing it, in case it's still locked up.

    hth
    Thank you Darrel, thank you indeed
    You are a real and great PIC wizard!

    You have made me extremely happy...

    ...have been struggling with this problem too long, I'm very happy that it is solved "so easily", meaning that the error here was almost close to a syntax error.

    Who could have guessed in the first place that you need to read/write both data registers to get it working. Is this said somewhere in the data sheet? If so, it has not caught my eye.

    This does slightly complicate the code for me, it would have been very handy if one could read the ports separately, but no big deal, not a real problem...

    THANK YOU again for helping me out of my desperate situation with this "strange" MCP23016 behavior...

  20. #20
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Thumbs up

    WooHoo!

    Pulled one out of my asparagus that time.

    Thanks for sticking with it keymuu!

    CYA round,
    DT

Similar Threads

  1. MCP23016 I2C serial I/O expander chip
    By GeoJoe in forum Serial
    Replies: 7
    Last Post: - 31st October 2007, 15:39
  2. MCP23016 missing D7 on I2CRead
    By TWSK in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 10th June 2007, 18:37
  3. Using I2C with FullSpeed USB
    By Demon in forum mel PIC BASIC Pro
    Replies: 15
    Last Post: - 8th July 2006, 04:52
  4. MCP23016 I/O expander
    By Demon in forum mel PIC BASIC Pro
    Replies: 42
    Last Post: - 24th October 2005, 01:01
  5. MCP23016 I/O expander with PBP?
    By Jon Chandler in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 22nd August 2005, 09:32

Members who have read this thread : 0

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