i2c_m_sync_cmd_write confusion

Go To Last Post
2 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm communicating with an ADXL345 Accelerometer using Atmel START / ASF4 calls.  Read operations work (single and multi-byte), but write operations always return 0.  Here's what I know:

  • Read operations (including multi-byte read operations) are working reliably
  • The SCL line shows a stable 100KHz rate
  • I've added 1K pullups on the SDA and SCL lines.  (At 10K, the rising edges were somewhat soft.)
  • Processor is a SAML22 Xplained Pro board

 

My code is (in summary):

uint32_t err;
uint8_t reg;

err = i2c_m_sync_enable(&ADXL345_0);
ASSERT(err >= 0);

err = i2c_m_sync_set_slaveaddr(&ADXL345_0, ADXL345_I2C_PRIMARY_ADDRESS, I2C_M_SEVEN);
ASSERT(err >= 0);

err = i2c_m_sync_cmd_read(&ADXL345_0, ADXL345_REG_DEVID, &reg, 1);
ASSERT(err >= 0);

printf("device ID = %d\n", reg);  // works

reg = ADXL345_MEASURE;            // = 0x08
err = i2c_m_sync_cmd_write(&ADXL345_0, ADXL345_REG_POWER_CTL, reg, 1);
ASSERT(err >= 0);                 // no error is raised

err = i2c_m_sync_cmd_read(&ADXL345_0, ADXL345_REG_POWER_CTL, &reg, 1);
ASSERT(err >= 0);                 // no error is raised

printf("device ID = %d\n", reg);  // always returns 0, should be 0x08

'Scope traces below.  I'm not sure why i2c_m_sync_cmd_write() is being broken into two operations (that's a second start in the middle, right?).   Of course, this could be due to my misreading of the ADXL345 data sheet, but more likely I'm not using i2c_m_sync_cmd_write() properly.  Suggestions?

 

scope grab

Last Edited: Wed. Jan 22, 2020 - 11:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Update:

 

Instead of using i2c_m_sync_cmd_write(), I switched to i2c_m_sync_transfer().  This sends the address and value in a single I2C transaction.  More importantly: it works.

 

Code is along these lines:

 

adxl345_err_t adxl345_dev_write_reg(adxl345_dev_t *dev, uint8_t reg_addr, uint8_t val) {
  uint8_t buf[2];
  struct _i2c_m_msg msg;
  int32_t ret;

  buf[0] = reg_addr;
  buf[1] = val;

  msg.addr = dev->slave_addr;
  msg.len = sizeof(buf);
  msg.flags = I2C_M_STOP;
  msg.buffer = buf;

  ret = i2c_m_sync_transfer(dev->i2c_descriptor, &msg);
  if (ret < 0) {
    return ADXL345_ERR_WRITE;
  }
  return ADXL345_ERR_NONE;
}

Here's what it looks like on the 'scope:

scope grab