refactor (cxx): C++ I2C example now uses MPU9250 instead of MCP9808

Also fixes the documentation of I2CTransfer::sync_transfer().
This commit is contained in:
Jakob Hasse 2021-11-17 10:29:50 +08:00
parent 460f3ad7b6
commit de6bc33f3c
14 changed files with 141 additions and 113 deletions

View File

@ -229,7 +229,7 @@ public:
std::vector<uint8_t> sync_read(uint8_t i2c_addr, size_t n_bytes);
/**
* Do a simple asynchronous write-read transfer.
* Do a simple synchronous write-read transfer.
*
* First, \c write_data will be written to the bus, then a number of \c read_n_bytes will be read from the bus
* with a repeated start condition. The slave device is determined by \c i2c_addr.

View File

@ -1,49 +0,0 @@
# Example: C++ I2C sensor read for MCP9808
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates usage of C++ exceptions in ESP-IDF.
In this example, the `sdkconfig.defaults` file sets the `CONFIG_COMPILER_CXX_EXCEPTIONS` option.
This enables both compile time support (`-fexceptions` compiler flag) and run-time support for C++ exception handling.
This is necessary for the C++ I2C API.
## How to use example
### Hardware Required
An MCP9808 sensor and any commonly available ESP32 development board.
Pullups aren't necessary as the default pullups are enabled in the I2CMaster class.
### Configure the project
```
idf.py menuconfig
```
### Build and Flash
```
idf.py -p PORT flash monitor
```
(Replace PORT with the name of the serial port.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
If the sensor is read correctly:
```
Current temperature: 24.875
```
If something went wrong:
```
I2C Exception with error: ESP_FAIL (-1)
Coulnd't read sensor!
```

View File

@ -1,2 +0,0 @@
idf_component_register(SRCS "sensor_mcp9808.cpp"
INCLUDE_DIRS ".")

View File

@ -1,54 +0,0 @@
/* ESP MCP9808 Sensor/I2C C++ 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 <iostream>
#include "i2c_cxx.hpp"
using namespace std;
using namespace idf;
#define ADDR 0x18
#define I2C_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */
#define I2C_MASTER_SCL_IO 19 /*!< gpio number for I2C master clock */
#define I2C_MASTER_SDA_IO 18 /*!< gpio number for I2C master data */
#define MCP_9808_TEMP_REG 0x05
/**
* Calculates the temperature of the MCP9808 from the read msb and lsb. Loosely adapted from the MCP9808's datasheet.
*/
float calc_temp(uint8_t msb, uint8_t lsb) {
float temperature;
msb &= 0x1F;
bool sign = msb & 0x10;
if (sign) {
msb &= 0x0F;
temperature = 256 - (msb * 16 + (float) lsb / 16);
} else {
temperature = (msb * 16 + (float) lsb / 16);
}
return temperature;
}
extern "C" void app_main(void)
{
try {
// creating master bus, writing temperature register pointer and reading the value
shared_ptr<I2CMaster> master(new I2CMaster(I2C_MASTER_NUM, I2C_MASTER_SCL_IO, I2C_MASTER_SDA_IO, 400000));
master->sync_write(ADDR, {MCP_9808_TEMP_REG});
vector<uint8_t> data = master->sync_read(ADDR, 2);
cout << "Current temperature: " << calc_temp(data[0], data[1]) << endl;
} catch (const I2CException &e) {
cout << "I2C Exception with error: " << e.what();
cout << " (" << e.error<< ")" << endl;
cout << "Coulnd't read sensor!" << endl;
}
}

View File

@ -5,4 +5,4 @@ cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/examples/cxx/experimental/experimental_cpp_component")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(sensor_mcp9808)
project(simple_i2c_rw_example)

View File

@ -0,0 +1,60 @@
# Example: C++ I2C sensor read for MPU9250
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates usage of C++ exceptions in ESP-IDF. It is the C++ equivalent to the [I2C Simple Example](../../../peripherals/i2c/i2c_simple/) which is written in C.
In this example, the `sdkconfig.defaults` file sets the `CONFIG_COMPILER_CXX_EXCEPTIONS` option. This enables both compile time support (`-fexceptions` compiler flag) and run-time support for C++ exception handling. This is necessary for the C++ I2C API.
## How to Use This Example
### Hardware Required
To run this example, you should have one ESP32, ESP32-S series or ESP32-C series based development board as well as an MPU9250. MPU9250 is an inertial measurement unit, which contains an accelerometer, gyroscope as well as a magnetometer, for more information about it, you can read the [datasheet of the MPU9250 sensor](https://invensense.tdk.com/wp-content/uploads/2015/02/PS-MPU-9250A-01-v1.1.pdf).
#### Pin Assignment:
**Note:** The following pin assignments are used by default, you can change these in the `menuconfig` .
| | SDA | SCL |
| ---------------- | -------------- | -------------- |
| ESP I2C Master | I2C_MASTER_SDA | I2C_MASTER_SCL |
| MPU9250 Sensor | SDA | SCL |
For the actual default value of `I2C_MASTER_SDA` and `I2C_MASTER_SCL`, see `Example Configuration` in `menuconfig`.
**Note:** There's no need to add external pull-up resistors for SDA/SCL pins, because the driver will enable the internal pull-up resistors.
### Configure the project
```
idf.py menuconfig
```
### Build and Flash
```
idf.py -p <PORT> flash monitor
```
Replace <PORT> with the name of the serial port. To exit the serial monitor, type ``Ctrl-]``.
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Output
If the sensor is read correctly:
```bash
I (328) i2c-simple-example: I2C initialized successfully
I (338) i2c-simple-example: WHO_AM_I = 71
I (338) i2c-simple-example: I2C de-initialized successfully
```
If something went wrong:
```
I2C Exception with error: ESP_FAIL (-1)
Couldn't read sensor!
```

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "simple_i2c_rw_example.cpp"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,17 @@
menu "Example Configuration"
config I2C_MASTER_SCL
int "SCL GPIO Num"
default 6 if IDF_TARGET_ESP32C3
default 19 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
help
GPIO number for I2C Master clock line.
config I2C_MASTER_SDA
int "SDA GPIO Num"
default 5 if IDF_TARGET_ESP32C3
default 18 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
help
GPIO number for I2C Master data line.
endmenu

View File

@ -0,0 +1,54 @@
/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0
*
* MPU9250 I2C Sensor C++ 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 <iostream>
#include "esp_log.h"
#include "i2c_cxx.hpp"
using namespace std;
using namespace idf;
static const char *TAG = "i2c-cxx-simple-example";
#define I2C_MASTER_NUM 0 /*!< I2C master i2c port number, the number of i2c peripheral interfaces
available will depend on the chip */
#define I2C_MASTER_SCL_IO CONFIG_I2C_MASTER_SCL /*!< GPIO number used for I2C master clock */
#define I2C_MASTER_SDA_IO CONFIG_I2C_MASTER_SDA /*!< GPIO number used for I2C master data */
#define MPU9250_SENSOR_ADDR 0x68 /*!< Slave address of the MPU9250 sensor */
#define MPU9250_WHO_AM_I_REG_ADDR 0x75 /*!< Register addresses of the "who am I" register */
extern "C" void app_main(void)
{
try {
// creating master bus
shared_ptr<I2CMaster> master(new I2CMaster(I2C_MASTER_NUM, I2C_MASTER_SCL_IO, I2C_MASTER_SDA_IO, 400000));
ESP_LOGI(TAG, "I2C initialized successfully");
// writing the pointer to the WHO_AM_I register to the device
master->sync_write(MPU9250_SENSOR_ADDR, {MPU9250_WHO_AM_I_REG_ADDR});
// reading back the value of WHO_AM_I register which should be 71
vector<uint8_t> data = master->sync_read(MPU9250_SENSOR_ADDR, 2);
ESP_LOGI(TAG, "WHO_AM_I = %X", data[0]);
} catch (const I2CException &e) {
cout << "I2C Exception with error: " << e.what();
cout << " (" << e.error<< ")" << endl;
cout << "Couldn't read sensor!" << endl;
}
// The I2CMaster object is de-initialized in its destructor when going out of scope.
ESP_LOGI(TAG, "I2C de-initialized successfully");
}

View File

@ -53,7 +53,7 @@ If there's an error with the SPI peripheral:
...
I (0) cpu_start: Starting scheduler on APP CPU.
E (434) spi: spicommon_bus_initialize_io(429): mosi not valid
Coulnd't read SPI!
Couldn't read SPI!
```
If the SPI pins are not connected properly, the resulting read may just return 0, this error can not be detected:

View File

@ -43,6 +43,6 @@ extern "C" void app_main(void)
this_thread::sleep_for(std::chrono::seconds(2));
} catch (const SPIException &e) {
cout << "Coulnd't read SPI!" << endl;
cout << "Couldn't read SPI!" << endl;
}
}

View File

@ -12,7 +12,7 @@ If you have a new I2C application to go (for example, read the temperature data
### Hardware Required
To run this example, you should have one ESP32, ESP32-S or ESP32-C based development board as well as a MPU9250. MPU9250 is a inertial measurement unit, which contains a accelerometer, gyroscope as well as a magnetometer, for more information about it, you can read the [PDF](https://invensense.tdk.com/wp-content/uploads/2015/02/PS-MPU-9250A-01-v1.1.pdf) of this sensor.
To run this example, you should have one ESP32, ESP32-S or ESP32-C based development board as well as a MPU9250. MPU9250 is a inertial measurement unit, which contains a accelerometer, gyroscope as well as a magnetometer, for more information about it, you can read the [datasheet of the MPU9250 sensor](https://invensense.tdk.com/wp-content/uploads/2015/02/PS-MPU-9250A-01-v1.1.pdf).
#### Pin Assignment:
@ -26,7 +26,7 @@ To run this example, you should have one ESP32, ESP32-S or ESP32-C based develop
For the actual default value of `I2C_MASTER_SDA` and `I2C_MASTER_SCL` see `Example Configuration` in `menuconfig`.
**Note: ** Theres no need to add an external pull-up resistors for SDA/SCL pin, because the driver will enable the internal pull-up resistors.
**Note:** There's no need to add an external pull-up resistors for SDA/SCL pin, because the driver will enable the internal pull-up resistors.
### Build and Flash
@ -41,7 +41,7 @@ See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/l
```bash
I (328) i2c-simple-example: I2C initialized successfully
I (338) i2c-simple-example: WHO_AM_I = 71
I (338) i2c-simple-example: I2C unitialized successfully
I (338) i2c-simple-example: I2C de-initialized successfully
```
## Troubleshooting

View File

@ -93,5 +93,5 @@ void app_main(void)
ESP_ERROR_CHECK(mpu9250_register_write_byte(MPU9250_PWR_MGMT_1_REG_ADDR, 1 << MPU9250_RESET_BIT));
ESP_ERROR_CHECK(i2c_driver_delete(I2C_MASTER_NUM));
ESP_LOGI(TAG, "I2C unitialized successfully");
ESP_LOGI(TAG, "I2C de-initialized successfully");
}