[SCM Framework][bsp Layer][cx32l003][bsp_i2c] I2C/IIC Hardware Configuration and Use

Introduction to I2C

I2C is a two-wire, two-way serial bus, which provides a simple and efficient method for data exchange between devices. The I2C standard is a true multi-host bus with conflict detection and arbitration mechanisms. It can prevent data conflicts between two or more hosts when requesting a control bus at the same time.

The I2C bus controller can satisfy various I2C bus specifications and support all the transmission modes that communicate with the I2C bus.

The I2C bus uses the "SCL" (serial clock bus) and "SDA" (serial data bus) of the connected device.To transfer information. Data is transmitted one byte and one byte at a time on the SDA data line by SCL clock line control between host and slave computers. Each byte is 8 bit length, and a SCL clock pulse transmits one bit. Data is transmitted by the highest bit MSB, each transmitted byte is followed by an answer bit, and each bit is sampled when the SCL is high; therefore,The SDA line can only be changed when the SCL is low and SDA remains stable when the SCL is high. When the SCL is high, jumps on the SDA line are treated as command interrupts (START or STOP), and the I2C logic handles byte transfers autonomously. It keeps track of serial transfers, and it has a state register (I2C_SR) that reflects the state of the I2C bus controller and the I2C bus.

I2C Main Features

The I2C controller supports the following features:
⚫ Supports four modes of operation: Host Send/Receive and Slave Send/Receive
⚫ Supports standard (100Kbps) / fast (400Kbps) / high speed (1Mbps) three working rates
⚫ 7-bit addressing support
⚫ Supports noise filtering
⚫ Support Broadcast Address
⚫ Support interrupt status query function

I2C Protocol Description

Typically, the standard I2C transport protocol consists of four parts:

  1. Start signal or repeat start signal

  2. Transport from machine address and R/W bit

  3. data transmission

  4. Stop signal

/********************************************************************************
* @file    bsp_i2c.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-04-11
* @brief   NULL
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>

#include "RTE_Components.h"
#include CMSIS_device_header
#include "cx32l003_hal.h"

#include "bsp_gpio.h"
#include "bsp_i2c.h"

/* Private Includes ----------------------------------------------------------*/
#include "business_gpio.h"
#include "business_function.h"

/* Private Variables ---------------------------------------------------------*/
#if BS_I2C0_EN
// Define IIC0 Information Handle
static I2C_HandleTypeDef i2c0_handle_t = {
    .Instance        = I2C,
    .Init.master     = I2C_MASTER_MODE_ENABLE, // Host mode enablement
    .Init.slave      = I2C_SLAVE_MODE_DISABLE, // Prohibit from slave mode
    .Mode            = HAL_I2C_MODE_MASTER,    // Host mode
    .Init.broadack   = I2C_BROAD_ACK_DISABLE,  // Broadcast Address Answer Forbidden
    .Init.speedclock = BS_I2C0_SPEED_RATE,     // I2C transfer rate
    .State           = HAL_I2C_STATE_RESET
};
#endif

/**
 * @brief  [Initialization] IIC Initialization
 * @note   NULL
 * @param  i2c_bus: IIC Group number
 * @retval None
 */
void bsp_i2c_init(bsp_i2c_bus_t i2c_bus)
{
#if BS_I2C0_EN
    if (i2c_bus == I2C_BUS0)
    {
        __HAL_RCC_I2C_CLK_ENABLE();
        BS_I2C0_SDA_GPIO_CLK_ENABLE();
        bsp_gpio_init_i2c(BS_I2C0_SCL_GPIO_PORT, BS_I2C0_SCL_PIN, GPIO_AF4_I2C_SCL);
        bsp_gpio_init_i2c(BS_I2C0_SDA_GPIO_PORT, BS_I2C0_SDA_PIN, GPIO_AF4_I2C_SDA);
        HAL_I2C_Init(&i2c0_handle_t);
    }
#endif
}

/**
 * @brief  [De-Initialization] IIC Clock Off and Pin Reset
 * @note   NULL
 * @param  i2c_bus: IIC Group number
 * @retval None
 */
void bsp_i2c_deinit(bsp_i2c_bus_t i2c_bus)
{
#if BS_I2C0_EN
    if (i2c_bus == I2C_BUS0)
    {
        __HAL_RCC_I2C_CLK_DISABLE();
        bsp_gpio_deinit(BS_I2C0_SCL_GPIO_PORT, BS_I2C0_SCL_PIN);
        bsp_gpio_deinit(BS_I2C0_SDA_GPIO_PORT, BS_I2C0_SDA_PIN);
        HAL_I2C_DeInit(&i2c0_handle_t);
    }
#endif
}

/**
 * @brief  i2c Read a byte
 * @note   NULL
 * @param  i2c_bus: IIC Group number
 * @param  dev_addr: Device Address
 * @param  reg_addr: Register Address
 * @param  r_data: Header pointer to send
 * @retval 0--Success 1--Failure
 */
uint8_t bsp_i2c_read_byte(bsp_i2c_bus_t i2c_bus, uint8_t dev_addr, uint8_t reg_addr, uint8_t *r_data)
{
    if (i2c_bus == I2C_BUS0)
    {
#if BS_I2C0_EN
        return HAL_I2C_Master_Receive(&i2c0_handle_t, dev_addr, &reg_addr, 1, r_data, 1);
#else
        return HAL_ERROR;
#endif
    }
    return HAL_ERROR;
}

/**
 * @brief  i2c Read multiple bytes
 * @note   NULL
 * @param  i2c_bus: IIC Group number
 * @param  dev_addr: Device Address
 * @param  w_data: txbuff Header pointer data format: (reg_addr, w_data, w_data1,...)
 * @param  w_size: txbuff length
 * @param  r_data: rxbuff Head Pointer
 * @param  r_size: rxbuff Size
 * @retval 0--Success 1--Failure
 */
uint8_t bsp_i2c_read_nbyte(bsp_i2c_bus_t i2c_bus, uint8_t dev_addr, uint8_t *w_data, uint16_t w_size, uint8_t *r_data, uint16_t r_size)
{
    if (i2c_bus == I2C_BUS0)
    {
#if BS_I2C0_EN
        return HAL_I2C_Master_Receive(&i2c0_handle_t, dev_addr, w_data, w_size, r_data, r_size);
#else
        return HAL_ERROR;
#endif
    }
    return HAL_ERROR;
}

/**
 * @brief  i2c Write a byte
 * @note   NULL
 * @param  i2c_bus: IIC Group number
 * @param  dev_addr: Device Address
 * @param  reg_addr: Register Address
 * @param  w_data: Byte value to be written
 * @retval 0--Success 1--Failure
 */
uint8_t bsp_i2c_write_byte(bsp_i2c_bus_t i2c_bus, uint8_t dev_addr, uint8_t reg_addr, uint8_t w_data)
{
    uint8_t ret = HAL_OK;

    if (i2c_bus == I2C_BUS0)
    {
#if BS_I2C0_EN
        uint8_t data[2] = {reg_addr, w_data};
        ret = HAL_I2C_Master_Transmit(&i2c0_handle_t, dev_addr, data, 2);
#else
        ret = HAL_ERROR;
#endif
    }
    else
    {
        ret = HAL_ERROR;
    }
    return ret;
}

/**
 * @brief  i2c Write multiple bytes
 * @note   NULL
 * @param  i2c_bus: IIC Group number
 * @param  dev_addr: Device Address
 * @param  w_data: txbuff Header pointer data format: (reg_addr, w_data, w_data1,...)
 * @param  w_size: txbuff length
 * @retval 0--Success 1--Failure
 */
uint8_t bsp_i2c_write_nbyte(bsp_i2c_bus_t i2c_bus, uint8_t dev_addr, uint8_t *w_data, uint16_t w_size)
{
    uint8_t ret = HAL_OK;

    if (i2c_bus == I2C_BUS0)
    {
#if BS_I2C0_EN
        ret = HAL_I2C_Master_Transmit(&i2c0_handle_t, dev_addr, w_data, w_size);
#else
        ret = HAL_ERROR;
#endif
    }
    else
    {
        ret = HAL_ERROR;
    }
    return ret;
}

// -------------------------- Bulk Function-------------------------------------------
/**
 * @brief  i2c Write multiple bytes without stop signal (with start signal and device address)
 * @note   NULL
 * @param  i2c_bus: IIC Group number
 * @param  dev_addr: Device Address
 * @param  w_data: txbuff Header pointer data format: (reg_addr, w_data, w_data1,...)
 * @param  w_size: txbuff length
 * @retval 0--Success 1--Failure
 */
uint8_t bsp_i2c_write_nbyte_nostop(bsp_i2c_bus_t i2c_bus, uint8_t dev_addr, uint8_t *w_data, uint16_t w_size)
{
    uint8_t ret = HAL_OK;

    if (i2c_bus == I2C_BUS0)
    {
#if BS_I2C0_EN
        ret = HAL_I2C_Master_Transmit_NOStop(&i2c0_handle_t, dev_addr, w_data, w_size);
#else
        ret = HAL_ERROR;
#endif
    }
    else
    {
        ret = HAL_ERROR;
    }
    return ret;
}

/**
 * @brief  i2c Write multiple bytes without stop signal (without start signal and device address)
 * @note   Must be used with [bsp_i2c_write_nbyte_nostop()]
 * @param  i2c_bus: IIC Group number
 * @param  w_data: txbuff Header pointer data format: (w_data, w_data1,...)
 * @param  w_size: txbuff length
 * @retval 0--Success 1--Failure
 */
uint8_t bsp_i2c_send_nbyte(bsp_i2c_bus_t i2c_bus, uint8_t *w_data, uint16_t w_size)
{
    uint8_t ret = HAL_OK;
    if (i2c_bus == I2C_BUS0)
    {
#if BS_I2C0_EN
        uint16_t i = 0;
        uint32_t i2c_flag = 0XFF;
        HAL_I2C_Wait_Flag(&i2c0_handle_t, &i2c_flag);
        while (i < w_size)
        {
            i2c_flag = 0XFF;
            HAL_I2C_Send_Byte(&i2c0_handle_t, w_data[i]);
            HAL_I2C_Wait_Flag(&i2c0_handle_t, &i2c_flag);
            if (i2c_flag != I2C_FLAG_MASTER_TX_DATA_ACK) // 0x00000028U
            {
                i2c0_handle_t.State = HAL_I2C_STATE_ERROR;
                i2c0_handle_t.ErrorCode = i2c0_handle_t.PreviousState;
                return HAL_ERROR;
            }
            i++;
        }
#else
        ret = HAL_ERROR;
#endif
    }
    else
    {
        ret = HAL_ERROR;
    }
    return ret;
}

/**
 * @brief  Send a stop signal
 * @note   NULL
 * @param  i2c_bus: IIC Group number
 * @param  state: false--Clear interrupt flag bit true--do not clear interrupt flag bit
 * @retval 0--Success 1--Failure
 */
uint8_t bsp_i2c_stop(bsp_i2c_bus_t i2c_bus, bool state)
{
    uint8_t ret = HAL_OK;

    if (i2c_bus == I2C_BUS0)
    {
#if BS_I2C0_EN
        HAL_I2C_Stop_Config(&i2c0_handle_t, (FunctionalState)true);
#else
        ret = HAL_ERROR;
#endif
    }
    else
    {
        ret = HAL_ERROR;
    }
    return ret;
}

/********************************************************************************
* @file    bsp_i2c.h
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-04-11
* @brief   NULL
********************************************************************************/

#ifndef __BSP_I2C_H
#define __BSP_I2C_H

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>

/* Public enum ---------------------------------------------------------------*/
typedef enum
{
    I2C_BUS0 = 0,
    I2C_BUS1 = 1,
    I2C_BUS2 = 2,
} bsp_i2c_bus_t;

/* Public Function Prototypes ------------------------------------------------*/

void bsp_i2c_init(bsp_i2c_bus_t i2c_bus);
void bsp_i2c_deinit(bsp_i2c_bus_t i2c_bus);

// Complete Logical Start-Answer-Data-Stop for Finished Products

uint8_t bsp_i2c_read_byte(bsp_i2c_bus_t i2c_bus, uint8_t dev_addr, uint8_t reg_addr, uint8_t *r_data);
uint8_t bsp_i2c_read_nbyte(bsp_i2c_bus_t i2c_bus, uint8_t dev_addr, uint8_t *w_data, uint16_t w_size, uint8_t *r_data, uint16_t r_size);

uint8_t bsp_i2c_write_byte(bsp_i2c_bus_t i2c_bus, uint8_t dev_addr, uint8_t reg_addr, uint8_t w_data);
uint8_t bsp_i2c_write_nbyte(bsp_i2c_bus_t i2c_bus, uint8_t dev_addr, uint8_t *w_data, uint16_t w_size);

// Bulk function

uint8_t bsp_i2c_write_nbyte_nostop(bsp_i2c_bus_t i2c_bus, uint8_t dev_addr, uint8_t *w_data, uint16_t w_size);
uint8_t bsp_i2c_send_nbyte(bsp_i2c_bus_t i2c_bus, uint8_t *w_data, uint16_t w_size);
uint8_t bsp_i2c_stop(bsp_i2c_bus_t i2c_bus, bool state);
#endif

Tags: Single-Chip Microcomputer stm32 I2C IIC

Posted on Fri, 15 Oct 2021 12:44:06 -0400 by maxxd