HUSB238 带有IIC接口的PD快充诱骗芯片 使用ESP32 IDF4.4驱动 代码 资料 原理图 开发笔记

芯片功能

读取当前达成PD协议的电压电流信息,以及能支持的电压电流配置;

通过IIC控制当前电源电压和最大电流;

介绍 HUSB238

简介:USB PD受电端芯片(PD Sink,也叫PD诱骗芯片)

描述:HUSB238是一款高度集成的USB PD受电端芯片(PD Sink,也叫PD诱骗芯片)。传输的额定功率可达100W。它兼容PD3.0 V1.3和Type-C V1.4。它还可以支持BC1.2 DCP、CDP和SDP和Apple 5V2.4A充电协议。这种方案也被称为桶形连接器替换(Barrel Connector Replacement),旨在替代传统的桶形连接器和DC插座(DC JACK)。HUSB238已经获得USB-IF认证,TID3666。它可以用于具有传统桶形连接器或USB micro-B电源连接器的电子设备,如物联网设备、无线充电器、无人机、智能扬声器、电动工具和其他设备。 HUSB238采用DFN-10L封装和SOT33-6L封装。

特性: USB-IF 认证 TID 3666 • 设备端USB PD sink控制器 • 支持Type-C 1.4 & USB PD3.0标准 n 可配置Rd n 支持死电池 • 传统的USB受电设备 n BC1.2 SDP, CDP和DCP检测 n Apple Divider 3检测 • 3.0至25V工作电压范围, • VIN, GATE最高耐压30V • CC1和CC2引脚25V高压保护 • 外部电阻网络设置动态申请电流电压值(VSET & ISET) • I2C 通信实现高级PDO申请 • Cable应用可模拟eMarker功能,适用于电流大于3A应用 • 集成负载开关驱动,可驱动PMOS或者负载开关芯片 • VBUS过压和欠压保护 • 过温保护,过温保护门限可配置 • 低功耗 • DFN-10L 和SOT33-6L封装形式 • 工作温度范围:-40°C - 125°C技术文档
 


以下是使用该芯片的时候的一些记录和IIC寄存器的资料,数据手册网上找不到的可以私信联系我免费发

使用的时候对IIC数据进行解析输出如下

网上很少关于该芯片IIC寄存器方面的描述在这里附上


ESP-IDF v4.4环境下的驱动 

HUSB238Driver.h

#ifndef __HUSB238_H__
#define __HUSB238_H__

#include <esp_log.h>

#define HUSB238_I2CAddress (uint8_t)(0x08)


/// @brief HUSB238 寄存器地址
enum HUSB238_reg_addr
{
    Reg_PD_STATUS0 = 0x00,
    Reg_PD_STATUS1,
    Reg_SRC_PDO_5V,
    Reg_SRC_PDO_9V,
    Reg_SRC_PDO_12V,
    Reg_SRC_PDO_15V,
    Reg_SRC_PDO_18V,
    Reg_SRC_PDO_20V,
    Reg_SRC_PDO_SEL,
    Reg_GO_COMMAND,
};


/// @brief 寄存器电流对应值
typedef enum
{
    PD_0_5A = 0x00,
    PD_0_7A,
    PD_1_0A,
    PD_1_25A,
    PD_1_5A,
    PD_1_75A,
    PD_2A,
    PD_2_25A,
    PD_2_5A,
    PD_2_75A,
    PD_3A,
    PD_3_25A,
    PD_3_5A,
    PD_4A,
    PD_4_5A,
    PD_5A,
} HUSB238_CURRENT_e;


/// @brief 写入 SRC_PDO(0x08) 设置输出电压用到
typedef enum
{
    Not_sel = 0x0,
    PDO_5V = 0x1,
    PDO_9V = 0x2,
    PDO_12V = 0x3,
    PDO_15V = 0x8,
    PDO_18V = 0x9,
    PDO_20V = 0xa,
} HUSB238_SELECT_Voltage_e;


/// @brief 读取 STATUS0(0x00) 状态寄存器值用到
typedef enum
{
    Voltage_unknown = 0x0,
    Voltage_5V,
    Voltage_9V,
    Voltage_12V,
    Voltage_15V,
    Voltage_18V,
    Voltage_20V,
} HUSB238_Voltage_e;


/// @brief 命令
enum HUSB238_CMD
{
    Request_PDO = 0b00001,
    Get_SRC_Cap = 0b00100,
    Hard_Reset = 0b10000,
};

typedef union
{
    struct
    {
        HUSB238_CURRENT_e PD_SRC_CURRENT : 4;
        HUSB238_Voltage_e PD_SRC_VOLTAGE : 4;
    } bit;
    uint8_t all;
} HUSB238_Reg_PD_STATUS0;

typedef union
{
    struct
    {
        uint8_t CURRENT_5V : 2;
        uint8_t VOLTAGE_5V : 1;
        uint8_t PD_RESPONSE : 3;
        uint8_t ATTACH : 1;
        uint8_t CC_DIR : 1;
    } bit;
    uint8_t all;
} HUSB238_Reg_PD_STATUS1;

typedef union
{
    struct
    {
        HUSB238_CURRENT_e SRC_CURRENT : 4;
        uint8_t RESERVED : 3;
        uint8_t SRC_DETECTED : 1;
    } bit;
    uint8_t all;
} HUSB238_Reg_SRC_PDO;

typedef union
{
    struct
    {
        uint8_t RESERVED : 4;
        HUSB238_SELECT_Voltage_e PDO_SELECT : 4;
    } bit;
    uint8_t all;
} HUSB238_Reg_SRC_PDO_SEL;

typedef struct
{
    HUSB238_Reg_PD_STATUS0 PD_STATUS0;
    HUSB238_Reg_PD_STATUS1 PD_STATUS1;
    HUSB238_Reg_SRC_PDO SRC_PDO_5V;
    HUSB238_Reg_SRC_PDO SRC_PDO_9V;
    HUSB238_Reg_SRC_PDO SRC_PDO_12V;
    HUSB238_Reg_SRC_PDO SRC_PDO_15V;
    HUSB238_Reg_SRC_PDO SRC_PDO_18V;
    HUSB238_Reg_SRC_PDO SRC_PDO_20V;
    HUSB238_Reg_SRC_PDO_SEL SRC_PDO;
    uint8_t GO_COMMAND;
} HUSB238_reg_t;




typedef struct
{
    bool detected;
    float current;
    uint16_t voltage;
} HUSB238_Capability_t;




/// @brief 初始化
/// @param sda sda
/// @param scl scl
void HUSB238_Init(int sda, int scl);

/// @brief regs 寄存器值 转化可输出能力列表
/// @param regs 大小为 10 
/// @param pdoList 大小为 6 !
void HUSB238_ExtractCap(HUSB238_Capability_t *pdoList);

/// @brief 获取当前PD输出能力
/// @param voltage 
/// @param current 
void HUSB238_GetCapabilities(uint16_t *voltage, float *current);



void HUSB238_GetCurrentMode(HUSB238_Voltage_e *voltage, HUSB238_CURRENT_e *current);
void HUSB238_SelVoltage(HUSB238_SELECT_Voltage_e voltage);

/// @brief 读取到的电压寄存器值转化电压值
/// @param voltage 从 STATUS0(0x00) 读取到的电压值
/// @return 电压值
uint16_t HUSB238_Voltage2PDO(HUSB238_Voltage_e voltage);

/// @brief 转化寄存器电流对应值
/// @param c 被转化的电流寄存器值
/// @return 返回电流值
float to_current(HUSB238_CURRENT_e c);

/// @brief 硬复位
void HUSB238_HardReset();

// 读取全部数据
void HUSB238_ReadAllReg(uint8_t *regs);

#endif /* __HUSB238_H */

HUSB238Driver.c

#include <string.h>
#include "HUSB238Driver.h"
#include "driver/i2c.h"

bool initlized = false;
// 电压值
uint16_t votlage_Table[] = {0, 5, 9, 12, 15, 18, 20};
// 电流值
float current_Table[] = {0.5f, 0.7f, 1.0f, 1.25f, 1.5f, 1.75f, 2.0f, 2.25f, 2.5f, 2.75f, 3.0f, 3.25f, 3.5f, 4.0f, 4.5f, 5.0f};

#define I2C_NUM I2C_NUM_0    /*!< I2C port number for master dev */
#define I2C_TX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
#define I2C_RX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
#define I2C_FREQ_HZ 100000   // 400000   /*!< I2C master clock frequency */

#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
#define READ_BIT I2C_MASTER_READ   /*!< I2C master read */
#define ACK_CHECK_EN 1             /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0            /*!< I2C master will not check ack from slave */
#define ACK_VAL (i2c_ack_type_t)0  /*!< I2C ack value */
#define NACK_VAL (i2c_ack_type_t)1 /*!< I2C nack value */

#define DEBUG_LOG false /*是否日志输出*/

/// @brief I2C 读取多个寄存器值
/// @param slaveAddr 从机地址
/// @param startAddress 开始地址
/// @param nBytesRead 字节数
/// @param data 读取缓存
/// @return 
int IRAM_ATTR HUSB238_I2CReadBytes(uint8_t slaveAddr, uint8_t startAddress, uint16_t nBytesRead, uint8_t *data)
{
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, slaveAddr << 1 | WRITE_BIT, ACK_CHECK_EN);
    i2c_master_write_byte(cmd, startAddress, ACK_CHECK_EN);

    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, slaveAddr << 1 | READ_BIT, ACK_CHECK_EN);
    if (nBytesRead > 1)
        i2c_master_read(cmd, data, nBytesRead - 1, ACK_VAL);
    i2c_master_read_byte(cmd, data + nBytesRead - 1, NACK_VAL);
    i2c_master_stop(cmd);

    int ret = i2c_master_cmd_begin(I2C_NUM, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}

/// @brief I2C写入寄存器值
/// @param slaveAddr 从机地址
/// @param writeAddress 写入寄存器地址
/// @param data 写入的数据
/// @return 
int IRAM_ATTR HUSB238_WriteReg(uint8_t slaveAddr, uint8_t writeAddress, uint8_t data)
{
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();

    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (slaveAddr << 1) | WRITE_BIT, ACK_CHECK_EN);
    i2c_master_write_byte(cmd, writeAddress, ACK_CHECK_EN);

    i2c_master_write_byte(cmd, data, 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);

    static uint8_t dataCheck;
    HUSB238_I2CReadBytes(slaveAddr, writeAddress, 1, &dataCheck);
    if (dataCheck != data)
        return -2;

    return ret;
}


/// @brief 发送Get_SRC_Cap命令
void HUSB238_RefreshSrcCap()
{
    uint8_t cmd = Get_SRC_Cap;
    HUSB238_WriteReg(HUSB238_I2CAddress, Reg_GO_COMMAND, cmd);
}


/// @brief 读取 HUSB238 全部寄存器数据
/// @param regs 大小为 10 的 uint8_t 类型数组
void HUSB238_ReadAllReg(uint8_t *regs)
{
    memset(regs, 0, 10);
    HUSB238_I2CReadBytes(HUSB238_I2CAddress, 0x00, 10, (uint8_t *)regs);
    if(DEBUG_LOG){
        printf("\nHUSB238_ReadAllReg:\n");
        for(int i = 0; i < 10; i++){
            printf("0x%02x: 0x%02x \n", i, regs[i]);
        }
        printf("\n");
    }    
    
}


/// @brief regs 寄存器值 转化可输出能力列表
/// @param regs 大小为 10 
/// @param pdoList 大小为 6 !
void HUSB238_ExtractCap(HUSB238_Capability_t *pdoList)
{
    uint8_t regs[10], have = 0;

    if (!pdoList)
    {
        return;
    }
    HUSB238_ReadAllReg(regs);
    HUSB238_Reg_SRC_PDO *reg;
    HUSB238_Capability_t cap;
    for (int i = 0; i < 6; i++)
    {
        reg = (HUSB238_Reg_SRC_PDO *)(regs + i + 2);
        // memcpy(&reg, &regs[i + 2], sizeof(uint8_t));
        // reg = static_cast<HUSB238_Reg_SRC_PDO>(regs[i + 2]);
        if (reg->bit.SRC_DETECTED){
            HUSB238_CURRENT_e current = reg->bit.SRC_CURRENT;
            cap.detected = true;
            cap.current = to_current(current);
            have = 1;
        }else{
            cap.detected = false;
        }
        cap.voltage = HUSB238_Voltage2PDO((HUSB238_Voltage_e)(i + 1));
        pdoList[i] = cap;
    }

    if(DEBUG_LOG && have == 1){
        printf("\n输出能力列表:\n");
        for(int i = 0; i < 6; i++){
            if(pdoList[i].detected == true){
                printf("| 输出电压: %dV | 输出电流: %.2fA\n", pdoList[i].voltage, pdoList[i].current);
            }
        }
        printf("\n");
    }
}


/// @brief 获取当前PD输出能力
/// @param voltage 电压 单位 'V'
/// @param current 电流 单位 'A'
void HUSB238_GetCapabilities(uint16_t *voltage, float *current)
{
    HUSB238_Voltage_e voltage_e;
    HUSB238_CURRENT_e current_e;

    HUSB238_RefreshSrcCap();
    vTaskDelay( 500 / portTICK_PERIOD_MS );
    HUSB238_GetCurrentMode(&voltage_e, &current_e);
    *voltage = HUSB238_Voltage2PDO(voltage_e);
    if(*voltage != 0){
        *current = to_current(current_e);
    }else{
        *current = 0;
    }
    if(DEBUG_LOG){
        printf("\n当前输出能力\n电压值:%dV\n电流值:%.2fA\r\n", *voltage, *current);
    }
}


/// @brief 请求PDO输出
void HUSB238_RequestPDO()
{
    uint8_t cmd = Request_PDO;
    HUSB238_WriteReg(HUSB238_I2CAddress, Reg_GO_COMMAND, cmd);
}

/// @brief 硬复位
void HUSB238_HardReset()
{
    uint8_t cmd = Hard_Reset;
    HUSB238_WriteReg(HUSB238_I2CAddress, Reg_GO_COMMAND, cmd);
}

/// @brief 初始化
/// @param sda sda
/// @param scl scl
void HUSB238_Init(int sda, int scl)
{
    i2c_port_t i2c_master_port = I2C_NUM;
    i2c_config_t conf;
    conf.mode = I2C_MODE_MASTER;
    conf.sda_io_num = sda;
    conf.sda_pullup_en = GPIO_PULLUP_DISABLE;
    conf.scl_io_num = scl;
    conf.scl_pullup_en = GPIO_PULLUP_DISABLE;
    conf.master.clk_speed = I2C_FREQ_HZ;
    conf.clk_flags = 0;
    i2c_param_config(i2c_master_port, &conf);
    i2c_driver_install(i2c_master_port, conf.mode, I2C_RX_BUF_DISABLE, I2C_TX_BUF_DISABLE, 0);
    initlized = true;
}


/// @brief 设置PD电压值
/// @param pdo 设置的电压(HUSB238_SELECT_Voltage_e)
void HUSB238_SelVoltage(HUSB238_SELECT_Voltage_e pdo)
{
    HUSB238_Reg_SRC_PDO_SEL targetPDO;
    targetPDO.all = 0xA;
    targetPDO.bit.PDO_SELECT = pdo;
    HUSB238_WriteReg(HUSB238_I2CAddress, Reg_SRC_PDO_SEL, targetPDO.all);
    HUSB238_RequestPDO();
}


/// @brief 读取PD当前状态寄存器值
/// @param voltage 电压状态值
/// @param current 电流状态值
void HUSB238_GetCurrentMode(HUSB238_Voltage_e *voltage, HUSB238_CURRENT_e *current)
{
    uint8_t reag[2] = {0};
    HUSB238_Reg_PD_STATUS0 status0;
    HUSB238_Reg_PD_STATUS1 status1;
    HUSB238_I2CReadBytes(HUSB238_I2CAddress, 0x00, 2, (uint8_t *)&reag);
    ((uint8_t *)&status0)[0] = reag[0];
    ((uint8_t *)&status1)[0] = reag[1];
    if(DEBUG_LOG){
        printf("status0.all = 0x%x\n", status0.all);
        printf("status1.all = 0x%x\n", status1.all);
    }

    *current = status0.bit.PD_SRC_CURRENT;
    *voltage = status0.bit.PD_SRC_VOLTAGE;
}


/// @brief 读取到的电压寄存器值转化电压值
/// @param voltage 从 STATUS0(0x00) 读取到的电压值
/// @return 电压值
uint16_t HUSB238_Voltage2PDO(HUSB238_Voltage_e voltage)
{
    if(DEBUG_LOG){
        printf("voltage: %d => %d\n", voltage, votlage_Table[voltage]);
    }
    return votlage_Table[voltage];
}

/// @brief 转化寄存器电流对应值
/// @param c 被转化的电流寄存器值
/// @return 返回电流值
float to_current(HUSB238_CURRENT_e c)
{
    uint8_t i = c & 0xf;
    if (i <= PD_5A)
    {
        if(DEBUG_LOG){
            printf("current: %d => %.2f\n", c, current_Table[i]);
        }
        return current_Table[i];
    }
    else
    {
        if(DEBUG_LOG){
            printf("current: %d => %.2f\n", c, 0.0f);
        }
        return 0.0f;
    }
}

使用示例


// PD 芯片相关变量
uint16_t PD_Voltage;
float PD_Current;

void deal_vTask( void * arg ){

    // HUSB238_1 Init
    printf("HUSB238_Init\n");
    HUSB238_Init(23, 22);

    HUSB238_Capability_t PDCapabilities[6];

	for( ;; ){
        // 获取当前输出电压电流值
        HUSB238_GetCapabilities(&PD_Voltage, &PD_Current);

        // 获取供电能力列表
        HUSB238_ExtractCap(PDCapabilities);

		printf("\n输出能力列表:\n");
        for(int i = 0; i < 6; i++){
            if(PDCapabilities[i].detected == true){
                printf("| 输出电压: %dV | 输出电流: %.2fA\n", PDCapabilities[i].voltage, PDCapabilities[i].current);
            }
        }
        printf("\n");

	    vTaskDelay( 1000 / portTICK_PERIOD_MS );
	}
} 

硬件原理图

注意该粗的线要粗呢

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值