Files
2018-09-28 15:35:45 +08:00

260 lines
9.2 KiB
C

/* I2C example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_err.h"
#include "driver/i2c.h"
static const char *TAG = "main";
/**
* TEST CODE BRIEF
*
* This example will show you how to use I2C module by running two tasks on i2c bus:
*
* - read external i2c sensor, here we use a MPU6050 sensor for instance.
* - Use one I2C port(master mode) to read or write the other I2C port(slave mode) on one ESP8266 chip.
*
* Pin assignment:
*
* - master:
* GPIO14 is assigned as the data signal of i2c master port
* GPIO2 is assigned as the clock signal of i2c master port
*
* Connection:
*
* - connect sda/scl of sensor with GPIO14/GPIO2
* - no need to add external pull-up resistors, driver will enable internal pull-up resistors.
*
* Test items:
*
* - read the sensor data, if connected.
*/
#define I2C_EXAMPLE_MASTER_SCL_IO 2 /*!< gpio number for I2C master clock */
#define I2C_EXAMPLE_MASTER_SDA_IO 14 /*!< gpio number for I2C master data */
#define I2C_EXAMPLE_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */
#define I2C_EXAMPLE_MASTER_TX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
#define I2C_EXAMPLE_MASTER_RX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
#define MPU6050_SENSOR_ADDR 0x68 /*!< slave address for MPU6050 sensor */
#define MPU6050_CMD_START 0x41 /*!< Command to set measure mode */
#define MPU6050_WHO_AM_I 0x75 /*!< Command to read WHO_AM_I reg */
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
#define ACK_VAL 0x0 /*!< I2C ack value */
#define NACK_VAL 0x1 /*!< I2C nack value */
#define LAST_NACK_VAL 0x2 /*!< I2C last_nack value */
/**
* Define the mpu6050 register address:
*/
#define SMPLRT_DIV 0x19
#define CONFIG 0x1A
#define GYRO_CONFIG 0x1B
#define ACCEL_CONFIG 0x1C
#define ACCEL_XOUT_H 0x3B
#define ACCEL_XOUT_L 0x3C
#define ACCEL_YOUT_H 0x3D
#define ACCEL_YOUT_L 0x3E
#define ACCEL_ZOUT_H 0x3F
#define ACCEL_ZOUT_L 0x40
#define TEMP_OUT_H 0x41
#define TEMP_OUT_L 0x42
#define GYRO_XOUT_H 0x43
#define GYRO_XOUT_L 0x44
#define GYRO_YOUT_H 0x45
#define GYRO_YOUT_L 0x46
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48
#define PWR_MGMT_1 0x6B
#define WHO_AM_I 0x75 /*!< Command to read WHO_AM_I reg */
/**
* @brief i2c master initialization
*/
static esp_err_t i2c_example_master_init()
{
int i2c_master_port = I2C_EXAMPLE_MASTER_NUM;
i2c_config_t conf;
conf.mode = I2C_MODE_MASTER;
conf.sda_io_num = I2C_EXAMPLE_MASTER_SDA_IO;
conf.sda_pullup_en = 0;
conf.scl_io_num = I2C_EXAMPLE_MASTER_SCL_IO;
conf.scl_pullup_en = 0;
ESP_ERROR_CHECK(i2c_driver_install(i2c_master_port, conf.mode));
ESP_ERROR_CHECK(i2c_param_config(i2c_master_port, &conf));
return ESP_OK;
}
/**
* @brief test code to write mpu6050
*
* 1. send data
* ___________________________________________________________________________________________________
* | start | slave_addr + wr_bit + ack | write reg_address + ack | write data_len byte + ack | stop |
* --------|---------------------------|-------------------------|----------------------------|------|
*
* @param i2c_num I2C port number
* @param reg_address slave reg address
* @param data data to send
* @param data_len data length
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_FAIL Sending command error, slave doesn't ACK the transfer.
* - ESP_ERR_INVALID_STATE I2C driver not installed or not in master mode.
* - ESP_ERR_TIMEOUT Operation timeout because the bus is busy.
*/
static esp_err_t i2c_example_master_mpu6050_write(i2c_port_t i2c_num, uint8_t reg_address, uint8_t *data, size_t data_len)
{
int ret;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, MPU6050_SENSOR_ADDR << 1 | WRITE_BIT, ACK_CHECK_EN);
i2c_master_write_byte(cmd, reg_address, ACK_CHECK_EN);
i2c_master_write(cmd, data, data_len, ACK_CHECK_EN);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
/**
* @brief test code to read mpu6050
*
* 1. send reg address
* ______________________________________________________________________
* | start | slave_addr + wr_bit + ack | write reg_address + ack | stop |
* --------|---------------------------|-------------------------|------|
*
* 2. read data
* ___________________________________________________________________________________
* | start | slave_addr + wr_bit + ack | read data_len byte + ack(last nack) | stop |
* --------|---------------------------|--------------------------------------|------|
*
* @param i2c_num I2C port number
* @param reg_address slave reg address
* @param data data to read
* @param data_len data length
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_FAIL Sending command error, slave doesn't ACK the transfer.
* - ESP_ERR_INVALID_STATE I2C driver not installed or not in master mode.
* - ESP_ERR_TIMEOUT Operation timeout because the bus is busy.
*/
static esp_err_t i2c_example_master_mpu6050_read(i2c_port_t i2c_num, uint8_t reg_address, uint8_t *data, size_t data_len)
{
int ret;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, MPU6050_SENSOR_ADDR << 1 | WRITE_BIT, ACK_CHECK_EN);
i2c_master_write_byte(cmd, reg_address, ACK_CHECK_EN);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
if (ret != ESP_OK) {
return ret;
}
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, MPU6050_SENSOR_ADDR << 1 | READ_BIT, ACK_CHECK_EN);
i2c_master_read(cmd, data, data_len, LAST_NACK_VAL);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
static esp_err_t i2c_example_master_mpu6050_init(i2c_port_t i2c_num)
{
uint8_t cmd_data;
vTaskDelay(100 / portTICK_RATE_MS);
i2c_example_master_init();
cmd_data = 0x00; // reset mpu6050
ESP_ERROR_CHECK(i2c_example_master_mpu6050_write(i2c_num, PWR_MGMT_1, &cmd_data, 1));
cmd_data = 0x07; // Set the SMPRT_DIV
ESP_ERROR_CHECK(i2c_example_master_mpu6050_write(i2c_num, SMPLRT_DIV, &cmd_data, 1));
cmd_data = 0x06; // Set the Low Pass Filter
ESP_ERROR_CHECK(i2c_example_master_mpu6050_write(i2c_num, CONFIG, &cmd_data, 1));
cmd_data = 0x18; // Set the GYRO range
ESP_ERROR_CHECK(i2c_example_master_mpu6050_write(i2c_num, GYRO_CONFIG, &cmd_data, 1));
cmd_data = 0x01; // Set the ACCEL range
ESP_ERROR_CHECK(i2c_example_master_mpu6050_write(i2c_num, ACCEL_CONFIG, &cmd_data, 1));
return ESP_OK;
}
static void i2c_task_example(void *arg)
{
uint8_t sensor_data[14];
uint8_t who_am_i, i;
double Temp;
static uint32_t error_count = 0;
int ret;
i2c_example_master_mpu6050_init(I2C_EXAMPLE_MASTER_NUM);
while (1) {
who_am_i = 0;
i2c_example_master_mpu6050_read(I2C_EXAMPLE_MASTER_NUM, WHO_AM_I, &who_am_i, 1);
if (0x68 != who_am_i) {
error_count++;
}
memset(sensor_data, 0, 14);
ret = i2c_example_master_mpu6050_read(I2C_EXAMPLE_MASTER_NUM, ACCEL_XOUT_H, sensor_data, 14);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "*******************\n");
ESP_LOGI(TAG, "WHO_AM_I: 0x%02x\n", who_am_i);
Temp = 36.53 + ((double)(int16_t)((sensor_data[6] << 8) | sensor_data[7]) / 340);
ESP_LOGI(TAG, "TEMP: %d.%d\n", (uint16_t)Temp, (uint16_t)(Temp * 100) % 100);
for (i = 0; i < 7; i++) {
ESP_LOGI(TAG, "sensor_data[%d]: %d\n", i, (int16_t)((sensor_data[i * 2] << 8) | sensor_data[i * 2 + 1]));
}
ESP_LOGI(TAG, "error_count: %d\n", error_count);
} else {
ESP_LOGE(TAG, "No ack, sensor not connected...skip...\n");
}
vTaskDelay(100 / portTICK_RATE_MS);
}
i2c_driver_delete(I2C_EXAMPLE_MASTER_NUM);
}
void app_main(void)
{
//start i2c task
xTaskCreate(i2c_task_example, "i2c_task_example", 2048, NULL, 10, NULL);
}