#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 chgbox_irq_disable_backup(); extern void chgbox_irq_enable_revert(); /////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////无线充///////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// #if(defined WIRELESS_ENABLE) && (WIRELESS_ENABLE) _wireless_hdl wl_hdl; #define __this (&wl_hdl) /* volatile struct _wireless_info info; */ static u16 wl_send_buff[10] __attribute__((aligned(4))); //10 * =20byte //控制充电口电压范围 #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 12 #define WL_OFFLINE_TIMES 15 static u16 power_table[AD_OK_COUNTS]; static u16 power_table_tmp[AD_OK_COUNTS]; static u8 power_cnt = 0; static volatile u8 data_ok = 0; static volatile u8 timer_100ms = 0; static u16 get_wireless_voltage(void); static void wl_timer2_close(void); void wl_timer2_open(void); ///dcdc en IO初始化 static void dcdc_io_init(void) { #if DCDC_CTRL_EN gpio_set_die(DCDC_EN_IO, 0); gpio_set_pull_down(DCDC_EN_IO, 0); gpio_set_pull_up(DCDC_EN_IO, 0); gpio_direction_output(DCDC_EN_IO, 0); #endif } /*------------------------------------------------------------------------------------*/ /**@brief DCDC使能 @param 无 @return 无 @note 使能后才能正常充电 */ /*------------------------------------------------------------------------------------*/ static void dcdc_set_en(u8 en) { #if DCDC_CTRL_EN if (en) { gpio_direction_output(DCDC_EN_IO, 1); } else { gpio_direction_output(DCDC_EN_IO, 0); } #endif } /*------------------------------------------------------------------------------------*/ /**@brief 无线充通信口初始化 @param 无 @return 无 */ /*------------------------------------------------------------------------------------*/ static void wpc_io_init(void) { gpio_set_die(WPC_IO, 1); gpio_set_pull_down(WPC_IO, 0); gpio_set_pull_up(WPC_IO, 0); gpio_direction_output(WPC_IO, 0); } /*------------------------------------------------------------------------------------*/ /**@brief 无线充10 ms调用 @param 无 @return 无 @note 记录无线充提供的电压,发送100ms事件 */ /*------------------------------------------------------------------------------------*/ void wireless_10ms_scan(void) { u16 power_tmp; if ((!__this->info.open) || __this->info.busy) { ///不在线或发数据中不动作 timer_100ms = 0; return; } power_tmp = get_wireless_voltage(); power_table[power_cnt++] = power_tmp; if (power_cnt >= AD_OK_COUNTS) { power_cnt = 0; data_ok = 1; } timer_100ms++; if (timer_100ms % 10 == 0) { timer_100ms = 0; app_chargebox_event_to_user(CHGBOX_EVENT_WL_100MS); /* put_event(EVENT_100MS); */ } } /*------------------------------------------------------------------------------------*/ /**@brief 无线充100ms调用 @param 无 @return 无 @note */ /*------------------------------------------------------------------------------------*/ void wireless_100ms_run_app(void) { wl_timer2_open(); wireless_100ms_run(); } /*------------------------------------------------------------------------------------*/ /**@brief 获取无线充当前提供的电压 @param 无 @return 无 @note */ /*------------------------------------------------------------------------------------*/ u16 get_wireless_power(void) { u8 i, j, k; u16 ad_sum, ad_min; while (!data_ok); 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; //去掉去掉最大与最小 AD_CUT_COUNTS*2 个 } /*------------------------------------------------------------------------------------*/ /**@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(WPC_IO, 1); break; case IO_LOW: gpio_direction_output(WPC_IO, 0); wl_timer2_close(); //最后一个动作后关闭 break; case IO_INIT: gpio_set_die(WPC_IO, 1); gpio_set_pull_down(WPC_IO, 0); gpio_set_pull_up(WPC_IO, 0); gpio_direction_output(WPC_IO, 0); break; case IO_OVERTURN://翻转 io_num = WPC_IO % 16; #if(WPC_IO <= IO_PORTA_15) JL_PORTA->OUT ^= BIT(io_num); #elif(WPC_IO <= IO_PORTB_15) JL_PORTB->OUT ^= BIT(io_num); #elif(WPC_IO <= IO_PORTC_15) JL_PORTC->OUT ^= BIT(io_num); #elif(WPC_IO <= IO_PORTD_7) JL_PORTD->OUT ^= BIT(io_num); #endif break; case IO_DIR_IN: //高阻 gpio_direction_input(WPC_IO); break; } } /*------------------------------------------------------------------------------------*/ /**@brief 打开无线充模块 @param 无 @return 无 @note 检测到无线充上线时调用,发送相关的初始化指令 */ /*------------------------------------------------------------------------------------*/ void wireless_api_open(void) { wl_timer2_open(); //初始化好timer chgbox_irq_disable_backup(); //关其他中断 irq_enable(IRQ_TIME2_IDX); //开本中断 power_cnt = 0; data_ok = 0; wireless_open(VOLTAGE_MIN, VOLTAGE_MAX); //发送信号强度包 get_signal_value(); __this->info.busy = 1; while (__this->info.busy) { asm("nop"); if (sys_info.status[WIRELESS_DET] == STATUS_OFFLINE) { wireless_close(); chgbox_irq_enable_revert(); return; } } chgbox_irq_enable_revert();//恢复中断(注意只打开原来开着的中断) //发送身份包 delay_2ms(3); get_identification(); wl_timer2_open(); chgbox_irq_disable_backup(); irq_enable(IRQ_TIME2_IDX); __this->info.busy = 1; while (__this->info.busy) { asm("nop"); if (sys_info.status[WIRELESS_DET] == STATUS_OFFLINE) { wireless_close(); chgbox_irq_enable_revert(); return; } } chgbox_irq_enable_revert(); //发送配置包 delay_2ms(3); get_configuration(); wl_timer2_open(); chgbox_irq_disable_backup(); irq_enable(IRQ_TIME2_IDX); __this->info.busy = 1; while (__this->info.busy) { asm("nop"); if (sys_info.status[WIRELESS_DET] == STATUS_OFFLINE) { wireless_close(); chgbox_irq_enable_revert(); return; } } chgbox_irq_enable_revert(); timer_100ms = 0; /* clear_one_event(EVENT_100MS); */ } /*------------------------------------------------------------------------------------*/ /**@brief 关闭无线充模块 @param 无 @return 无 @note 无线充下线时调用 */ /*------------------------------------------------------------------------------------*/ void wireless_api_close(void) { wireless_close(); data_ok = 0; power_cnt = 0; dcdc_set_en(0); } /*------------------------------------------------------------------------------------*/ /**@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 */ /*------------------------------------------------------------------------------------*/ void wl_timer2_open(void) { u32 prd_cnt; u8 index; JL_TIMER2->CON = BIT(14);//清pending for (index = 0; index < (sizeof(timer_div) / sizeof(timer_div[0])); index++) { prd_cnt = WL_TIMER_UNIT_US * (clk_get("timer") / 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); /* JL_TIMER2->CON = (index << 4) | BIT(0);//osc lsb */ /* JL_TIMER2->CON |= BIT(14);//清pending */ JL_TIMER2->CON = (index << 4) | BIT(0) | BIT(3); //osc clk /* log_info("PRD : 0x%x / %d", JL_TIMER2->PRD, clk_get("timer")); */ } /*------------------------------------------------------------------------------------*/ /**@brief 关闭timer2模块 @param 无 @return 无 @note */ /*------------------------------------------------------------------------------------*/ static void wl_timer2_close(void) { JL_TIMER2->CON = 0;//osc clk } /*------------------------------------------------------------------------------------*/ /**@brief 获取无线充输入电压 @param 无 @return 无 @note */ /*------------------------------------------------------------------------------------*/ static u16 get_wireless_voltage(void) { u16 volt; //注意分压,上下拉及外部路相关, 默认开下拉四分一 volt = adc_get_voltage(WL_AD_DET_CH) * 4; //四分一分压 return volt; } /*------------------------------------------------------------------------------------*/ /**@brief 无线充AD检测上下线IO初始化 @param 无 @return 无 @note */ /*------------------------------------------------------------------------------------*/ void wl_ad_det_init(void) { adc_add_sample_ch(WL_AD_DET_CH); //注意:初始化AD_KEY之前,先初始化ADC gpio_set_die(WL_AD_DET_IO, 0); gpio_set_direction(WL_AD_DET_IO, 1); gpio_set_pull_down(WL_AD_DET_IO, 1); gpio_set_pull_up(WL_AD_DET_IO, 0); } /*------------------------------------------------------------------------------------*/ /**@brief 无线充2ms检测 @param 无 @return 无 @note 利用AD值检测无线充的上下线 */ /*------------------------------------------------------------------------------------*/ void wireless_online_det_2ms(void) { static u16 wl_detect_cnt = 0; if (sys_info.status[WIRELESS_DET] == STATUS_ONLINE) { if (get_wireless_voltage() < WL_ONLINE_VOLT) { wl_detect_cnt++; sys_info.life_cnt = 0; if (wl_detect_cnt >= WL_OFFLINE_TIMES) { wl_detect_cnt = 0; sys_info.status[WIRELESS_DET] = STATUS_OFFLINE; app_chargebox_event_to_user(CHGBOX_EVENT_WIRELESS_OFFLINE); } } } else { if (get_wireless_voltage() >= WL_ONLINE_VOLT) { wl_detect_cnt++; sys_info.life_cnt = 0; if (wl_detect_cnt >= WL_ONLINE_TIMES) { wl_detect_cnt = 0; sys_info.status[WIRELESS_DET] = STATUS_ONLINE; app_chargebox_event_to_user(CHGBOX_EVENT_WIRELESS_ONLINE); } } } } /*------------------------------------------------------------------------------------*/ /**@brief 无线充2毫秒扫描 @param 无 @return 无 @note */ /*------------------------------------------------------------------------------------*/ void wl_2ms_scan() { static u16 cnt = 0; wireless_online_det_2ms(); cnt++; if ((cnt % 5) == 0) { //10ms wireless_10ms_scan(); cnt = 0; } } /*------------------------------------------------------------------------------------*/ /**@brief 无线充模块初始化 @param 无 @return 无 @note 初始化控制结构体、ad、对应的io,注册相关接口 */ /*------------------------------------------------------------------------------------*/ void wireless_init_api(void) { ///注意顺序不能改变 memset(__this, 0x0, sizeof(_wireless_hdl)); //AD采集初始化 wl_ad_det_init(); dcdc_io_init(); wpc_io_init(); __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); //2msscan注册 sys_s_hi_timer_add(NULL, wl_2ms_scan, 2); } #endif//end of WIRELESS_ENABLE #endif