mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-05-21 00:56:38 +08:00
260 lines
9.2 KiB
C
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);
|
|
} |