KT25-0812_82A-UART/apps/common/charge_box/chgbox_wireless.c
2025-08-12 18:09:23 +08:00

495 lines
14 KiB
C
Raw Permalink 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 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