This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

PCF8575C: When is a WRITE 0xFFFF necessary to use this part as input pins?

Part Number: PCF8575C

I'm having a figth with this port expander and interrupts, but want to first clear up this possible misunderstanding on my side:

Is it enough to write once, then wait for interrupt(s) and just keep reading the port?

I'm not a native speaker and to me, what the data sheet states is ambiguous:

Before reading from the PCF8575C, all ports desired as input should be set to logic 1.

When using this part however, I have to write 0xFFFF every time just before a read, or I read nonsense values.

So I interpret the data sheet as "Every time, just before reading from the PCF8575C, all ports desired as input should be set to logic 1."

Is this true, do I interpret the data sheet correctly in this way?

Or should I indeed be able to write 0xFFFF once (clearing the interrupt pin) and then repetetively read the port status upon interupt, also clearing the interrupt pin by the read?

In my hands, this pseudo code works (without worrying about the interrupt pin for now)

while True
  write_PCF8575(0xFFFF)
  port_status_16_bits = read_PCF8575()
***do something with the result

While this code fails after the first read:

write_PCF8575(0xFFFF)
while True
   port_status_16_bits = read_PCF8575()
*** do something with the result but do not rewrite the PCF8575 with anything

Thanks for enlightening me.

  • A 0 pin strongly drives low. A 1 pin weakly drives high. So to be able to read the external voltage at a pin, it must be in the 1 state.

    This means that you need to do the write only once. (Or not at all, because 1 is the default state after power up.)

  • Thank you Cemens.

    That part I already understood. Unfortunately, see my pseudo code, I already write the pins high before reading and cannot read subsequent words after the first one.

    I've been digging into the data sheet and as far as my limited knowledge on logic schemes goes, the only way a pin (page 12 of the data sheet outlining the binary logic circuit of one P-port) can go low again, is if one writes a 0.

    In my case, somehow the pin goes low "by itself". So we can consider this an anomaly and indeed writing a 1 once  should suffice for multiple reads?!?.

    In that case, I should try to get my hand on a logic analyser.

  • Apologies for misspelling your name Clemens, can't edit a reply.

  • What you describe should not happen. Please show the write/read_PCF functions.

  • It is part of a larger code, I quote the entire program here, in line 30 the essential line is marked. Goal is to activate a relay when a corresponding radar sensor detects motion. Motion pulls the PCF8575C to ground by an optocoupler (817C). The code below works like a charm, running on a Raspberry Pi Zero W.

    When I move the essential code line to before the While loop (ie. write only once), in no time all relays become active, as if the 0x20 PCF8575C loses bit by bit the high level. Only two radar detectors are connected, the other P ports are unconnected. Behaviour is the same when I swap the PCF8575C for another one, ie. the chip is not broken I think.

    #!/usr/bin/env python3

    from smbus import SMBus
    import RPi.GPIO as GPIO
    import time

    INTERRUPT_GPIO = 17

    i2cbus = SMBus(1)
    i2cradar = 0x20
    i2crelay = 0x21

    hiByte = 0xFF
    loByte = 0xFF

    i2cbus.write_word_data(i2cradar,loByte,hiByte)
    oldState = i2cbus.read_word_data(i2cradar,0x20)

    while True:
    i2cbus.write_word_data(i2cradar,loByte,hiByte) #essential
    portState = i2cbus.read_word_data(i2cradar,0x20)
    if portState != oldState:
    bits ='{0:16b}'.format(portState)
    print bits.zfill(16), " ", time.localtime().tm_sec
    oldState = portState
    hiReflect = (portState >>8) & 0xFF
    loReflect = (portState & 0xFF)
    i2cbus.write_word_data(i2crelay,loReflect,hiReflect)
    time.sleep(0.1)
    else:
    time.sleep(0.01)
  • The SMBus class assumes that devices have registers, and that all accesses begin with a write of the register number. This is not true for the PCF.

    To write to the PCF, use i2cbus.write_byte_data(addr, loByte, hiByte).
    To read from the PCF, use i2cbus.read_word_data(addr, loByte).

    (The write_byte_data call pretends that the first data byte is the register number. The read_word_data call writes a byte that gets ignored by the PCF because it acts only after two bytes have been written.)

  • Hi Clemens, I take your word for it, but your suggested code does not resolve the issue.

    As long as the 'essential' line is not inside the while loop, I see the bits on the read port fall within a second, one after another, regardless off word- or byte read/write.

    Generally speaking the order of falling is low bit to high bit (in a 16-bit word) but not exactly so and not every time the same.

    I've swapped around boards, tried to lower the Vcc (which obviously did not work as Vcc min is 4.5V).

    Then I added 5 MΩ  resistors between Vcc and the port pin (for 2 pins that connected to the radar module).

    Lo and behold, the code (writing 0xFFFF once) then works for the two pins with resistors but other pins still drop.

    Hence my suspicion is that due to capacitive loads (although the pcb tracks are only 5 cm long and end in a pin header) the pins cannot maintain the '1' state, and only briefly after writing do so (swing up, then fade low?). In other words: the internal pull up resistors seem not to be able to deliver enough power to keep the pins in an 'up' state. Measuring the voltage level on unconnected input pins confirm this. A pin written with '1' once reads 145 mV (as soon as the multimeter readout stabilizes and slowy dropping to zero) while a pin written '1' continuously reads  1.9V when Vcc is 5V). Attaching a volt meter (Voltcraft  VC170) is enough to pull a pin low, (unfortunately I do not own a oscilloscope or logic analyser).

    This also seems to be in accordance with figure 13 of the datasheet (on page 15) where for the rise time of the voltage on the example pin P5 the iOHT is higher than IOH (which according to the table are -10mA vs -4mA).

    Just touching with the bare hand the pins that were written once in '1' state, but have fallen since and thus read '0', is enough to read a '1' intermittently.

    So all in all I do not yet know the exact cause of the problem but I can design my way around it by adding pull-up resistors to my PCB for every input pin. Unless, of course, given the observations above, you can give me a better solution.

  • IOHT is active only during the ACK. If your external device does not actively drive high, you indeed need a pull-up resistor.

  • Until now, I did not realise this. Thanks, this explains everything.

    One more question to get a complete understanding of the difference between PCF8575 and PCF8575C: In the block diagram of the PFC8575 (without the C) the output pin is connected to a 100 mA current source through a p-channel mosfet. Would in using the PCF8575 in stead of the PCF8575C lie the solution of my problem? When writing high to the flipflop, this is cconverted to low by the inverter, and a low is fed to the gate of the p-channel mosfet, which opens and connects the 100mA current source to the output pin.

    Or does the same activity limited to the ACK time here also hold?

  • Hello,

    Hence my suspicion is that due to capacitive loads (although the pcb tracks are only 5 cm long and end in a pin header) the pins cannot maintain the '1' state, and only briefly after writing do so (swing up, then fade low?). In other words: the internal pull up resistors seem not to be able to deliver enough power to keep the pins in an 'up' state. Measuring the voltage level on unconnected input pins confirm this. A pin written with '1' once reads 145 mV (as soon as the multimeter readout stabilizes and slowy dropping to zero) while a pin written '1' continuously reads  1.9V when Vcc is 5V). Attaching a volt meter (Voltcraft  VC170) is enough to pull a pin low, (unfortunately I do not own a oscilloscope or logic analyser).

    Your suspicion is correct. Due to PCB traces and other parasitics, P-port will deviate back to a low state overtime unless an ACK occurs (as stated by Clemens). When ACK is present, typical IOHT = ~-1mA is present. Given direction of current in figure 8.2.2 on page 12, current goes from P-port to VCC. Once ACK subsides, parasitics take over, and P-port floats back down to low potential usually GND unless external pullups are present. Doing some quick research, it looks like the internal pullups of raspberry Pi are 50k - 60k ohm resistors which are very weak in regards to I2C. This is why when stronger external pullups are used, the problem goes away.

    One more question to get a complete understanding of the difference between PCF8575 and PCF8575C: In the block diagram of the PFC8575 (without the C) the output pin is connected to a 100 mA current source through a p-channel mosfet. Would in using the PCF8575 in stead of the PCF8575C lie the solution of my problem? When writing high to the flipflop, this is cconverted to low by the inverter, and a low is fed to the gate of the p-channel mosfet, which opens and connects the 100mA current source to the output pin.

    I believe this is an error in the datasheet when it says "100mA." I believe it should be a 100uA current source. Regardless of the error, the idea is the same. This should solve your problem, in that a P-port will stay high regardless of parasitics because of the 100uA current source pullup up to VCC. To overcome the bias, p-port should be driven low. 

    This is the only difference between PCF8575 and PCF8575C is the internal 100uA current source.

    Regards,

    Tyler