I2C Slave as SMBus

Hi,

I am trying to use an Arduino as a SMBus slave to respond to requests from the 3DR Solo. The smart batteries it uses are no longer made and are starting to die so i am looking to use a standard lipo battery with an Arduino as the “Smart Battery” collecting info from the standard battery.

Based on the code below the receiveEvent comes through and then the requestEvent. This continues for around cycles and then stops (I am assuming the Solo stops as it is not getting back the info it expects and times out).

Any advice on what could be going wrong or pointing to any examples where this has been used before would be great.

Here is the code i am using.

/*
 Great info on I2C including Slave
 http://www.gammon.com.au/forum/?id=10896

*/

#include <Wire.h>

const byte MY_ADDRESS = 0x0B;
int myVoltage = 15000;

byte BATT_SMBUS_VOLTAGE = 9;

unsigned long previousMillis = 0;
long interval = 1000;   
int ledState = LOW; 
byte command;
const int ledPin =  LED_BUILTIN;
int myCounter =0;

void setup() {
  
  command = 0;
  
  Wire.begin (MY_ADDRESS);
  Wire.onReceive (receiveEvent);  // interrupt handler for incoming messages
  Wire.onRequest (requestEvent);  // interrupt handler for when data is wanted
  
  //Set LED Hight to Show it has Started
  pinMode(LED_BUILTIN, OUTPUT);
  ledState = HIGH;
  digitalWrite(ledPin, ledState);

  //Begin Serial for debuging
  Serial.begin(9600); 

}

void loop() {

  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time you were in loop
    previousMillis = currentMillis; 

    //Decrease voltage by 5mV each second
    myVoltage = myVoltage - 5 ;

  }
}

void receiveEvent (int howMany)
  {
  command = Wire.read ();  // remember command for when we get request
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    digitalWrite(ledPin, ledState);
    
    //Print register requested
    Serial.print("command = ");    
    Serial.println(command);
    
  } // end of receiveEvent

void requestEvent ()
  {
  
  
  if (command == 9){  //9 = battery voltage request
    //Send voltage in 2 bytes
    Wire.write((byte) (myVoltage>>8));
    Wire.write((byte) (myVoltage));
    
    //Print voltage sent and number of times loop entered
    Serial.print("Send Voltage = ");
    Serial.println(myVoltage);

    myCounter = myCounter + 1;
    Serial.print("Count = ");
    Serial.println(myCounter);    
    
  }
  }  // end of requestEvent

I was missing sending a PEC (CRC-8) code after the 2 bytes. I implemented this and have had it working. I just need to get it working reliably.

Hi,
I know this topic is somewhat old but I would be intreseted in knowing if you has success implementing the PEC byte ?

Any chance to get the code here ?
Thanks

Hi, sorry i didn't get any notification that someone had posted on this tread.

Here is the tread on the 3DR forum that i started. There are links to working code in here.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.