lpcware

Unexpected behavior from I2C master transfer function

Discussion created by lpcware Employee on Jun 15, 2016
Content originally posted in LPCWare by psatyshur on Sun Nov 17 09:29:32 MST 2013
I am not sure where to post this. I hope this is the right section. I am using LPCOpen V2.0 on an LPV11u37 device. I am attempting to communicate to an I2C slave device using a modified version of the I2C sample code. Single transactions on the I2C bus work fine, but when I need to perform multiple transactions in a row, odd things happen.

For example: I need to modify a register on my I2C slave device. This involves reading the current value of the register, modifying the register, and writing back the result. To read the register, I send one byte -- the address of the register to read. I then receive on byte -- the current value of that register. I then modify it and (in a new I2C transaction) write two bytes, the register address and then the new value to write. My original code to do this looks like this:

I2C_XFER_T DS3232M_I2C;
DS3232M_I2C.slaveAddr = DS3232M_SLA_ADDRESS;

uint8_t RecieveData;
uint8_t SendData[2];
int ret;

DS3232M_I2C.txBuff = SendData;
DS3232M_I2C.rxBuff = &RecieveData;

//Get the current control register
SendData[0] = DS3232M_REG_CONTROL;
DS3232M_I2C.txSz = 1;
DS3232M_I2C.rxSz = 1;
ret = Chip_I2C_MasterTransfer(DEFAULT_I2C, &DS3232M_I2C);

//Disable the requested alarm
SendData[1] = (RecieveData & (~AlarmNumber));
DS3232M_I2C.txSz = 2;
DS3232M_I2C.rxSz = 0;
ret = Chip_I2C_MasterTransfer(DEFAULT_I2C, &DS3232M_I2C);


This code results in incorrect behavior. Watching the bus on my progocol analyzer, the first transaction occurs correctly, but the second one does not. The data transmitted in the second transaction seems to start at SendData[1] instead of SendData[0]. Looking at the actual send and receive variables SendData, and RecieveData, the registers are updated as I expect. However, looking at the pointers DS3232M_I2C.rxBuff and DS3232M_I2C.txBuff, I see that they are incremented by the number of bytes sent or received. Is this the correct behavior of this function? I can fix this problem by reassigning the pointers before every transaction like so:

I2C_XFER_T DS3232M_I2C;
DS3232M_I2C.slaveAddr = DS3232M_SLA_ADDRESS;

uint8_t RecieveData;
uint8_t SendData[2];
int ret;

DS3232M_I2C.txBuff = SendData;
DS3232M_I2C.rxBuff = &RecieveData;

//Get the current control register
SendData[0] = DS3232M_REG_CONTROL;
DS3232M_I2C.txSz = 1;
DS3232M_I2C.rxSz = 1;
ret = Chip_I2C_MasterTransfer(DEFAULT_I2C, &DS3232M_I2C);

//Disable the requested alarm
SendData[1] = (RecieveData & (~AlarmNumber));
DS3232M_I2C.txSz = 2;
DS3232M_I2C.rxSz = 0;
DS3232M_I2C.txBuff = SendData;
DS3232M_I2C.rxBuff = &RecieveData;
ret = Chip_I2C_MasterTransfer(DEFAULT_I2C, &DS3232M_I2C);


But this seems unnecessary. If this is the expected behavior, it might be wise to note this in the documentation for this function to keep any other idiots like me from getting confused by it in the future. :P

Outcomes