Last active
March 27, 2020 04:13
-
-
Save HectorCarreno/4dc91b84112d4b9f1da9965ea5959069 to your computer and use it in GitHub Desktop.
Using the I2C driver provided by Espressif was developed this git for an ADLX345 accelerometer and ESP WROOM 32 MCU
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* I2C ADXL345 and Espressif ESP WROOM 32 | |
This is an input for developers world, it's a code checked and work for this accelerometer. | |
Any doubt, contact with the provider of this git. | |
*/ | |
#include <stdio.h> | |
#include "esp_log.h" | |
#include "driver/i2c.h" | |
/** | |
* BIKE TRACKER DEVELOPMENT | |
* | |
* This is a development for bikes tracker application using BG96 from Quectel company, | |
* ADLX345 accelerometer, SD card reader and ESP32 from Espressif . | |
* | |
* | |
* | |
* Pin assignment: | |
* | |
* - Master pins I2C protocol: | |
* GPIO21 is assigned as the data signal of i2c master port | |
* GPIO22 is assigned as the clock signal of i2c master port | |
* | |
* Connection: | |
* | |
* - Connect with the SDA and SCL pins of sensor ADXL345 | |
* - Isn't necessary add the external pull-up resistors, this driver will enable | |
* internal pull-up resistors, but for a major performance use it. | |
* | |
*/ | |
#define SAMPLE_PERIOD_MS 100 // Sample period delay | |
#define I2C_SCL_IO 22 // GPIO pin for I2C Wire Master Clock | |
#define I2C_SDA_IO 21 // GPIO pin for I2C Wire Data Input/Output | |
#define I2C_FREQ_HZ 100000 // Clock Frequency for I2C | |
#define I2C_PORT_NUM I2C_NUM_1 // Master Port Enable Macro | |
#define I2C_TX_BUF_DISABLE 0 // I2C Master don't need buffer | |
#define I2C_RX_BUF_DISABLE 0 // I2C master don't need buffer | |
// I2C common protocol defines | |
#define WRITE_BIT I2C_MASTER_WRITE // Macro with Write bit to configure | |
#define READ_BIT I2C_MASTER_READ // Macro with Read bit to configure | |
#define ACK_CHECK_EN 0x1 // Acknowledge bit Enable | |
#define ACK_CHECK_DIS 0x0 // Acknowledge bit Disable | |
#define ACK_VAL 0x0 // Acknowledge Value | |
#define NACK_VAL 0x1 // Non Acknowledge Value | |
// ADXL345 defines | |
#define ADXL345_I2C_ADDR 0x53 // ADXL35 default address | |
#define DEVICE_ID 0x00 // Device ID, 0 by default | |
#define PWR_CTL_REG 0x2D // POWER Control Register | |
#define STANDBY_MODE_CONF 0x08 // Standby mode bit | |
#define SLEEP_MODE_CONF 0x04 // Sleep Mode bit | |
#define BW_RATE_REG 0x2C // Bandwidth Rate Register | |
#define DATA_RATE 0x07 // Output data rate 12.5Hz by default | |
#define LOW_POWER_MODE 0x10 // Bit LOW POWER configuration | |
#define DATA_FORMAT_REG 0x31 | |
#define LEFT_JUSTIFIED 0X04 // Data x,y,z Left justified | |
#define GRAVITY_RANGE_BITS 0x01 // Gravity range of ±4g | |
#define RANGE_FULL_RES 0x08 // Full resolution for ±4 g | |
#define OFSX 0x1E // X axis offset | |
#define OFSY 0x1F // Y axis offset | |
#define OFSZ 0x20 // Z axis offset | |
#define INT_ENABLE 0x2E //Interrupts | |
#define INT_MAP 0x2F //Interrupts | |
#define INT_SOURCE 0x30 //Interrupts | |
#define OVERRUN 0x01 // Overrun mode | |
#define DATAX0 0x32 // LSB X axis... it is only needed | |
#define DATAX1 0x33 // MSB X axis | |
#define DATAY0 0x34 // LSB y axis | |
#define DATAY1 0x35 // MSB y axis | |
#define DATAZ0 0x36 // LSB z axis | |
#define DATAZ1 0x37 // MSB z axis | |
#define GRAVITY 9.80665 // Gravity value [m/s2] | |
#define DEVIAT_SENSIVILITY_X_Y 0.0040 // 4mg/LSB for x and y axis | |
#define DEVIAT_SENSIVILITY_Z 0.0043 // 4.3mg/LSB for z axis | |
#define SENSIVILITY 256 // LSB/g | |
// Structure to hold accelerometer bits | |
typedef struct ACCEL_DATA_BITS { | |
int16_t X0; | |
int16_t X1; | |
int16_t Y0; | |
int16_t Y1; | |
int16_t Z0; | |
int16_t Z1; | |
}ACCEL_DATA_BITS_t; | |
// Structure to hold acceleration working data | |
typedef struct ACCEL_DATA | |
{ | |
int16_t X; | |
int16_t Y; | |
int16_t Z; | |
}ACCEL_DATA_t; | |
// Structure to hold acceleration output values | |
typedef struct ACCEL_VAL | |
{ | |
double X; | |
double Y; | |
double Z; | |
}ACCE_VAL_t; | |
// Structure to configure the offset mode | |
typedef struct OFFSET | |
{ | |
uint8_t X; | |
uint8_t Y; | |
uint8_t Z; | |
}OFFSET_VAL_t; | |
static const char *TAG = "I2C_BICKER_TRACKER"; | |
/** | |
* @ Sequence to read I2C slave device | |
* | START | SLAVE ADDRESS + READ BIT + ACK | REGISTER + ACK | READ << 1 + ACK | READ 1 Byte + NACK | STOP | | |
*/ | |
static esp_err_t I2C_Master_Read_Slave_Reg(i2c_port_t i2c_num, uint8_t i2c_addr, uint8_t i2c_reg, uint8_t* data_rd, size_t size) | |
{ | |
if (size == 0) { | |
return ESP_OK; | |
} | |
i2c_cmd_handle_t cmd = i2c_cmd_link_create(); | |
i2c_master_start(cmd); | |
// first, send device address (indicating write) & register to be read | |
i2c_master_write_byte(cmd, ( i2c_addr << 1 ), ACK_CHECK_EN); | |
// send register we want | |
i2c_master_write_byte(cmd, i2c_reg, ACK_CHECK_EN); | |
// Send repeated start | |
i2c_master_start(cmd); | |
// now send device address (indicating read) & read data | |
i2c_master_write_byte(cmd, ( i2c_addr << 1 ) | READ_BIT, ACK_CHECK_EN); | |
if (size > 1) { | |
i2c_master_read(cmd, data_rd, size - 1, ACK_VAL); | |
} | |
i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL); | |
i2c_master_stop(cmd); | |
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS); | |
i2c_cmd_link_delete(cmd); | |
return ret; | |
} | |
/** | |
* @ Sequence to read I2C slave device | |
* | START | Slave Address + Write Bit + Acknowledge | Register + Acknowledge | Write N Bytes + Acknowledge | STOP | | |
*/ | |
static esp_err_t I2C_Master_Write_Slave_Reg(i2c_port_t i2c_num, uint8_t i2c_addr, uint8_t i2c_reg, uint8_t* data_wr, size_t size) | |
{ | |
i2c_cmd_handle_t cmd = i2c_cmd_link_create(); | |
i2c_master_start(cmd); | |
// first, send device address (indicating write) & register to be written | |
i2c_master_write_byte(cmd, ( i2c_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN); | |
// send register we want | |
i2c_master_write_byte(cmd, i2c_reg, ACK_CHECK_EN); | |
// write the data | |
i2c_master_write(cmd, data_wr, size, ACK_CHECK_EN); | |
i2c_master_stop(cmd); | |
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS); | |
i2c_cmd_link_delete(cmd); | |
return ret; | |
} | |
/* Read contents of a ADXL345 register | |
---------------------------------------------------------------------------*/ | |
esp_err_t ADXL345_REG_READER( uint8_t REG, uint8_t *P_DATA, uint8_t COUNT ) | |
{ | |
return( I2C_Master_Read_Slave_Reg( I2C_PORT_NUM, ADXL345_I2C_ADDR, REG, P_DATA, COUNT ) ); | |
} | |
/* Write value to specified ADXL345 register | |
---------------------------------------------------------------------------*/ | |
esp_err_t ADXL345_REG_WRITER( uint8_t reg, uint8_t *pdata, uint8_t count ) | |
{ | |
return( I2C_Master_Write_Slave_Reg( I2C_PORT_NUM, ADXL345_I2C_ADDR, reg, pdata, count ) ); | |
} | |
/**************************** | |
* ADXL345 Initialize * | |
****************************/ | |
static void ADXL345_Initialize() | |
{ | |
uint8_t val; // Work Value on the function | |
// Before re-configuring, must enter 'STANDBY' mode | |
ADXL345_REG_READER( PWR_CTL_REG, &(val), 1 ); | |
val &= ~(STANDBY_MODE_CONF); | |
ADXL345_REG_WRITER(PWR_CTL_REG, &(val), 1 ); | |
// check if the ID by default is the correct for the ADXL345 sensor. | |
ADXL345_REG_READER(DEVICE_ID, &(val), 1); | |
if (val == 0xE5) { | |
ESP_LOGI( TAG, "ADXL345 ID:0x%X (OK)", val ); | |
} else { | |
ESP_LOGE( TAG, "ADXL345 ID:0x%X !!!! (NOT correct; should be 0xE5)", val ); | |
} | |
// All is good about the ADXL345 configuration until here ---> OK | |
/* | |
** Configure accelerometer for: | |
** - Sleep Mode (125ms) | |
** - Low Power System | |
** - Full Scale of +/-4g | |
*/ | |
// Configuring the "SLEEP" mode operation | |
val = SLEEP_MODE_CONF; // val take the value for into sleep mode operation to 8 Hz | |
ADXL345_REG_WRITER(PWR_CTL_REG, &(val), 1 ); // write in the Power Control Register the... | |
// sleep mode operation. | |
// All is good about the ADXL345 configuration until here ---> OK | |
// Configure the data operation with low power consumption | |
// Configure the data rate operation to 100Hz | |
val = (LOW_POWER_MODE | DATA_RATE ); | |
ADXL345_REG_WRITER(BW_RATE_REG, &(val), 1 ); | |
// All is good about the ADXL345 configuration until here ---> OK | |
// Configure the data format to ±4 g full resolution | |
val = (GRAVITY_RANGE_BITS | RANGE_FULL_RES ); | |
ADXL345_REG_WRITER(DATA_FORMAT_REG, &(val), 1 ); | |
// All is good about the ADXL345 configuration until here ---> OK | |
/******************************* | |
* Configure the interrupts * | |
*******************************/ | |
val = (OVERRUN ); | |
ADXL345_REG_WRITER(INT_ENABLE, &(val), 1 ); | |
// All is good about the ADXL345 configuration until here ---> OK | |
val = (OVERRUN ); | |
ADXL345_REG_WRITER(INT_MAP, &(val), 1 ); | |
// All is good about the ADXL345 configuration until here ---> OK | |
val = (OVERRUN ); | |
ADXL345_REG_WRITER(INT_SOURCE, &(val), 1 ); | |
// All is good about the ADXL345 configuration until here ---> OK | |
/*********************************************** | |
* Re-Configure the Sleep and Standby modes * | |
***********************************************/ | |
// Reconfigure done by "SLEEP" mode disable | |
ADXL345_REG_READER( PWR_CTL_REG, &(val), 1 ); | |
val &= ~(SLEEP_MODE_CONF); | |
ADXL345_REG_WRITER(PWR_CTL_REG, &(val), 1 ); | |
// Reconfigure done by "STANDBY" mode disable | |
val |= (STANDBY_MODE_CONF); | |
ADXL345_REG_WRITER(PWR_CTL_REG, &(val), 1 ); | |
// All is good about the ADXL345 configuration until here ---> OK | |
} | |
/**************************** | |
* MASTER Mode Initialize * | |
****************************/ | |
static void I2C_Master_Initialize() | |
{ | |
int i2c_master_port = I2C_PORT_NUM; | |
i2c_config_t conf; | |
conf.mode = I2C_MODE_MASTER; | |
conf.sda_io_num = I2C_SDA_IO; | |
conf.sda_pullup_en = GPIO_PULLUP_ENABLE; | |
conf.scl_io_num = I2C_SCL_IO; | |
conf.scl_pullup_en = GPIO_PULLUP_ENABLE; | |
conf.master.clk_speed = I2C_FREQ_HZ; | |
i2c_param_config(i2c_master_port, &conf); | |
i2c_driver_install(i2c_master_port, conf.mode, | |
I2C_RX_BUF_DISABLE, I2C_TX_BUF_DISABLE, 0); | |
} | |
static void Offset_configuration() | |
{ | |
OFFSET_VAL_t offset_axis; | |
offset_axis.X = 0xFC; | |
offset_axis.Y = 0x02; | |
offset_axis.Z = 0xFF; | |
ADXL345_REG_WRITER(OFSX, (uint8_t *)&offset_axis, sizeof(offset_axis) ); | |
} | |
/*************************************** | |
* Make the task desired function * | |
***************************************/ | |
static void I2C_Acceleration_Calc_Task(void* arg) | |
{ | |
esp_err_t err; | |
ACCEL_DATA_BITS_t acc; | |
ACCEL_DATA_t accel; | |
ACCE_VAL_t acc_val; | |
ESP_LOGI( TAG, "ESP I2C - ADXL345 Accelerometer" ); | |
while (1) { | |
// Note: as configured, reading data from the output registers will start next acquisition | |
Offset_configuration(); | |
err = ADXL345_REG_READER( DATAX0, (uint8_t *)&acc.X0, sizeof(acc.X0) ); | |
err = ADXL345_REG_READER( DATAX1, (uint8_t *)&acc.X1, sizeof(acc.X1) ); | |
// Swap Big Endian | |
acc.X1 = acc.X1 << 8; | |
accel.X = acc.X0 | acc.X1; | |
err = ADXL345_REG_READER( DATAY0, (uint8_t *)&acc.Y0, sizeof(acc.Y0) ); | |
err = ADXL345_REG_READER( DATAY1, (uint8_t *)&acc.Y1, sizeof(acc.Y1) ); | |
// Swap Big Endian | |
acc.Y1 = acc.Y1 << 8; | |
accel.Y = acc.Y0 | acc.Y1; | |
err = ADXL345_REG_READER( DATAZ0, (uint8_t *)&acc.Z0, sizeof(acc.Z0) ); | |
err = ADXL345_REG_READER( DATAZ1, (uint8_t *)&acc.Z1, sizeof(acc.Z1) ); | |
// Swap Big Endian | |
acc.Z1 = acc.Z1 << 8; | |
accel.Z = acc.Z0 | acc.Z1; | |
// acc.X = BYTE_SWAP( acc.X ); | |
// acc.Y = BYTE_SWAP( acc.Y ); | |
// acc.Z = BYTE_SWAP( acc.Z ); | |
// byte-swap values to make little-endian | |
acc_val.X = -accel.X * DEVIAT_SENSIVILITY_X_Y * GRAVITY; | |
acc_val.Y = -accel.Y * DEVIAT_SENSIVILITY_X_Y * GRAVITY; | |
acc_val.Z = -accel.Z * DEVIAT_SENSIVILITY_Z * GRAVITY; | |
// shift each value to align 14-bits in 16-bit ints | |
ESP_LOGI( TAG, "Accelerometer err:%d x:%2f y:%2f z:%2f", err, acc_val.X, acc_val.Y, acc_val.Z ); | |
vTaskDelay( pdMS_TO_TICKS( SAMPLE_PERIOD_MS ) ); | |
} | |
} | |
void app_main() | |
{ | |
I2C_Master_Initialize(); // Initialize I2C master communication | |
ADXL345_Initialize(); // Initialize I2C configuration | |
// Make the task | |
xTaskCreate(I2C_Acceleration_Calc_Task, "i2c_test_task_0", 1024 * 2, (void* ) 0, 10, NULL); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment