HMC5883L not working in continuous mode! I'm just starting with the HMC5883L, I'm writing my code with C and also my own I2C library.

I noticed that the values on the Arduino IDE's serial monitor are constant.

Then I developed a function to read the mode register. So the value should be 0x00 for continuous mode.

But, what I get is that the device work in single mode which has the value 0x01 at first cycle of the program, then it goes to idle mode with the value 0x03.

So, why is that and what to do?

#include &lt;I2C.h&gt;

#define HMC5883L_read   0x3D
#define HMC5883L_write  0x3C

#define Configuration_Register_A    0x00  //Read/Write
#define Configuration_Register_B    0x01  //Read/Write
#define Mode_Register               0x02  //Read/Write
#define Data_Output_X_MSB_Register  0x03  //Read
#define Data_Output_X_LSB_Register  0x04  //Read
#define Data_Output_Z_MSB_Register  0x05  //Read
#define Data_Output_Z_LSB_Register  0x06  //Read
#define Data_Output_Y_MSB_Register  0x07  //Read
#define Data_Output_Y_LSB_Register  0x08  //Read
#define Status_Register             0x09  //Read
#define Identification_Register_A   0x10  //Read
#define Identification_Register_B   0x11  //Read
#define Identification_Register_C   0x12  //Read
#define declination_angle 3.46


void HMC5883L_init (void);
int16_t data_read (int16_t *results);
uint8_t HMC5883L_read_reg (uint8_t reg);

int16_t results[3];
float m_scale = 1.0;

void setup() {
  // put your setup code here, to run once:
  I2C_init();
  Serial.begin(9600);
  HMC5883L_init();
  Serial.print("mode register ");
  HMC5883L_read_reg(Mode_Register);
  Serial.println();
}

void loop() {
  // put your main code here, to run repeatedly:
  data_read(results);
  Serial.print("x-axis = ");
  Serial.println(results[0]);
  Serial.print("z-axis = ");
  Serial.println(results[1]);
  Serial.print("y-axis = ");
  Serial.println(results[2]);
  Serial.println();
  Serial.print("mode register ");
  HMC5883L_read_reg(Mode_Register);
  Serial.println();
_delay_ms(500);
}


void HMC5883L_init (void)
{
  I2C_start(HMC5883L_write);
  I2C_tx(Configuration_Register_A);
  I2C_tx(0x07);
  I2C_tx(Configuration_Register_B);
  I2C_tx(0x01);
  I2C_tx(Mode_Register);
  I2C_tx(0x00);
  I2C_stop();  
}

int16_t data_read (int16_t *results)
{
  uint16_t lsb,msb;
  int16_t status_of_process = 0;
  I2C_start(HMC5883L_write);
  I2C_tx(Data_Output_X_MSB_Register);
  I2C_start(HMC5883L_read);

  msb = I2C_rx();
  lsb = I2C_rx();
  results[0] = msb &lt;&lt; 8 | lsb;  

  msb = I2C_rx();
  lsb = I2C_rx();
  results[1] = msb &lt;&lt; 8 | lsb;

  msb = I2C_rx();
  lsb = I2C_rx();
  results[2] = msb &lt;&lt; 8 | lsb;

  I2C_stop();

  return status_of_process;
}

uint8_t HMC5883L_read_reg (uint8_t reg)
{
  uint8_t reg_dat;
  I2C_start(HMC5883L_write);
  I2C_tx(reg);
  I2C_start(HMC5883L_read);
  reg_dat = I2C_rx();
  Serial.println(reg_dat);
}


Regards,
The problem stems from this function:

void HMC5883L_init (void)
{
  I2C_start(HMC5883L_write);
  I2C_tx(Configuration_Register_A);
  I2C_tx(0x07);
  I2C_tx(Configuration_Register_B);
  I2C_tx(0x01);
  I2C_tx(Mode_Register);
  I2C_tx(0x00);
  I2C_stop();  
}


The way I2C in most chips work, when writing, is that the first byte defines the register to write to. All subsequent bytes are the data to write into that register and successive registers.


  To minimize the communication between the master and this device, the address pointer updated automatically without
  master intervention. This automatic address pointer update has two additional features. First when address 12 or higher
  is accessed the pointer updates to address 00 and secondly when address 08 is reached, the pointer rolls back to
  address 03.


So you are actually writing:

REG  CONTENT
0x00 0x07
0x01 Configuration_Register_B (0x01)
0x02 0x01
0x03 Mode_Register (0x02)
0x04 0x00


You need to either start a new transaction for each register you want to set a value in (explicit setting) or rely on the address pointer increment to move to the right register for you (implicit setting).

So either:

void HMC5883L_init (void)
{
  I2C_start(HMC5883L_write);
  I2C_tx(Configuration_Register_A);
  I2C_tx(0x07);
  I2C_stop();  

  I2C_start(HMC5883L_write);
  I2C_tx(Configuration_Register_B);
  I2C_tx(0x01);
  I2C_stop();  

  I2C_start(HMC5883L_write);
  I2C_tx(Mode_Register);
  I2C_tx(0x00);
  I2C_stop();  
}


Or, since the registers are in sequence in the address space:

void HMC5883L_init (void)
{
  I2C_start(HMC5883L_write);
  I2C_tx(Configuration_Register_A);
  I2C_tx(0x07);
  I2C_tx(0x01);
  I2C_tx(0x00);
  I2C_stop();  
}


Oh, and don't forget to have an I2C_stop() after reading your register in:

uint8_t HMC5883L_read_reg (uint8_t reg)
{
  uint8_t reg_dat;
  I2C_start(HMC5883L_write);
  I2C_tx(reg);
  I2C_start(HMC5883L_read);
  reg_dat = I2C_rx();
  I2C_stop(); // &lt;----- MISSING
  Serial.println(reg_dat);
}