How to do I2C double start to communicate to LTC2992?

Status
Not open for further replies.

ariesboy571

Active member
Hey, all. So...I've run around in circles with this, for about three weeks, now. I'm getting mostly nowhere, and I have questions. The story so far:
I'm using (or, attempting to use) an LTC2992 to monitor a power supply I've designed. The problem I'm having is that the LTC2992 is a really finicky beast, or seems to be, because it wants double-starts on virtually every I2C operation. The data sheet for the chip is helpful but somewhat obtuse; perhaps I'm not understanding what I'm reading (most likely) or just don't know what to do with it (ah, the days I wish I had Paul's understanding of this)...but basically, I'm trying to make my timing work, and it's just...not.
There's a Linear/Analog development board for this chip, and I have both that, and their "Linduino" thingie, and after a moderate amount of trouble, I managed to obtain an "ideal" timing plot. Ideal, meaning, the registers all get set, the readings all come in and look good, etc etc etc.
theirs.jpg
I have timing plots of generic, hardware-agnostic I2C timing, that represent my own efforts to contact the chip; they look nothing at all like the "ideal" plot (delays look wrong, no double-start):
mine.jpg
My question is, how do I put in the delays I'm seeing, between accesses; how, of all things, do I actually do a double-start on I2C? I can see it very clearly, in the "ideal" plot, but it never happens on mine.
I loaded and am currently using the i2c_t3 library (https://forum.pjrc.com/threads/21680-New-I2C-library-for-Teensy3) but I'm getting exactly the same plot as with the standard Wire library.
One problem with the "Linduino" code that they're using is that there are low-level I2C commands in their Sketchbook library, that are hardware-specific for the microcontroller they're using. I read the relevant sections of the Kinetis spec sheet, but don't see any commands or registers that seem relevant.
Anyone got any ideas?
 
By "double start", maybe you mean "repeated start"?

With the Arduino Wire library, you accomplish a repeated start using Wire.endTransmission(false).

https://www.arduino.cc/en/Reference/WireEndTransmission

Of course, right after Wire.endTransmission(false), you would do another Wire.beginTransmission() or Wire.requestFrom(). Likewise, Wire.requestFrom() supports an optional 3rd parameter to perform a repeated start.

https://www.arduino.cc/en/Reference/WireRequestFrom

The general idea is you quickly do another Wire.beginTransmission() or Wire.requestFrom() after each with a repeated start, until the very last where you allow it to stop normally.

Repeated start is fully supported on all Teensy boards using the normal Arduino Wire library functions. There's no need to use the more complex i2c_t3 library just to get repeated start.
 
Last edited:
I had not heard of 'double start' - and didn't find it as such but this tutorial may shed some light - or show your case to be different?:: robot-electronics.co.uk/i2c-tutorial

There is a second start sent for a read (or write) as shown in the sequence there - this is what they show for a read:
Reading from the Slave
1. Send a start sequence
2. Send 0xC0 ( I2C address of the CMPS03 with the R/W bit low (even address)
3. Send 0x01 (Internal address of the bearing register)
4. Send a start sequence again (repeated start)
5. Send 0xC1 ( I2C address of the CMPS03 with the R/W bit high (odd address)
6. Read data byte from CMPS03
7. Send the stop sequence.

Has this device ever connected? Perhaps using the SCAN sample? That will clarify the device address.

Note: Teensy use requires a set of pullup resistors on the lines, the internal pullups are not sufficient.
 
Okay, here's the code I'm using. I'm still not certain exactly what you mean. I should check my coffee supply; does caffeine degrade with time?

Code:
#include <i2c_t3.h>

#define LTC2992_ADDR	0x6F

void setup() {
	
	//Wire.begin();
	Wire.begin(I2C_MASTER, 0x00, I2C_PINS_33_34, I2C_PULLUP_EXT, 400000);
	
	// Initialize the serial port to the PC. If we don't have a serial port, don't continue...
	Serial.begin(250000);			
	while(!Serial) { true; }

	Serial.print(__LINE__); Serial.println(": Serial port started.");
	
	Serial.print(__LINE__); Serial.println(": set up I2C.");
	
	delay(500);
	
	// Now set up the mode we want on the LTC2992. For this configuration, continuous scan with only SENSE1 and SENSE2 voltages selected...
	Wire.endTransmission(false);
	Wire.beginTransmission(LTC2992_ADDR);
    Wire.write(0x00);               // to the CTRLA Register (0x00)...
    Wire.write(0x0E);               // bit 7=0, 6-5=00, 4-3=10, 2-0=110; so, 00010110 = 0x16...
    Wire.endTransmission() ;       // stop transmitting
    Serial.print(__LINE__); Serial.println(": sent setup.");
	
	Serial.println();
	
	while(1); // okay stop right there...
}

void loop() {

}

All that gives me is exactly what was there before. Duplicating the beginTransmission() command just writes that address twice.
 
And this:
Code:
#include <i2c_t3.h>

#define LTC2992_ADDR	0x6F

void setup() {
	
	//Wire.begin();
	Wire.begin(I2C_MASTER, 0x00, I2C_PINS_33_34, I2C_PULLUP_EXT, 400000);
	
	// Initialize the serial port to the PC. If we don't have a serial port, don't continue...
	Serial.begin(250000);			
	while(!Serial) { true; }

	Serial.print(__LINE__); Serial.println(": Serial port started.");
	
	Serial.print(__LINE__); Serial.println(": set up I2C.");
	
	delay(500);
	
	// Now set up the mode we want on the LTC2992. For this configuration, continuous scan with only SENSE1 and SENSE2 voltages selected...
	Wire.beginTransmission(LTC2992_ADDR);
	Wire.endTransmission(false);
    Wire.write(0x00);               // to the CTRLA Register (0x00)...
    Wire.write(0x0E);               // bit 7=0, 6-5=00, 4-3=10, 2-0=110; so, 00010110 = 0x16...
    Wire.endTransmission() ;       // stop transmitting
    Serial.print(__LINE__); Serial.println(": sent setup.");
	
	Serial.println();
	
	while(1); // okay stop right there...
}

void loop() {

}

gives me this:
View attachment 14949

Which is a "double start" I suppose, since the first transmission technically never ended, but it's not the same thing that's happening in the very first timing plot I posted. The logic level goes down, then up and down again very quickly.
 
And this:
Code:
#include <i2c_t3.h>

#define LTC2992_ADDR	0x6F

void setup() {
	
	//Wire.begin();
	Wire.begin(I2C_MASTER, 0x00, I2C_PINS_33_34, I2C_PULLUP_EXT, 400000);
	
	// Initialize the serial port to the PC. If we don't have a serial port, don't continue...
	Serial.begin(250000);			
	while(!Serial) { true; }

	Serial.print(__LINE__); Serial.println(": Serial port started.");
	
	Serial.print(__LINE__); Serial.println(": set up I2C.");
	
	delay(500);
	
	// Now set up the mode we want on the LTC2992. For this configuration, continuous scan with only SENSE1 and SENSE2 voltages selected...
	Wire.beginTransmission(LTC2992_ADDR);
	Wire.endTransmission(false);
    Wire.write(0x00);               // to the CTRLA Register (0x00)...
    Wire.write(0x0E);               // bit 7=0, 6-5=00, 4-3=10, 2-0=110; so, 00010110 = 0x16...
    Wire.endTransmission() ;       // stop transmitting
    Serial.print(__LINE__); Serial.println(": sent setup.");
	
	Serial.println();
	
	while(1); // okay stop right there...
}

void loop() {

}

gives me this:
mine2.jpg

Which is a "double start" I suppose, since the first transmission technically never ended, but it's not the same thing that's happening in the very first timing plot I posted. The logic level goes down, then up and down again very quickly.

This is the relevant section from the LTC2992 datasheet. I'm wondering about the "R/W bit set to zero" part.

Write Protocol
The master begins a write operation with a START condi-
tion followed by the 7-bit slave address and the R/W bit
set to zero. After the addressed LTC2992 acknowledges
the address byte, the master then sends a command byte
that indicates which internal register the master wishes to
write. The LTC2992 acknowledges this and then latches
the command byte into its internal register address pointer.
The master then delivers the data byte and the LTC2992
acknowledges once more and writes the data into the in-
ternal register pointed to by the register address pointer. If
the master continues sending additional data bytes with a
write word or extended write command, the additional data
bytes will be acknowledged by the LTC2992, the register
address pointer will automatically increment by one, and
data will be written as previously stated. The write opera-
tion terminates and the register address pointer resets to
0x00 when the master sends a STOP condition.

Read Protocol
The master begins a read operation with a START condi-
tion followed by the 7-bit slave address and the R/W bit
set to zero. After the addressed LTC2992 acknowledges
the address byte, the master then sends a command byte
that indicates which internal register the master wishes to
read. The LTC2992 acknowledges this and then latches the
command byte into its internal register address pointer.
The master then sends a repeated START condition fol-
lowed by the same 7-bit address with the R/W bit now set
to 1. The LTC2992 acknowledges and sends the contents
of the requested register. The transmission terminates
when the master sends a STOP condition. If the master
acknowledges the transmitted data byte, as in a read word
command, the LTC2992 will send the contents of the next
register. If the master keeps acknowledging, the LTC2992
will keep incrementing the register address pointer and
sending out data bytes. The read operation terminates
and the register address pointer resets to 0x00 when the
master sends a STOP condition.
 
Well, it seems to be working. Although I can't really explain how. This code:

Code:
//#include <i2c_t3.h>
#include <Wire.h>
#define LTC2992_ADDR	0x6F

void setup() {
	
	Wire.begin();
    Wire.setSDA(34);    
    Wire.setSCL(33);    
	
	
//	Wire.begin(I2C_MASTER, 0x00, I2C_PINS_33_34, I2C_PULLUP_EXT, 50000);
	
	// Initialize the serial port to the PC. If we don't have a serial port, don't continue...
	Serial.begin(250000);			
	while(!Serial) { true; }

	Serial.print(__LINE__); Serial.println(": Serial port started.");
	
	Serial.print(__LINE__); Serial.println(": set up I2C.");
	
	delay(500);
	
	// Now set up the mode we want on the LTC2992. For this configuration, continuous scan with only SENSE1 and SENSE2 voltages selected...
	Wire.beginTransmission(LTC2992_ADDR);
    Wire.write(0x00);               // to the CTRLA Register (0x00)...
    Wire.write(0x0E);               // bit 7=0, 6-5=00, 4-3=10, 2-0=110; so, 00010110 = 0x16...
    Wire.endTransmission() ;       // stop transmitting
    Serial.print(__LINE__); Serial.println(": sent setup.");
	
	delay(10);
	
	Wire.beginTransmission(LTC2992_ADDR);
	Wire.write(0x00);
	Wire.endTransmission(false);
	Wire.requestFrom(LTC2992_ADDR, 1);       // ...and request the 1-byte register value.
    while (Wire.available()) {    // if we got anything...
        Serial.print(__LINE__); Serial.print(": ADC Setup Register is "); Serial.println(Wire.read(), HEX); // print it as hex 
    }
	Wire.endTransmission(true);
	
	delay(10);
	
	Wire.beginTransmission(LTC2992_ADDR);
	Wire.write(0x00);
	Wire.endTransmission(false);
	Wire.requestFrom(LTC2992_ADDR, 1);       // ...and request the 1-byte register value.
    while (Wire.available()) {    // if we got anything...
        Serial.print(__LINE__); Serial.print(": ADC Setup Register is "); Serial.println(Wire.read(), HEX); // print it as hex 
    }
	Wire.endTransmission(true);
	
	
	while(1); // okay stop right there...
}

void loop() {

}

generates this trace (this is part of it) on the read back from the 0x00 register:
mine3.jpg

When I repeat the read, the value (0x0E) is still in the register. So it seems to be working. The value is staying set, on the repeated read at the end of the setup() function.

To say that this is confusing is rather an understatement, although in my case, that's not difficult to do.
 
Got it working!

Thank you, Paul!

As it turns out, although the hardware-specific implementation *looks* a certain way on the logic analyzer, it's a little deceptive, because after correctly tweaking the endTransmission() statements, everything just...turned on. And works beautifully.
 
Status
Not open for further replies.
Back
Top