diff options
Diffstat (limited to 'components/drivers/sensors/mpu6050_sensor.cpp')
| -rw-r--r-- | components/drivers/sensors/mpu6050_sensor.cpp | 462 |
1 files changed, 462 insertions, 0 deletions
diff --git a/components/drivers/sensors/mpu6050_sensor.cpp b/components/drivers/sensors/mpu6050_sensor.cpp new file mode 100644 index 0000000000..8f6557a7ce --- /dev/null +++ b/components/drivers/sensors/mpu6050_sensor.cpp @@ -0,0 +1,462 @@ +/* + * File : MPU6050_sensor.cpp + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2014, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2014-12-20 Bernard the first version + * 2015-1-11 RT_learning modify the mpu6050 initialize + */ + +#include <string.h> +#include <stdio.h> +#include <rtdevice.h> + +#include "mpu6050_sensor.h" + + +const static sensor_t _MPU6050_sensor[] = +{ + { + .name = "Accelerometer", + .vendor = "Invensense", + .version = sizeof(sensor_t), + .handle = 0, + .type = SENSOR_TYPE_ACCELEROMETER, + .maxRange = SENSOR_ACCEL_RANGE_16G, + .resolution = 1.0f, + .power = 0.5f, + .minDelay = 10000, + .fifoReservedEventCount = 0, + .fifoMaxEventCount = 64, + }, + { + .name = "Gyroscope", + .vendor = "Invensense", + .version = sizeof(sensor_t), + .handle = 0, + .type = SENSOR_TYPE_GYROSCOPE, + .maxRange = SENSOR_GYRO_RANGE_2000DPS, + .resolution = 1.0f, + .power = 0.5f, + .minDelay = 10000, + .fifoReservedEventCount = 0, + .fifoMaxEventCount = 64, + } +}; + +MPU6050::MPU6050(int sensor_type, const char* iic_bus, int addr) + : SensorBase(sensor_type) +{ + this->i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(iic_bus); + if (this->i2c_bus == NULL) + { + printf("MPU6050: No IIC device:%s\n", iic_bus); + return; + } + + this->i2c_addr = addr; + + /* register to sensor manager */ + SensorManager::registerSensor(this); +} + +int MPU6050::read_reg(rt_uint8_t reg, rt_uint8_t *value) +{ + struct rt_i2c_msg msgs[2]; + + msgs[0].addr = this->i2c_addr; + msgs[0].flags = RT_I2C_WR; + msgs[0].buf = ® + msgs[0].len = 1; + + msgs[1].addr = this->i2c_addr; + msgs[1].flags = RT_I2C_RD; /* Read from slave */ + msgs[1].buf = (rt_uint8_t *)value; + msgs[1].len = 1; + + if (rt_i2c_transfer(this->i2c_bus, msgs, 2) == 2) + return RT_EOK; + + return -RT_ERROR; +} + +int MPU6050::read_buffer(rt_uint8_t reg, rt_uint8_t* value, rt_size_t size) +{ + struct rt_i2c_msg msgs[2]; + + msgs[0].addr = this->i2c_addr; + msgs[0].flags = RT_I2C_WR; + msgs[0].buf = ® + msgs[0].len = 1; + + msgs[1].addr = this->i2c_addr; + msgs[1].flags = RT_I2C_RD; /* Read from slave */ + msgs[1].buf = (rt_uint8_t *)value; + msgs[1].len = size; + + if (rt_i2c_transfer(this->i2c_bus, msgs, 2) == 2) + return RT_EOK; + + return -RT_ERROR; +} + +int MPU6050::write_reg(rt_uint8_t reg, rt_uint8_t value) +{ + struct rt_i2c_msg msgs[2]; + + msgs[0].addr = this->i2c_addr; + msgs[0].flags = RT_I2C_WR; + msgs[0].buf = ® + msgs[0].len = 1; + + msgs[1].addr = this->i2c_addr; + msgs[1].flags = RT_I2C_WR | RT_I2C_NO_START; + msgs[1].buf = (rt_uint8_t *)&value; + msgs[1].len = 1; + + if (rt_i2c_transfer(this->i2c_bus, msgs, 2) == 2) + return RT_EOK; + + return -RT_ERROR; +} + + +MPU6050_Accelerometer::MPU6050_Accelerometer(const char* iic_name, int addr) + : MPU6050(SENSOR_TYPE_ACCELEROMETER, iic_name, addr) +{ + int index; + uint8_t id; + rt_uint8_t value[6] = {0}; + rt_int32_t x, y, z; + SensorConfig config = {SENSOR_MODE_NORMAL, SENSOR_DATARATE_400HZ, SENSOR_ACCEL_RANGE_2G}; + + /* initialize MPU6050 */ + write_reg(MPU6050_PWR_MGMT_1, 0x80); /* reset mpu6050 device */ + write_reg(MPU6050_SMPLRT_DIV, 0x00); /* Sample Rate = Gyroscope Output Rate / (1 + SMPLRT_DIV) */ + write_reg(MPU6050_PWR_MGMT_1, 0x03); /* Wake up device , set device clock Z axis gyroscope */ + write_reg(MPU6050_CONFIG, 0x03); /* set DLPF_CFG 42Hz */ + write_reg(MPU6050_GYRO_CONFIG, 0x18); /* set gyro 2000deg/s */ + write_reg(MPU6050_ACCEL_CONFIG, 0x08); /* set acc +-4g/s */ + + + x_offset = y_offset = z_offset = 0; + x = y = z = 0; + + /* read MPU6050 id */ + read_buffer(MPU6050_WHOAMI, &id, 1); + if (id != MPU6050_ID) + { + printf("Warning: not found MPU6050 id: %02x\n", id); + } + + /* get offset */ + for (index = 0; index < 200; index ++) + { + read_buffer(MPU6050_ACCEL_XOUT_H, value, 6); + + x += (((rt_int16_t)value[0] << 8) | value[1]); + y += (((rt_int16_t)value[2] << 8) | value[3]); + z += (((rt_int16_t)value[4] << 8) | value[5]); + } + x_offset = x / 200; + y_offset = y / 200; + z_offset = z / 200; + + this->enable = RT_FALSE; + this->sensitivity = SENSOR_ACCEL_SENSITIVITY_2G; + this->config = config; +} + +int +MPU6050_Accelerometer::configure(SensorConfig *config) +{ + int range; + uint8_t value; + + if (config == RT_NULL) return -1; + + /* TODO: set datarate */ + + /* get range and calc the sensitivity */ + range = config->range.accel_range; + switch (range) + { + case SENSOR_ACCEL_RANGE_2G: + this->sensitivity = SENSOR_ACCEL_SENSITIVITY_2G; + range = 0; + break; + case SENSOR_ACCEL_RANGE_4G: + this->sensitivity = SENSOR_ACCEL_SENSITIVITY_4G; + range = 0x01 << 2; + break; + case SENSOR_ACCEL_RANGE_8G: + this->sensitivity = SENSOR_ACCEL_SENSITIVITY_8G; + range = 0x02 << 2; + break; + case SENSOR_ACCEL_RANGE_16G: + this->sensitivity = SENSOR_ACCEL_SENSITIVITY_16G; + range = 0x03 << 2; + break; + default: + return -1; + } + + /* set range to sensor */ + read_reg(MPU6050_ACCEL_CONFIG, &value); + value &= ~(0x3 << 2); + value |= range; + write_reg(MPU6050_ACCEL_CONFIG, value); + + return 0; +} + +int +MPU6050_Accelerometer::activate(int enable) +{ + uint8_t value; + + if (enable && this->enable == RT_FALSE) + { + /* enable accelerometer */ + read_reg(MPU6050_PWR_MGMT_2, &value); + value &= ~(0x07 << 2); + write_reg(MPU6050_PWR_MGMT_2, value); + } + + if (!enable && this->enable == RT_TRUE) + { + /* disable accelerometer */ + read_reg(MPU6050_PWR_MGMT_2, &value); + value |= (0x07 << 2); + write_reg(MPU6050_PWR_MGMT_2, value); + } + + if (enable) this->enable = RT_TRUE; + else this->enable = RT_FALSE; + + return 0; +} + +int +MPU6050_Accelerometer::poll(sensors_event_t *event) +{ + rt_uint8_t value[6]; + rt_int16_t x, y, z; + + /* parameters check */ + if (event == NULL) return -1; + + /* get event data */ + event->version = sizeof(sensors_event_t); + event->sensor = (int32_t) this; + event->timestamp = rt_tick_get(); + event->type = SENSOR_TYPE_ACCELEROMETER; + + read_buffer(MPU6050_ACCEL_XOUT_H, value, 6); + + /* get raw data */ + x = (((rt_int16_t)value[0] << 8) | value[1]); + y = (((rt_int16_t)value[2] << 8) | value[3]); + z = (((rt_int16_t)value[4] << 8) | value[5]); + + if (config.mode == SENSOR_MODE_RAW) + { + event->raw_acceleration.x = x; + event->raw_acceleration.y = y; + event->raw_acceleration.z = z; + } + else + { + + x -= x_offset; y -= y_offset; z -= z_offset; + event->acceleration.x = x * this->sensitivity * SENSORS_GRAVITY_STANDARD; + event->acceleration.y = y * this->sensitivity * SENSORS_GRAVITY_STANDARD; + event->acceleration.z = z * this->sensitivity * SENSORS_GRAVITY_STANDARD; + } + + return 0; +} + +void +MPU6050_Accelerometer::getSensor(sensor_t *sensor) +{ + /* get sensor description */ + if (sensor) + { + memcpy(sensor, &_MPU6050_sensor[0], sizeof(sensor_t)); + } +} + +MPU6050_Gyroscope::MPU6050_Gyroscope(const char* iic_name, int addr) + : MPU6050(SENSOR_TYPE_GYROSCOPE, iic_name, addr) +{ + int index; + uint8_t id; + rt_uint8_t value[6]; + rt_int32_t x, y, z; + + /* initialize MPU6050 */ + write_reg(MPU6050_PWR_MGMT_1, 0x80); /* reset mpu6050 device */ + write_reg(MPU6050_SMPLRT_DIV, 0x00); /* Sample Rate = Gyroscope Output Rate / (1 + SMPLRT_DIV) */ + write_reg(MPU6050_PWR_MGMT_1, 0x03); /* Wake up device , set device clock Z axis gyroscope */ + write_reg(MPU6050_CONFIG, 0x03); /* set DLPF_CFG 42Hz */ + write_reg(MPU6050_GYRO_CONFIG, 0x18); /* set gyro 2000deg/s */ + write_reg(MPU6050_ACCEL_CONFIG, 0x08); /* set acc +-4g/s */ + + x_offset = y_offset = z_offset = 0; + x = y = z = 0; + + /* read MPU6050 id */ + read_reg(MPU6050_WHOAMI, &id); + if (id != MPU6050_ID) + { + printf("Warning: not found MPU6050 id: %02x\n", id); + } + + /* get offset */ + for (index = 0; index < 200; index ++) + { + read_buffer(MPU6050_GYRO_XOUT_H, value, 6); + + x += (((rt_int16_t)value[0] << 8) | value[1]); + y += (((rt_int16_t)value[2] << 8) | value[3]); + z += (((rt_int16_t)value[4] << 8) | value[5]); + } + x_offset = x / 200; + y_offset = y / 200; + z_offset = z / 200; + + this->enable = RT_FALSE; + this->sensitivity = SENSOR_GYRO_SENSITIVITY_250DPS; +} + +int +MPU6050_Gyroscope::configure(SensorConfig *config) +{ + int range; + uint8_t value; + + if (config == RT_NULL) return -1; + + /* TODO: set datarate */ + + /* get range and calc the sensitivity */ + range = config->range.gyro_range; + switch (range) + { + case SENSOR_GYRO_RANGE_250DPS: + this->sensitivity = SENSOR_GYRO_SENSITIVITY_250DPS; + range = 0; + break; + case SENSOR_GYRO_RANGE_500DPS: + this->sensitivity = SENSOR_GYRO_SENSITIVITY_500DPS; + range = 0x01 << 2; + break; + case SENSOR_GYRO_RANGE_1000DPS: + this->sensitivity = SENSOR_GYRO_SENSITIVITY_1000DPS; + range = 0x02 << 2; + break; + case SENSOR_GYRO_RANGE_2000DPS: + this->sensitivity = SENSOR_GYRO_SENSITIVITY_2000DPS; + range = 0x03 << 2; + break; + default: + return -1; + } + + /* set range to sensor */ + read_reg(MPU6050_GYRO_CONFIG, &value); + value &= ~(0x3 << 2); + value |= range; + write_reg(MPU6050_GYRO_CONFIG, value); + + return 0; +} + +int +MPU6050_Gyroscope::activate(int enable) +{ + uint8_t value; + + if (enable && this->enable == RT_FALSE) + { + /* enable gyroscope */ + read_reg(MPU6050_PWR_MGMT_1, &value); + value &= ~(0x01 << 4); + write_reg(MPU6050_PWR_MGMT_1, value); + + read_reg(MPU6050_PWR_MGMT_2, &value); + value &= ~(0x07 << 0); + write_reg(MPU6050_PWR_MGMT_2, value); + } + + if (!enable && this->enable == RT_TRUE) + { + /* disable gyroscope */ + read_reg(MPU6050_PWR_MGMT_2, &value); + value |= (0x07 << 0); + write_reg(MPU6050_PWR_MGMT_2, value); + } + + if (enable) this->enable = RT_TRUE; + else this->enable = RT_FALSE; + + return 0; +} + +int +MPU6050_Gyroscope::poll(sensors_event_t *event) +{ + rt_uint8_t value[6]; + rt_int16_t x, y, z; + + /* parameters check */ + if (event == NULL) return -1; + + /* get event data */ + event->version = sizeof(sensors_event_t); + event->sensor = (int32_t) this; + event->timestamp = rt_tick_get(); + event->type = SENSOR_TYPE_GYROSCOPE; + + read_buffer(MPU6050_GYRO_XOUT_H, value, 6); + + /* get raw data */ + x = (((rt_int16_t)value[0] << 8) | value[1]); + y = (((rt_int16_t)value[2] << 8) | value[3]); + z = (((rt_int16_t)value[4] << 8) | value[5]); + + + if (config.mode == SENSOR_MODE_RAW) + { + event->raw_gyro.x = x; + event->raw_gyro.y = y; + event->raw_gyro.z = z; + } + else + { + x -= x_offset; y -= y_offset; z -= z_offset; + event->gyro.x = x * this->sensitivity * SENSORS_DPS_TO_RADS; + event->gyro.y = y * this->sensitivity * SENSORS_DPS_TO_RADS; + event->gyro.z = z * this->sensitivity * SENSORS_DPS_TO_RADS; + } + + return 0; +} + +void +MPU6050_Gyroscope::getSensor(sensor_t *sensor) +{ + /* get sensor description */ + if (sensor) + { + memcpy(sensor, &_MPU6050_sensor[1], sizeof(sensor_t)); + } +} + |
