Issue with MLX90614 I2C read (repeated start bit)

10 Mar 2010

I have trouble reading from the MLX90614 sensor. It seems that when i2c.write command is issued to initate the i2c.read command, there is a stop bit sent after write and before read. Instead of stop bit, Master needs to send a repeated start bit and then issue i2c.read command. MLX90614 uses SMbus, which is very similar to I2C.

http://www.robot-electronics.co.uk/htm/using_the_i2c_bus.htm shows that the I2C protocol has the repeated start bit just like SMbus does.

MCU is NXP LPC1768

 

10 Mar 2010 . Edited: 10 Mar 2010

Is your problem similar which discussed here?

10 Mar 2010

It is similar and I have looked at that solution before. The problem is the device 'read' protocol goes like this:

START->slave_address->WRITE->ACK->command->ACK->REPEATED_START->slave_address->READ->ACK..... followed by the data bytes.

But the 'write' provided by mbed seems to do this:

START->slave_address->WRITE->ACK->command->ACK->STOP

 

Is there any way for Master to send REPEATED_START instead of STOP after the write command?

12 Mar 2010

I think mbed may not have API that implement the "repeated-START" since the I2C library has very simple calls.

By the way, Does MLX90614's "Repeated-START" is mandatory for its communication? 
I believe the I2C bus devices which is handling the repeated-START as same as normal start. So even if the transactions separated into two, still it has same meaning for the I2C device.

Or is it mandatory from viewpoint if your system?
Unless your I2C bus is not having other bus master, the "repeated-START" may be able to be replaced by "STOP" and "START" with no problem.

http://www.i2c-bus.org/repeated-start-condition/

12 Mar 2010

There is only one master on the bus. I have verified that i can do a write command since I was able to change the Address of the sensor from the default to the desired. I have also verified that i can begin accessing the device, since if(i2c.write((addressInner<<1), cmd, 1)==0) is triggered. I have also attempted to put the read command right after the write command in hopes that if START is followed right after STOP, it would be the same as REPEATED START:

i2c.write((addressInner<<1), cmd, 1);      
i2c.read((addressInner<<1), temp1, 3);

Still no luck. It appears that another person using Arduino had an almost exact issue: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1214872633

Is it possible to change the way i2c.write and/or i2c.read command operates? I am thinking that if i could change i2c.read to include a part of i2c.write in it, thus removing the STOP that usually comes after i2c.write, I would be able to resolve my situation.

Any comments and insights are greatly welcomed as i am starting to run out of time, but would rather use I2C(SMbus) than PWM.

Thanks in advance

12 Mar 2010

Maybe try using I2C routines from the DriverLibrary. I made it compile with the online compiler: DriverLibrary

See the original zip for documentation and examples. The I2C\master one looks like exactly what you need:

" - Finally, the master send two bytes to slave, send repeat start immediately and receive from slave a number of data byte."

14 Mar 2010

Thank you for your response. I have looked through the DriverLibrary, and i think this would work. Unfortunately, I can't figure it out. Any chance you could help me out.

The addresses of the devices are 0x04, 0x08, 0x10. The RAM address to read is 0x07. It will send 3 bytes back. The pins are sda=p9, scl=p10. Frequency 10K->100K. 

The i2c.write command from the original mbed library works fine. I would like to only use the read function from the DriverLibrary.

21 Mar 2010

The repeat-start is not currently supported in the I2C API; I'll add a feature request to investigate adding this.

Did you get it working in the end?

Simon

22 Mar 2010

I couldn't figure out the DriverLibrary. I've tried to use DigitalInOut and use the timing information to imitate SMBus (I2C with repeated start), but i still seem to get 0xFF, 0xFF, 0xFF. Do you know if it's even possible to use DigitalInOut to imitate an SMBus?

Thanks for any information,

Denis

16 May 2010

I have just been trying to get a LEGO Mindstorms Ultrasonic sensor to talk to my mbed, with no luck.

Looks like I may have the same problem with not being able to send a repeat start (using standard I2C class), per the discussion here http://forums.nxtasy.org/index.php?showtopic=2092

Any word on when support for repeat-start might be available?

 

16 May 2010

It's on my work list for this week. Not sure when it will go live once I get it working, but hopefully not too long.

19 May 2010 . Edited: 19 May 2010

I have some experience with i2c implementations in other libraries for AVR and PIC microcontrollers. Normally these implementations all have the high-level i2c-functions (like mbed) for the standard cases. But they all also expose the low level i2c-functions (from which the high-level functions are built) for the special cases (Access to i2c-memory-chips etc.). I don't know the i2c implementation in the mbed library, but maybe it could be also possible to expose the low-level functions.

Normally the low-level i2c-functions for an i2c-master at least consist of:

void i2c_start(void);
void i2c_stop(void);
void i2c_putc(char ch);
char i2c_getc(ACK | NO_ACK);

Generally with these four functions (some libraries also implement i2c_restart, but actually it's practically the same as i2c_start) one can accomplish all i2c communication sequence needs.

If the mbed library implements similar low-level i2c-functions, it would maybe be the easiest solution to just expose those functions for public use instead of implementing a new high-level function just for the start->send_even_address->send_data->restart->send_odd_address->get_data->stop sequence, which then still might not fullfill all possible sequence needs. For example there are situations, where one can write to multiple slave chips on one i2c-bus without sending stop in between by just having a repeating sequence of start->send_slave(n)_address->send_data ... and the stop only sent at the end of all the repeats (for n slave chips). This is convenient for slave chips which can synchronize their latch-in of newly clocked-in data with the stop command (i.e. some i2c-multiple-output-PWM-LED-drivers etc.).

Best regards
Neni

02 Jun 2010

I'm using the same Temperature Sensor (MLX90614) and ofcause i had the same problem with the repeated start bit. So I programed the reading function myself and now its working. But i needed some days for that....

11 Jun 2010

Sorry, should have posted here earlier - the latest version of the library does support repeated start. We're currently looking at implementing a lower level interface to I2C (individual byte reads, writes, stop start etc.) in addition to the current interface. If this plays nicely with the existing structure, this should be released soon.

24 Dec 2010

Getting that 'low' probably isn't needed, so long as a write+read is supported.   This is what I put into Tollos (on the mbed) -- using the LPC library to do the actual tricky bits & arbitration.   This can do pure writes or reads, or a mixture.   [It was a bit trickier to implement on STM, but the interface is the same.]

Mike

-----------

/* --------------------------------------------------------------- */
/* i2cIO -- i2C general I/O function                               */
/*                                                                 */
/*   device -- channel and physical address of device              */
/*             (channel shifted left 16 bits and ORed with 7-bit   */
/*             or 10-bit i2c physical address); currently only     */
/*             7-bit addresses are supported                       */
/*   put    -- start of byte(s) to write                           */
/*   putlen -- count of byte(s) to write [may be 0]                */
/*   get    -- start of byte(s) to read                            */
/*   getlen -- count of byte(s) to read [may be 0]                 */
/*                                                                 */
/*   returns 0 if OK, negative if error                            */
/*                                                                 */
/* put is ignored if putlen is 0 (NULL recommended).               */
/* get is ignored if getlen is 0 (NULL recommended).               */
/*                                                                 */
/* This function will automatically initialize the appropriate     */
/* i2c channel when first called for a channel, unless already     */
/* initialized by an explicit call to i2cInitIO.                   */
/* --------------------------------------------------------------- */
int i2cIO(uint device, byte *put, uint putlen, byte *get, uint getlen) {
  uint channel=i2cChannel(device); // channel 0-2
  uint addr=i2cAddr7Bit(device);   // physical address
  I2C_M_SETUP_Type blok;           // Master setup control block
  Status mtd;                      // value from LPC functions

  if (channel>=I2C_CHANNELS) return -1; // minimal checking

  // initialise channel if needed   if (!businit[channel]) {    if (i2cInitIO(channel, busspeed[channel])) return -2;    }

  // fill in control block   blok.sl_addr7bit=addr;   blok.tx_data=put;   blok.tx_length=putlen;   blok.rx_data=get;   blok.rx_length=getlen;   blok.retransmissions_max=5;

  mtd=I2C_MasterTransferData(bus[channel], &blok, I2C_TRANSFER_POLLING);   if (mtd==ERROR) return -1;   return 0;  // SUCCESS   } // i2cIO