Hi Peter,
I thought we'd agreed to implement the whole of the auto-increment
logic, not just for specific registers ?
Thanks again for the feedback. Dealing with one register value at a time
(versus a buffer of response values) does simplify the code flow.
The following code appears to handle multi-byte reads correctly. I just
wanted to confirm this is what you were looking for before moving on to
the test code?
/*
* Callback handler whenever a 'I2C_START_RECV' (read) event is received.
*/
static void lsm303dlhc_mag_read(LSM303DLHCMagState *s)
{
/*
* Set the LOCK bit whenever a new read attempt is made. This will be
* cleared in I2C_FINISH. Note that DRDY is always set to 1 in this driver.
*/
s->sr = 0x3;
}
/*
* Callback handler whenever a 'I2C_FINISH' event is received.
*/
static void lsm303dlhc_mag_finish(LSM303DLHCMagState *s)
{
/*
* Clear the LOCK bit when the read attempt terminates.
* This bit is initially set in the I2C_START_RECV handler.
*/
s->sr = 0x1;
}
/*
* Low-level slave-to-master transaction handler (read attempts).
*/
static uint8_t lsm303dlhc_mag_recv(I2CSlave *i2c)
{
LSM303DLHCMagState *s = LSM303DLHC_MAG(i2c);
switch (s->pointer) {
case LSM303DLHC_MAG_REG_CRA:
s->buf = s->cra;
break;
case LSM303DLHC_MAG_REG_CRB:
s->buf = s->crb;
break;
case LSM303DLHC_MAG_REG_MR:
s->buf = s->mr;
break;
case LSM303DLHC_MAG_REG_OUT_X_H:
s->buf = (uint8_t)(s->x >> 8);
break;
case LSM303DLHC_MAG_REG_OUT_X_L:
s->buf = (uint8_t)(s->x);
break;
case LSM303DLHC_MAG_REG_OUT_Z_H:
s->buf = (uint8_t)(s->z >> 8);
break;
case LSM303DLHC_MAG_REG_OUT_Z_L:
s->buf = (uint8_t)(s->z);
break;
case LSM303DLHC_MAG_REG_OUT_Y_H:
s->buf = (uint8_t)(s->y >> 8);
break;
case LSM303DLHC_MAG_REG_OUT_Y_L:
s->buf = (uint8_t)(s->y);
break;
case LSM303DLHC_MAG_REG_SR:
s->buf = s->sr;
break;
case LSM303DLHC_MAG_REG_IRA:
s->buf = s->ira;
break;
case LSM303DLHC_MAG_REG_IRB:
s->buf = s->irb;
break;
case LSM303DLHC_MAG_REG_IRC:
s->buf = s->irc;
break;
case LSM303DLHC_MAG_REG_TEMP_OUT_H:
/* Check if the temperature sensor is enabled or not (CRA & 0x80). */
if (s->cra & 0x80) {
s->buf = (uint8_t)(s->temperature >> 8);
} else {
s->buf = 0;
}
break;
case LSM303DLHC_MAG_REG_TEMP_OUT_L:
if (s->cra & 0x80) {
s->buf = (uint8_t)(s->temperature & 0xf0);
} else {
s->buf = 0;
}
break;
default:
s->buf = 0;
break;
}
/*
* The address pointer on the LSM303DLHC auto-increments whenever a byte
* is read, without the master device having to request the next address.
*
* The auto-increment process has the following logic:
*
* - if (s->pointer == 8) then s->pointer = 3
* - else: if (s->pointer >= 12) then s->pointer = 0
* - else: s->pointer += 1
*
* Reading an invalid address return 0.
*/
if (s->pointer == LSM303DLHC_MAG_REG_OUT_Y_L) {
s->pointer = LSM303DLHC_MAG_REG_OUT_X_H;
} else if (s->pointer >= LSM303DLHC_MAG_REG_IRC) {
s->pointer = LSM303DLHC_MAG_REG_CRA;
} else {
s->pointer++;
}
return s->buf;
}