leddie/firmware/lib/mma8653.c

99 lines
2.3 KiB
C

#include "mma8653.h"
#include <util/twi.h>
#define AXL_ADDR 0x1D
#define AXL_ERR_RET(e) if(1){err = e; goto err;}
#define TRY(c) if(1){ret = c; if (ret) return c;}
static int mma8653_i2c_transfer(int write, uint8_t reg, uint8_t *data, uint8_t length)
{
int err = 0;
// WRITE TARGET REGISTER
// Send start
TWCR = (1<<TWINT) | (1<<TWSTA) | (1 << TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != TW_START)
AXL_ERR_RET(1);
// Send device address
TWDR = (AXL_ADDR << 1);
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != TW_MT_SLA_ACK)
AXL_ERR_RET(2);
// Write register address
TWDR = reg;
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != TW_MT_DATA_ACK)
AXL_ERR_RET(3);
if (!write) {
// Get data
// Send re-start
TWCR = (1<<TWINT) | (1<<TWSTA) | (1 << TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != TW_REP_START)
AXL_ERR_RET(4);
// Command a read cycle
TWDR = (AXL_ADDR << 1) | (!write);
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != (write ? TW_MT_SLA_ACK : TW_MR_SLA_ACK))
AXL_ERR_RET(5);
}
while (length--) {
if (write) {
TWDR = *(data++);
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != TW_MT_DATA_ACK)
AXL_ERR_RET(6);
} else {
// Read byte
TWCR = (1<<TWINT) | (1<<TWEN) | ( (length != 0) << TWEA);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != (length != 0 ? TW_MR_DATA_ACK : TW_MR_DATA_NACK))
AXL_ERR_RET(6);
*(data++) = TWDR;
}
}
// Send stop
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
while (TWCR & (1<<TWSTO));
return 0;
err:
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); // Send stop to abort
return err;
}
static inline int mma8653_i2c_write(uint8_t reg, uint8_t value)
{
return mma8653_i2c_transfer(1, reg, &value, 1);
}
int mma8653_init() {
int ret;
TWBR = 0xff;
//TWSR = 3;
TRY(mma8653_i2c_write(0x2A, (1 << 1) | (1 << 0)));
TRY(mma8653_i2c_write(0x2B, (1 << 7))); // Test mode en
return 0;
}
int mma8653_get_measurements(struct axl_result *measurements) {
int ret;
int8_t buffer[4];
TRY(mma8653_i2c_transfer(0, 0x0, (uint8_t*) buffer, 4));
measurements->x = buffer[1];
measurements->y = buffer[2];
measurements->z = buffer[3];
return 0;
}