doc/i2c-example: cleanup readme of i2c example

1. Update i2c README to add more detail according to the template.[TW#26530]
2. Move some specific configuration to KConfig
This commit is contained in:
morris
2018-10-08 16:50:26 +08:00
parent 12bf6e599c
commit 89d7f7bc89
9 changed files with 569 additions and 343 deletions
@@ -0,0 +1,4 @@
set(COMPONENT_SRCS "i2c_example_main.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
register_component()
@@ -0,0 +1,124 @@
menu "Example Configuration"
menu "I2C Master"
config I2C_MASTER_SCL
int "SCL GPIO Num"
default 19
help
GPIO number for I2C Master clock line.
config I2C_MASTER_SDA
int "SDA GPIO Num"
default 18
help
GPIO number for I2C Master data line.
config I2C_MASTER_PORT_NUM
int "Port Number"
default 1
help
Port number for I2C Master device.
config I2C_MASTER_FREQUENCY
int "Master Frequency"
default 100000
help
I2C Speed of Master device.
endmenu
menu "I2C Slave"
config I2C_SLAVE_SCL
int "SCL GPIO Num"
default 26
help
GPIO number for I2C Slave clock line.
config I2C_SLAVE_SDA
int "SDA GPIO Num"
default 25
help
GPIO number for I2C Slave data line.
config I2C_SLAVE_PORT_NUM
int "Port Number"
default 0
help
Port number for I2C Slave device.
config I2C_SLAVE_ADDRESS
hex "ESP Slave Address"
default 0x28
help
Hardware Address of I2C Slave Port.
endmenu
menu "BH1750 Sensor"
choice BH1750_ADDR
prompt "BH1750 I2C Address"
default BH1750_I2C_ADDRESS_LOW
help
Hardware address of BH1750, which is 2 types, and determined by ADDR terminal.
config BH1750_I2C_ADDRESS_LOW
bool "BH1750 I2C Address(ADDR=0)"
help
I2C Address of BH1750 Sensor according to your schemetic configuration.
config BH1750_I2C_ADDRESS_High
bool "BH1750 I2C Address(ADDR=1)"
help
I2C Address of BH1750 Sensor according to your schemetic configuration.
endchoice
config BH1750_ADDR
hex
default 0x5C if BH1750_I2C_ADDRESS_High
default 0x23 if BH1750_I2C_ADDRESS_LOW
choice BH1750_MODE
prompt "BH1750 Operation Mode"
default BH1750_ONETIME_L_RESOLUTION
help
Operation Mode of BH1750.
Different mode means different resolution and measurement time.
config BH1750_CONTINU_H_RESOLUTION
bool "Continuously H-Resolution Mode"
help
Resolution is 1lx, measurement time is typically 120ms.
config BH1750_CONTINU_H_RESOLUTION2
bool "Continuously H-Resolution Mode2"
help
Resolution is 0.5lx, measurement time is typically 120ms.
config BH1750_CONTINU_L_RESOLUTION
bool "Continuously L-Resolution Mode"
help
Resolution is 4lx, measurement time is typically 16ms.
config BH1750_ONETIME_H_RESOLUTION
bool "One Time H-Resolution Mode"
help
Resolution is 1lx, measurement time is typically 120ms.
It is automatically set to Power Down mode after measurement.
config BH1750_ONETIME_H_RESOLUTION2
bool "One Time H-Resolution Mode2"
help
Resolution is 0.5lx, measurement time is typically 120ms.
It is automatically set to Power Down mode after measurement.
config BH1750_ONETIME_L_RESOLUTION
bool "One Time L-Resolution Mode"
help
Resolution is 4lx, measurement time is typically 16ms.
It is automatically set to Power Down mode after measurement.
endchoice
config BH1750_OPMODE
hex
default 0x10 if BH1750_CONTINU_H_RESOLUTION
default 0x11 if BH1750_CONTINU_H_RESOLUTION2
default 0x13 if BH1750_CONTINU_L_RESOLUTION
default 0x20 if BH1750_ONETIME_H_RESOLUTION
default 0x21 if BH1750_ONETIME_H_RESOLUTION2
default 0x23 if BH1750_ONETIME_L_RESOLUTION
endmenu
endmenu
@@ -0,0 +1,3 @@
#
# Main Makefile. This is basically the same as a component makefile.
#
@@ -0,0 +1,291 @@
/* i2c - Example
For other examples please check:
https://github.com/espressif/esp-idf/tree/master/examples
See README.md file to get detailed usage of this 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 "esp_log.h"
#include "driver/i2c.h"
#include "sdkconfig.h"
static const char *TAG = "i2c-example";
#define _I2C_NUMBER(num) I2C_NUM_##num
#define I2C_NUMBER(num) _I2C_NUMBER(num)
#define DATA_LENGTH 512 /*!< Data buffer length of test buffer */
#define RW_TEST_LENGTH 128 /*!< Data length for r/w test, [0,DATA_LENGTH] */
#define DELAY_TIME_BETWEEN_ITEMS_MS 1000 /*!< delay time between different test items */
#define I2C_SLAVE_SCL_IO CONFIG_I2C_SLAVE_SCL /*!< gpio number for i2c slave clock */
#define I2C_SLAVE_SDA_IO CONFIG_I2C_SLAVE_SDA /*!< gpio number for i2c slave data */
#define I2C_SLAVE_NUM I2C_NUMBER(CONFIG_I2C_SLAVE_PORT_NUM) /*!< I2C port number for slave dev */
#define I2C_SLAVE_TX_BUF_LEN (2 * DATA_LENGTH) /*!< I2C slave tx buffer size */
#define I2C_SLAVE_RX_BUF_LEN (2 * DATA_LENGTH) /*!< I2C slave rx buffer size */
#define I2C_MASTER_SCL_IO CONFIG_I2C_MASTER_SCL /*!< gpio number for I2C master clock */
#define I2C_MASTER_SDA_IO CONFIG_I2C_MASTER_SDA /*!< gpio number for I2C master data */
#define I2C_MASTER_NUM I2C_NUMBER(CONFIG_I2C_MASTER_PORT_NUM) /*!< I2C port number for master dev */
#define I2C_MASTER_FREQ_HZ CONFIG_I2C_MASTER_FREQUENCY /*!< I2C master clock frequency */
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define BH1750_SENSOR_ADDR CONFIG_BH1750_ADDR /*!< slave address for BH1750 sensor */
#define BH1750_CMD_START CONFIG_BH1750_OPMODE /*!< Operation mode */
#define ESP_SLAVE_ADDR CONFIG_I2C_SLAVE_ADDRESS /*!< ESP32 slave address, you can set any 7bit value */
#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 */
SemaphoreHandle_t print_mux = NULL;
/**
* @brief test code to read esp-i2c-slave
* We need to fill the buffer of esp slave device, then master can read them out.
*
* _______________________________________________________________________________________
* | start | slave_addr + rd_bit +ack | read n-1 bytes + ack | read 1 byte + nack | stop |
* --------|--------------------------|----------------------|--------------------|------|
*
*/
static esp_err_t i2c_master_read_slave(i2c_port_t i2c_num, 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);
i2c_master_write_byte(cmd, (ESP_SLAVE_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;
}
/**
* @brief Test code to write esp-i2c-slave
* Master device write data to slave(both esp32),
* the data will be stored in slave buffer.
* We can read them out from slave buffer.
*
* ___________________________________________________________________
* | start | slave_addr + wr_bit + ack | write n bytes + ack | stop |
* --------|---------------------------|----------------------|------|
*
*/
static esp_err_t i2c_master_write_slave(i2c_port_t i2c_num, uint8_t *data_wr, size_t size)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (ESP_SLAVE_ADDR << 1) | WRITE_BIT, ACK_CHECK_EN);
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;
}
/**
* @brief test code to operate on BH1750 sensor
*
* 1. set operation mode(e.g One time L-resolution mode)
* _________________________________________________________________
* | start | slave_addr + wr_bit + ack | write 1 byte + ack | stop |
* --------|---------------------------|---------------------|------|
* 2. wait more than 24 ms
* 3. read data
* ______________________________________________________________________________________
* | start | slave_addr + rd_bit + ack | read 1 byte + ack | read 1 byte + nack | stop |
* --------|---------------------------|--------------------|--------------------|------|
*/
static esp_err_t i2c_master_sensor_test(i2c_port_t i2c_num, uint8_t *data_h, uint8_t *data_l)
{
int ret;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, BH1750_SENSOR_ADDR << 1 | WRITE_BIT, ACK_CHECK_EN);
i2c_master_write_byte(cmd, BH1750_CMD_START, 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;
}
vTaskDelay(30 / portTICK_RATE_MS);
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, BH1750_SENSOR_ADDR << 1 | READ_BIT, ACK_CHECK_EN);
i2c_master_read_byte(cmd, data_h, ACK_VAL);
i2c_master_read_byte(cmd, data_l, 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;
}
/**
* @brief i2c master initialization
*/
static esp_err_t i2c_master_init()
{
int i2c_master_port = I2C_MASTER_NUM;
i2c_config_t conf;
conf.mode = I2C_MODE_MASTER;
conf.sda_io_num = I2C_MASTER_SDA_IO;
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf.scl_io_num = I2C_MASTER_SCL_IO;
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf.master.clk_speed = I2C_MASTER_FREQ_HZ;
i2c_param_config(i2c_master_port, &conf);
return i2c_driver_install(i2c_master_port, conf.mode,
I2C_MASTER_RX_BUF_DISABLE,
I2C_MASTER_TX_BUF_DISABLE, 0);
}
/**
* @brief i2c slave initialization
*/
static esp_err_t i2c_slave_init()
{
int i2c_slave_port = I2C_SLAVE_NUM;
i2c_config_t conf_slave;
conf_slave.sda_io_num = I2C_SLAVE_SDA_IO;
conf_slave.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf_slave.scl_io_num = I2C_SLAVE_SCL_IO;
conf_slave.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf_slave.mode = I2C_MODE_SLAVE;
conf_slave.slave.addr_10bit_en = 0;
conf_slave.slave.slave_addr = ESP_SLAVE_ADDR;
i2c_param_config(i2c_slave_port, &conf_slave);
return i2c_driver_install(i2c_slave_port, conf_slave.mode,
I2C_SLAVE_RX_BUF_LEN,
I2C_SLAVE_TX_BUF_LEN, 0);
}
/**
* @brief test function to show buffer
*/
static void disp_buf(uint8_t *buf, int len)
{
int i;
for (i = 0; i < len; i++) {
printf("%02x ", buf[i]);
if ((i + 1) % 16 == 0) {
printf("\n");
}
}
printf("\n");
}
static void i2c_test_task(void *arg)
{
int i = 0;
int ret;
uint32_t task_idx = (uint32_t)arg;
uint8_t *data = (uint8_t *)malloc(DATA_LENGTH);
uint8_t *data_wr = (uint8_t *)malloc(DATA_LENGTH);
uint8_t *data_rd = (uint8_t *)malloc(DATA_LENGTH);
uint8_t sensor_data_h, sensor_data_l;
int cnt = 0;
while (1) {
ESP_LOGI(TAG, "TASK[%d] test cnt: %d", task_idx, cnt++);
ret = i2c_master_sensor_test(I2C_MASTER_NUM, &sensor_data_h, &sensor_data_l);
xSemaphoreTake(print_mux, portMAX_DELAY);
if (ret == ESP_ERR_TIMEOUT) {
ESP_LOGE(TAG, "I2C Timeout");
} else if (ret == ESP_OK) {
printf("*******************\n");
printf("TASK[%d] MASTER READ SENSOR( BH1750 )\n", task_idx);
printf("*******************\n");
printf("data_h: %02x\n", sensor_data_h);
printf("data_l: %02x\n", sensor_data_l);
printf("sensor val: %.02f [Lux]\n", (sensor_data_h << 8 | sensor_data_l) / 1.2);
} else {
ESP_LOGW(TAG, "%s: No ack, sensor not connected...skip...", esp_err_to_name(ret));
}
xSemaphoreGive(print_mux);
vTaskDelay((DELAY_TIME_BETWEEN_ITEMS_MS * (task_idx + 1)) / portTICK_RATE_MS);
//---------------------------------------------------
for (i = 0; i < DATA_LENGTH; i++) {
data[i] = i;
}
xSemaphoreTake(print_mux, portMAX_DELAY);
size_t d_size = i2c_slave_write_buffer(I2C_SLAVE_NUM, data, RW_TEST_LENGTH, 1000 / portTICK_RATE_MS);
if (d_size == 0) {
ESP_LOGW(TAG, "i2c slave tx buffer full");
ret = i2c_master_read_slave(I2C_MASTER_NUM, data_rd, DATA_LENGTH);
} else {
ret = i2c_master_read_slave(I2C_MASTER_NUM, data_rd, RW_TEST_LENGTH);
}
if (ret == ESP_ERR_TIMEOUT) {
ESP_LOGE(TAG, "I2C Timeout");
} else if (ret == ESP_OK) {
printf("*******************\n");
printf("TASK[%d] MASTER READ FROM SLAVE\n", task_idx);
printf("*******************\n");
printf("====TASK[%d] Slave buffer data ====\n", task_idx);
disp_buf(data, d_size);
printf("====TASK[%d] Master read ====\n", task_idx);
disp_buf(data_rd, d_size);
} else {
ESP_LOGW(TAG, "TASK[%d] %s: Master read slave error, IO not connected...\n",
task_idx, esp_err_to_name(ret));
}
xSemaphoreGive(print_mux);
vTaskDelay((DELAY_TIME_BETWEEN_ITEMS_MS * (task_idx + 1)) / portTICK_RATE_MS);
//---------------------------------------------------
int size;
for (i = 0; i < DATA_LENGTH; i++) {
data_wr[i] = i + 10;
}
xSemaphoreTake(print_mux, portMAX_DELAY);
//we need to fill the slave buffer so that master can read later
ret = i2c_master_write_slave(I2C_MASTER_NUM, data_wr, RW_TEST_LENGTH);
if (ret == ESP_OK) {
size = i2c_slave_read_buffer(I2C_SLAVE_NUM, data, RW_TEST_LENGTH, 1000 / portTICK_RATE_MS);
}
if (ret == ESP_ERR_TIMEOUT) {
ESP_LOGE(TAG, "I2C Timeout");
} else if (ret == ESP_OK) {
printf("*******************\n");
printf("TASK[%d] MASTER WRITE TO SLAVE\n", task_idx);
printf("*******************\n");
printf("----TASK[%d] Master write ----\n", task_idx);
disp_buf(data_wr, RW_TEST_LENGTH);
printf("----TASK[%d] Slave read: [%d] bytes ----\n", task_idx, size);
disp_buf(data, size);
} else {
ESP_LOGW(TAG, "TASK[%d] %s: Master write slave error, IO not connected....\n",
task_idx, esp_err_to_name(ret));
}
xSemaphoreGive(print_mux);
vTaskDelay((DELAY_TIME_BETWEEN_ITEMS_MS * (task_idx + 1)) / portTICK_RATE_MS);
}
vSemaphoreDelete(print_mux);
vTaskDelete(NULL);
}
void app_main()
{
print_mux = xSemaphoreCreateMutex();
ESP_ERROR_CHECK(i2c_slave_init());
ESP_ERROR_CHECK(i2c_master_init());
xTaskCreate(i2c_test_task, "i2c_test_task_0", 1024 * 2, (void *)0, 10, NULL);
xTaskCreate(i2c_test_task, "i2c_test_task_1", 1024 * 2, (void *)1, 10, NULL);
}