I2C Repeated start

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

I2C Repeated start

3,850 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by bobi-one on Mon Oct 27 06:41:33 MST 2014
I Am trying to interface an  accelerometer with LPC1549 and trying to use the LPCOpen library.
Reusing the example for periph_i2cm_interrupt. I noticed that my chip requires repeated start when reading from it.
How can i modify  SetupXferRecAndExecutein order to do such thing?

static void SetupXferRecAndExecute(uint8_t devAddr,
   uint8_t *txBuffPtr,
   uint16_t txSize,
   uint8_t *rxBuffPtr,
   uint16_t rxSize)
{
/* Setup I2C transfer record */
i2cmXferRec.slaveAddr = devAddr;
i2cmXferRec.status = 0;
i2cmXferRec.txSz = txSize;
i2cmXferRec.rxSz = rxSize;
i2cmXferRec.txBuff = txBuffPtr;
i2cmXferRec.rxBuff = rxBuffPtr;

Chip_I2CM_Xfer(LPC_I2C0, &i2cmXferRec);
/* Enable Master Interrupts */
Chip_I2C_EnableInt(LPC_I2C0, I2C_INTENSET_MSTPENDING | I2C_INTENSET_MSTRARBLOSS | I2C_INTENSET_MSTSTSTPERR);
/* Wait for transfer completion */
WaitForI2cXferComplete(&i2cmXferRec);
/* Clear all Interrupts */
Chip_I2C_ClearInt(LPC_I2C0, I2C_INTENSET_MSTPENDING | I2C_INTENSET_MSTRARBLOSS | I2C_INTENSET_MSTSTSTPERR);
}

Labels (1)
0 Kudos
10 Replies

3,349 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by 1234567890 on Sun Nov 02 07:18:41 MST 2014

Quote:

I believe the functions work and all the problems are cause because of the data coming from the sensor.



Well, of course Sunday is the day to believe, but when your parameter is definately wrong...
And 'data_write' and '&data_write[0]' is the same in C, just for clarification. Have a look at the C-book of your choice; chapter 'arrays and strings' or so.
Using an address instead of a value cannot 'work' (and vice versa).
0 Kudos

3,349 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by bobi-one on Fri Oct 31 01:34:24 MST 2014

Quote: 1234567890

Quote: bobi-one
  static void MPU9150_writeByte(uint8_t address, uint8_t subAddress, uint8_t data)
{
   char data_write[2];
   char data_read[2];
   data_write[0] = subAddress;
   data_write[1] = data;
   SetupXferRecAndExecute(address, &data_write, 2, data_read,1);
}

  static char MPU9150_readByte(uint8_t address, uint8_t subAddress)
{
    char data[1]; // `data` will store the register data     
    char data_write[1];
    data_write[0] = subAddress;
    SetupXferRecAndExecute(address, &data_write,1, data, 1);
    return data[0]; 
}

  static void MPU9150_readBytes(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest)
{    
    int ii;
    char data[14];
    char data_write[1];
    data_write[0] = subAddress;
    SetupXferRecAndExecute(address,&data_write,1,data, count);
    for(ii = 0; ii < count; ii++) {
     dest[ii] = data[ii];
    }
} 
 




And no errors or warnings from the compiler? At the first glance
&data_write
is wrong; must be only
data_write
because data_write is an array like data_read.


Oh, i just noticed those ampersands ( there was even a warning).
I believe the functions work and all the problems are cause because of the data coming from the sensor. 
Have somebody else worked with MPU9150? Because the driver I am familiar with is for linux kernel and it is hard to interface just like that?

Regards,
Boyko
0 Kudos

3,349 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by LabRat on Wed Oct 29 19:32:19 MST 2014
It's not very difficult to use own functions with this sample...

As sample I've added EEPROM access functions.
//EEPROM access
#define BUFF_SIZE 64
uint8_t tx_buff[BUFF_SIZE];
uint8_t rx_buff[BUFF_SIZE];
uint8_t tx_data[BUFF_SIZE];
uint16_t address;
uint16_t len;

//read bytes from address
static int read_address(uint16_t address, uint16_t bytes)
{
 tx_buff[0] = (address >> 8) & 0xFF;
 tx_buff[1] =  address & 0xFF;
[color=#f00] SetupXferRecAndExecute(I2C_ADDR_7BIT, &tx_buff[0], 2, &rx_buff[0], bytes);[/color]
 if (i2cmXferRec.status == I2CM_STATUS_OK)
 {
  return 1;
 }
 return 0;
}

//write bytes to address
static int write_address(uint16_t address, uint16_t bytes)
{
 tx_buff[0] = (address >> 8) & 0xFF;
 tx_buff[1] =  address & 0xFF;
 memcpy(&tx_buff[2],&tx_data[0],bytes);
 [color=#f00]SetupXferRecAndExecute(I2C_ADDR_7BIT, &tx_buff[0], bytes+2, &rx_buff[0], 0);[/color]
 if (i2cmXferRec.status == I2CM_STATUS_OK)
 {
  return 1;
 }
 return 0;
}

//write data
tx_data[0] = 0x12;
tx_data[1] = 0x34;
tx_data[2] = 0x56;
tx_data[3] = 0x78;
address = 0x10;
len = 4;
ret = write_address(address,len);
printf("Write Data to Address  0x%04X-",address);
if(ret)printf("Success ");
else printf("Error ");
for(i=0; i < len; i++){printf("%02X ",tx_data);}
printf("\n");


//read data
address = 0x10;
len = 4;
ret = read_address(address,len);
printf("Read Data from Address 0x%04X-",address);
if(ret)printf("Success ");
else printf("Error ");
for(i=0; i < len; i++){printf("%02X ",rx_buff);}
printf("\n");

This EEPROM sample is accessing data bytes with a [color=#f00]2 byte address[/color].

I think MPU-9150 is accessing registers with 1 byte.
So a register write function should transmit 2 bytes (register_address + data) and receive 0.
A register read function should transmit 1 byte (register address) and receive 1 byte (data).
Usually SetupXferRecAndExecute is doing everything what's necessary, you just have to fill the buffers and use the correct I2C 7bit address...


0 Kudos

3,349 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by 1234567890 on Wed Oct 29 13:01:39 MST 2014

Quote: bobi-one
  static void MPU9150_writeByte(uint8_t address, uint8_t subAddress, uint8_t data)
{
   char data_write[2];
   char data_read[2];
   data_write[0] = subAddress;
   data_write[1] = data;
   SetupXferRecAndExecute(address, &data_write, 2, data_read,1);
}

  static char MPU9150_readByte(uint8_t address, uint8_t subAddress)
{
    char data[1]; // `data` will store the register data     
    char data_write[1];
    data_write[0] = subAddress;
    SetupXferRecAndExecute(address, &data_write,1, data, 1);
    return data[0]; 
}

  static void MPU9150_readBytes(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest)
{    
    int ii;
    char data[14];
    char data_write[1];
    data_write[0] = subAddress;
    SetupXferRecAndExecute(address,&data_write,1,data, count);
    for(ii = 0; ii < count; ii++) {
     dest[ii] = data[ii];
    }
} 
 




And no errors or warnings from the compiler? At the first glance
&data_write
is wrong; must be only
data_write
because data_write is an array like data_read.
0 Kudos

3,349 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by LabRat on Wed Oct 29 08:52:28 MST 2014
I2C protocol of MPU-9150 doesn't look exotic  :)

Would suggest to [color=#f00]read[/color] WHO_AM_I register (Type: Read Only)...
0 Kudos

3,349 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by NXP_Paul on Wed Oct 29 08:28:22 MST 2014
The fact that you're getting values back from the slave device, and there are no I2C errors reported is a good sign.
Now the question is whether the software is corrupting the values, or is the data on the bus not what you really expected.
You really need to get a scope and observe what is being transmitted on the bus.  I prefer a scope to a logic analyzer for looking at the I2C bus since it provides much more detail.

Paul
0 Kudos

3,349 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by bobi-one on Wed Oct 29 07:52:20 MST 2014
Hi,
Writing to the WHO_I_M register of the slave doesn't return the expected value( only a couple of times actually did), so i presume the communication with it is not  working correctly. I did not observe any error conditions from the I2C .
Regards
0 Kudos

3,349 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by NXP_Paul on Wed Oct 29 07:08:16 MST 2014
The attached sequences are standard I2C communications, so these should not cause any issues.
What do you mean that your code is failing on simple WHO_AM_I tests? I am not sure I understand what you are trying to accomplish.  I assume you are trying to read back a specific register, and receive a specific response, but please confirm.
What is the result returned by the I2C functions (is there a NACK, or other error conditions)?

Paul
0 Kudos

3,349 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by bobi-one on Wed Oct 29 05:52:23 MST 2014
Thanks for the reply Paul,
Those are the functions that i wrote. But it seems the data that is coming  isn't quite as expected ( I cannot put logic analyser at the moment to observe the communication)

  static void MPU9150_writeByte(uint8_t address, uint8_t subAddress, uint8_t data)
{
   char data_write[2];
   char data_read[2];
   data_write[0] = subAddress;
   data_write[1] = data;
   SetupXferRecAndExecute(address, &data_write, 2, data_read,1);
}

  static char MPU9150_readByte(uint8_t address, uint8_t subAddress)
{
    char data[1]; // `data` will store the register data     
    char data_write[1];
    data_write[0] = subAddress;
    SetupXferRecAndExecute(address, &data_write,1, data, 1);
    return data[0]; 
}

  static void MPU9150_readBytes(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest)
{    
    int ii;
    char data[14];
    char data_write[1];
    data_write[0] = subAddress;
    SetupXferRecAndExecute(address,&data_write,1,data, count);
    for(ii = 0; ii < count; ii++) {
     dest[ii] = data[ii];
    }
} 
 

I have attached the communication sequence required by the slave device. But my code is failing on simple WHO_AM_I reading ( returns different values).
Any suggestions how to fix my application?
0 Kudos

3,349 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by NXP_Paul on Mon Oct 27 08:43:29 MST 2014
Hi
Generally, you only need to specify a value greater than zero for rxSize (i2cmXferRec.rxSz = rxSize).  This should provide the repeated start between the tx and rx messages.

Paul
0 Kudos