I2C

Last Updated on : 2024-11-20 02:14:53download

File description

API files

The I2C API is located in ty_i2c.h. The driver code for different chip platforms is located in ty_i2c_xxxx.c.

tuya_ble_sdk_demo
└── board
     ├── include
     |    └── ty_i2c.h
     ├── xxxx                      /* xxxx represents the chip platform, such as TLSR825x */
     |    └── ty_board_xxxx        /* xxxx represents the chip platform, such as ty_board_tlsr825x */
     |         └── ty_i2c_xxxx.c   /* xxxx represents the chip platform, such as ty_i2c_tlsr825x.c */
     └── board.h

Demo files

File structure of tuya_board_api_demo:

tuya_ble_sdk_demo
├── app  /* API example */
|    ├── include
|    |    └── ty_board_demo
|    |    |    ├── demo_config.h        /* Demo configuration file */
|    |    |    └── ty_i2c_demo.h        /* I2C sample code */
|    |    ├── tuya_ble_board_api_demo.h /* Entry point to Board API example */
|    |    └── tuya_ble_sdk_demo.h       /* Entry point to tuya_ble_sdk application */
|    └── src
|         ├── ty_board_demo
|         |    └── ty_i2c_demo.c        /* I2C sample code */
|         ├── tuya_ble_board_api_demo.c /* Entry point to Board API example */
|         └── tuya_ble_sdk_demo.c       /* Entry point to tuya_ble_sdk application */
└── board /* Example of modifying API code */

Modify demo_config.h to toggle to the I2C example.

#define BOARD_API_DEMO          BOARD_API_I2C

API list

Function name Description
ty_i2c_init Initialize the I2C.
ty_i2c_start I2C hardware: Start I2C transmission.
ty_i2c_stop I2C hardware: Stop I2C transmission.
ty_i2c_control I2C hardware: Control the I2C.
ty_i2c_uninit I2C hardware: Disable the I2C.
ty_i2c_send I2C hardware: Send data.
i2c_send_bytes I2C software: Send multiple-byte data.
i2c_rcv_bytes I2C software: Receive multiple-byte data.
i2c_soft_cfg I2C software: Configure the peripheral register.
i2c_soft_gpio_init I2C software: Initialize the I2C pin.
i2c_start I2C software: Send the start signal.
i2c_stop I2C software: Send the stop signal.
i2c_delay I2C software: Delay in microseconds.

API description

ty_i2c_init

Function name ty_i2c_init
Function prototype uint32_t ty_i2c_init(void);
Description Initialize the I2C.
Parameter None
Return value 0: Success.
Others: Failure.
Notes You can add or modify functions, parameters, and return values as needed.

ty_i2c_start

Function name ty_i2c_start
Function prototype uint32_t ty_i2c_start(void);
Description I2C hardware: Start I2C transmission.
Parameter None
Return value 0: Success.
Others: Failure.
Notes You can add or modify functions, parameters, and return values as needed.

ty_i2c_stop

Function name ty_i2c_stop
Function prototype uint32_t ty_i2c_stop(void);
Description I2C hardware: Stop I2C transmission.
Parameter None
Return value 0: Success.
Others: Failure.
Notes You can add or modify functions, parameters, and return values as needed.

ty_i2c_control

Function name ty_i2c_control
Function prototype uint32_t ty_i2c_control(uint8_t cmd, void* arg);
Description I2C hardware: Control the I2C.
Parameter cmd [in]: The control command.
arg [in]: The parameter of the command.
Return value 0: Success.
Others: Failure.
Notes You can add or modify functions, parameters, and return values as needed.

ty_i2c_uninit

Function name ty_i2c_uninit
Function prototype uint32_t ty_i2c_uninit(void);
Description I2C hardware: Disable the I2C.
Parameter None
Return value 0: Success.
Others: Failure.
Notes You can add or modify functions, parameters, and return values as needed.

ty_i2c_send

Function name ty_i2c_send
Function prototype uint32_t ty_i2c_send(const uint8_t addr, const uint8_t* buf, uint32_t size);
Description I2C hardware: Send data.
Parameter addr [in]: The address.
buf [in]: Data to be sent.
size [in]: Size of the data.
Return value 0: Success.
Others: Failure.
Notes You can add or modify functions, parameters, and return values as needed.

i2c_send_bytes

Function name i2c_send_bytes
Function prototype void i2c_send_bytes(uint8_t adderss_cmd, uint8_t *buff, uint8_t len);
Description I2C software: Send multiple-byte data.
Parameter adderss_cmd [in]: The peripheral address and the read-write command.
buff [in]: Data to be sent.
len [in]: The length of the data.
Return value None
Notes You can add or modify functions, parameters, and return values as needed.

i2c_rcv_bytes

Function name i2c_rcv_bytes
Function prototype void i2c_rcv_bytes(uint8_t adderss_cmd, uint8_t *buff, uint8_t len);
Description I2C software: Receive multiple-byte data.
Parameter adderss_cmd [in]: The peripheral address and the read-write command.
buff [out]: Data received.
len [in]: The length of the data.
Return value None
Notes You can add or modify functions, parameters, and return values as needed.

i2c_soft_cfg

Function name i2c_soft_cfg
Function prototype void i2c_soft_cfg(uint8_t adderss_cmd, uint8_t reg_addr, uint8_t data);
Description I2C software: Configure the peripheral register.
Parameter adderss_cmd [in]: The peripheral address and the read-write command.
reg_addr [in]: The register address.
data [in]: The register value.
Return value None
Notes You can add or modify functions, parameters, and return values as needed.

i2c_soft_gpio_init

Function name i2c_soft_gpio_init
Function prototype void i2c_soft_gpio_init(void);
Description I2C software: Initialize the I2C pin.
Parameter None
Return value None
Notes You can add or modify functions, parameters, and return values as needed.

i2c_start

Function name i2c_start
Function prototype void i2c_start(void);
Description I2C software: Send the start signal.
Parameter None
Return value None
Notes You can add or modify functions, parameters, and return values as needed.

i2c_stop

Function name i2c_stop
Function prototype void i2c_stop(void);
Description I2C software: Send the stop signal.
Parameter None
Return value None
Notes You can add or modify functions, parameters, and return values as needed.

i2c_delay

Function name i2c_delay
Function prototype void i2c_delay(unsigned long tim_1us);
Description I2C software: Delay in microseconds.
Parameter tim_1us[in]: Time in microseconds.
Return value None
Notes None

Data type

None.

API example

Use TLSR825x as an example. You can add I2C API functions or call APIs provided by the chip vendor in the application code.

ty_i2c.h

/* ! This macro is used to distinguish between I2C software and I2C hardware. The I2C software/hardware interfaces have been specialized in this demo, so this macro can be ignored. */
#define  USE_SOFT_I2C            0

/* ! Modified the type of addr, and added the addr_len parameter and the ty_i2c_rcv function. */
uint32_t ty_i2c_send(const uint32_t addr, const uint8_t addr_len, const uint8_t* buf, uint32_t size);
uint32_t ty_i2c_rcv(const uint32_t addr, const uint8_t addr_len, uint8_t* buf, uint32_t size);

ty_i2c_tlsr825x.c

/* ! Configure the I2C pin. SLAVE_ADDR_WRITE is added for I2C hardware initialization. */
#define TLSR_I2C_GPIO_GROUP     I2C_GPIO_GROUP_C0C1
#define I2C_PIN_SDA             GPIO_PC0
#define I2C_PIN_SCL             GPIO_PC1
#define SLAVE_ADDR_WRITE        (0x44 << 1 | 0x00)  // (0x68 << 1 | 0x00)

/* ! Modified the input parameters of i2c_master_init. */
uint32_t ty_i2c_init(void)
{
    i2c_gpio_set(TLSR_I2C_GPIO_GROUP);
    i2c_master_init(SLAVE_ADDR_WRITE, (unsigned char)(CLOCK_SYS_CLOCK_HZ/(4*200000)));
    return 0;
}

/* ! Modified the parameters and content of the data sending function. The addr parameter represents the register address, and addr_len represents the number of bytes of the address. */
uint32_t ty_i2c_send(const uint32_t addr, const uint8_t addr_len, const uint8_t* buf, uint32_t size)
{
     i2c_write_series(addr, addr_len, buf, size);
     return 0;
}

/* ! Added the data receiving function that uses the same parameters as the data sending function. */
uint32_t ty_i2c_rcv(const uint32_t addr, const uint8_t addr_len, uint8_t* buf, uint32_t size)
{
     i2c_read_series(addr, addr_len, buf, size);
     return 0;
}

Sample application

Description

Use I2C hardware or software to drive the peripherals to regularly collect data from sensors.

Sample code

The sample code uses the TLSR825x platform.

I2C_API_DEMO_SHT3X - sample driver for the temperature and humidity sensor SHT30-DIS

The 16-bit commands of SHT3x can be used as register addresses.

#include "ty_i2c_demo.h"
#include "ty_i2c.h"
#include "tuya_ble_log.h"
#include "tuya_ble_port.h"

/***********************************************************
************************micro define************************
***********************************************************/
/* Demo config */
#define I2C_API_DEMO_S              0x00            /* software I2C */
#define I2C_API_DEMO_H              0x01            /* hardware I2C */
#define I2C_API_DEMO_MODE           I2C_API_DEMO_S

/* slave device config */
#define I2C_SLAVE_ADDR              0x44
#define I2C_DAQ_TIME_MS             1000            /* 1s / 1Hz */
/* register map */
#define SHT3X_CMD_MEAS_PERI_1_H     0x2130          /* measurement: periodic 1 mps, high repeatability */
#define SHT3X_CMD_FETCH_DATA        0xE000          /* readout measurements for periodic mode */

/* I2C command */
#define I2C_CMD_BIT_WRITE           0
#define I2C_CMD_BIT_READ            1
#define I2C_ADDR_CMD_W              (I2C_SLAVE_ADDR << 1 | I2C_CMD_BIT_WRITE)
#define I2C_ADDR_CMD_R              (I2C_SLAVE_ADDR << 1 | I2C_CMD_BIT_READ)

/***********************************************************
***********************variable define**********************
***********************************************************/
static tuya_ble_timer_t sg_daq_timer;

/***********************************************************
***********************function define**********************
***********************************************************/
/**
 * @brief check checksum
 * @param[in] data: data to be checked
 * @param[in] len: data length
 * @param[in] crc_val: crc value
 * @return check result
 */
static uint8_t __check_crc_8(uint8_t* data, uint16_t len, uint8_t crc_val)
{
    uint8_t i;
    uint8_t crc = 0xFF;

    while (len--) {
        crc ^= *data;
        for (i = 8; i > 0; --i) {
            if (crc & 0x80) {
                crc = (crc << 1) ^ 0x31;
            } else {
                crc = (crc << 1);
            }
        }
        data++;
    }

    if (crc != crc_val){
        return 0;
    }
    return 1;
}

/**
 * @brief write command to SHT3x
 * @param[in] cmd: command
 * @param[in] stop: whether a stop signal needs to be sent
 * @return none
 */
static void __i2c_write_cmd_sht3x(uint16_t cmd, bool stop)
{
#if (I2C_API_DEMO_MODE == I2C_API_DEMO_S)
    uint8_t cmd_bytes[2];
    cmd_bytes[0] = (uint8_t)(cmd >> 8);
    cmd_bytes[1] = (uint8_t)(cmd & 0x00FF);
    i2c_start();
    i2c_send_bytes(I2C_ADDR_CMD_W, cmd_bytes, 2);
    if (stop) {
        i2c_stop();
    }
#else
    ty_i2c_send(cmd, 2, null, 0);
#endif
}

/**
 * @brief read data from SHT3x
 * @param[out] buf: data buffer
 * @param[in] len: data length
 * @return none
 */
static void __i2c_read_data_sht3x(uint8_t *buf, uint8_t len)
{
#if (I2C_API_DEMO_MODE == I2C_API_DEMO_S)
    i2c_start();
    i2c_rcv_bytes(I2C_ADDR_CMD_R, buf, len);
    i2c_stop();
#else
    ty_i2c_rcv(0, 0, buf, len);
#endif
}

/**
 * @brief data acquisition timer handler
 * @param none
 * @return none
 */
static void __daq_timer_handler(void)
{
    uint8_t buf[6];
    /* send fetch command to SHT3x */
    __i2c_write_cmd_sht3x(SHT3X_CMD_FETCH_DATA, 0);
    /* read data from SHT3x */
    __i2c_read_data_sht3x(buf, 6);
    /* check CRC value */
    if ((!__check_crc_8(buf, 2, buf[2])) ||
        (!__check_crc_8(buf+3, 2, buf[5]))) {
        TUYA_APP_LOG_ERROR("__sht3x_check_crc failed.");
        return;
    }
    /* calculate temperature and humidity */
    int32_t temp = ((int16_t)buf[0] << 8 | buf[1]) * 175 / 65535 - 45;
    uint32_t humi = ((uint16_t)buf[3] << 8 | buf[4]) * 100 / 65535;
    TUYA_APP_LOG_INFO("Temperature: %d, Humidity: %d", temp, humi);
}

/**
 * @brief ty_i2c api demo init
 * @param none
 * @return none
 */
void ty_i2c_demo_init(void)
{
    /* I2C init */
#if (I2C_API_DEMO_MODE == I2C_API_DEMO_S)
    i2c_soft_gpio_init();
#else
    ty_i2c_init();
#endif
    /* SHT3x: start periodic measurement */
    __i2c_write_cmd_sht3x(SHT3X_CMD_MEAS_PERI_1_H, 0);
    /* creat and start DAQ timer */
    tuya_ble_timer_create(&sg_daq_timer, I2C_DAQ_TIME_MS, TUYA_BLE_TIMER_REPEATED, (tuya_ble_timer_handler_t)__daq_timer_handler);
    tuya_ble_timer_start(sg_daq_timer);
}

I2C_API_DEMO_MPU6050 - sample driver for the motion sensor MPU6050

Sensor documents:

#include "ty_i2c_demo.h"
#include "ty_i2c.h"
#include "tuya_ble_log.h"
#include "tuya_ble_port.h"

/***********************************************************
************************micro define************************
***********************************************************/
/* Demo config */
#define I2C_API_DEMO_S              0x00            /* software I2C */
#define I2C_API_DEMO_H              0x01            /* hardware I2C */
#define I2C_API_DEMO_MODE           I2C_API_DEMO_S

/* slave device config */
#define I2C_SLAVE_ADDR              0x68
#define I2C_DAQ_TIME_MS             5               /* 5ms / 200Hz */
#define MPU6050_DEV_ID              0x68
/* register map */
#define MPU6050_RA_SMPRT_DIV        0x19
#define MPU6050_RA_CONFIG           0x1A
#define MPU6050_RA_GYRO_CONFIG      0x1B
#define MPU6050_RA_ACCEL_CONFIG     0x1C
#define MPU6050_RA_ACCEL_XOUT_H     0x3B
#define MPU6050_RA_PWR_MGMT_1       0x6B
#define MPU6050_RA_WHO_AM_I         0x75

/* I2C command */
#define I2C_CMD_BIT_WRITE           0
#define I2C_CMD_BIT_READ            1
#define I2C_ADDR_CMD_W              (I2C_SLAVE_ADDR << 1 | I2C_CMD_BIT_WRITE)
#define I2C_ADDR_CMD_R              (I2C_SLAVE_ADDR << 1 | I2C_CMD_BIT_READ)

/***********************************************************
***********************variable define**********************
***********************************************************/
static tuya_ble_timer_t sg_daq_timer;

/***********************************************************
***********************function define**********************
***********************************************************/
/**
 * @brief write register of MPU6050
 * @param[in] reg_addr: register address
 * @param[in] reg_val: value to be written
 * @return none
 */
static void __i2c_write_reg(uint8_t reg_addr, uint8_t reg_val)
{
#if (I2C_API_DEMO_MODE == I2C_API_DEMO_S)
    i2c_soft_cfg(I2C_ADDR_CMD_W, reg_addr, reg_val);
#else
    ty_i2c_send(reg_addr, 1, &reg_val, 1);
#endif
}

/**
 * @brief read register of MPU6050
 * @param[in] reg_addr: register address
 * @param[out] reg_val: register value
 * @param[in] len: register length
 * @return none
 */
static void __i2c_read_reg(uint8_t reg_addr, uint8_t *reg_val, uint8_t len)
{
#if (I2C_API_DEMO_MODE == I2C_API_DEMO_S)
    i2c_start();
    i2c_send_bytes(I2C_ADDR_CMD_W, &reg_addr, 1);
    i2c_start();
    i2c_rcv_bytes(I2C_ADDR_CMD_R, reg_val, len);
    i2c_stop();
#else
    ty_i2c_rcv(reg_addr, 1, reg_val, len);
#endif
}

/**
 * @brief data acquisition timer handler
 * @param none
 * @return none
 */
static void __daq_timer_handler(void)
{
    uint8_t i;
    uint8_t tmp_buf[14];
    int16_t accel[3], gyro[3];
    /* read data from MPU6050 */
    __i2c_read_reg(MPU6050_RA_ACCEL_XOUT_H, tmp_buf, 14);
    /* calculate acceleration (g) and angular velocity (dps) */
    for (i = 0; i < 3; i++) {
        accel[i] = ((int16_t)tmp_buf[i*2] << 8) | tmp_buf[i*2+1];
        accel[i] /= 2048;
        gyro[i] = ((int16_t)tmp_buf[i*2+8] << 8) | tmp_buf[i*2+9];
        gyro[i] = gyro[i] * 10 / 164;
    }
    TUYA_APP_LOG_INFO("ax: %d,   ay: %d,   az: %d,   gx: %d,  gy: %d,  gz: %d",
                       accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2]);
}

/**
 * @brief ty_i2c api demo init
 * @param none
 * @return none
 */
void ty_i2c_demo_init(void)
{
    /* I2C init */
#if (I2C_API_DEMO_MODE == I2C_API_DEMO_S)
    i2c_soft_gpio_init();
#else
    ty_i2c_init();
#endif
    /* reset MPU6050 and exit sleep mode */
    __i2c_write_reg(MPU6050_RA_PWR_MGMT_1, 0x80);
    i2c_delay(200*1000);
    /* check communication */
    uint8_t dev_id;
    __i2c_read_reg(MPU6050_RA_WHO_AM_I, &dev_id, 1);
    if (dev_id != MPU6050_DEV_ID) {
        TUYA_APP_LOG_ERROR("MPU6050 is not found.");
        return;
    }
    /* MPU6050 init */
    __i2c_write_reg(MPU6050_RA_PWR_MGMT_1, 0x01);   /* set clock source: PLL_XGYRO */
    __i2c_write_reg(MPU6050_RA_GYRO_CONFIG, 0x03);  /* set gyroscope's full-scale range: 2000dps */
    __i2c_write_reg(MPU6050_RA_ACCEL_CONFIG, 0x03); /* set accelerometer's full-scale range: 16g */
    __i2c_write_reg(MPU6050_RA_SMPRT_DIV, 0x04);    /* set sample rate: 1kHz/(1+4) = 200Hz */
    __i2c_write_reg(MPU6050_RA_CONFIG, 0x02);       /* set DLPF */

    /* creat and start DAQ timer */
    tuya_ble_timer_create(&sg_daq_timer, I2C_DAQ_TIME_MS, TUYA_BLE_TIMER_REPEATED, (tuya_ble_timer_handler_t)__daq_timer_handler);
    tuya_ble_timer_start(sg_daq_timer);
}