Hello,
I am trying to use the Teensy 3.6 to communicate with a bq40z80 chip from Texas Instruments. The chips is a fuel gauge / 'smart' battery management chip. A standard was developed called, SMBus that operates from the well known I2C protocol. However, it has a special start bit that is not typically used in I2C devices. Therefore, the <Wire.h> library does not work to communicate the the battery chip..
A thread here shows how they got it to work, but it uses a library that was built for AVR devices. Unfortunately I just don't think I know enough to be able to convert that to work with the Teensy/ARM platform.
I am hoping that the i2c_t3.h library can suffice. So this is the description of the SMBus protocol..
Below is my code to try and retrieve the voltage from the chip, but the result from Wire.available() is 0.
Supposedly, someone was able to use this "i2cmaster" library for AVR devices, to get the data they wanted. Below is that code.. (if I could somehow adapt this to use the "i2c_t3" instead?)
If anything, check out the last 3 functions. Particularly the lines containing "i2c_rep_start()". That seems like something I want to be able to use if i2c_t3 supports something like that
Any ideas on how to go about properly requesting data from the chip?
Thank you for any and all help! It is vastly appreciated and would make me a very happy person if I can get this working.
I am trying to use the Teensy 3.6 to communicate with a bq40z80 chip from Texas Instruments. The chips is a fuel gauge / 'smart' battery management chip. A standard was developed called, SMBus that operates from the well known I2C protocol. However, it has a special start bit that is not typically used in I2C devices. Therefore, the <Wire.h> library does not work to communicate the the battery chip..
A thread here shows how they got it to work, but it uses a library that was built for AVR devices. Unfortunately I just don't think I know enough to be able to convert that to work with the Teensy/ARM platform.
I am hoping that the i2c_t3.h library can suffice. So this is the description of the SMBus protocol..
Below is my code to try and retrieve the voltage from the chip, but the result from Wire.available() is 0.
Code:
//#include <Wire.h>
#include <i2c_t3.h>
int led = 13;
// the setup routine runs once when you press reset:
void setup() {
Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 100000);
Serial.begin(9600);
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
while(!Serial){
}
Serial.println("Sending..");
Wire.beginTransmission(0x16);
Wire.write(0x9); //get voltage
Wire.endTransmission();
}
// the loop routine runs over and over again forever:
void loop() {
byte num=0;
//receive
Serial.println("Receiving...");
Wire.requestFrom(0x16, 4);
Serial.println(Wire.available());
while(Wire.available())
{
char c = Wire.read();
Serial.print(c);
}
Serial.print("\ndone\n");
delay(1000);
}
Supposedly, someone was able to use this "i2cmaster" library for AVR devices, to get the data they wanted. Below is that code.. (if I could somehow adapt this to use the "i2c_t3" instead?)
If anything, check out the last 3 functions. Particularly the lines containing "i2c_rep_start()". That seems like something I want to be able to use if i2c_t3 supports something like that
Code:
#include <i2cmaster.h>
#define readBufferLen 17
char readBuffer[readBufferLen];
uint8_t i2cBuffer[readBufferLen];
#define deviceaddress B00010110
uint8_t serialCommand, loopCount;
unsigned int serialData;
void setup() {
i2c_init();
PORTC = (1 << PORTC4) | (1 << PORTC5); //enable pullups
Serial.begin(9600);
Serial.println("Ready!");
Serial.println("------");
Serial.print("Mfg: ");
i2c_smbus_read_block(0x20,i2cBuffer,readBufferLen);
Serial.print((char*)i2cBuffer);
Serial.print(" | Dev: ");
i2c_smbus_read_block(0x21,i2cBuffer,readBufferLen);
Serial.print((char*)i2cBuffer);
Serial.print(" | Chem: ");
i2c_smbus_read_block(0x22,i2cBuffer,readBufferLen);
Serial.println((char*)i2cBuffer);
serialData = i2c_smbus_read_word(0x1b);
Serial.print("Date: ");
Serial.print((uint8_t)(serialData >> 5) & B00001111,DEC);
Serial.print('/');
Serial.print((uint8_t)serialData & B00011111,DEC);
Serial.print('/');
Serial.print((serialData >> 9) + 1980,DEC);
Serial.print(" | Cycles: ");
Serial.println(i2c_smbus_read_word(0x17));
}
void loop() {
if (loopCount > 10) {
// gather things
int currVoltage, currAmps, estPercent, currTemp, timeLeft;
currVoltage = i2c_smbus_read_word(0x9);
currAmps = i2c_smbus_read_word(0xA);
estPercent = i2c_smbus_read_word(0xD);
currTemp = i2c_smbus_read_word(0x8);
timeLeft = i2c_smbus_read_word(0x13);
Serial.print((float)currVoltage / 1000, 2);
Serial.print("v, ");
Serial.print((float)currAmps / 1000, 2);
Serial.print(" A, ");
Serial.print(((float)currTemp/10 - 273.15) * 1.8 + 32, 2);
Serial.print(" F, ");
Serial.print(estPercent,DEC);
Serial.print("%, ");
Serial.print(timeLeft,DEC);
Serial.println(" min remaining.");
loopCount = 0;
}
loopCount++;
if (Serial.available()) {
delay(500);
uint8_t x = 0;
if (Serial.peek() == 'w') {
// write
Serial.read(); // get the state out of the buffer
while (Serial.peek() != ';') {
readBuffer[x] = Serial.read();
x++;
if (x > readBufferLen) return;
}
readBuffer[x] = 0; // null the buffer
Serial.read(); // get the semicolon out of there
serialCommand = strtoul(readBuffer, NULL, 0);
Serial.print("Writing word using command: ");
Serial.print(serialCommand,HEX);
x = 0;
while (Serial.peek() != ';') {
readBuffer[x] = Serial.read();
x++;
if (x > readBufferLen) return;
}
readBuffer[x] = 0; // null the buffer
Serial.read(); // clear the semicolon
serialData = strtoul(readBuffer, NULL, 0);
Serial.print(", data: ");
Serial.println(serialData,HEX);
i2c_smbus_write_word(serialCommand,serialData);
Serial.println("Completed.");
} else if (Serial.peek() == 'r') {
// read word
Serial.read(); // get the state out of the buffer
while (Serial.peek() != ';') {
readBuffer[x] = Serial.read();
x++;
if (x > readBufferLen) return;
}
readBuffer[x] = 0; // null the buffer
Serial.read(); // clear the semicolon
serialCommand = strtoul(readBuffer, NULL, 0);
Serial.print("Reading word using command: ");
Serial.println(serialCommand,HEX);
serialData = i2c_smbus_read_word(serialCommand);
Serial.print("Completed, received: ");
Serial.print(serialData,HEX);
Serial.print(" (hex), ");
Serial.print(serialData,DEC);
Serial.println(" (dec)");
} else if (Serial.peek() == 'b') {
// read block
Serial.read(); // get the state out of the buffer
while (Serial.peek() != ';') {
readBuffer[x] = Serial.read();
x++;
if (x > readBufferLen) return;
}
Serial.read(); // clear the semicolon
readBuffer[x] = 0;
serialCommand = strtoul(readBuffer, NULL, 0);
Serial.print("Reading block using command: ");
Serial.println(serialCommand,HEX);
x = i2c_smbus_read_block(serialCommand,i2cBuffer,readBufferLen);
Serial.print("Completed, received ");
Serial.print(x,DEC);
Serial.println(" bytes:");
x = 0;
for (x=0; x<readBufferLen; x++) {
Serial.print(i2cBuffer[x]);
}
Serial.println();
} else {
Serial.print("Junk: ");
Serial.println(Serial.read(),HEX);
}
}
delay(500);
}
void i2c_smbus_write_word ( uint8_t command, unsigned int data ) {
i2c_start_wait(deviceaddress + I2C_WRITE);
i2c_write(command);
i2c_write((uint8_t)data);
i2c_write((uint8_t)(data>>8));
i2c_stop();
return;
}
unsigned int i2c_smbus_read_word ( uint8_t command ) {
unsigned int buffer = 0;
i2c_start_wait(deviceaddress + I2C_WRITE);
i2c_write(command);
i2c_rep_start(deviceaddress + I2C_READ);
buffer = i2c_readAck();
buffer += i2c_readNak() << 8;
return buffer;
}
uint8_t i2c_smbus_read_block ( uint8_t command, uint8_t* blockBuffer, uint8_t blockBufferLen ) {
uint8_t x = 0;
uint8_t y = 0;
i2c_start_wait(deviceaddress + I2C_WRITE);
i2c_write(command);
i2c_rep_start(deviceaddress + I2C_READ);
y = i2c_readAck();
for (x=0; x<y-1; x++) {
blockBuffer[x] = i2c_readAck();
}
blockBuffer[x] = i2c_readNak();
blockBuffer[x+1] = 0;
return y;
}
Any ideas on how to go about properly requesting data from the chip?
Thank you for any and all help! It is vastly appreciated and would make me a very happy person if I can get this working.