Shop OBEX P1 Docs P2 Docs Learn Events
PCF8574 INT pin question - Rewritten for clarity — Parallax Forums

PCF8574 INT pin question - Rewritten for clarity

RickHRickH Posts: 40
edited 2008-05-26 15:33 in BASIC Stamp
Please read update 2 for most current findings.

Update 1:

I currently have 2 PCF8974 IC2 Bus Expander chips wired up on pins 8, 9 for IC2 com and Pins 10 and 11 for their respective INT pins. I finally got the first chip to trigger Pin 10 but the second chip still will not trigger Pin 11. I have swaped the chips and have replaced them several times. The wiring is correct, also chip 1 is at %000 and chip 2 is at %001 for their addresses. They each have a 4.7K Pullup resistor for the INT pin 13.

Both chips can read their pins on a read routine. Chip 1 can run its read routine using an "if Pin10 = 0" statement with no problem. I dug up my old Logic probe and found that when I Make a change to the state of Bus 1 that I get 2 pulses and one LOW. I expect this as per the datasheet. On Bus 2 I get nothing, it stays High all the time, With one exeption and I find this quite strange:

1.) if I make a change to bus 1, bus 1 triggers PIN10 and I get 2 pulses and 1 LOW on my probe at Bus 1's INT pin
2.) then I make a change to bus 2 I trigger PIN11 but I only get one pulse and I do not get a Low on my probe at bus 2's INT pin.
3.) If I make another change to bus 2 I get no INT, No pules

Note I do get data back from #1 and #2 and nothing back from #3.
Once data has changed on bus 1 I can only get bus 2 to trigger 1 time until I trigger bus 1 again

Update 2:
I left my probe on Bus 2 INT Pin and when I make a change to bus 1 I get the 2 pulses and a low. I am now assuming that only the lowest addressed chip is in control of the INTerrupt. This will make my coding a bit more complex I'm thinking.

this is an example of my code:

I2Cpin          CON     8                       ' SDA on 0; SCL on 1
DevType         CON     %0111 << 4              ' Device type
DevAddr1         CON     %000 << 1
DevAddr2         CON     %001 << 1
DevAddr3         CON     %010 << 1
Rd8574_1          CON     DevType | DevAddr1 | 1   ' read from PCF8574
Rd8574_2          CON     DevType | DevAddr2 | 1   ' read from PCF8574
Wr8574_3          CON     DevType | DevAddr3       ' write to PCF8574
IC2Inputs          CON     %11111111
IC2Outputs         CON     %00000000
ioByte1          VAR     Byte                    ' i/o byte for PCF8574
ioByte2          VAR     Byte
ioByteArray      VAR     Bit(16)
idx              VAR     Nib
storage          VAR     Byte
idxa             VAR     Nib
INT1             PIN     10
INT2             PIN     11

Main:
  GOSUB Scan1
  IF INT1 = 0 THEN
  DEBUG HOME
    DEBUG BIN INT1,CR
    GOSUB Buttons
  ENDIF
  IF INT2 = 0 THEN
  DEBUG HOME
    DEBUG BIN INT2,CR
    GOSUB Buttons2
  ENDIF

GOTO Main

Buttons:
  I2CIN I2Cpin, Rd8574_1, (IC2Inputs), [noparse][[/noparse]ioByte1]
    ioByte1 = ~ioByte1

    DEBUG HOME
    idxa = 0
    FOR idx = 7 TO 0
      storage = ioByte1 << idx
      storage = storage >> 7
      ioByteArray(idxa) = storage
      idxa = idxa + 1
    NEXT
          DEBUG CLS
    FOR idx = 0 TO 7
      CCMod = idx + 16
      IF ioBytearray(idx)= 1 THEN
        GOSUB MIDI_Output
      ENDIF

      DEBUG "bit: ", DEC idx, " Data: ", BIN ioBytearray(idx),CR
    NEXT
    I2COUT I2Cpin, Wr8574_3, (IC2Outputs), [noparse][[/noparse]ioByte1]
RETURN

Buttons2:
    I2CIN I2Cpin, Rd8574_2, (IC2Inputs), [noparse][[/noparse]ioByte2]
    ioByte2 = ~ioByte2
    idxa = 8
    FOR idx = 7 TO 0
      storage = ioByte2 << idx
      storage = storage >> 7
      ioByteArray(idxa) = storage
      idxa = idxa + 1
    NEXT
      DEBUG CLS
    FOR idx = 8 TO 15
      IF ioBytearray(idx)= 1 THEN
        GOSUB MIDI_Output
      ENDIF
      DEBUG "bit: ", DEC idx, " Data: ", BIN ioBytearray(idx),CR
    NEXT
RETURN

Post Edited (RickH) : 5/26/2008 12:43:19 PM GMT

Comments

  • RickHRickH Posts: 40
    edited 2008-05-25 12:58
    I'm getting frustrated at this point. Without the Chip 2 INT pin working I will need to scan the bus constantly witch slows down my analog drastically. After Retesting I have found this:

    1.) Push a button on chip 1 (any of the 8) I get 2 pulses from my probe and a low on Input 10, nothing on Input 11
    2.) Push a button on chip 2 (any of the 8) I get 1 Pulse and 1 low 1 time, it will not triger a second time until Chip 1 Changes state. I also get the same 1 low and 1 pulse from Pin 10 at the same time.

    This is really messing my project up and I can not see using this IC2 chips without the INT working properly. If anyone has any suggestions I would be grateful.
  • Mike GreenMike Green Posts: 23,101
    edited 2008-05-25 15:49
    Please re-read the datasheet for the device (PCF8574 I assume, not PCF8974). As you noted, the chip is supposed to trigger the INT line low for each edge of any input change (from low to high or from high to low). This would indeed give you two INT pulses for each input pulse (low to high to low) to an I/O expander input pin. Note that the PCF8574 pins have to be in input mode (the default) with the pin values set to ones. I haven't gone through your code, but make sure that the I2COUT sets them properly.

    There is supposed to be absolutely no interaction between the two chips from a hardware perspective.

    I've not used these chips with a Stamp for a long time, but I use them with a Propeller currently and they appear to work the way the datasheet says.
  • RickHRickH Posts: 40
    edited 2008-05-26 12:39
    Do I need to send an IC2OUT to set up the inputs or will my IC2IN statements do that?

    My %000 chip works the way the data sheet says. Even if I swap the chips the first one works. Just not the second one.

    Post Edited (RickH) : 5/26/2008 12:45:17 PM GMT
  • Mike GreenMike Green Posts: 23,101
    edited 2008-05-26 13:52
    I think the problem is that your I2CIN and I2COUT statements are wrong. The PBasic manual has all the information in the chapters on these, but ...

    1) Do not include the state of the R/W bit in the I2C address. I think the statements strip this out, but they may not.

    2) For some reason, you're using the register address field to write an output state to the PCF8574. This is unnecessary on an output cycle since (in your case) it will briefly force all the output pins to low, then set the output pins to the state you want. In the case of the I2CIN, you're writing an all ones value to the PCF8574, which does make the pins work as inputs, then doing a read cycle to fetch the pin states. Note that this forcing the output state first to zero, then back to one will cause an /INT pulse or two.

    I would not use the register address field at all and just set the state of the PCF8574s during initialization

    During the program initialization you'd do:

    I2COUT I2Cpin, DevType | DevAddr1, [noparse][[/noparse]%11111111] ' Set device 1 to inputs
    I2COUT I2Cpin, DevType | DevAddr2, [noparse][[/noparse]%11111111] ' Set device 2 to inputs
    I2COUT I2Cpin, DevType | DevAddr3, [noparse][[/noparse]%00000000] ' Set device 3 to zero outputs

    Note that you could also set device 3 to one bits if that's the output state you want.

    Now to read the input state of either device 1 or device 2, you'd just do:

    I2CIN I2Cpin, DevType | DevAddr1, [noparse][[/noparse]ioByte] ' Read the current state of device 1
    I2CIN I2Cpin, DevType | DevAddr2, [noparse][[/noparse]ioByte] ' Read the current state of device 2

    To change the current output state of device 3, you'd just do:

    I2COUT I2Cpin, DevType | DevAddr3, [noparse][[/noparse]ioByte] ' Update the current state of device 3
  • RickHRickH Posts: 40
    edited 2008-05-26 14:17
    It says it expects a "," at the end of the IC2OUT statements. I believe you must have all 4 parameters (Pin, Address, Direction,Data) in the statement. I added it and I get nothing, so then I add the Direction back and I get nothing. I reloaded my old code and I get data from chip 1 but nothing from chip 2 unless I change data on chip 1 first. I am not sure why initializing the chips with an IC2out would break it but it has.

    The reason I put the direction in the register address field for directions is that is what is explained in N&V 79:
    N&V 79 said...
    Using the PCF8574 is very easy. The only thing we have to do is replace the Address parameter
    in the Stamp’s I2C commands with a value that represents the desired direction (input = 1, output
    = 0) of the device’s pins. Additionally, we have to refresh the state of output pins whenever we do
    a read (I2CIN). This is accomplished by ORing the output bits with the direction value.
  • Mike GreenMike Green Posts: 23,101
    edited 2008-05-26 14:31
    You're right about the extra comma, sorry. Just don't put anything there like: I2CIN I2Cpin, DevType | DevAddr1,,[noparse][[/noparse]ioByte]

    The suggestion from N&V#79 is not bad. It just mixes up several functions and, as in your situation, may cause things to not work or to work in strange and mysterious ways. In addition, it doesn't work as expected with writes (I2COUT).

    Make sure you've wired the address pins (A0-A2) correctly.
  • RickHRickH Posts: 40
    edited 2008-05-26 14:31
    Interesting, When I use my original code and I add an IC2Out statement to my Chip 2 subroutine ( used the same one in Cip 1 subroutine) It works perfectly. So I am assuming that I must write to the IC2 bus after every IC2In statement to make the IC2 INT work. Makes no cents but it works perfectly.

    I2Cpin          CON     8                       ' SDA on 0; SCL on 1
    DevType         CON     %0111 << 4              ' Device type
    DevAddr1         CON     %000 << 1
    DevAddr2         CON     %001 << 1
    DevAddr3         CON     %010 << 1
    Rd8574_1          CON     DevType | DevAddr1 | 1   ' read from PCF8574
    Rd8574_2          CON     DevType | DevAddr2 | 1   ' read from PCF8574
    Wr8574_3          CON     DevType | DevAddr3       ' write to PCF8574
    IC2Inputs          CON     %11111111
    IC2Outputs         CON     %00000000
    ioByte1          VAR     Byte                    ' i/o byte for PCF8574
    ioByte2          VAR     Byte
    ioByteArray      VAR     Bit(16)
    idx              VAR     Nib
    storage          VAR     Byte
    idxa             VAR     Nib
    INT1             PIN     10
    INT2             PIN     11
    Main:
      GOSUB Scan1
      IF INT1 = 0 THEN
      DEBUG HOME
        DEBUG BIN INT1,CR
        GOSUB Buttons
      ENDIF
      IF INT2 = 0 THEN
      DEBUG HOME
        DEBUG BIN INT2,CR
        GOSUB Buttons2
      ENDIF
    
    GOTO Main
    
    Buttons:
      I2CIN I2Cpin, Rd8574_1, (IC2Inputs), [noparse][[/noparse]ioByte1]
        ioByte1 = ~ioByte1
    
        DEBUG HOME
        idxa = 0
        FOR idx = 7 TO 0
          storage = ioByte1 << idx
          storage = storage >> 7
          ioByteArray(idxa) = storage
          idxa = idxa + 1
        NEXT
        DEBUG CLS
        FOR idx = 0 TO 7
          CCMod = idx + 16
          IF ioBytearray(idx)= 1 THEN
            GOSUB MIDI_Output
          ENDIF
    
          DEBUG "bit: ", DEC idx, " Data: ", BIN ioBytearray(idx),CR
        NEXT
        I2COUT I2Cpin, Wr8574_3, (IC2Outputs), [noparse][[/noparse]ioByte1]
    RETURN
    
    Buttons2:
        I2CIN I2Cpin, Rd8574_2, (IC2Inputs), [noparse][[/noparse]ioByte2]
        ioByte2 = ~ioByte2
        idxa = 8
        FOR idx = 7 TO 0
          storage = ioByte2 << idx
          storage = storage >> 7
          ioByteArray(idxa) = storage
          idxa = idxa + 1
        NEXT
        DEBUG CLS
        FOR idx = 8 TO 15
          IF ioBytearray(idx)= 1 THEN
            GOSUB MIDI_Output
          ENDIF
    
          DEBUG "bit: ", DEC idx, " Data: ", BIN ioBytearray(idx),CR
        NEXT
        [color=#990000]I2COUT I2Cpin, Wr8574_3, (IC2Outputs), [noparse][[/noparse]ioByte1][/color]
    RETURN
    
  • Mike GreenMike Green Posts: 23,101
    edited 2008-05-26 14:36
    It's not that you have to have an I2COUT after every I2CIN, it's that you run into problems with the extra write cycles caused by the use of the register address parameter for a device that doesn't use register addressing.

    Also, you don't need to include the R/W bit in your device addresses. The I2CIN and I2COUT statements force the bit value that's needed for the operation being performed.
  • RickHRickH Posts: 40
    edited 2008-05-26 14:44
    I understand what you mean, I just can't seam to get it to work without all the parameters filled in. I need the [noparse][[/noparse]ioBytes] in the initialization stage or I get an error missing argument. and I need the address paramiter of %11111111 or %00000000 or I get the same error. How would I do this with the IC2IN and OUT statements?
  • Mike GreenMike Green Posts: 23,101
    edited 2008-05-26 14:59
    I checked the most recent manual. I was correct. You don't need the extra comma or the address parameter. You need to update your copy of the Stamp Editor. This was changed in a recent update. The examples I posted at 7:52 should work with the latest Stamp Editor.
  • RickHRickH Posts: 40
    edited 2008-05-26 15:07
    Ahh, ok. Thanks for your help. I'm going to download the new Stamp editor later today and give it a try.

    I found this:
    Rev Notes said...
    Added support for optional Address argument in I2CIN and I2COUT
    commands. This allows communication with some products that only
    require a SlaveID. The syntax is now:
    I2CIN Pin, SlaveID, {Address {\LowAddress},} [noparse][[/noparse]InputData]
    —and—
    I2COUT Pin, SlaveID, {Address {\LowAddress},} [noparse][[/noparse]OutputData]
    in BASIC Stamp Windows Editor v1.32.
    This item will only
    benefit applications that
    use products which don’t
    require an Address value.
    Post Edited (RickH) : 5/26/2008 3:19:37 PM GMT
  • RickHRickH Posts: 40
    edited 2008-05-26 15:33
    OK I ot it to work with:

    I2CIN I2Cpin, Rd8574_1, (IC2Inputs), [noparse][[/noparse]ioByte1]
      I2COUT I2Cpin, Wr8574_3, (IC2Outputs), [noparse][[/noparse]ioByte1]
      I2CIN I2Cpin, Rd8574_2, (IC2Inputs), [noparse][[/noparse]ioByte2]
    



    as initalizing the chips and then:


    Buttons:
      I2CIN I2Cpin, Rd8574_1, [noparse][[/noparse]ioByte1]
        ioByte1 = ~ioByte1
    
        DEBUG HOME
        idxa = 0
        FOR idx = 7 TO 0
          storage = ioByte1 << idx
          storage = storage >> 7
          ioByteArray(idxa) = storage
          idxa = idxa + 1
        NEXT
        DEBUG CLS
        FOR idx = 0 TO 7
          CCMod = idx + 16
          IF ioBytearray(idx)= 1 THEN
            GOSUB MIDI_Output
          ENDIF
    
          DEBUG "bit: ", DEC idx, " Data: ", BIN ioBytearray(idx),CR
        NEXT
        I2COUT I2Cpin, Wr8574_3, [noparse][[/noparse]ioByte1]
    RETURN
    
    Buttons2:
        I2CIN I2Cpin, Rd8574_2, [noparse][[/noparse]ioByte2]
        ioByte2 = ~ioByte2
        idxa = 8
        FOR idx = 7 TO 0
          storage = ioByte2 << idx
          storage = storage >> 7
          ioByteArray(idxa) = storage
          idxa = idxa + 1
        NEXT
        DEBUG CLS
        FOR idx = 8 TO 15
          IF ioBytearray(idx)= 1 THEN
            GOSUB MIDI_Output
          ENDIF
    
          DEBUG "bit: ", DEC idx, " Data: ", BIN ioBytearray(idx),CR
        NEXT
        I2COUT I2Cpin, Wr8574_3, [noparse][[/noparse]ioByte1]
    RETURN
    



    But I still need to use the IC2OUT in every Subroutine or I will not get a proper INT back.

    Also It gives me nothing when I initalize them with IC2OUT, I must use IC2IN to initialize them.
Sign In or Register to comment.