Files
Power-Pico/software/Power_Pico/BSP/PD/fusb302_dev.c

204 lines
6.9 KiB
C
Raw Normal View History

2026-02-26 17:20:03 +08:00
#include "fusb302_dev.h"
#include "i2c.h"
#include "cmsis_os2.h"
#define FUSB302_USE_OS 1
#if FUSB302_USE_OS == 1
#define clock_ms() osKernelGetTickCount()
#define delay_ms(ms) osDelay(ms)
#else
#define clock_ms() HAL_GetTick()
#define delay_ms(ms) HAL_Delay(ms)
#endif
#define PD_POLLING 100
#define TYPEC_SINK_WAIT_CAP 350
#define REQUEST_TO_PS_READY 580
#define PPS_REQUEST 5000
FUSB302_dev_t fusb302_dev;
App_PD_t app_pd;
FUSB302_ret_t fusb302_i2c_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t count)
{
HAL_I2C_Mem_Read(&hi2c1, dev_addr, reg_addr, I2C_MEMADD_SIZE_8BIT, data, count, 10);
return FUSB302_SUCCESS;
}
FUSB302_ret_t fusb302_i2c_write(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t count)
{
HAL_I2C_Mem_Write(&hi2c1, dev_addr, reg_addr, I2C_MEMADD_SIZE_8BIT, data, count, 10);
return FUSB302_SUCCESS;
}
FUSB302_ret_t fusb302_delay_ms_wrapper(uint32_t ms)
{
#if FUSB302_USE_OS == 1
osDelay(ms);
#else
HAL_Delay(ms);
#endif
return FUSB302_SUCCESS;
}
void status_power_ready(status_power_t status, uint16_t voltage, uint16_t current)
{
app_pd.ready_voltage = voltage;
app_pd.ready_current = current;
app_pd.status_power = status;
}
void set_default_power(void)
{
status_power_ready(STATUS_POWER_TYP, PD_V(5.0), PD_A(1.0));
}
void handle_protocol_event(PD_protocol_event_t events)
{
if (events & PD_PROTOCOL_EVENT_SRC_CAP) {
app_pd.wait_src_cap = 0;
app_pd.get_src_cap_retry_count = 0;
app_pd.wait_ps_rdy = 1;
app_pd.time_wait_ps_rdy = clock_ms();
app_pd.state = PD_STATE_GET_CAPS; // 更新状态:已收到能力,可以请求了
}
if (events & PD_PROTOCOL_EVENT_REJECT) {
if (app_pd.wait_ps_rdy) {
app_pd.wait_ps_rdy = 0;
app_pd.state = PD_STATE_FAILED; // 更新状态:请求被拒绝
}
}
if (events & PD_PROTOCOL_EVENT_PS_RDY) {
PD_power_info_t p;
uint8_t i, selected_power = PD_protocol_get_selected_power(&app_pd.protocol);
PD_protocol_get_power_info(&app_pd.protocol, selected_power, &p);
app_pd.wait_ps_rdy = 0;
if (p.type == PD_PDO_TYPE_AUGMENTED_PDO) {
// PPS mode
FUSB302_set_vbus_sense(&fusb302_dev, 0);
if (app_pd.PPS_voltage_next) {
// Two stage startup for PPS voltage < 5V
PD_protocol_set_PPS(&app_pd.protocol, app_pd.PPS_voltage_next, app_pd.PPS_current_next, false);
app_pd.PPS_voltage_next = 0;
app_pd.send_request = 1;
} else {
app_pd.time_PPS_request = clock_ms();
status_power_ready(STATUS_POWER_PPS,
PD_protocol_get_PPS_voltage(&app_pd.protocol), PD_protocol_get_PPS_current(&app_pd.protocol));
app_pd.state = PD_STATE_SUCCESS_PPS; // 更新状态成功协商到PPS
}
} else {
FUSB302_set_vbus_sense(&fusb302_dev, 1);
status_power_ready(STATUS_POWER_TYP, p.max_v, p.max_i);
app_pd.state = PD_STATE_SUCCESS_FIXED; // 更新状态:协商到了一个固定电压
}
}
}
void handle_FUSB302_event(FUSB302_event_t events)
{
if (events & FUSB302_EVENT_DETACHED) {
PD_protocol_reset(&app_pd.protocol);
app_pd.cc = 0;
return;
}
if (events & FUSB302_EVENT_ATTACHED) {
uint8_t cc1 = 0, cc2 = 0, cc = 0;
FUSB302_get_cc(&fusb302_dev, &cc1, &cc2);
PD_protocol_reset(&app_pd.protocol);
if (cc1 && cc2 == 0) {
cc = cc1;
app_pd.cc = 1;
} else if (cc2 && cc1 == 0) {
cc = cc2;
app_pd.cc = 2;
}
/* TODO: handle no cc detected error */
if (cc > 1) {
app_pd.wait_src_cap = 1;
} else {
set_default_power();
}
}
if (events & FUSB302_EVENT_RX_SOP) {
PD_protocol_event_t protocol_event = 0;
uint16_t header;
uint32_t obj[7];
FUSB302_get_message(&fusb302_dev, &header, obj);
PD_protocol_handle_msg(&app_pd.protocol, header, obj, &protocol_event);
if (protocol_event) {
handle_protocol_event(protocol_event);
}
}
if (events & FUSB302_EVENT_GOOD_CRC_SENT) {
uint16_t header;
uint32_t obj[7];
delay_ms(4); /* Delay respond in case there are retry messages */
if (PD_protocol_respond(&app_pd.protocol, &header, obj)) {
FUSB302_tx_sop(&fusb302_dev, header, obj);
}
}
}
bool fusb302_timer(void)
{
uint32_t t = clock_ms();
if (app_pd.wait_src_cap && t - app_pd.time_wait_src_cap > TYPEC_SINK_WAIT_CAP) {
app_pd.time_wait_src_cap = t;
if (app_pd.get_src_cap_retry_count < 3) {
uint16_t header;
app_pd.get_src_cap_retry_count += 1;
/* Try to request soruce capabilities message (will not cause power cycle VBUS) */
PD_protocol_create_get_src_cap(&app_pd.protocol, &header);
FUSB302_tx_sop(&fusb302_dev, header, 0);
} else {
app_pd.get_src_cap_retry_count = 0;
/* Hard reset will cause the source power cycle VBUS. */
FUSB302_tx_hard_reset(&fusb302_dev);
PD_protocol_reset(&app_pd.protocol);
}
}
if (app_pd.wait_ps_rdy) {
if (t - app_pd.time_wait_ps_rdy > REQUEST_TO_PS_READY) {
app_pd.wait_ps_rdy = 0;
set_default_power();
}
} else if (app_pd.send_request || (app_pd.status_power == STATUS_POWER_PPS && t - app_pd.time_PPS_request > PPS_REQUEST)) {
app_pd.wait_ps_rdy = 1;
app_pd.send_request = 0;
app_pd.state = PD_STATE_NEGOTIATING; // 更新状态:正在协商中
app_pd.time_PPS_request = t;
uint16_t header;
uint32_t obj[7];
/* Send request if option updated or regularly in PPS mode to keep power alive */
PD_protocol_create_request(&app_pd.protocol, &header, obj);
app_pd.time_wait_ps_rdy = clock_ms();
FUSB302_tx_sop(&fusb302_dev, header, obj);
}
if (t - app_pd.time_polling > PD_POLLING) {
app_pd.time_polling = t;
return true;
}
return false;
}
bool is_power_ready(void) { return app_pd.status_power == STATUS_POWER_TYP; }
bool is_PPS_ready(void) { return app_pd.status_power == STATUS_POWER_PPS; }
void send_power_request(void) { app_pd.send_request = 1; }
uint8_t fusb302_dev_init(void) {
fusb302_dev.i2c_address = 0x22<<1; // FUSB302 I2C address
fusb302_dev.i2c_read = fusb302_i2c_read;
fusb302_dev.i2c_write = fusb302_i2c_write;
fusb302_dev.delay_ms = fusb302_delay_ms_wrapper;
if (FUSB302_init(&fusb302_dev) == FUSB302_SUCCESS && FUSB302_get_ID(&fusb302_dev, 0, 0) == FUSB302_SUCCESS) {
PD_protocol_init(&app_pd.protocol);
app_pd.state = PD_STATE_IDLE; // 初始状态
return 0;
}
return 1;
}