Sunday, October 20, 2013

ADXL345 Accelerometer using ATmega32

The ADXL345 is a tiny, low cost and ultra-low power 3-axis accelerometer which works on both SPI and TWI interfaces. It has use selectable sensitivity and give quite reliable readings considering its cost. The ADLX345 circuit in the IMU has TWI interface. I will be using ATmega32 in the following project clocked at 8MHz using the internal oscillator.
Here is the circuit diagram of how the ADXL345 accelerometer is connected, also you can see that the slave address is given as 0x53. The address can also be found out from the I2C scanner as shown here.
The ADX345 supports the standard (100 kHz) and the fast (400 kHz) data transfer modes. For more info see datasheet.

Click here for ADXL345 datasheet.

The I2C device addressing for ADXL345 can be seen in the datasheet.
The ATmega32 acts as a master and the ADXL345 as the slave.
To start communication you need to first configure the connection between ADXL345 and ATmega32 in a mode supported by ADXL345. This can be done as show :
1
2
3
4
5
6
7
8
void TWI_Init(void)
{
    //set SCL to 400kHz
    TWSR = 0x00;
    TWBR = 0x02;
    //enable TWI
    TWCR = (1<<TWEN);
}
Inserting the above values of TWBR and TWSR in the following equation results in SCL frequency of 400 kHz when the main CPU is clocked at 8 MHz.

Single-Byte write:

See the I2C device addressing picture above for the description.
  1. Send start condition
    1
    2
    3
    4
    5
    void TWI_Start(void)
    {
        TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
        while ((TWCR & (1<<TWINT)) == 0);
    }
  2. Check for Acknowledgement
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    uint8_t TWI_GetStatus(void)
    {
        uint8_t status;
        //mask status
        status = TWSR & 0xF8;
        return status;
    }
    
    if(TWI_GetStatus() != 0x08)
    {
        return error;
    }
    The status codes can be found out in the ATmega32 datasheet.
  3. Send the Slave address + Data direction bit (R/W)
    1
    2
    3
    4
    5
    6
    7
    8
    void TWI_Write(uint8_t u8data)
    {
        TWDR = u8data;
        TWCR = (1<<TWINT)|(1<<TWEN);
        while ((TWCR & (1<<TWINT)) == 0);
    }
    
    TWI_Write(0b10100110);
    The last zero in TWI_Write implies the Master write mode
  4. Check for Acknowledgement
    1
    2
    3
    4
    if(TWI_GetStatus() != 0x18)
    {
        return error;
    }
  5. Send the register address and check for Acknowledgement
    1
    2
    3
    4
    5
    TWI_Write(reg);
    if(TWI_GetStatus() != 0x28)
    {
       return error;
    }
  6. Send the data and receive acknowledgement
    1
    2
    3
    4
    5
    TWI_Write(data);
    if(TWI_GetStatus() != 0x28)
    {
        return error;
    }
  7. Send Stop condition
    1
    TWI_Stop();
Complete code:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
uint8_t ADXL_write(uint8_t reg, uint8_t data)
{
    TWI_Start();
    if(TWI_GetStatus() != 0x08)
    {
        return error;
    }
    TWI_Write(0b10100110);
    if(TWI_GetStatus() != 0x18)
    {
        return error;
    }
    TWI_Write(reg);
    if(TWI_GetStatus() != 0x28)
    {
        return error;
    }
    TWI_Write(data);
    if(TWI_GetStatus() != 0x28)
    {
        return error;
    }
    TWI_Stop();
    return success;
}
 

Single-Byte Read:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
uint8_t ADXL_read(uint8_t reg)
{
    uint8_t data;
    TWI_Start();
    if(TWI_GetStatus() != 0x08)
    {
        return error;
    }
    TWI_Write(0b10100110);
    if(TWI_GetStatus() != 0x18)
    {
        return error;
    }
    TWI_Write(reg);
    if(TWI_GetStatus() != 0x28)
    {
        return error;
    }
    TWI_Start();
    if(TWI_GetStatus() != 0x10)
    {
        return error;
    }
    TWI_Write(0b10100111);
    if(TWI_GetStatus() != 0x40)
    {
        return error;
    }
    data = TWI_ReadNACK();
    if(TWI_GetStatus() != 0x58)
    {
        return error;
    }
    TWI_Stop();
    return data;
}

1
2
3
4
5
6
uint8_t TWIReadNACK(void)
{
    TWCR = (1<<TWINT)|(1<<TWEN);
    while ((TWCR & (1<<TWINT)) == 0);
    return TWDR;
}
Using these function data can be obtained form ADXL345 accelerometer. I'll be posting a full functional code later.

No comments :

Post a Comment