天天看点

[单片机框架][bsp层][cx32l003][bsp_i2c] I2C/IIC硬件配置和使用

I2C 简介

I2C 是双线双向的串行总线,它为设备之间数据交换提供了一种简单高效的方法。I2C 标准是一个具有冲突检测机制和仲裁机制的真正意义上的多主机总线。它能防止两个或者多个主机在同时请求控制总线时发生数据冲突。

I2C 总线控制器,能满足 I2C 总线的各种规格并支持所有与 I2C 总线通信的传输模式。

I2C 总线使用连接设备的"SCL"(串行时钟总线)和"SDA"(串行数据总线)来传送信息。数据在主机与从机之间通过 SCL 时钟线控制在 SDA 数据线上实现一个字节一个字节的同步传输, 每个字节为 8位长度,一个 SCL 时钟脉冲传输一个数据位,数据由最高位 MSB 开始传输,每个传输字节后跟随一个应答位, 每个位在 SCL 为高时采样; 因此, SDA 线只有在 SCL 为低时才可以改变, 在 SCL为高时 SDA 保持稳定。 当 SCL 为高时, SDA 线上的跳变视为命令中断(START 或 STOP), I2C 逻辑能自主地处理字节的传输。它能保持跟踪串行传送,而且还有一个状态寄存器(I2C_SR)能反映I2C 总线控制器和 I2C 总线的状态。

I2C 主要特性

I2C 控制器支持以下特性:

⚫ 支持主机发送/接收,从机发送/接收四种工作模式

⚫ 支持标准(100Kbps)/快速(400Kbps)/高速(1Mbps)三种工作速率

⚫ 支持 7 位寻址功能

⚫ 支持噪声过滤功能

⚫ 支持广播地址

⚫ 支持中断状态查询功能

I2C 协议描述

通常标准 I2C 传输协议包含四个部分:

  1. 起始信号或重复起始信号
  2. 从机地址传输和 R/W 位传输
  3. 数据传输
  4. 停止信号
/********************************************************************************
* @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
// 定义IIC0信息句柄
static I2C_HandleTypeDef i2c0_handle_t = {
    .Instance        = I2C,
    .Init.master     = I2C_MASTER_MODE_ENABLE, // 主机模式使能
    .Init.slave      = I2C_SLAVE_MODE_DISABLE, // 从机模式禁止
    .Mode            = HAL_I2C_MODE_MASTER,    // 主机模式
    .Init.broadack   = I2C_BROAD_ACK_DISABLE,  // 广播地址应答禁止
    .Init.speedclock = BS_I2C0_SPEED_RATE,     // I2C传输速率
    .State           = HAL_I2C_STATE_RESET
};
#endif

/**
 * @brief  [初始化] IIC初始化
 * @note   NULL
 * @param  i2c_bus: IIC组号
 * @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  [反初始化] IIC关闭时钟并复位引脚
 * @note   NULL
 * @param  i2c_bus: IIC组号
 * @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读取一个字节
 * @note   NULL
 * @param  i2c_bus: IIC组号
 * @param  dev_addr: 器件地址
 * @param  reg_addr: 寄存器地址
 * @param  r_data: 欲发送的数据头指针
 * @retval 0--成功 1--失败
 */
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, ®_addr, 1, r_data, 1);
#else
        return HAL_ERROR;
#endif
    }
    return HAL_ERROR;
}

/**
 * @brief  i2c读取多个字节
 * @note   NULL
 * @param  i2c_bus: IIC组号
 * @param  dev_addr: 器件地址
 * @param  w_data: txbuff头指针 数据格式:(reg_addr, w_data, w_data1, ...)
 * @param  w_size: txbuff长度
 * @param  r_data: rxbuff的头指针
 * @param  r_size: rxbuff的大小
 * @retval 0--成功 1--失败
 */
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写入一个字节
 * @note   NULL
 * @param  i2c_bus: IIC组号
 * @param  dev_addr: 器件地址
 * @param  reg_addr: 寄存器地址
 * @param  w_data: 需要写入的字节值
 * @retval 0--成功 1--失败
 */
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写入多个字节
 * @note   NULL
 * @param  i2c_bus: IIC组号
 * @param  dev_addr: 器件地址
 * @param  w_data: txbuff头指针 数据格式:(reg_addr, w_data, w_data1, ...)
 * @param  w_size: txbuff长度
 * @retval 0--成功 1--失败
 */
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;
}

// ---------------------散装函数-----------------------------
/**
 * @brief  i2c写入多个字节且无停止信号(带起始信号和器件地址)
 * @note   NULL
 * @param  i2c_bus: IIC组号
 * @param  dev_addr: 器件地址
 * @param  w_data: txbuff头指针 数据格式:(reg_addr, w_data, w_data1, ...)
 * @param  w_size: txbuff长度
 * @retval 0--成功 1--失败
 */
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写入多个字节且无停止信号(不带起始信号和器件地址)
 * @note   必须配合[bsp_i2c_write_nbyte_nostop()]使用
 * @param  i2c_bus: IIC组号
 * @param  w_data: txbuff头指针 数据格式:(w_data, w_data1, ...)
 * @param  w_size: txbuff长度
 * @retval 0--成功 1--失败
 */
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  发送一个停止信号
 * @note   NULL
 * @param  i2c_bus: IIC组号
 * @param  state: false--清除中断标志位  true--不清除中断标记位
 * @retval 0--成功 1--失败
 */
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);

// 成品全套逻辑 启动-应答-数据-停止

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);

// 散装函数

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      

继续阅读