Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 1 of 1

Thread: SMBus with i2c_t3?

  1. #1
    Junior Member
    Join Date
    Dec 2019
    Posts
    4

    SMBus with i2c_t3?

    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..

    Click image for larger version. 

Name:	PAC1720-SMBus-Protocol.png 
Views:	1 
Size:	51.6 KB 
ID:	18750

    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.
    Attached Thumbnails Attached Thumbnails Click image for larger version. 

Name:	jEpgk.png 
Views:	1 
Size:	5.3 KB 
ID:	18749  

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •