I2c communication hmc5883

Hello guys,
I have this simple sketch to read raw data from an hmc5883 compass module.

#define compass_address 0x1E //0011110b, I2C 7bit address of HMC5883


#include <Wire.h>
#define HWire Wire

void setup() {
  //Initialize Serial and I2C communications
  Serial.begin(115200);

  HWire.begin();

  //Check if the compass is responding.
  HWire.beginTransmission(compass_address);               
  int error = HWire.endTransmission(); 
  if (error != 0) {
    Serial.println("Compass not responding");
    error = 4;                                                  //Set the error status to 4.
    while (true) {                                              //Stay in this loop because the Compass did not responde.
    }
  }
  Serial.println("Compass communication succesful");

  delay(1000);


  //Put the HMC5883 IC into the correct operating mode
  HWire.beginTransmission(compass_address); //open communication with HMC5883

  HWire.write(0x00);                                            //We want to write to the Configuration Register A (00 hex).
  HWire.write(0x78);                                            //Set the Configuration Regiser A bits as 01111000 to set sample rate (average of 8 at 75Hz).
  HWire.write(0x20);                                            //Set the Configuration Regiser B bits as 00100000 to set the gain at +/-1.3Ga.
  HWire.write(0x00);                                            //Set the Mode Regiser bits as 00000000 to set Continues-Measurement Mode.


  HWire.endTransmission();

  delay(1000);
}

void loop() {

  int16_t x, y, z; //triple axis data


  //Tell the HMC5883 where to begin reading data
  HWire.beginTransmission(compass_address);
  HWire.write(0x03); //select register 3, X MSB register
  HWire.endTransmission();

  delay(1);

  //Read data from each axis, 2 registers per axis
  long micros_counter = micros();
  HWire.requestFrom(compass_address, 6);
  micros_counter = micros() - micros_counter;

  x = HWire.read() << 8; //X msb
  x |= HWire.read(); //X lsb
  z = HWire.read() << 8; //Z msb
  z |= HWire.read(); //Z lsb
  y = HWire.read() << 8; //Y msb
  y |= HWire.read(); //Y lsb

  //Print out values of each axis
  Serial.print("x: ");
  Serial.print(x);
  Serial.print("  y: ");
  Serial.print(y);
  Serial.print("  z: ");
  Serial.println(z);

  //Print out how long it took
  Serial.println(micros_counter);


  delay(1000);
}

I was planning to use an stm32 with stm32duino core, but I have the same problem with an arduino Mega.

I get the right compass data, but Wire.requestfrom takes forever, >3,5ms. Sadly, this is not acceptable for my application. I mean, why would recviving 6 bytes take over 3ms? I can receive 14 bytes if an mpu6050 in around 0,7ms no problem.

After looking at the oscilloscope I noticed something very strange. (look at picture, I hope I embeded it right)
test

Firstly I set the register pointer to 3, everthing ok. Then I start the read section, send adress an read bit amd then? Nothing for 3ms. Why is there an pause for 3ms? I subsect it could be the hmc5883's fault because the datasheet says it wants to be told how many bytes it is supoosed to send out after the adress with the read bit. As far as I understand, the Arduino Ide doesnt support this, it just sends the addes + read bit then reads from the slave and just sends nack if it has read enough, right? (This seems kinda cheesy to me, but I guess it works?)

Anyway the hmc5883 says in it's datasheet that it wants to be specicically told how many bytes it is supposed to print out, which, if you look at the oscilloscope picture, isn't happening.
There's an 3ms pause, in which the clock stays low. But I thought it is the master's responsability to send out the clock pulses, isn't it? So the 3ms has to be the master's fault, right? Then it does not have anything to do with the hmc5883 wanting to be told how many bytes it is supposed to send out, or does it?

I am a bit confused here and the twi.cpp library seems very complicated.

So tldr: Why is there a 3ms delay of doing nothing?

EDIT: I didn't show how I set the pointer in the picture. But I con confirm that part works good and fast.

Yes, but what you see is called clock stretching. The slave holds the clock line low until it is ready to send the data.

Thank you, I have read a bit of i2c stuff on the internet and understand this now.
I have solved my timing problem though. I wrote my interely own software i2c library with direct register acces based on SoftWire - Arduino Reference
I made it so that i can start the communication by writing the adress, then exit the function, do sth else (while the slave can do its clock stretching) and then come back later to recommence the clock and read the data.
This way I can reduce a call normaly taking 4ms into 2 calls taking 0,3 and 0,7ms respectively, this is fast enough for me.
I will not post my solution in more detail because its very hacky and unpractical, but it works.
Sorry to ask, but how do I close this?

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