I am doing a project where I need to get fast current and voltage and to store it in arrays. I would like to reach MHz (don't know if possible). Therefor I choosed INA226 because it is pretty accurate and can handle high speed (HS) mode (at least the datasheet says that: http://www.ti.com/product/INA226/datasheet ).
I found this nice library already made for Arduino and INA226 GitHub - jarzebski/Arduino-INA226: INA226 Bi-directional Current/Power Monitor Arduino Librar. I use it and it works, but I cant speed it up.
I was googleing a lot around and tried to change twi.h, wire.h and ina226.h / ina226.ccp and TWBR, but it all didnt help.
I controlled the speed by using millis().
Here is my simple code to try if I can reach HS (Wire.setClock(xxxxxx) didn't work as well):
/*
INA226 Bi-directional Current/Power Monitor. Simple Example.
Read more: http://www.jarzebski.pl/arduino/czujniki-i-sensory/cyfrowy-czujnik-pradu-mocy-ina226.html
GIT: https://github.com/jarzebski/Arduino-INA226
Web: http://www.jarzebski.pl
(c) 2014 by Korneliusz Jarzebski
*/
#include <Wire.h>
#include <INA226.h>
INA226 ina;
void checkConfig()
{
Serial.print("Mode: ");
switch (ina.getMode())
{
case INA226_MODE_POWER_DOWN: Serial.println("Power-Down"); break;
case INA226_MODE_SHUNT_TRIG: Serial.println("Shunt Voltage, Triggered"); break;
case INA226_MODE_BUS_TRIG: Serial.println("Bus Voltage, Triggered"); break;
case INA226_MODE_SHUNT_BUS_TRIG: Serial.println("Shunt and Bus, Triggered"); break;
case INA226_MODE_ADC_OFF: Serial.println("ADC Off"); break;
case INA226_MODE_SHUNT_CONT: Serial.println("Shunt Voltage, Continuous"); break;
case INA226_MODE_BUS_CONT: Serial.println("Bus Voltage, Continuous"); break;
case INA226_MODE_SHUNT_BUS_CONT: Serial.println("Shunt and Bus, Continuous"); break;
default: Serial.println("unknown");
}
Serial.print("Samples average: ");
switch (ina.getAverages())
{
case INA226_AVERAGES_1: Serial.println("1 sample"); break;
case INA226_AVERAGES_4: Serial.println("4 samples"); break;
case INA226_AVERAGES_16: Serial.println("16 samples"); break;
case INA226_AVERAGES_64: Serial.println("64 samples"); break;
case INA226_AVERAGES_128: Serial.println("128 samples"); break;
case INA226_AVERAGES_256: Serial.println("256 samples"); break;
case INA226_AVERAGES_512: Serial.println("512 samples"); break;
case INA226_AVERAGES_1024: Serial.println("1024 samples"); break;
default: Serial.println("unknown");
}
Serial.print("Bus conversion time: ");
switch (ina.getBusConversionTime())
{
case INA226_BUS_CONV_TIME_140US: Serial.println("140uS"); break;
case INA226_BUS_CONV_TIME_204US: Serial.println("204uS"); break;
case INA226_BUS_CONV_TIME_332US: Serial.println("332uS"); break;
case INA226_BUS_CONV_TIME_588US: Serial.println("558uS"); break;
case INA226_BUS_CONV_TIME_1100US: Serial.println("1.100ms"); break;
case INA226_BUS_CONV_TIME_2116US: Serial.println("2.116ms"); break;
case INA226_BUS_CONV_TIME_4156US: Serial.println("4.156ms"); break;
case INA226_BUS_CONV_TIME_8244US: Serial.println("8.244ms"); break;
default: Serial.println("unknown");
}
Serial.print("Shunt conversion time: ");
switch (ina.getShuntConversionTime())
{
case INA226_SHUNT_CONV_TIME_140US: Serial.println("140uS"); break;
case INA226_SHUNT_CONV_TIME_204US: Serial.println("204uS"); break;
case INA226_SHUNT_CONV_TIME_332US: Serial.println("332uS"); break;
case INA226_SHUNT_CONV_TIME_588US: Serial.println("558uS"); break;
case INA226_SHUNT_CONV_TIME_1100US: Serial.println("1.100ms"); break;
case INA226_SHUNT_CONV_TIME_2116US: Serial.println("2.116ms"); break;
case INA226_SHUNT_CONV_TIME_4156US: Serial.println("4.156ms"); break;
case INA226_SHUNT_CONV_TIME_8244US: Serial.println("8.244ms"); break;
default: Serial.println("unknown");
}
Serial.print("Max possible current: ");
Serial.print(ina.getMaxPossibleCurrent());
Serial.println(" A");
Serial.print("Max current: ");
Serial.print(ina.getMaxCurrent());
Serial.println(" A");
Serial.print("Max shunt voltage: ");
Serial.print(ina.getMaxShuntVoltage());
Serial.println(" V");
Serial.print("Max power: ");
Serial.print(ina.getMaxPower());
Serial.println(" W");
}
void setup()
{
Serial.begin(115200);
Serial.println("Initialize INA226");
Serial.println("-----------------------------------------------");
// Default INA226 address is 0x40
ina.begin();
// Configure INA226
ina.configure(INA226_AVERAGES_4, INA226_BUS_CONV_TIME_140US, INA226_SHUNT_CONV_TIME_140US, INA226_MODE_SHUNT_BUS_CONT);
// Calibrate INA226. Rshunt = 0.01 ohm, Max excepted current = 4A
ina.calibrate(0.004356, 5);
// Display configuration
checkConfig();
Serial.println("-----------------------------------------------");
int l;
float v_data[l];
float i_data[l];
}
void loop()
{
float v;
float i;
int l=10000;
float v_data[l];
float i_data[l];
unsigned long previousMillis= millis();
unsigned long currentMillis = millis();
Serial.println(currentMillis - previousMillis);
for (int g = 0; g < l; g = g + 1) {
v = ina.readBusVoltage(), 3;//g+0.0001;//
i = ina.readShuntCurrent(), 3;//g+1.001;//
v_data[g]=v;
i_data[g]=i;
}
currentMillis = millis();
Serial.println(currentMillis - previousMillis);
Serial.print("Bus voltage: ");
Serial.print("\t");
Serial.print(v_data[8888], 3);
Serial.println(" V");
Serial.print("\n");
Serial.print("Shunt current: ");
Serial.print("\t");
Serial.print(i_data[8888], 3);
Serial.println(" A");
Serial.print("\n");
delay(500);
}
I would be really happy about any kind of help and suggestion. I am on one's last legs.. >:( ..
I tried really a lot to enhance the I2C frequency of my Due to communicate with INA226, but nothing worked...is there maybe a bug? I can only slow it down to sth. like Wire.setClock(50000L), but 400000L is just the regular frequency...does anybody sth. know about that?
By the way, I tried the same Code with Arduino Uno and just Wire.setClock(200000L) was the fastes on which did work...thats normal?
I gave it a lot of tries and I cant speed up over 100kHz...slowing down is possible.
If I try to use the SoftI2CMaster library an error appears... looks like it doesnt find the <avr\io.h> ...
but manually I found it under ...Arduino\hardware\tools\avr\avr\include\avr
strange things are happening here with arduino and I2C :o
UPDATE:
And as I just saw, have PIN 20 and PIN 21 internal pull-ups:
"TWI 1: 20 (SDA) and 21 (SCL)
TWI 2: SDA1 and SCL1.
Support TWI communication using the Wire library. SDA1 and SCL1 can be controlled using the Wire1 class provided by the Wire library. While SDA and SCL have internal pullup resistors, SDA1 and SCL1 have not. Adding two pullup resistor on SDA1 and SCL1 lines is required for using Wire1."
Why it is slower than expected, I don't know. But first get the I2C bus right, and test with that.
In the schematic are no pullup resistors. Without pullup resistors the I2C is high impedance and won't work properly.
An actual piece of "cable" is always bad for I2C. The SDA and SCL should preferrably not be next to each other in the same cable, and the maximum capacitance to GND is 400pF for I2C. The worst thing is when SDA and SCL use twisted pair or are next to each other in a ribbon cable.
The schematic show SDA and SCL next to each other, and I think that is a flat flex cable ?
That is for sure a design mistake.
Add pullup resistors to 3.3V. Start with 4k7 and see if that is enough to overcome the trouble with the cable. You can lower the value to 2k2 (or even 1k5) if needed.
I tried what you wrote, but nothing works...maybe I really try another cable...or I have to be happy with 100kHz.
I am really getting crazy...so frustrating...why the hell does it not work?!
Wire.setClock() and Due are no friends....
Do you use the newest Arduino IDE 1.6.6 ? (1.6.7 at december 17)
You can test with the i2c_scanner : Arduino Playground - I2cScanner
Keep it running while you try to add pullup resistors.
The internal pullup resistors for the Due are 50k to 150k, that is by far not enough to compensate for the cable trouble.
There was a really stupid line in the INA226.cpp library which puts a delay to 1 ms....So didn't matter how fast the I2C is, the delay limits the steps from one to an other measurement.
I have put the limit to delayMicroseconds(140) instead of delay(1) and it is way more faster now. The struggle has an end:).
There was a really stupid line in the INA226.cpp library which puts a delay to 1 ms....So didn't matter how fast the I2C is, the delay limits the steps from one to an other measurement.
I have put the limit to delayMicroseconds(140) instead of delay(1) and it is way more faster now. The struggle has an end:).
I should have asked in my first reply, which code or library you use
Do you use this ?
I think the delay is for the conversion time of the INA226.
In that code are three wrong lines, the Wire.requestFrom() should not be encapsulated by Wire.beginTransmission and Wire.endTransmission, and the while(!Wire.available()) is wrong.
Those are common mistakes, but only made by people who don't understand how to use the Wire library.
I think so too...but some micros ( delayMicroseconds(140) ) shoulb be enough with 800kHz or 2.4MHz, or what do you think? My INA226_XXX_CONV_TIME_140US in my code means it is 140us.
Do you have a correct version of the library or can you please say which lines you mean? Does it not proper work without these changes?
Yeah I just started with I2C and found already a lot of different problems...but now I am hopefully smarter:)
140us is a long time for the Due. I would make a software timer with micros().
If the INA226 is in continues mode, then I don't know why to wait after setting the register address. Perhaps it is in the datasheet, but I didn't read it. I'm not sure, therefor I print an error in the example below.
Is the value from the registers a signed integer ? Because readRegister16() returns a signed integer.
int16_t INA226::readRegister16(uint8_t reg)
{
int16_t value;
Wire.beginTransmission(inaAddress);
Wire.write(reg);
Wire.endTransmission(); // or use parameter 'false' for repeated start.
int n = Wire.requestFrom(inaAddress, 2);
if( n==2 )
{
uint8_t vha = Wire.read();
uint8_t vla = Wire.read();
value = word(vha, vla);
}
else
{
Serial.println("ERROR, the INA226 was not ready");
value = -1; // to indicate an error, this might be a bad idea.
}
return value;
}
I don't have a Due or a INA226, so I'm just guessing what I think is best.
Did you know that Wire.write() does not transmit data ? It only fills the transmit buffer inside the Wire library. The Wire.endTransmission() transmits everything and wait until everything has finished.
The Wire.requestFrom() starts an I2C transmission, and waits until all the data has been received and finishes the I2C transmission. Only after that it returns. The received bytes are waiting in a receive buffer inside the Wire library.
Did you know that Wire.write() does not transmit data ? It only fills the transmit buffer inside the Wire library. The Wire.endTransmission() transmits everything and wait until everything has finished.
The Wire.requestFrom() starts an I2C transmission, and waits until all the data has been received and finishes the I2C transmission. Only after that it returns. The received bytes are waiting in a receive buffer inside the Wire library.
The received bytes are waiting in a receive buffer inside the Wire library or inside the microcontroller? The entity buffer is a real hardware; should it not be within the MCU?