7. SMBus

7.1. 概述

  • SMBus(System Management Bus)组件基于I2C总线协议扩展,提供系统管理总线规范兼容的通信接口。主要特性包括:

    • 协议兼容性

      • 支持SMBus 2.0规范定义的标准协议格式

      • 自动生成/校验数据包CRC(PEC)

      • 支持7位/10位设备地址格式

    • 传输模式支持

      • 主机模式和从机模式下的单字节/双字节读写操作

      • 主机模式带命令码的字节/字/块传输(Block Write/Read)

      • 支持正常模式(100Khz),快速模式(400kHz)和高速模式(1MHz)

    • 数据完整性保障

      • 硬件自动计算PEC校验码

      • 提供端到端的数据保护机制

      • 支持多字节传输的CRC校验

7.2. 关键API功能

  • 基础传输接口

    • hpm_smbus_master_write_byte: 主机单字节写入(无命令码)

    • hpm_smbus_master_read_byte: 主机单字节读取(无命令码)

    • hpm_smbus_master_write: 主机多字节写入(无命令码)

    • hpm_smbus_master_read: 主机多字节读取(无命令码)

    • hpm_smbus_slave_write: 从机多字节写入(无命令码)

    • hpm_smbus_slave_read: 从机多字节读取(无命令码)

  • 增强型传输接口

    • hpm_smbus_master_write_byte_in_command: 主机带命令码的字节写入

    • hpm_smbus_master_read_byte_in_command: 主机带命令码的字节读取

    • hpm_smbus_master_write_word_in_command: 主机带命令码的双字节写入

    • hpm_smbus_master_read_word_in_command: 主机带命令码的双字节读取

    • hpm_smbus_master_write_block_in_command: 主机带命令码的块写入操作

    • hpm_smbus_master_read_block_in_command: 主机带命令码的块读取操作

  • 底层协议支持

    • hpm_smbus_pec_crc8: PEC校验码生成算法(CRC-8)

7.3. API调用流程介绍

7.3.1. I2C初始化

7.3.1.1. 主机模式

  • 调用 i2c_init_master API 来初始化 I2C为主机模式。该API在 hpm_i2c_drv 驱动中定义。

    • i2c_init_master API原型:

      hpm_stat_t i2c_init_master(I2C_Type *ptr, uint32_t src_clk_in_hz, i2c_config_t *config);
      
      • 参数说明:

        参数名

        类型

        描述

        ptr

        I2C_Type*

        指向I2C控制器基地址的指针

        src_clk_in_hz

        uint32_t

        I2C时钟源频率

        config

        i2c_config_t*

        指向I2C配置结构体的指针

      • 返回值:

        • status_success: 成功

        • status_invalid_argument: 无效参数

  • 举例: 实例化I2C0,设置I2C0为主机模式,100Khz速度,7bit地址模式。

    #define TEST_SMBUS                HPM_I2C0
    #define TEST_SMBUS_CLOCK_NAME     clock_i2c0
    
    i2c_config_t config;    /* 定义I2C配置结构体 */
    board_init_i2c_clock(TEST_SMBUS);
    init_i2c_pins(TEST_SMBUS);
    
    config.i2c_mode = i2c_mode_normal;
    config.is_10bit_addressing = false;
    freq = clock_get_frequency(TEST_SMBUS_CLOCK_NAME);
    stat = i2c_init_master(TEST_SMBUS, freq, &config);
    if (stat != status_success) {
        return stat;
    }
    

7.3.1.2. 从机模式

  • 调用 i2c_init_slave API 来初始化 I2C为从机模式。该API在 hpm_i2c_drv 驱动中定义。

    • i2c_init_slave API原型:

      hpm_stat_t i2c_init_slave(I2C_Type *ptr, uint32_t src_clk_in_hz, i2c_config_t *config);
      
      • 参数说明:

        参数名

        类型

        描述

        ptr

        I2C_Type*

        指向I2C控制器基地址的指针

        src_clk_in_hz

        uint32_t

        I2C时钟源频率

        config

        i2c_config_t*

        指向I2C配置结构体的指针

      • 返回值:

        • status_success: 成功

        • status_invalid_argument: 无效参数

  • 举例: 实例化I2C0,设置I2C0为从机模式,100Khz速度,7bit地址模式,从机设备地址为0x16。

    #define TEST_SMBUS                HPM_I2C0
    #define TEST_SMBUS_CLOCK_NAME     clock_i2c0
    
    i2c_config_t config;    /* 定义I2C配置结构体 */
    board_init_i2c_clock(TEST_SMBUS);
    init_i2c_pins(TEST_SMBUS);
    config.i2c_mode = i2c_mode_slave;
    config.is_10bit_addressing = false;
    config.slave_address = 0x16;
    freq = clock_get_frequency(TEST_SMBUS_CLOCK_NAME);
    stat = i2c_init_slave(TEST_SMBUS, freq, &config);
    if (stat!= status_success) {
        return stat;
    }
    

7.3.2. 读写操作

7.3.2.1. 基础传输接口

  • 仅支持主机模式单字节读写操作(无命令码)

    • 主机模式

      • 主机单字节写入

        • 调用 hpm_smbus_master_write_byte API 来实现主机模式下的单字节写入操作。

          • hpm_smbus_master_write_byte API原型:

            hpm_stat_t hpm_smbus_master_write_byte(I2C_Type *ptr, uint8_t slave_address, uint8_t data);
            
            • 参数说明:

              参数名

              类型

              描述

              ptr

              I2C_Type*

              指向I2C控制器基地址的指针

              slave_address

              uint8_t

              从设备地址

              data

              uint8_t

              要写入的数据

            • 返回值:

              • status_success: 成功

              • status_invalid_argument: 无效参数

              • status_timeout: 超时

              • status_fail: 失败

          • 举例: 主机模式下,通过I2C总线向从设备0x16写入数据0x55。

            /* 初始化I2C,不做举例... */
            hpm_stat_t stat;
            stat = hpm_smbus_master_write_byte(TEST_SMBUS, 0x16, 0x55);
            if (stat!= status_success) {
                printf("hpm_smbus_master_write_byte failed.\n");
            }
            
      • 主机单字节读取

        • 调用 hpm_smbus_master_read_byte API 来实现主机模式下的单字节读取操作。

          • hpm_smbus_master_read_byte API原型:

            hpm_stat_t hpm_smbus_master_read_byte(I2C_Type *ptr, uint8_t slave_address, uint8_t *data);
            
            • 参数说明:

              参数名

              类型

              描述

              ptr

              I2C_Type*

              指向I2C控制器基地址的指针

              slave_address

              uint8_t

              从设备地址

              data

              uint8_t*

              读取到的数据

            • 返回值:

              • status_success: 成功

              • status_invalid_argument: 无效参数

          • 举例: 主机模式下,通过I2C总线从从设备0x16读取数据。

            hpm_stat_t stat;
            uint8_t data;
            /* 初始化I2C,不做举例... */
            stat = hpm_smbus_master_read_byte(TEST_SMBUS, 0x16, &data);
            if (stat!= status_success) {
                printf("hpm_smbus_master_read_byte failed.\n");
            }
            
  • 支持主机模式和从机模式下的多字节读写操作(无命令码)

    • 主机模式

      • 主机多字节写入

        • 调用 hpm_smbus_master_write API 来实现主机模式下的多字节写入操作。

          • hpm_smbus_master_write API原型:

            hpm_stat_t hpm_smbus_master_write(I2C_Type *ptr, uint8_t slave_address, uint8_t *data, uint32_t size);
            
            • 参数说明:

              参数名

              类型

              描述

              ptr

              I2C_Type*

              指向I2C控制器基地址的指针

              slave_address

              uint8_t

              从设备地址

              data

              uint8_t*

              要写入的数据

              size

              uint32_t

              数据长度(字节)

            • 返回值:

              • status_success: 成功

              • status_invalid_argument: 无效参数

              • status_timeout: 超时

              • status_fail: 失败

          • 举例: 主机模式下,通过I2C总线向从设备0x16写入多个数据。

            hpm_stat_t stat;
            uint8_t data[3] = {0x11, 0x22, 0x33};
            /* 初始化I2C,不做举例... */
            stat = hpm_smbus_master_write(TEST_SMBUS, 0x16, data, 3);
            if (stat!= status_success) {
                printf("hpm_smbus_master_write failed.\n");
            }
            
      • 主机多字节读取

        • 调用 hpm_smbus_master_read API 来实现主机模式下的多字节读取操作。

          • hpm_smbus_master_read API原型:

            hpm_stat_t hpm_smbus_master_read(I2C_Type *ptr, uint8_t slave_address, uint8_t *data, uint32_t size);
            
            • 参数说明:

              参数名

              类型

              描述

              ptr

              I2C_Type*

              指向I2C控制器基地址的指针

              slave_address

              uint8_t

              从设备地址

              data

              uint8_t*

              读取到的数据

              size

              uint32_t

              数据长度(字节)

            • 返回值:

              • status_success: 成功

              • status_invalid_argument: 无效参数

              • status_timeout: 超时

              • status_fail: 失败

          • 举例: 主机模式下,通过I2C总线从从设备0x16读取多个数据。

            hpm_stat_t stat;
            uint8_t data[3];
            /* 初始化I2C,不做举例... */
            stat = hpm_smbus_master_read(TEST_SMBUS, 0x16, data, 3);
            if (stat!= status_success) {
                printf("hpm_smbus_master_read failed.\n");
            }
            
    • 从机模式

      • 从机多字节写入

        • 调用 hpm_smbus_slave_write API 来实现从机模式下的单字节写入操作。

          • hpm_smbus_slave_write API原型:

            hpm_stat_t hpm_smbus_slave_write(I2C_Type *ptr, uint8_t *data, uint32_t size);
            
            • 参数说明:

              参数名

              类型

              描述

              ptr

              I2C_Type*

              指向I2C控制器基地址的指针

              data

              uint8_t

              要写入的数据

              size

              uint32_t

              数据长度(字节)

            • 返回值:

              • status_success: 成功

              • status_invalid_argument: 无效参数

              • status_timeout: 超时

              • status_fail: 失败

          • 举例: 从机模式下,如果总线主机下发的地址设备是该从机地址,写入数据。

            hpm_stat_t stat;
            uint8_t data[3];
            /* 初始化I2C,不做举例... */
            /* 等待地址命中 */
            do {
                stat = hpm_smbus_slave_write(TEST_SMBUS, data_buff, TEST_TRANSFER_DATA_IN_BYTE);
            } while (stat == status_fail);
            
      • 从机多字节读取

        • 调用 hpm_smbus_slave_read API 来实现从机模式下的单字节读取操作。

          • hpm_smbus_slave_read API原型:

            hpm_stat_t hpm_smbus_slave_read(I2C_Type *ptr, uint8_t *data, uint32_t size);
            
            • 参数说明:

              参数名

              类型

              描述

              ptr

              I2C_Type*

              指向I2C控制器基地址的指针

              data

              uint8_t*

              读取到的数据

              size

              uint32_t

              数据长度(字节)

            • 返回值:

              • status_success: 成功

              • status_invalid_argument: 无效参数

              • status_timeout: 超时

              • status_fail: 失败

          • 举例: 从机模式下,如果总线主机下发的地址设备是该从机地址,读取数据。

            hpm_stat_t stat;
            uint8_t data[3];
            /* 初始化I2C,不做举例... */
            /* 等待地址命中 */
            do {
                stat = hpm_smbus_slave_read(TEST_SMBUS, data_buff, TEST_TRANSFER_DATA_IN_BYTE);
            } while (stat == status_fail);
            

7.3.2.2. 增强型传输接口

  • 仅支持主机模式带命令码的字节/字(16bit)/块传输(Block Write/Read)

    • 主机带命令码的字节写入

      • 调用 hpm_smbus_master_write_byte_in_command API 来实现主机模式下的带命令码的字节写入操作。

        • hpm_smbus_master_write_byte_in_command API原型:

          hpm_stat_t hpm_smbus_master_write_byte_in_command(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint8_t data);
          
          • 参数说明:

            参数名

            类型

            描述

            ptr

            I2C_Type*

            指向I2C控制器基地址的指针

            slave_address

            uint8_t

            从设备地址

            command

            uint8_t

            命令码

            data

            uint8_t

            要写入的数据

          • 返回值:

            • status_success: 成功

            • status_invalid_argument: 无效参数

            • status_timeout: 超时

            • status_fail: 失败

        • 举例: 主机模式下,通过I2C总线向从设备0x16写入命令0x01和数据0x55。

          hpm_stat_t stat;
          /* 初始化I2C,不做举例... */
          stat = hpm_smbus_master_write_byte_in_command(TEST_SMBUS, 0x16, 0x01, 0x55);
          if (stat!= status_success) {
              printf("hpm_smbus_master_write_byte_in_command failed.\n");
          }
          
    • 主机带命令码的字节读取

      • 调用 hpm_smbus_master_read_byte_in_command API 来实现主机模式下的带命令码的字节读取操作。

        • hpm_smbus_master_read_byte_in_command API原型:

        hpm_stat_t hpm_smbus_master_read_byte_in_command(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint8_t *data);
        
        • 参数说明:

          参数名

          类型

          描述

          ptr

          I2C_Type*

          指向I2C控制器基地址的指针

          slave_address

          uint8_t

          从设备地址

          command

          uint8_t

          命令码

          data

          uint8_t*

          读取到的数据

        • 返回值:

          • status_success: 成功

          • status_invalid_argument: 无效参数

          • status_timeout: 超时

          • status_fail: 失败

        • 举例: 主机模式下,通过I2C总线从从设备0x16读取命令0x01的数据。

          hpm_stat_t stat;
          uint8_t data;
          /* 初始化I2C,不做举例... */
          stat = hpm_smbus_master_read_byte_in_command(TEST_SMBUS, 0x16, 0x01, &data);
          if (stat!= status_success) {
              printf("hpm_smbus_master_read_byte_in_command failed.\n");
          }
          
    • 主机带命令码的字写入

      • 调用 hpm_smbus_master_write_word_in_command API 来实现主机模式下的带命令码的字写入操作。

        • hpm_smbus_master_write_word_in_command API原型:

        hpm_stat_t hpm_smbus_master_write_word_in_command(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint16_t data);
        
        • 参数说明:

          参数名

          类型

          描述

          ptr

          I2C_Type*

          指向I2C控制器基地址的指针

          slave_address

          uint8_t

          从设备地址

          command

          uint8_t

          命令码

          data

          uint16_t

          要写入的数据

        • 返回值:

          • status_success: 成功

          • status_invalid_argument: 无效参数

          • status_timeout: 超时

          • status_fail: 失败

        • 举例: 主机模式下,通过I2C总线向从设备0x16写入命令0x01和数据0x5555。

        hpm_stat_t stat;
        /* 初始化I2C,不做举例... */
        stat = hpm_smbus_master_write_word_in_command(TEST_SMBUS, 0x16, 0x01, 0x5555);
        if (stat!= status_success) {
            printf("hpm_smbus_master_write_word_in_command failed.\n");
        }
        
    • 主机带命令码的字读取

      • 调用 hpm_smbus_master_read_word_in_command API 来实现主机模式下的带命令码的字读取操作。

        • hpm_smbus_master_read_word_in_command API原型:

          hpm_stat_t hpm_smbus_master_read_word_in_command(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint16_t *data);
          
          • 参数说明:

            参数名

            类型

            描述

            ptr

            I2C_Type*

            指向I2C控制器基地址的指针

            slave_address

            uint8_t

            从设备地址

            command

            uint8_t

            命令码

            data

            uint16_t*

            读取到的数据

          • 返回值:

            • status_success: 成功

            • status_invalid_argument: 无效参数

            • status_timeout: 超时

            • status_fail: 失败

        • 举例: 主机模式下,通过I2C总线从从设备0x16读取命令0x01的数据。

        hpm_stat_t stat;
        uint16_t data;
        /* 初始化I2C,不做举例... */
        stat = hpm_smbus_master_read_word_in_command(TEST_SMBUS, 0x16, 0x01, &data);
        if (stat!= status_success) {
            printf("hpm_smbus_master_read_word_in_command failed.\n");
        }
        
    • 主机带命令码的块写入

      • 调用 hpm_smbus_master_write_block_in_command API 来实现主机模式下的带命令码的块写入操作。

        • hpm_smbus_master_write_block_in_command API原型:

          hpm_stat_t hpm_smbus_master_write_block_in_command(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint8_t *data, uint32_t size);
          
          • 参数说明:

            参数名

            类型

            描述

            ptr

            I2C_Type*

            指向I2C控制器基地址的指针

            slave_address

            uint8_t

            从设备地址

            command

            uint8_t

            命令码

            data

            uint8_t*

            要写入的数据

            size

            uint32_t

            数据长度(字节)

          • 返回值:

            • status_success: 成功

            • status_invalid_argument: 无效参数

            • status_timeout: 超时

            • status_fail: 失败

        • 举例: 主机模式下,通过I2C总线向从设备0x16写入命令0x01和多个数据。

        hpm_stat_t stat;
        
        uint8_t data[3] = {0x11, 0x22, 0x33};
        /* 初始化I2C,不做举例... */
        stat = hpm_smbus_master_write_block_in_command(TEST_SMBUS, 0x16, 0x01, data, 3);
        if (stat!= status_success) {
            printf("hpm_smbus_master_write_block_in_command failed.\n");
        }
        
    • 主机带命令码的块读取

      • 调用 hpm_smbus_master_read_block_in_command API 来实现主机模式下的带命令码的块读取操作。

        • hpm_smbus_master_read_block_in_command API原型:

          hpm_stat_t hpm_smbus_master_read_block_in_command(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint8_t *data, uint32_t size);
          
          • 参数说明:

            参数名

            类型

            描述

            ptr

            I2C_Type*

            指向I2C控制器基地址的指针

            slave_address

            uint8_t

            从设备地址

            command

            uint8_t

            命令码

            data

            uint8_t*

            读取到的数据

            size

            uint32_t

            数据长度(字节)

          • 返回值:

            • status_success: 成功

            • status_invalid_argument: 无效参数

            • status_timeout: 超时

            • status_fail: 失败

        • 举例: 主机模式下,通过I2C总线从从设备0x16读取命令0x01的数据。

      hpm_stat_t stat;
      uint8_t data[3];
      /* 初始化I2C,不做举例... */
      stat = hpm_smbus_master_read_block_in_command(TEST_SMBUS, 0x16, 0x01, data, 3);
      if (stat!= status_success) {
          printf("hpm_smbus_master_read_block_in_command failed.\n");
      }