Okay, I can see the changes.
As shown now, the LEDs on the receiving IC will block the data high as they are reversed. The LEDs on the transmitting side aren't a good idea either. If you want LEDs you need to put them from the data line to ground through a resistor, not in series with the connection to cable socket.
Just seen your picture - it looks like you have removed the LEDs, good (I was just about to suggest this.. :-) )
So now it looks as if you have direct connections from IC1 to IC2. If this is the case then if the code (looks reasonable at a glance) and IC wiring are correct then it should work.
If you can confirm with a multimeter that the input pins are seeing a high (or low) voltage and the read value is different, then this would confirm the issue is one or the other of the above. Maybe just apply a known voltage directly and see if you can read that okay)
However, if you are reading different values when the pullups are on/off then that would seem to indicate the read is correct. Try reading a direct voltage and post results, I'm just checking the datasheet for the ICs, will add more shortly.
EDIT - about the pullups:
You can use the internal pullups if you don't mind the line "relaxing" to high when not driven (i.e. default state 1) These are often used for interfacing with open drain buses, or for button to ground, etc to save an external pullup.
If you want to have the lines default state low though, (as is the case for you) you need a pulldown to stop the high impedance floating. Since the IC in question doesn't have internal pulldowns, you need to add them externally.
EDIT - Doh! I've just seen the problem...
In your code you set 1 pin at a time to output and all the rest to inputs. This means that if you have internal pullups on, the undriven pins will default to high! When a pin is set to input, it is high impedance, so effectively it's like disconnecting that end of the line, and the weak pullups will pull the receiving end high.
You need to keep all pins as outputs, and just set one high at a time, this will keep all the pins driven - try this with the pullups on, it should work.
If you know the lines will be driven correctly all the time, you don't need the pullups, but it doesn't hurt to keep them on.
Here is the relevant code (in the intialise registers function):
i2c_start_wait(SLAVE_ADDRESS(0x4E)+I2C_WRITE); // Address Slave 1
i2c_write(0x00); // Set memory pointer to the IODIRA register (IODIRA address is 0x00 - see Page 9)
i2c_write(~(Value)); // Set only one pin at a time as an output and everything else as inputs
i2c_stop();
Change it to:
i2c_start_wait(SLAVE_ADDRESS(0x4E)+I2C_WRITE); // Address Slave 1
i2c_write(0x00); // Set memory pointer to the IODIRA register (IODIRA address is 0x00 - see Page 9)
i2c_write(0x00); // Set all pins as outputs
i2c_stop();
While not specifically the answer to your question, in a similar situation faced on one of our product upgrades, we used a workaround: An identically addressed I2C device needed to be added to the design, but conveniently the parts had Chip-Enable lines.
So the design simply added a CE off one of the controller GPIOs - actually we added 2, so that we could potentially stick in 2 more of the parts when inevitably the software team outgrows the additional 100% capacity we've just provided them.
Best Answer
Correct. Another slave device which uses address
0x20 - 0x27
would conflict with an existing MCP23017 device using the same address within that address range, if they were connected on the same I2C bus. Each I2C slave needs a unique address on an I2C bus.Two ways to mitigate a slave address conflict would be either spreading the devices across multiple I2C buses on the I2C master (e.g. the Raspberry Pi), or using an I2C multiplexer device on a single I2C bus (which effectively creates multiple I2C buses itself). [See below for another approach.]
This depends on the device (i.e. read their datasheet) but typically the I2C address, or the range of selectable I2C addresses, is fixed for each model of slave device.
One exception is where a slave device is totally programmable (e.g. some I2C slaves are actually PIC devices running firmware to make them into permanent I2C slaves) and in those cases, I have seen more flexibility about which addresses they can be programmed to use.
Edited to add: Another approach to avoid I2C bus address conflict, as kindly commented by @DoxyLover, is to use the Linear Technologies I2C address translators - LTC4316, LTC4317, LTC4318. These devices re-write the I2C addresses "on-the-fly" between their input and output "channels". Effectively, they create new I2C bus segments, with a configurable pattern of (in theory, transparent) I2C address translation between the original and new I2C bus segments.
From their datasheets, they also add other features e.g. built-in "stuck bus" detection and voltage level translation. However, while they support common I2C features, there are a few which they don't support e.g. 10-bit addressing and Device ID. As always, read the datasheets.
In the context of the original question, an LTC4316 looks like it would be able to create a new I2C bus segment, where another set of (up to) eight MCP23017 devices could be connected. Let's assume that I2C addresses
0x30 - 0x37
are free on the I2C bus directly connected to the master, but the new set of MCP23017 devices need to use their fixed addresses0x20 - 0x27
. The LTC4316 would be configured with a "translation byte" value of0x10
.On the LTC4316 "output" I2C bus segment, the new set of eight MCP23017 devices "see" their usual
0x20 - 0x27
I2C addresses, as they require. However on the "input" I2C bus segment where the I2C master is connected, the I2C master would address them using I2C addresses0x30 - 0x37
, with the LTC4316 translating an address of0x3n
on the "input" (master side) bus segment, to0x2n
on the "output" (slave side) bus segment [wheren
=0 - 7
].