INA219_WE icon indicating copy to clipboard operation
INA219_WE copied to clipboard

Can the reading of the resuts be speed ut with burst reading?

Open Albin76 opened this issue 3 years ago • 7 comments

I am making a power logger to log the power consumption for a esp32 BME280 sensor that's is active less than 350ms thanks to ESPNOW to a SD card and are with your great library getting really good measurement speeds since it can set the ADC to 9-bit unlike other libraries. I get a full sampling every 1700us (shunt, busvoltage, current and voltage) and have seen that I get varied values between the measurements so its not just the same INA219 reading read twice.

I noticed that each "get_value" request is taking way more (200-220us each, 620 for three) than the 84us the 9-bit conversion in the datasheet states and started to think it about and remembered that I read that Sparkfun BME280 library (in pull request 50) is using burst reading according to bme280 datasheet section 4 and reads all registers at one time and then divides them up. Would this be possible to do here as well and will it speed up the reading and minimise the risk that two "get" is from different samplings? I noticed that this is way over my head and I do not have the knowledge myself to do it but thought it might be something you know how to do and was interested in?

Just an idea... that might be totally stupid but thought it was worth asking you.

Best regards, Albin

Albin76 avatar Jan 13 '21 20:01 Albin76

Hi @Albin76 , sorry for the late response. A burst read should be possible since the registers are in sequential order. I will try that but it will still need some time.

wollewald avatar May 15 '21 10:05 wollewald

I measured now (today) Attiny85, getCurrent_mA() only. 6 measure (and 6 serial.print) is 280ms, SAMPLE_MODE_16 equal with BIT_MODE_12, so the TinyWire is slow, maybe.

BCsabaEngine avatar Oct 15 '22 15:10 BCsabaEngine

Hi @BCsabaEngine , can you share your complete code? Then I could see more details. e.g. if you are you using the continuous or triggered mode, which baud rate you use for Serial.print and so on.

And what is the clock speed of your ATtiny85? And which board package do you use? E.g. ATtinyCore from spence Konde or attiny from David A. Mellis?

wollewald avatar Oct 15 '22 18:10 wollewald

Hi @BCsabaEngine ,

it is the Serial.print() which is slow. I have tested the following small sketch:

void setup() {
  Serial.begin(9600);
  delay(1000);
  unsigned long startTime = millis();
  unsigned long durationTime = 0;
  for(int i=0; i<100; i++){
    Serial.println("Hello World, here I am!");
  }
  durationTime = millis()-startTime;
  Serial.println(durationTime);
}

void loop() {   }

The result is 2646 milliseconds which means 26.46 milliseconds per Serial.println(). 6 Serial.println() of this length plus the expected 51 ms for 6 measurements at Sample_Mode_16 would take ~210 milliseconds.

If I reduce the string to be printed to "Hello Word" it's still 1483 milliseconds for 100 Serial.println().

With a baud rate of 115200 and "Hello World" 100 Serial.println() take only 129 milliseconds, which is 1.29 milliseconds per println(),

So, if you need to print all results then I would recommend to keep the output as short as possible and the baud rate as high as possible.

My ATttiny85 was set to 8 MHz clock rate and I have applied the package from Spence Konde.

wollewald avatar Oct 16 '22 10:10 wollewald

Hi @wollewald !

Thank you for fast response. I use this code to measure 6 INA219 (at final with different I2C address) current, now emulate with same I2C address.

#include <SoftwareSerial.h>
#include <TinyWireM.h>

#include "INA219_WE.h"

#define TX    3
#define RX    2
#define LED    1
#define I2C_ADDRESS 0x40

SoftwareSerial Serial(RX, TX);
INA219_WE ina219 = INA219_WE(I2C_ADDRESS);

void setup() {
  pinMode(LED, OUTPUT);

  Serial.begin(9600);

  TinyWireM.begin();

  if (!ina219.init()) {
    Serial.println(F("INA219 NOT connected"));
    while (1) {}
  }
  else {
    Serial.println(F("INA219 connected"));
  }

  ina219.setMeasureMode(CONTINUOUS);
  ina219.setADCMode(SAMPLE_MODE_16);
  ina219.setBusRange(BRNG_16);
  ina219.setPGain(PG_40);
}

uint32_t lastOutput = 0;
void loop() {
  uint8_t isany = false;
  for (int i = 0; i < 6; i++) {

    int16_t mA = (int16_t)ina219.getCurrent_mA();

    if (mA < 0)
      mA = mA * -1;

    if (mA != 0) {
      isany = true;
      digitalWrite(LED, HIGH);
    }

    Serial.print(mA);
    Serial.print(F(" "));
  }

  Serial.print(millis() - lastOutput); // shows 250-320 msec
  Serial.println();
  lastOutput = millis();

  if (!isany)
    digitalWrite(LED, LOW);

  delay(1); // to operate LED
}

I use David A. Mellis soultion with 8Mhz (clock runs good, I measured) and serial with 9200baud. It can be a bottleneck, I will try the 115200 baud rate (now use 9200 for safety, because attiny85 talks with an atmega328. Both can use 115200, but it should be safe for me) and reduce the serial communication. I will disable RX side of serial (stopListening or set 999 to rx pin).

I have researched some improvement:

  • do now use abs(ina219.getCurrent_mA()), because abs() is a macro only and it occurs calculate exporession two times, use abs with local variable only.
  • use delay() to make the LED works

Thank you for your work, I will reply when I will get measure info.

ps: this is a DCC model train occupancy detector (is a train on the track?), when I measure AC current. Not a real AC (sinus wave), it just change the polarity very fast to send digital info. This is the reason of abs() use.

BCsabaEngine avatar Oct 16 '22 13:10 BCsabaEngine

Problem solved. The RX input of SoftwareSerial add 250ms delay to my code. If I used stopListening, 6x measure is about 20ms. I have refactored code: output is a cstring, eliminate String object, etc.

I must use delay to slow down sketch to 10 iteration / sec. With 9600 baud. stopListening is the must.

#if not defined (__AVR_ATtiny85__)
#error "Unknown processor, can run on ATtiny85"
#endif

#include <SoftwareSerial.h>
#include <TinyWireM.h>

#include "INA219_WE.h"

#define TX            3
#define RX            99 //supress listening, earlier 2
#define LED           1
#define I2C_ADDRESS   0x40

SoftwareSerial Serial(RX, TX);
INA219_WE ina219 = INA219_WE(I2C_ADDRESS);

void setup() {
  pinMode(LED, OUTPUT);

  Serial.begin(9600);
  Serial.stopListening();

  TinyWireM.begin();

  if (!ina219.init()) {
    Serial.println(F("INA219 NOT connected"));
    while (1) {}
  }
  else {
    Serial.println(F("INA219 connected"));
  }

  ina219.setMeasureMode(CONTINUOUS);
  ina219.setADCMode(SAMPLE_MODE_16);
  ina219.setBusRange(BRNG_16);
  ina219.setPGain(PG_40);
}

char output [6 * (4 + 1)] = "";
uint32_t lastOutput = 0;
void loop() {
  uint8_t isany = false;

  output[0] = '\0';
  for (int i = 0; i < 6; i++) {

    int16_t mA = (int16_t)ina219.getCurrent_mA();
    mA = abs(mA);

    if (mA != 0) {
      isany = true;
      digitalWrite(LED, HIGH);
    }

    char value[4 + 1];
    sprintf(value, "%02X", mA);
    strcat (output, value);

    delay(10);
  }

  Serial.println(output);

  if (!isany)
    digitalWrite(LED, LOW);

  delay(10); // to operate LED
}

Thank you for your support!

BCsabaEngine avatar Oct 17 '22 10:10 BCsabaEngine

Great that you found the bottleneck! Good luck for your project.

wollewald avatar Oct 17 '22 11:10 wollewald