mcu_hi3321_watch/tjd/driver/charger/charger_port.c
2025-05-26 20:15:20 +08:00

291 lines
9.8 KiB
C

#include "charger_port.h"
#include "adc.h"
#include "adc_porting.h"
#include "charger_api.h"
#include "cmsis_os2.h"
#include "common_pm.h"
#include "gpio.h"
#include "pinctrl.h"
#include "pm.h"
#include "power_display_service.h"
#include "sys_config.h"
#include "tcxo.h"
#define ENABLE_PRINT_INFO 0
#if ENABLE_PRINT_INFO
#define static_print_info(...) sys_chrg_log_i(__VA_ARGS__) // 一般信息打印宏控制
#define static_print_warn(...) sys_chrg_log_w(__VA_ARGS__) // 警告信息打印一般常开
#define static_print_error(...) sys_chrg_log_e(__VA_ARGS__) // 错误信息打印一般常开
#else
#define static_print_info(...)
#define static_print_warn(...)
#define static_print_error(...)
#endif
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif
#define CHARGER_STATUS_PORT_ADC_CHANNEL ADC_CHANNEL_0
#define CHARGER_PORT_ADC_CHANNEL ADC_CHANNEL_2
#define CHARGER_ADC_CLOCK ADC_CLOCK_500KHZ
#define CHARGING_TIME_INDEX_OFTIME 30
#define TESTADC_DISACRD_DELAY_MS 5
#define adc_trans_sytick_to_voltage_without_auto_scan(x) ((float)(((float)(x) * 18) / 40960))
#define CHARGER_TASK_TIMER_PERIOD (1000 * 30)
#define ADC_SAMPLE_COUNT 10
#define ADC_DISCARD_COUNT 10
typedef struct
{
signed int (*func_event_handler)(void *param);
void *param;
void (*func_event_debug)(char *str, ...);
void *payload;
} charger_driver_event_info_t;
// signed int charger_duty_task(void *arg);
static bool g_adc_init_flag = false;
static float g_average_value = 0.0;
static float g_status_value = 0.0;
static const float g_charger_max_power = 350;
static const float g_charger_average_current = 250;
static osTimerId_t g_charger_handle = NULL;
static float g_charging_time_curve_voltage = 4.4;
static uint16_t g_power = 0;
static uint32_t g_charging_time_count = 0;
#pragma pack(4)
struct battery_curve
{
float voltage;
uint16_t power_percent;
};
#pragma pack()
// 放电曲线
static struct battery_curve g_dischargeCurve[] = {
{4.2580, 100}, {4.2465, 99}, {4.2384, 98}, {4.2276, 97}, {4.2170, 96},
{4.2091, 95}, {4.1984, 94}, {4.1903, 93}, {4.1797, 92}, {4.1692, 91},
{4.1587, 90}, {4.1508, 89}, {4.1400, 88}, {4.1295, 87}, {4.1216, 86},
{4.1113, 85}, {4.1007, 84}, {4.0928, 83}, {4.0826, 82}, {4.0720, 81},
{4.0645, 80}, {4.0538, 79}, {4.0433, 78}, {4.0356, 77}, {4.0251, 76},
{4.0177, 75}, {4.0087, 74}, {4.0003, 73}, {3.9943, 72}, {3.9869, 71},
{3.9788, 70}, {3.9665, 69}, {3.9515, 68}, {3.9362, 67}, {3.9256, 66},
{3.9131, 65}, {3.9030, 64}, {3.8965, 63}, {3.8888, 62}, {3.8820, 61},
{3.8770, 60}, {3.8710, 59}, {3.8650, 58}, {3.8599, 57}, {3.8533, 56},
{3.8467, 55}, {3.8418, 54}, {3.8350, 53}, {3.8290, 52}, {3.8239, 51},
{3.8173, 50}, {3.8117, 49}, {3.8070, 48}, {3.8012, 47}, {3.7954, 46},
{3.7913, 45}, {3.7855, 44}, {3.7805, 43}, {3.7764, 42}, {3.7715, 41},
{3.7665, 40}, {3.7624, 39}, {3.7575, 38}, {3.7534, 37}, {3.7498, 36},
{3.7452, 35}, {3.7406, 34}, {3.7373, 33}, {3.7327, 32}, {3.7281, 31},
{3.7253, 30}, {3.7211, 29}, {3.7179, 28}, {3.7137, 27}, {3.7097, 26},
{3.7057, 25}, {3.7026, 24}, {3.6989, 23}, {3.6952, 22}, {3.6921, 21},
{3.6882, 20}, {3.6843, 19}, {3.6812, 18}, {3.6771, 17}, {3.6738, 16},
{3.6690, 15}, {3.6642, 14}, {3.6603, 13}, {3.6548, 12}, {3.6492, 11},
{3.6446, 10}, {3.6382, 9}, {3.6324, 8}, {3.6288, 7}, {3.6253, 6},
{3.6222, 5}, {3.6198, 4}, {3.6159, 3}, {3.6108, 2}, {3.6053, 1},
{3.5000, 0},
};
static float find_power_in_discharge_curve(float voltage)
{
if (voltage <= 0) {
return 0;
}
const int size = ARRAY_SIZE(g_dischargeCurve);
int i;
for(i = 0; i < (size-1); i++){
if(g_dischargeCurve[i].voltage <= voltage)
break;
}
return (g_dischargeCurve[i].power_percent*100);
}
uint16_t get_power_value(void) { return g_power; }
float get_status_value(void) { return g_status_value; }
// static void charger_task_callback(uintptr_t data)
// {
// uint32_t ret = 0;
// static charger_driver_event_info_t g_msg_data = {
// .func_event_handler = charger_duty_task,
// .param = NULL,
// .func_event_debug = NULL,
// .payload = NULL,
// };
// static unsigned int g_msg_size = sizeof(charger_driver_event_info_t);
// ret = osal_msg_queue_write_copy(tjd_task_driver_event_get_queue_id(), &g_msg_data, g_msg_size, 0);
// if (ret != 0) {
// static_print_error("msg send failed! err=0x%x", ret);
// }
// }
uint32_t charger_host_peripheral_init(void)
{
uint32_t ret = 0;
if (g_adc_init_flag) {
static_print_info("charger host peripheral already init");
return CHARGER_SUCC;
}
g_adc_init_flag = true;
// g_charger_handle = osTimerNew((osTimerFunc_t)charger_task_callback, osTimerPeriodic, 0, NULL);
// if (g_charger_handle == NULL) {
// static_print_error("create charger timer failed");
// return CHARGER_FAIL;
// }
return CHARGER_SUCC;
}
uint32_t charger_host_peripheral_deinit(void)
{
uint32_t ret = 0;
if (!g_adc_init_flag) {
static_print_info("charger host peripheral not init");
return CHARGER_SUCC;
}
g_adc_init_flag = false;
return CHARGER_SUCC;
}
static float adc_stick_transfer_voltage(uint16_t stick) { return adc_trans_sytick_to_voltage_without_auto_scan(stick); }
static bool adc_get_sample_result(float *voltage, uint8_t channel)
{
uint32_t sample_number = ADC_SAMPLE_COUNT;
uint32_t discard_number = ADC_DISCARD_COUNT;
uint32_t stick = 0;
uint32_t sample_zero_count = 0;
const power_display_svr_api_t *display_api = power_display_svr_get_api();
/* after channel is enabled, sample result is error in previous samplings, need to be discarded */
for (uint32_t i = 0; i < discard_number; i++) {
uint32_t irq_sts = osal_irq_lock();
uapi_adc_manual_sample(ADC_CHANNEL_NONE);
uapi_tcxo_delay_ms((uint64_t)TESTADC_DISACRD_DELAY_MS);
osal_irq_restore(irq_sts);
}
for (uint32_t i = 0; i < sample_number; i++) {
uint32_t irq_sts = osal_irq_lock();
uint32_t sample_result = (uint32_t)uapi_adc_manual_sample(ADC_CHANNEL_NONE);
uapi_tcxo_delay_ms((uint64_t)TESTADC_DISACRD_DELAY_MS);
// osal_printk("sample_result = %u.\r\n", sample_result);
if (sample_result == 0) {
sample_zero_count++;
}
stick += sample_result;
osal_irq_restore(irq_sts);
}
sample_number -= sample_zero_count;
if (sample_number > 0) {
stick = (stick / sample_number);
} else {
*voltage = 0;
return false;
}
float val = adc_stick_transfer_voltage((uint16_t)stick);
*voltage = val * 12.2 / 2.2;
/* 补偿数值 */
if (display_api->get_screen_state() == SCREEN_OFF) {
*voltage = *voltage + 0.02;
} else {
*voltage = *voltage + 0.04 ;
}
return true;
}
static uint32_t adc_manual_sample(float *voltage, adc_channel_t channel)
{
uapi_pm_add_sleep_veto(PM_ID_CHARGER);
uapi_adc_init(CHARGER_ADC_CLOCK);
uapi_adc_power_en(AFE_SCAN_MODE_MAX_NUM, true);
uint32_t ret = uapi_adc_open_channel(channel);
if (ret != CHARGER_SUCC) {
uapi_adc_power_en(AFE_SCAN_MODE_MAX_NUM, false);
uapi_adc_deinit();
uapi_pm_remove_sleep_veto(PM_ID_CHARGER);
static_print_error("uapi_adc_open_channel failed : %d\r\n", ret);
return ret;
}
if (!adc_get_sample_result(voltage, channel)) {
static_print_info("adc get sample result failed.");
*voltage = 0;
}
uapi_adc_close_channel(channel);
uapi_adc_power_en(AFE_SCAN_MODE_MAX_NUM, false);
uapi_pm_remove_sleep_veto(PM_ID_CHARGER);
uapi_adc_deinit();
return CHARGER_SUCC;
}
uint32_t charger_status_sample(void) { return adc_manual_sample(&g_status_value, CHARGER_STATUS_PORT_ADC_CHANNEL); }
// signed int charger_duty_task(void *arg)
// {
// if (!tjd_driver_charger_get_ops()->get_chargng_status()) {
// osTimerStop(g_charger_handle);
// return 0;
// }
// const uint32_t size = ARRAY_SIZE(g_chargingTimeCurve);
// const uint32_t time = g_charging_time_count * CHARGER_TASK_TIMER_PERIOD;
// const uint32_t index = time / CHARGING_TIME_INDEX_OFTIME;
// double power = 0;
// if (index < size) {
// power = g_chargingTimeCurve[index].power / g_charger_max_power;
// } else {
// power = g_chargingTimeCurve[size - 1].power / g_charger_max_power;
// }
// ++g_charging_time_count;
// return 0;
// }
uint32_t charger_sample(void)
{
uint32_t ret = adc_manual_sample(&g_average_value, CHARGER_PORT_ADC_CHANNEL);
if (ret != CHARGER_SUCC) {
return ret;
}
uint16_t power = find_power_in_discharge_curve(g_average_value);
uint16_t percent = sql_setting_get_battery_percent();
if (tjd_service_charger_get_charger_status())
{
percent += g_charger_average_current * 10/3600/g_charger_max_power*10000; //CHARGER_SCAN_TIME = 10s
if(percent > 10000)
{
percent = 10000;
}
}else{
if(percent > power)
{
percent = (percent+power)/2;
}else if((percent < 500)&&(power > 3000))
{
//适用于异常重启/死机重启
percent = power;
}
}
sql_setting_set_battery_percent(percent);
g_power = min(power, percent);
static_print_info("power = %d percent = %d", power, percent);
static_print_info("g_power [%d] g_average_value[%f]", g_power, g_average_value);
return CHARGER_SUCC;
}