Files
Power-Pico/software/Power_Pico/BSP/PD/fusb302_dev.c
不吃油炸鸡 495baa3905 update
2026-02-26 17:20:03 +08:00

204 lines
6.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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;
}