1

I've been looking for a solution for this problem for quite a time I tried different I2C libraries; like,

I2C master library using hardware TWI interface * Author: Peter Fleury

But the same problem, I think my problem is in the HMC5883L_my library.

Update: I have to mention that I'm including I2C_TWSR_Check(); function to check the status of the I2C operations success in the HMC5883L library in int16_t data_read (int16_t *results_ptr); function, and as a result I get a successful operations all the time. But, the problem is when the serial monitor of the Arduino IDE is open and I'm watching the values and moving the module with different vectors, as soon as x-axis changes from -ve to +ve values, the serial monitor stops and I have to close it and open it again.

#include <avr/io.h>
#include <Arduino.h>
#include "HMC5883L_my.h"
#include "I2C.h"

int16_t results[3];

void HMC5883L_init (void)
{
  I2C_start(HMC5883L_write);
  I2C_tx(Configuration_Register_A);
  I2C_tx(0x78);
  I2C_tx(0x20);
  I2C_tx(0x00);
  I2C_stop();
}

int16_t data_read (int16_t *results_ptr)
{
  uint16_t lsb,msb;
  int16_t status_of_process = 0;

  I2C_start(HMC5883L_write);
  I2C_TWSR_Check();
  I2C_tx(Data_Output_X_MSB_Register);
  I2C_TWSR_Check();
  I2C_stop();

  I2C_start(HMC5883L_read);
  I2C_TWSR_Check();

  msb = I2C_rx();
  lsb = I2C_rx();
  I2C_TWSR_Check();

  results[0] = msb << 8 | lsb;

  Serial.print("x-axis = ");
  Serial.println(results[0]);

  msb = I2C_rx();
  lsb = I2C_rx();
  I2C_TWSR_Check();

  results[1] = msb << 8 | lsb;

  Serial.print("z-axis = ");
  Serial.println(results[1]);

  msb = I2C_rx();
  lsb = I2C_rx();
  I2C_TWSR_Check();
  results[2] = msb << 8 | lsb;

  Serial.print("y-axis = ");
  Serial.println(results[2]);
  I2C_TWSR_Check();
  I2C_stop();
  Serial.println();
  return status_of_process;
}

void 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();
  Serial.println(reg_dat);
}

As you can see I put I2C_TWSR_Check(); after each I2C operation to see if there's any problem during read operation but I can't see any problem when the module stops reading if x-axis value get to positive region.

This is my I2C library but I don't think there's a serious problem with it because it worked with other I2C modules without any problem.

/*
 * I2C_Library.c
 *
 * Created: 6/6/2017 12:34:39 AM
 * Author : wolfrose
 */

#include <avr/io.h>
#include <Arduino.h>
#include "I2C.h"

void I2C_init(void)
{
    //set SCL to 100kHz
    TWSR = 0x00;
    TWBR = 0x48;
    //enable TWI
    TWCR = (1<<TWEN);
}

void I2C_start(uint8_t address)
{
    TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
    TWDR = address;
    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
    while (!(TWCR & (1<<TWINT)));
}

void I2C_stop(void)
{
    TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}

void I2C_tx(uint8_t data)
{
    TWDR = data;
    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
    while (!(TWCR & (1<<TWINT)));
}

uint8_t I2C_rx(void)
{
    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
    while (!(TWCR & (1<<TWINT)));
    return TWDR;
}

void I2C_TWSR_Check(void)
{
  uint8_t Status;
  Status = TWSR & 0xF8;
  switch(Status)
  {
    /////////////// MASTER TRANSMITTER //////////////
    case 0x08:
    Serial.println("Start is OK");
     break;
    case 0x10:
    Serial.println("Re start");
     break;
    case 0x18:
    Serial.println("SLA+W OK ACK");
     break;
    case 0x20:
    Serial.println("SLA+W no ACK");
     break;
    case 0x28:
    Serial.println("data TX OK ACK");
     break;
    case 0x30:
    Serial.println("data TX OK no ACK");
     break;
    case 0x38:        // arbitration lost in SLA+W or data TX
    Serial.println("arbitration lost in SLA+W or data TX");
     break;

    /////////////// MASTER RECEIVER //////////////
    case 0x40:
    Serial.println("SLA+R OK ACK");
     break;
    case 0x48:
    Serial.println("SLA+R OK NO ACK");
     break;
    case 0x50:
    Serial.println("data RX OK ACK");
     break;
    case 0x58:
    Serial.println("data RX OK NO ACK");
     break;

     default:
     Serial.println("Error");
    break;
  }
}
16
  • 1
    Have you seen this: hackaday.com/2017/07/29/…
    – Jot
    Jul 30, 2017 at 22:17
  • 1
    are any of the error messages being displayed? Jul 31, 2017 at 0:23
  • 1
    I don't see where the 'wait for ack/nak' on transmit nor where the 'send ack/nak' after receive is being handled. Is that handled in the hardware? if not, it needs to be handled in the code. Jul 31, 2017 at 0:29
  • 1
    since your calling the I2C_TWSR_Check() function after each communication is complete, you should be seeing the output from this: Serial.println("SLA+R OK ACK"); all the time there is a successful receive communication and the output from this: Serial.println("data TX OK ACK"); all the time there is a successful transmit communication. Your question does not mention this output. please apply an EDIT to update Jul 31, 2017 at 2:49
  • 1
    why is the posted code sending start and stop for each byte when sending/receiving a multibyte value. The normal way that I2C works (after establishing communication) is the master sends start, command, stop. then the slave sends ack then if the command was to send data then the slave sends start, data ... data, stop. then the master sends ACK. A very similar sequence is used when the master wants to send data. Jul 31, 2017 at 2:58

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.