- I have a PIC16F18875, on a board where it is configured as I2C master.
- 7 bit addressing, 100 kHz clock
- Several different I2C slave devices are on the bus.
- am using MPLAB X IDE with MCC plugin
- using the MCC-generated code for interacting with the peripherals
- I can read most slave ICs on the board, like some ADCs, and am getting sensible values back
- the UCD9090 PMIC, though, is only giving me 0xFF back, no matter which register is attempted to be read
- oscilloscope shows good signal integrity
- with a RaspberryPi's I²C attached to the same bus, I can read the 9090 just fine
- the logic analyzer shows that the slave is transmitting the value to be read back, a nack and the last stop with 36ms (milli) delay after the address-read (see image below)
- it is shown that the library code used generates a START+STOP after the address and register# bytes have been sent
- using i2c_masterOperation(), i2c_setBuffer() etc
- whereas the RaspberryPi logic analyzer readout shows it does the REPEATED START
- according to this, some slave devices need a REPEATED START, instead of a STOP+START, to be readable
- hence it looks to me that that's the problem
Now, from the MCC generated I2C interface header file, I see no way of telling the code to use the method of repeated-start instead of stop-start. Haven't seen anything configurable on the sparsely populated I2C page in MCC, either. So, before I go and muck about within autp-generated code...
Is there a way to "properly" do that? Otherwise, I guess I'll have to dig through their library code and find how to modify it to do what's necessary.
Update: What I was trying, having been made aware of the state machine altering nature of the setCallbackX functions by brhans, is this:
i2c_error_t i2c_readRegRepeatStart(uint8_t reg, void* data, uint8_t size)
{
i2c_error_t ret;
__i2c_buf.reg = reg;
i2c_setBuffer(&__i2c_buf.reg, 1);
i2c_setDataCompleteCallback( i2c_restartRead, 0 );
ret = i2c_masterOperation(false); // writing the start,addr,reg,restart part
i2c_setDataCompleteCallback( i2c_returnStop, 0 );
if (ret == I2C_NOERR)
{
i2c_setBuffer(data, size);
ret = i2c_masterOperation(true); // reading the data bytes
}
return (ret);
}
I call this like: i2c_readRegRepeatStart( registerNum, &someUshortVar, 2 ). This code does produce a sequence on the logic analyzer screen that starts out good:
- Start
- W, Addr, Ack
- W, Data, Ack
- Repeat Start -- good, that's what I wanted to see, instead of stop/start
- R, Addr, Ack
- R, Data, Ack
- R, Data, Ack
So far, so good, right? Well, almost. Instead of now a STOP, this is what follows:
- R, Data, Ack (19 times)
- R, Data, Nack (once)
- Stop
- Start
- R, Addr, Ack
- R, Data, Ack
- R, Data, Ack
- Stop
I haven't figured out yet what's going on. It seems in principle what's supposed to be done, and I traced down to where the buffer pointer and size are set within the MCC library, and it clearly has the value of 2 (size), then the driver is engaged to perform the I2C operation, and it does that weird stuff.
I2C_SetDataCompleteCallback
to change the FSM sequence from the defaultI2C_CallbackReturnStop
toI2C_CallbackRestartRead
before starting the I2C operation. \$\endgroup\$