Hello,
I have a Xavier devkit.
I’m struggling with an i2c device on /dev/i2c-8 which uses a non-standard protocol for updating it’s FW.
The write transactions go through without problem. But the read transactions require the address rw/wr bit to be set to 1 and this is where the problems start.
A read transaction looks like this:
/******************************************************************************/
// Read transaction
//{DEVICE_ADDR[7:1], 1'b1}
// 0xAC Loader Module (shown with bit 0 masked to a 0)
//<ACK_FROM_SLAVE>
//REGISTER_ADDRESS_MSB
// 16-bit register address to allow 65536 registers on slave
//<ACK_FROM_SLAVE>
//REGISTER_ADDRESS_LSB
// 16-bit register address to allow 65536 registers on slave
//<ACK_FROM_SLAVE>
//NUMBER_OF_WORDS_MSB
// Number of 16-bit words to write or read, max of 100
//<ACK_FROM_SLAVE>
//NUMBER_OF_WORDS_LSB
// Number of 16-bit words to write or read, max of 100
//<ACK_FROM_SLAVE>
//WORD_1_MSB_FROM_SLAVE
//<ACK_FROM_MASTER>
//WORD_1_LSB_FROM_SLAVE
//<ACK_FROM_MASTER>
//...
//FINAL_BYTE_FROM_SLAVE
//<ACK_FROM_SLAVE>
/******************************************************************************/
So with the device on address 0x28, and register 0x0000 returning 0x0123 I expect things to go like this:
S 0x51 ACK 0 ACK 0 ACK 0 ACK 1 ACK 0x01 ACK 0x23 ACK P
When I open the bus I check for the i2c functs
int open(const QString &bus)
{
if ((m_fd = fileOps::open(bus.toLatin1(), O_RDWR)) < -1)
{
qDebug() << Q_FUNC_INFO << "Failed to open i2c bus " << bus;
return -1;
}
unsigned long funcs = 0;
if (ioctl(m_fd, I2C_FUNCS, &funcs))
{
qDebug() << Q_FUNC_INFO << "Could not retrieve bus functionalities";
goto Error;
}
if (!(funcs & I2C_FUNC_PROTOCOL_MANGLING))
{
qDebug() << Q_FUNC_INFO << "The required I2C_FUNC_PROTOCOL_MANGLING functionality is not available";
goto Error;
}
if (!(funcs & I2C_FUNC_NOSTART))
{
qDebug() << Q_FUNC_INFO << "The required I2C_FUNC_NOSTART functionality is not available";
goto Error;
}
if (!(funcs & I2C_FUNC_10BIT_ADDR))
{
qDebug() << Q_FUNC_INFO << "Bus " << bus << " does not support 10-bit chip addressing";
}
return m_fd;
Error:
fileOps::close(m_fd);
return -1;
}
I2C_FUNC_PROTOCOL_MANGLING and I2C_FUNC_NOSTART are both present so it should be all good.
My read function looks like this:
int read_word(quint16 reg, quint16 &word)
{
if (!isOpen())
{
qDebug() << Q_FUNC_INFO << "Device not open";
return -1;
}
int retval = 0;
quint8 header[4];
quint8 output[2];
struct i2c_msg msgs[3];
struct i2c_rdwr_ioctl_data msgset[1];
// Header
msgs[0].addr = m_slaveAddress;
msgs[0].flags = I2C_M_REV_DIR_ADDR;
msgs[0].len = 4;
msgs[0].buf = header;
msgs[0].buf[0] = reg >> 8; // REGISTER_ADDRESS_MSB
msgs[0].buf[1] = reg % 256; // REGISTER_ADDRESS_LSB
msgs[0].buf[2] = 0; // NUMBER_OF_WORDS_MSB
msgs[0].buf[3] = 1; // NUMBER_OF_WORDS_LSB
// word
msgs[1].addr = m_slaveAddress;
msgs[1].flags = I2C_M_RD | I2C_M_NOSTART;
msgs[1].len = 2;
msgs[1].buf = output;
msgset[0].msgs = msgs;
msgset[0].nmsgs = 2;
if ((retval = ioctl(m_fd, I2C_RDWR, &msgset)) < 0)
{
int errsv = errno;
qWarning() << "ioctl(I2C_RDWR) failed" << "|" << "retval:" << retval << "|" << "errsv:" << errsv << strerror(errsv);
return retval;
}
qDebug() << "MSB" << output[0];
qDebug() << "LSB" << output[1];
word = output[1] + (output[0] << 8);
return 0;
}
Reading some man pages it seems that I2C_M_REV_DIR_ADDR should do the trick of inverting the rd/wr bit but it has no effect.
I’m looking at the signals form oscilloscope and the rd/wr bit is at 0 regardless of I2C_M_REV_DIR_ADDR being set in the first message.
With msgs[0].flags set to I2C_M_REV_DIR_ADDR is the same as having 0; The i2c traffic looks like this:
S 0x50 ACK 0 ACK 0 ACK 0 ACK 1 ACK 0xFF ACK 0xFF ACK P
With msgs[0].flags set to I2C_M_RD the address byte is 0x51 but all the reset is garbage
S 0x51 ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK P
Why does I2C_M_REV_DIR_ADDR have no effect?
Thanks
-Damien