KT24-1110_65E-HA-651B/apps/common/charge_box/chgbox_wireless.c
2024-11-10 18:44:17 +08:00

576 lines
17 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 "gpio.h"
#include "app_config.h"
#include "system/includes.h"
#include "device/wireless_charge.h"
#include "chgbox_ctrl.h"
#include "asm/adc_api.h"
#include "chgbox_box.h"
#include "device/chargebox.h"
#include "chgbox_wireless.h"
#if (TCFG_CHARGE_BOX_ENABLE)
#define LOG_TAG_CONST APP_CHGBOX
#define LOG_TAG "[CHG_WL]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
extern void delay_2ms(int cnt);
extern void wireless_port_set_wakeup_enable(u8 enable);
///////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////无线充/////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
#if(defined TCFG_WIRELESS_ENABLE) && (TCFG_WIRELESS_ENABLE)
_wireless_hdl wl_hdl;
#define __this (&wl_hdl)
static u16 wl_send_buff[10] __attribute__((aligned(4))); //10 * =20byte
static int wl_100ms_timer, wl_ad_timer, wl_ad_timeout;
static u32 g_wireless_voltage;
static u8 wl_send_over_msg, wl_init_ok;
//控制充电口电压范围
#define VOLTAGE_MIN 6100
#define VOLTAGE_MAX 6200
//取中间 (AD_OK_COUNTS-AD_CUT_COUNTS*2)计算均值(去掉头部与尾部)
#define AD_OK_COUNTS 5
#define AD_CUT_COUNTS 1
//无线充上线检测
#define WL_ONLINE_VOLT 3500 ///电压大于3.5才认为是有充电器放上来
#define WL_ONLINE_TIMES 3
#define WL_OFFLINE_TIMES 5
static u16 power_table[AD_OK_COUNTS];
static u16 power_table_tmp[AD_OK_COUNTS];
//无线充电通信的时候不能进入低功耗
static volatile u8 is_wl_comm_active = 0;
static u8 wl_comm_idle_query(void)
{
return (!is_wl_comm_active);
}
REGISTER_LP_TARGET(wl_comm_lp_target) = {
.name = "chgbox_wl_comm",
.is_idle = wl_comm_idle_query,
};
/*------------------------------------------------------------------------------------*/
/**@brief timer2中断回调
@param 无
@return 无
@note 注意调用的所有代码需放在ram里
*/
/*------------------------------------------------------------------------------------*/
SEC(.chargebox_code)
___interrupt
static void wl_timer2_isr(void)
{
JL_TIMER2->CON |= BIT(14);
wireless_250us_run();
}
static const u32 timer_div[] = {
/*0000*/ 1,
/*0001*/ 4,
/*0010*/ 16,
/*0011*/ 64,
/*0100*/ 2,
/*0101*/ 8,
/*0110*/ 32,
/*0111*/ 128,
/*1000*/ 256,
/*1001*/ 4 * 256,
/*1010*/ 16 * 256,
/*1011*/ 64 * 256,
/*1100*/ 2 * 256,
/*1101*/ 8 * 256,
/*1110*/ 32 * 256,
/*1111*/ 128 * 256,
};
#define MAX_TIME_CNT 0x7fff
#define MIN_TIME_CNT 0x100
#define WL_TIMER_UNIT_US 250 //单位us
/*------------------------------------------------------------------------------------*/
/**@brief 开启timer2模块
@param 无
@return 无
@note
*/
/*------------------------------------------------------------------------------------*/
static void wl_timer2_open(void)
{
u32 prd_cnt, timer_clk;
u8 index;
#if (TCFG_CLOCK_SYS_SRC == SYS_CLOCK_INPUT_PLL_RCL)
timer_clk = clk_get("lsb");
#else
timer_clk = clk_get("timer");
#endif
JL_TIMER2->CON = BIT(14);//清pending
for (index = 0; index < (sizeof(timer_div) / sizeof(timer_div[0])); index++) {
prd_cnt = WL_TIMER_UNIT_US * (timer_clk / 1000000) / timer_div[index];
if (prd_cnt > MIN_TIME_CNT && prd_cnt < MAX_TIME_CNT) {
break;
}
}
JL_TIMER2->CNT = 0;
JL_TIMER2->PRD = prd_cnt;
request_irq(IRQ_TIME2_IDX, 3, wl_timer2_isr, 0);
#if (TCFG_CLOCK_SYS_SRC == SYS_CLOCK_INPUT_PLL_RCL)
JL_TIMER2->CON = (index << 4) | BIT(0); //lsb clk
#else
JL_TIMER2->CON = (index << 4) | BIT(0) | BIT(3); //osc clk
#endif
is_wl_comm_active = 1;
}
/*------------------------------------------------------------------------------------*/
/**@brief 关闭timer2模块
@param 无
@return 无
@note
*/
/*------------------------------------------------------------------------------------*/
static void wl_timer2_close(void)
{
JL_TIMER2->CON = BIT(14);
is_wl_comm_active = 0;
}
///dcdc en IO初始化
static void dcdc_io_init(void)
{
#if TCFG_DCDC_CTRL_EN
gpio_set_die(TCFG_DCDC_EN_IO, 0);
gpio_set_pull_down(TCFG_DCDC_EN_IO, 0);
gpio_set_pull_up(TCFG_DCDC_EN_IO, 0);
gpio_direction_output(TCFG_DCDC_EN_IO, 0);
#endif
}
/*------------------------------------------------------------------------------------*/
/**@brief DCDC使能
@param 无
@return 无
@note 使能后才能正常充电
*/
/*------------------------------------------------------------------------------------*/
static void dcdc_set_en(u8 en)
{
#if TCFG_DCDC_CTRL_EN
log_info("dcdc en: %d\n", en);
if (en) {
gpio_direction_output(TCFG_DCDC_EN_IO, 1);
} else {
gpio_direction_output(TCFG_DCDC_EN_IO, 0);
}
#endif
}
/*------------------------------------------------------------------------------------*/
/**@brief 无线充通信口初始化
@param 无
@return 无
*/
/*------------------------------------------------------------------------------------*/
static void wpc_io_init(void)
{
gpio_set_die(TCFG_WPC_COMM_IO, 1);
gpio_set_pull_down(TCFG_WPC_COMM_IO, 0);
gpio_set_pull_up(TCFG_WPC_COMM_IO, 0);
gpio_direction_output(TCFG_WPC_COMM_IO, 0);
}
/*------------------------------------------------------------------------------------*/
/**@brief 无线充AD检测上下线IO初始化
@param 无
@return 无
@note
*/
/*------------------------------------------------------------------------------------*/
static void wl_ad_det_init(u8 die_en)
{
gpio_set_die(TCFG_WL_AD_DET_IO, die_en);
gpio_set_direction(TCFG_WL_AD_DET_IO, 1);
gpio_set_pull_down(TCFG_WL_AD_DET_IO, 0);
gpio_set_pull_up(TCFG_WL_AD_DET_IO, 0);
if (!die_en) {
gpio_set_pull_down(TCFG_WL_AD_DET_IO, 1);
adc_add_sample_ch(TCFG_WL_AD_DET_CH);
wireless_port_set_wakeup_enable(0);
} else {
wireless_port_set_wakeup_enable(1);
}
}
SEC(.chargebox_code)
static u32 wl_read_ad_io_status(void)
{
u32 v = 0;
u32 mask = TCFG_WL_AD_DET_IO % IO_GROUP_NUM;
#if (TCFG_WL_AD_DET_IO <= IO_PORTA_15)
v = !!(JL_PORTA->IN & BIT(mask));
#elif(TCFG_WL_AD_DET_IO <= IO_PORTB_15)
v = !!(JL_PORTB->IN & BIT(mask));
#elif(TCFG_WL_AD_DET_IO <= IO_PORTC_15)
v = !!(JL_PORTC->IN & BIT(mask));
#elif(TCFG_WL_AD_DET_IO <= IO_PORTD_7)
v = !!(JL_PORTD->IN & BIT(mask));
#endif
return v;
}
/*------------------------------------------------------------------------------------*/
/**@brief 获取无线充输入电压
@param 无
@return 无
@note
*/
/*------------------------------------------------------------------------------------*/
static u16 get_wireless_voltage(void)
{
u16 volt;
//注意分压,上下拉及外部路相关, 默认开下拉四分一
volt = adc_get_voltage(TCFG_WL_AD_DET_CH) * 4;
return volt;
}
/*------------------------------------------------------------------------------------*/
/**@brief 无线充100ms调用
@param 无
@return 无
@note
*/
/*------------------------------------------------------------------------------------*/
static void wireless_100ms_run_app(void *priv)
{
if (sys_info.temperature_limit) {
if (sys_info.status[WIRELESS_DET] == STATUS_ONLINE) {
sys_info.status[WIRELESS_DET] = STATUS_OFFLINE;
app_chargebox_event_to_user(CHGBOX_EVENT_WIRELESS_OFFLINE);
}
return;
}
//查看是否有数据需要发送
wireless_100ms_run();
if (__this->info.busy) {
wl_timer2_open();
}
}
/*------------------------------------------------------------------------------------*/
/**@brief 通过电压数组计算均值
@param 无
@return 无
@note
*/
/*------------------------------------------------------------------------------------*/
static u16 wireless_calc_power(void)
{
u8 i, j, k;
u16 ad_sum, ad_min;
memcpy(power_table_tmp, power_table, sizeof(power_table));
for (i = 1; i < AD_OK_COUNTS; i++) {
for (j = i; j > 0; j--) {
if (power_table_tmp[j] < power_table_tmp[j - 1]) {
ad_min = power_table_tmp[j];
power_table_tmp[j] = power_table_tmp[j - 1];
power_table_tmp[j - 1] = ad_min;
}
}
}
ad_sum = 0;
for (k = AD_CUT_COUNTS; k < (AD_OK_COUNTS - AD_CUT_COUNTS); k++) {
ad_sum = power_table_tmp[k] + ad_sum;
}
ad_sum = (ad_sum / (AD_OK_COUNTS - (AD_CUT_COUNTS * 2)));
return ad_sum;
}
static void wireless_ad_detect_run(void *priv)
{
static u8 power_cnt = 0;
u16 power_tmp;
power_tmp = get_wireless_voltage();
power_table[power_cnt++] = power_tmp;
if (power_cnt >= AD_OK_COUNTS) {
usr_timer_del(wl_ad_timer);
wl_ad_timer = 0;
wl_ad_timeout = 0;
power_cnt = 0;
g_wireless_voltage = wireless_calc_power();
if (g_wireless_voltage < WL_ONLINE_VOLT) {
sys_info.status[WIRELESS_DET] = STATUS_OFFLINE;
app_chargebox_event_to_user(CHGBOX_EVENT_WIRELESS_OFFLINE);
}
log_info("wireless_power: %d mV\n", g_wireless_voltage);
}
}
static void wireless_ad_detect_start(void *priv)
{
if (wl_ad_timer == 0) {
wl_ad_timer = usr_timer_add(NULL, wireless_ad_detect_run, 10, 1);//10ms
}
}
static void wireless_ad_detect_init(void)
{
if (wl_ad_timeout == 0) {
wl_ad_timeout = sys_timeout_add(NULL, wireless_ad_detect_start, 25);
}
}
/*------------------------------------------------------------------------------------*/
/**@brief 获取无线充当前提供的电压
@param 无
@return 无
@note
*/
/*------------------------------------------------------------------------------------*/
u16 get_wireless_power(void)
{
return g_wireless_voltage;
}
/*------------------------------------------------------------------------------------*/
/**@brief 无线充通信io设置
@param 无
@return 无
@note 供库调用注意代码要放ram
*/
/*------------------------------------------------------------------------------------*/
SEC(.chargebox_code)
void wpc_io_set(u8 mode)
{
u8 io_num;
switch (mode) {
case IO_HIGH:
gpio_direction_output(TCFG_WPC_COMM_IO, 1);
break;
case IO_LOW:
gpio_direction_output(TCFG_WPC_COMM_IO, 0);
wl_timer2_close(); //最后一个动作后关闭
if (wl_send_over_msg) {
app_chargebox_event_to_user(CHGBOX_EVENT_WL_DATA_OVER);
}
break;
case IO_INIT:
gpio_set_die(TCFG_WPC_COMM_IO, 1);
gpio_set_pull_down(TCFG_WPC_COMM_IO, 0);
gpio_set_pull_up(TCFG_WPC_COMM_IO, 0);
gpio_direction_output(TCFG_WPC_COMM_IO, 0);
break;
case IO_OVERTURN://翻转
io_num = TCFG_WPC_COMM_IO % IO_GROUP_NUM;
#if(TCFG_WPC_COMM_IO <= IO_PORTA_15)
JL_PORTA->OUT ^= BIT(io_num);
#elif(TCFG_WPC_COMM_IO <= IO_PORTB_15)
JL_PORTB->OUT ^= BIT(io_num);
#elif(TCFG_WPC_COMM_IO <= IO_PORTC_15)
JL_PORTC->OUT ^= BIT(io_num);
#elif(TCFG_WPC_COMM_IO <= IO_PORTD_7)
JL_PORTD->OUT ^= BIT(io_num);
#endif
break;
case IO_DIR_IN: //高阻
gpio_direction_input(TCFG_WPC_COMM_IO);
break;
}
}
/*------------------------------------------------------------------------------------*/
/**@brief 无线充发送一个数据包封装
@param 无
@return 无
@note 仅在握手阶段调用!!!
*/
/*------------------------------------------------------------------------------------*/
static bool wireless_send_pack_deal(void)
{
bool ret = true;
local_irq_disable();
wl_timer2_open();
__this->info.busy = 1;
while (__this->info.busy) {
asm("nop");
if (JL_TIMER2->CON & BIT(15)) {
JL_TIMER2->CON |= BIT(14);
wireless_250us_run();
}
if (wl_read_ad_io_status() == 0) {
ret = false;
break;
}
}
wl_timer2_close();
local_irq_enable();
if (ret == false) {
sys_info.status[WIRELESS_DET] = STATUS_OFFLINE;
app_chargebox_event_to_user(CHGBOX_EVENT_WIRELESS_OFFLINE);
}
return ret;
}
/*------------------------------------------------------------------------------------*/
/**@brief 打开无线充模块
@param 无
@return 无
@note 检测到无线充上线时调用,发送相关的初始化指令
*/
/*------------------------------------------------------------------------------------*/
void wireless_api_open(void)
{
if (sys_info.temperature_limit) {
sys_info.status[WIRELESS_DET] = STATUS_OFFLINE;
app_chargebox_event_to_user(CHGBOX_EVENT_WIRELESS_OFFLINE);
return;
}
wireless_open(VOLTAGE_MIN, VOLTAGE_MAX);
//发送信号强度包
get_signal_value();
if (wireless_send_pack_deal() == false) {
goto __err_exit;
}
//发送身份包
delay_2ms(3);
get_identification();
if (wireless_send_pack_deal() == false) {
goto __err_exit;
}
//发送配置包
delay_2ms(3);
get_configuration();
if (wireless_send_pack_deal() == false) {
goto __err_exit;
}
wl_ad_det_init(0);//初始化成模拟口
app_chargebox_event_to_user(CHGBOX_EVENT_WL_DATA_OVER);
wl_100ms_timer = sys_timer_add(NULL, wireless_100ms_run_app, 100);
wl_send_over_msg = 1;
return;
__err_exit:
wireless_close();
return;
}
/*------------------------------------------------------------------------------------*/
/**@brief 关闭无线充模块
@param 无
@return 无
@note 无线充下线时调用
*/
/*------------------------------------------------------------------------------------*/
void wireless_api_close(void)
{
wireless_close();
dcdc_set_en(0);
wl_ad_det_init(1);
wl_send_over_msg = 0;
if (wl_100ms_timer) {
sys_timer_del(wl_100ms_timer);
wl_100ms_timer = 0;
}
}
/*------------------------------------------------------------------------------------*/
/**@brief 无线充上线检测
@param 无
@return 无
@note 利用AD值检测无线充的上线
*/
/*------------------------------------------------------------------------------------*/
static int wireless_on_det_timer;
static void wireless_online_det(void *priv)
{
u16 power_voltage;
static u16 wl_on_detect_cnt = 0;
static u16 wl_off_detect_cnt = 0;
sys_info.life_cnt = 0;
power_voltage = get_wireless_voltage();
if (power_voltage >= WL_ONLINE_VOLT) {
wl_on_detect_cnt++;
wl_off_detect_cnt = 0;
g_wireless_voltage += power_voltage;
if (wl_on_detect_cnt >= WL_ONLINE_TIMES) {
wl_on_detect_cnt = 0;
g_wireless_voltage = g_wireless_voltage / WL_ONLINE_TIMES;
sys_info.status[WIRELESS_DET] = STATUS_ONLINE;
app_chargebox_event_to_user(CHGBOX_EVENT_WIRELESS_ONLINE);
goto __online_det_exit;
}
} else {
wl_off_detect_cnt++;
wl_on_detect_cnt = 0;
g_wireless_voltage = 0;
if (wl_off_detect_cnt >= WL_OFFLINE_TIMES) {
wl_off_detect_cnt = 0;
goto __online_det_exit;
}
}
return;
__online_det_exit:
wl_ad_det_init(1);//初始化成数字口
usr_timer_del(wireless_on_det_timer);
wireless_on_det_timer = 0;
}
void wireless_io_wakeup_deal(void)
{
if (!wl_init_ok) {
return;
}
if ((sys_info.status[WIRELESS_DET] == STATUS_OFFLINE) && (wireless_on_det_timer == 0)) {
wl_ad_det_init(0);//初始化成AD口
wireless_on_det_timer = usr_timer_add(NULL, wireless_online_det, 5, 1);//6ms
}
}
void wireless_data_over_run(void)
{
if (sys_info.status[WIRELESS_DET] == STATUS_OFFLINE) {
return;
}
wireless_ad_detect_init();
}
/*------------------------------------------------------------------------------------*/
/**@brief 无线充模块初始化
@param 无
@return 无
@note 初始化控制结构体、ad、对应的io注册相关接口
*/
/*------------------------------------------------------------------------------------*/
void wireless_init_api(void)
{
///注意顺序不能改变
memset(__this, 0x0, sizeof(_wireless_hdl));
//AD采集初始化
wl_ad_det_init(1);
dcdc_io_init();
wpc_io_init();
wl_send_over_msg = 0;
__this->get_wl_power = get_wireless_power;
__this->dcdc_en_set = dcdc_set_en;
__this->wpc_set = wpc_io_set;
__this->send_buff = wl_send_buff;
wireless_lib_init(__this, VOLTAGE_MIN, VOLTAGE_MAX);
wl_init_ok = 1;
}
#endif//end of WIRELESS_ENABLE
#endif