一:增加了纹波滤波,当纹波板有电阻时打开辅助继电器应该为3帧过冲,使用五次过滤可以消除异常纹波
二、修改了负载启动的顺序,先开启辅助继电器使地相通,再开启D+D-继电器 feat: 发布V1.1.23版本,优化负载初始化继电器时序 - 更新所有头文件版本号至V1.1.21~V1.1.23,协议板固件版本更新为0x0127 - 新增纹波滤波相关宏定义与函数,实现继电器闭合后纹波过滤 - 调整负载初始化流程:先下发辅助继电器,等待回码后延迟30ms再打开北向继电器 - 优化D+/D-寄存器上位机显示单位,适配0.001V解析格式 - 补充YMODEM升级文档说明,完善传输校验与重发规则 - 清理冗余调试打印与Allegro工程日志文件
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_comm.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.19
|
||||
当前版本号 : V1.1.23
|
||||
主要功能 : 实现对外通讯协议 MODBUS 服务端,以独立线程等待处理响应请求数据。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "stm32f4xx_hal.h"
|
||||
|
||||
#define HOLD_REG_FIRMWARE_VERSION 0x0300U /* 协议板固件版本,只读 */
|
||||
#define CHRG_FIRMWARE_VERSION 0x0123U /* 当前协议板版本:V1.1.19 */
|
||||
#define CHRG_FIRMWARE_VERSION 0x0127U /* 当前协议板版本:V1.1.23 */
|
||||
|
||||
rt_uint8_t ucDiscInBuf[(TOTAL_DISC_REGS+BITS_UCHAR-1)/BITS_UCHAR];
|
||||
rt_uint8_t ucCoilBuf[(TOTAL_COIL_REGS+BITS_UCHAR-1)/BITS_UCHAR];
|
||||
@@ -618,7 +618,7 @@ eMBException funcReadHoldingRegister (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
|
||||
|
||||
/*
|
||||
* 协议板版本号使用独立的只读地址0x0300,不占用现有通道保持寄存器空间。
|
||||
* 当前版本V1.1.19编码为0x0123,Modbus响应按高字节在前返回01 23。
|
||||
* 当前版本V1.1.23编码为0x0127,Modbus响应按高字节在前返回01 27。
|
||||
* 该特殊地址只支持一次读取一个寄存器,避免与普通连续寄存器混用。
|
||||
*/
|
||||
if (regAddress == HOLD_REG_FIRMWARE_VERSION) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_comm.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.19
|
||||
当前版本号 : V1.1.21
|
||||
主要功能 : 实现对外通讯协议 MODBUS 服务端,以独立线程等待处理响应请求数据。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -233,6 +233,8 @@ void chrg_sink_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx,
|
||||
pSW->VZ = ((frame_data[14] << 8) | frame_data[15]);
|
||||
pSW->VF = ((frame_data[16] << 8) | frame_data[17]);
|
||||
|
||||
//rt_kprintf("VZ=%d,VF=%d\n",pSW->VZ,pSW->VF);
|
||||
|
||||
#if NORTH_SINK_DEBUG
|
||||
LOG_D("Sink[%d] real volt: %d mV", idx,
|
||||
((frame_data[4] << 8) | frame_data[5]) * 10);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_north.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.19
|
||||
当前版本号 : V1.1.21
|
||||
主要功能 : 实现北向通信交互,包括接收命令解析,发送请求命令,切换通路。以独立线程处理。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -28,12 +28,16 @@
|
||||
#endif
|
||||
|
||||
/* 南向COM批次中单通道连续收到有效回码后的最大发送条数。 */
|
||||
#define SOU_COM_BURST_MAX 8U
|
||||
#define SOU_COM_BURST_MAX 6U
|
||||
|
||||
/* 自动停止带载后,电压恢复时需要连续确认的新P1采样帧数。 */
|
||||
#define SINK_LOAD_RESTART_CONFIRM_COUNT 3U
|
||||
|
||||
#define THR_NAME_NORTH "thr.nor"
|
||||
/* 主继电器闭合后的纹波瞬态过滤参数,单位为新的P1采样帧。 */
|
||||
#define RIPPLE_RELAY_IGNORE_P1_COUNT 5U
|
||||
#define RIPPLE_MEDIAN_WINDOW_SIZE 3U
|
||||
|
||||
#define THR_NAME_NORTH "thr.nor"
|
||||
#define DEV_NAME_NORTH "uart3"
|
||||
|
||||
#define LEN_FRAME_HEAD (4) // [帧长, 0x00, id, 命令]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_roll_sou.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.14
|
||||
当前版本号 : V1.1.22
|
||||
主要功能 : 实现南向通信轮巡请求命令。以独立线程处理。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -619,6 +619,13 @@ static int sou_com_batch_complete(rt_uint8_t ch, rt_uint16_t reg, rt_uint16_t va
|
||||
}
|
||||
|
||||
pBatch->cur_idx++;
|
||||
if ((reg == REG_REL_ON) &&
|
||||
(((value & MAIN_REL_ON) != 0U) || (value == FU_REL_ON))) {
|
||||
chrg_eload_ripple_filter_relay_start(ch);
|
||||
}
|
||||
if ((reg == REG_WORK) && (value == WORK_STOP)) {
|
||||
chrg_eload_ripple_filter_relay_stop(ch);
|
||||
}
|
||||
/* 暂时关闭副继电器与主继电器之间的固定延时;需要恢复时重新启用本段。 */
|
||||
if ((reg == REG_REL_ON) && (value == ALL_REL_OFF) &&
|
||||
(pBatch->cur_idx < pBatch->reg_cnt) &&
|
||||
@@ -983,6 +990,15 @@ void chrg_roll_sou_thread_entry (void *data)
|
||||
"batch changed", &retry_count[batch_ch]);
|
||||
}
|
||||
} else if (run != RUN_AUTO) {
|
||||
if ((run == RUN_LCD) && (single_reg == REG_REL_ON) &&
|
||||
(((single_value & MAIN_REL_ON) != 0U) ||
|
||||
(single_value == FU_REL_ON))) {
|
||||
chrg_eload_ripple_filter_relay_start(single_ch);
|
||||
}
|
||||
if ((run == RUN_LCD) && (single_reg == REG_WORK) &&
|
||||
(single_value == WORK_STOP)) {
|
||||
chrg_eload_ripple_filter_relay_stop(single_ch);
|
||||
}
|
||||
sou_single_command_finish(run);
|
||||
} else {
|
||||
if (version_probe) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_roll_sou.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.21
|
||||
主要功能 : 实现南向通信轮巡请求命令。以独立线程处理。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_eload.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.22
|
||||
主要功能 : 源载命令数据解析,封装,读写请求。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -20,6 +20,14 @@
|
||||
#include "chrg_south.h"
|
||||
|
||||
#define ELOAD_VALID_VOLTAGE_MIN_MV 2000U
|
||||
#define DPDM_HOST_READ_SCALE 10U
|
||||
|
||||
static rt_uint16_t chrg_eload_dpdm_host_value(rt_uint16_t value)
|
||||
{
|
||||
rt_uint32_t scaled_value = (rt_uint32_t)value * DPDM_HOST_READ_SCALE;
|
||||
|
||||
return (scaled_value > 0xFFFFU) ? 0xFFFFU : (rt_uint16_t)scaled_value;
|
||||
}
|
||||
|
||||
extern void LCD_SHOW(rt_uint8_t idx, struct eload_p1_t *pP1, struct chrg_eload_t *pLOAD, struct chrg_switch_t *pSW, rt_uint8_t online);
|
||||
|
||||
@@ -41,9 +49,104 @@ rt_uint32_t chrg_eload_get_sample_seq(rt_uint8_t idx)
|
||||
}
|
||||
return g_eload_sample_seq[idx];
|
||||
}
|
||||
static rt_uint16_t ripple_base[TOTAL_SOU_CHS] = {0};
|
||||
static rt_uint8_t ripple_cal_flag[TOTAL_SOU_CHS] = {0};
|
||||
rt_uint16_t real_ripple[TOTAL_SOU_CHS] = {0};
|
||||
typedef struct {
|
||||
rt_uint16_t samples[RIPPLE_MEDIAN_WINDOW_SIZE];
|
||||
rt_uint16_t filtered_value;
|
||||
rt_uint8_t sample_count;
|
||||
rt_uint8_t sample_next;
|
||||
rt_uint8_t ignore_count;
|
||||
rt_uint8_t ignore_total;
|
||||
rt_tick_t relay_start_tick;
|
||||
rt_uint32_t frame_count;
|
||||
rt_bool_t relay_started;
|
||||
} chrg_ripple_filter_t;
|
||||
|
||||
static chrg_ripple_filter_t g_ripple_filter[TOTAL_SOU_CHS] = {0};
|
||||
|
||||
static rt_uint16_t chrg_eload_ripple_median(rt_uint16_t value0,
|
||||
rt_uint16_t value1, rt_uint16_t value2)
|
||||
{
|
||||
if (value0 > value1) {
|
||||
rt_uint16_t temp = value0;
|
||||
value0 = value1;
|
||||
value1 = temp;
|
||||
}
|
||||
if (value1 > value2) {
|
||||
rt_uint16_t temp = value1;
|
||||
value1 = value2;
|
||||
value2 = temp;
|
||||
}
|
||||
if (value0 > value1) {
|
||||
value1 = value0;
|
||||
}
|
||||
return value1;
|
||||
}
|
||||
|
||||
static rt_uint16_t chrg_eload_ripple_filter_update(rt_uint8_t idx,
|
||||
rt_uint16_t raw_value)
|
||||
{
|
||||
chrg_ripple_filter_t *pFilter = &g_ripple_filter[idx];
|
||||
|
||||
pFilter->frame_count++;
|
||||
|
||||
if (pFilter->ignore_count > 0U) {
|
||||
pFilter->ignore_count--;
|
||||
return pFilter->filtered_value;
|
||||
}
|
||||
pFilter->samples[pFilter->sample_next] = raw_value;
|
||||
pFilter->sample_next = (pFilter->sample_next + 1U) % RIPPLE_MEDIAN_WINDOW_SIZE;
|
||||
if (pFilter->sample_count < RIPPLE_MEDIAN_WINDOW_SIZE) {
|
||||
pFilter->sample_count++;
|
||||
}
|
||||
if (pFilter->sample_count < RIPPLE_MEDIAN_WINDOW_SIZE) {
|
||||
pFilter->filtered_value = raw_value;
|
||||
} else {
|
||||
pFilter->filtered_value = chrg_eload_ripple_median(
|
||||
pFilter->samples[0], pFilter->samples[1], pFilter->samples[2]);
|
||||
}
|
||||
return pFilter->filtered_value;
|
||||
}
|
||||
|
||||
void chrg_eload_ripple_filter_reset(rt_uint8_t idx)
|
||||
{
|
||||
chrg_ripple_filter_t *pFilter;
|
||||
|
||||
if (idx >= TOTAL_SOU_CHS) {
|
||||
return;
|
||||
}
|
||||
pFilter = &g_ripple_filter[idx];
|
||||
pFilter->sample_count = 0U;
|
||||
pFilter->sample_next = 0U;
|
||||
pFilter->ignore_count = (rt_uint8_t)RIPPLE_RELAY_IGNORE_P1_COUNT;
|
||||
pFilter->ignore_total = pFilter->ignore_count;
|
||||
}
|
||||
|
||||
void chrg_eload_ripple_filter_relay_start(rt_uint8_t idx)
|
||||
{
|
||||
chrg_ripple_filter_t *pFilter;
|
||||
|
||||
if (idx >= TOTAL_SOU_CHS) {
|
||||
return;
|
||||
}
|
||||
pFilter = &g_ripple_filter[idx];
|
||||
chrg_eload_ripple_filter_reset(idx);
|
||||
pFilter->relay_start_tick = rt_tick_get();
|
||||
pFilter->frame_count = 0U;
|
||||
pFilter->relay_started = RT_TRUE;
|
||||
}
|
||||
|
||||
void chrg_eload_ripple_filter_relay_stop(rt_uint8_t idx)
|
||||
{
|
||||
chrg_ripple_filter_t *pFilter;
|
||||
|
||||
if (idx >= TOTAL_SOU_CHS) {
|
||||
return;
|
||||
}
|
||||
pFilter = &g_ripple_filter[idx];
|
||||
pFilter->relay_started = RT_FALSE;
|
||||
pFilter->relay_start_tick = 0U;
|
||||
pFilter->frame_count = 0U;
|
||||
}
|
||||
|
||||
/* ======================== Ymodem 升级应答缓存 ======================== */
|
||||
static rt_uint8_t g_eload_ymodem_resp = 0; // 南向返回的ymodem应答字节(0=无应答)
|
||||
@@ -360,7 +463,8 @@ int chrg_eload_parse (rt_uint8_t idx, rt_uint8_t pt, rt_uint8_t *data, rt_uint16
|
||||
pLOAD->vpkp = swap_u16(pP1->Vpkp);
|
||||
pLOAD->vpkn = swap_u16(pP1->Vpkn);
|
||||
pLOAD->vpp = swap_u16(pP1->Vpp);
|
||||
pLOAD->Ripple = swap_u16(pP1->Ripple);
|
||||
pLOAD->Ripple = chrg_eload_ripple_filter_update(idx,
|
||||
swap_u16(pP1->Ripple));
|
||||
/* 保留功率板返回的真实电流,供卸载保护判断使用。 */
|
||||
pSW->Now_current = pLOAD->current;
|
||||
/*
|
||||
@@ -374,6 +478,7 @@ int chrg_eload_parse (rt_uint8_t idx, rt_uint8_t pt, rt_uint8_t *data, rt_uint16
|
||||
pLOAD->vpkn = 0;
|
||||
pLOAD->vpp = 0;
|
||||
pLOAD->Ripple = 0;
|
||||
chrg_eload_ripple_filter_reset(idx);
|
||||
pSW->VZ = 0;
|
||||
pSW->VF = 0;
|
||||
}
|
||||
@@ -415,8 +520,11 @@ int chrg_eload_parse (rt_uint8_t idx, rt_uint8_t pt, rt_uint8_t *data, rt_uint16
|
||||
usRegHoldBuf[HOLD_REG_CH0_VPKN+idx*TOTAL_HOLD_CH_REGS] = pLOAD->vpkn;
|
||||
usRegHoldBuf[HOLD_REG_CH0_VPP+idx*TOTAL_HOLD_CH_REGS] = pLOAD->vpp;
|
||||
usRegHoldBuf[HOLD_REG_CH0_Ripple+idx*TOTAL_HOLD_CH_REGS] = pLOAD->Ripple;
|
||||
usRegHoldBuf[HOLD_REG_CH0_VZ+idx*TOTAL_HOLD_CH_REGS] = pSW->VZ;
|
||||
usRegHoldBuf[HOLD_REG_CH0_VF+idx*TOTAL_HOLD_CH_REGS] = pSW->VF;
|
||||
/* 上位机D+/D-寄存器按0.001V解释,内部/LCD仍保持0.01V原始值。 */
|
||||
usRegHoldBuf[HOLD_REG_CH0_VZ+idx*TOTAL_HOLD_CH_REGS] =
|
||||
chrg_eload_dpdm_host_value(pSW->VZ);
|
||||
usRegHoldBuf[HOLD_REG_CH0_VF+idx*TOTAL_HOLD_CH_REGS] =
|
||||
chrg_eload_dpdm_host_value(pSW->VF);
|
||||
// rt_kprintf("---------NOW VOLT END = %d\n----------",pSW->Now_voltage);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_eload.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.22
|
||||
主要功能 : 源载命令数据解析,封装,读写请求,寄存器定义,数据结构定义。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -299,6 +299,9 @@ extern int chrg_eload_parse_version (rt_uint8_t idx, rt_uint8_t *data, rt_uint16
|
||||
其它说明: 每成功解析一帧P1数据后递增,用于区分控制命令前后的新旧量测
|
||||
*****************************************************************/
|
||||
extern rt_uint32_t chrg_eload_get_sample_seq(rt_uint8_t idx);
|
||||
extern void chrg_eload_ripple_filter_reset(rt_uint8_t idx);
|
||||
extern void chrg_eload_ripple_filter_relay_start(rt_uint8_t idx);
|
||||
extern void chrg_eload_ripple_filter_relay_stop(rt_uint8_t idx);
|
||||
// 定义2条继电器指令,控制主继电器和滤波继电器(保留原有有效指令,移除未使用的停止指令)
|
||||
static const rt_uint8_t EXTRA_CMD_SOURCE[8] = {0x03, 0x06, 0x00, 0x01, 0x00, 0x01, 0x18, 0x28};
|
||||
extern int chrg_eload_send_relay(rt_uint8_t cmd_type);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_sink.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.19
|
||||
当前版本号 : V1.1.21
|
||||
主要功能 : 北向数据sink请求数据填充及发送。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -24,6 +24,15 @@
|
||||
#define SINK_UNLOAD_CURRENT_MAX_MA 200U // 判定负载已安全卸载的最大实际电流
|
||||
#define SINK_UNLOAD_CONFIRM_COUNT 2U // 连续满足低电流条件的量测帧数
|
||||
#define SINK_SHORT_KEEPALIVE_MS 30U // 短路测试WORK_START保活下发周期
|
||||
#define SINK_INIT_NORTH_RELAY_DELAY_MS 30U // 辅助继电器回码后打开北向继电器的等待时间
|
||||
|
||||
#define SINK_INIT_STAGE_CLEAR_RELAY 0U
|
||||
#define SINK_INIT_STAGE_AUX_RELAY 1U
|
||||
#define SINK_INIT_STAGE_DELAY 2U
|
||||
#define SINK_INIT_STAGE_REST 3U
|
||||
|
||||
static rt_uint8_t g_sink_init_stage[TOTAL_SOU_CHS] = {0};
|
||||
static rt_tick_t g_sink_init_north_relay_tick[TOTAL_SOU_CHS] = {0};
|
||||
|
||||
/* 主继电器闭合跟踪:1=已提交ALL_REL_ON(主继电器应已闭合) 0=未闭合/已断开。
|
||||
* 用于0V硬保护区分"首次开载/握手恢复"(主继电器未闭合,Now_voltage=0属正常)
|
||||
@@ -241,31 +250,12 @@ int sink_set_pd (rt_uint8_t pd, rt_uint8_t *buf)
|
||||
return chrg_north_send(frame, len);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
函数名称: chrg_sink_work_init
|
||||
函数描述: 执行负载INIT入口,将副继电器和初始化命令按顺序提交南向
|
||||
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
|
||||
输出参数: 立即打开北向Sink继电器和enable,并进入INIT_AUX_WAIT后台确认
|
||||
返回说明: 0:初始化批次提交成功 <0:参数或命令提交失败
|
||||
其它说明: 南向顺序为FU_REL_ON、CURRENT=0、MODE、VON和可选测试停止;
|
||||
北向按“CC线->协议->电压查询”顺序执行,南北向从批次入队后并行执行
|
||||
*****************************************************************/
|
||||
static int chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
static rt_uint8_t chrg_sink_init_build_commands(struct chrg_switch_t *pSW,
|
||||
rt_uint16_t *regs, rt_uint16_t *vals)
|
||||
{
|
||||
struct chrg_north_t *pNOR = &chrgnorth;
|
||||
rt_uint16_t regs[6];
|
||||
rt_uint16_t vals[6];
|
||||
rt_bool_t first_start;
|
||||
rt_uint8_t count;
|
||||
|
||||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||||
return -1;
|
||||
}
|
||||
/* COM进入INIT前已经设置On_work,使用原工作状态区分首次提交和后台重试。 */
|
||||
first_start = (pSW->sink.work_mode != SINK_WORK_INIT_AUX_WAIT) ?
|
||||
RT_TRUE : RT_FALSE;
|
||||
if (pSW->sink.test.test_mode_old == SINK_TEST_SHORT) {
|
||||
/* 短路测试退出:先断开全部继电器,再打开辅助继电器,最后停止短路测试。 */
|
||||
regs[0] = REG_REL_ON; vals[0] = ALL_REL_OFF;
|
||||
regs[1] = REG_REL_ON; vals[1] = FU_REL_ON;
|
||||
regs[2] = REG_CURRENT_OUT + 1; vals[2] = 0;
|
||||
@@ -289,18 +279,70 @@ static int chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
vals[count++] = ModbusRTU_DYNA_CMD_MODE_STOP;
|
||||
}
|
||||
}
|
||||
if (chrg_sou_com_batch_submit(idx, regs, vals, count) != 0) {
|
||||
return count;
|
||||
}
|
||||
|
||||
static int chrg_sink_init_submit_stage(eIDX_SOU_CH idx,
|
||||
struct chrg_switch_t *pSW)
|
||||
{
|
||||
rt_uint16_t regs[6];
|
||||
rt_uint16_t vals[6];
|
||||
rt_uint8_t total;
|
||||
rt_uint8_t start;
|
||||
rt_uint8_t count;
|
||||
rt_bool_t short_exit;
|
||||
|
||||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||||
return -1;
|
||||
}
|
||||
total = chrg_sink_init_build_commands(pSW, regs, vals);
|
||||
short_exit = (pSW->sink.test.test_mode_old == SINK_TEST_SHORT) ?
|
||||
RT_TRUE : RT_FALSE;
|
||||
|
||||
switch (g_sink_init_stage[idx]) {
|
||||
case SINK_INIT_STAGE_CLEAR_RELAY:
|
||||
start = 0U;
|
||||
count = 1U;
|
||||
break;
|
||||
case SINK_INIT_STAGE_AUX_RELAY:
|
||||
start = short_exit ? 1U : 0U;
|
||||
count = 1U;
|
||||
break;
|
||||
case SINK_INIT_STAGE_REST:
|
||||
start = short_exit ? 2U : 1U;
|
||||
count = (rt_uint8_t)(total - start);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return chrg_sou_com_batch_submit(idx, ®s[start], &vals[start], count);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
函数名称: chrg_sink_work_init
|
||||
函数描述: 执行负载INIT入口,先提交辅助继电器命令
|
||||
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
|
||||
输出参数: 进入INIT_AUX_WAIT后台等待辅助继电器回码
|
||||
返回说明: 0:初始化命令提交成功 <0:参数或命令提交失败
|
||||
其它说明: 收到01 02有效回码后等待30ms,再打开北向Sink继电器
|
||||
*****************************************************************/
|
||||
static int chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
{
|
||||
rt_bool_t short_exit;
|
||||
|
||||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||||
return -1;
|
||||
}
|
||||
short_exit = (pSW->sink.test.test_mode_old == SINK_TEST_SHORT) ?
|
||||
RT_TRUE : RT_FALSE;
|
||||
g_sink_init_stage[idx] = short_exit ? SINK_INIT_STAGE_CLEAR_RELAY :
|
||||
SINK_INIT_STAGE_AUX_RELAY;
|
||||
g_sink_init_north_relay_tick[idx] = 0U;
|
||||
if (chrg_sink_init_submit_stage(idx, pSW) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pSW->sink.On_work = 1;
|
||||
if (first_start) {
|
||||
/* 南向批次已入队,北向按“CC->协议”顺序立即开始完整握手。 */
|
||||
chrg_nor_sw_rel((eIDX_NOR_CH)idx, ID_SINK);
|
||||
pNOR->enable[idx] = 1;
|
||||
/* Protocol-before-CC test flow is disabled in this version. */
|
||||
pSW->sub = IDX_SET_SINK_CC_BEFORE_PD;
|
||||
}
|
||||
pSW->sink.work_mode = SINK_WORK_INIT_AUX_WAIT;
|
||||
return 0;
|
||||
}
|
||||
@@ -316,6 +358,7 @@ static int chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
static int chrg_sink_work_init_aux_wait(eIDX_SOU_CH idx,
|
||||
struct chrg_switch_t *pSW)
|
||||
{
|
||||
struct chrg_north_t *pNOR = &chrgnorth;
|
||||
struct chrg_south_t *pSOU = &chrgsouth;
|
||||
int batch_result;
|
||||
|
||||
@@ -325,10 +368,34 @@ static int chrg_sink_work_init_aux_wait(eIDX_SOU_CH idx,
|
||||
if (chrg_sou_com_batch_is_pending(idx)) {
|
||||
return 0;
|
||||
}
|
||||
if (g_sink_init_stage[idx] == SINK_INIT_STAGE_DELAY) {
|
||||
if ((rt_int32_t)(rt_tick_get() -
|
||||
g_sink_init_north_relay_tick[idx]) < 0) {
|
||||
return 0;
|
||||
}
|
||||
chrg_nor_sw_rel((eIDX_NOR_CH)idx, ID_SINK);
|
||||
rt_kprintf("-------D+D- OPEN------\n");
|
||||
pNOR->enable[idx] = 1;
|
||||
pSW->sub = IDX_SET_SINK_CC_BEFORE_PD;
|
||||
g_sink_init_stage[idx] = SINK_INIT_STAGE_REST;
|
||||
if (chrg_sink_init_submit_stage(idx, pSW) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
batch_result = chrg_sou_com_batch_get_result(idx);
|
||||
if (batch_result <= 0) {
|
||||
/* 北向保持当前事务,南向独立重试完整初始化批次。 */
|
||||
return chrg_sink_work_init(idx, pSW);
|
||||
return chrg_sink_init_submit_stage(idx, pSW);
|
||||
}
|
||||
if (g_sink_init_stage[idx] == SINK_INIT_STAGE_CLEAR_RELAY) {
|
||||
g_sink_init_stage[idx] = SINK_INIT_STAGE_AUX_RELAY;
|
||||
return chrg_sink_init_submit_stage(idx, pSW);
|
||||
}
|
||||
if (g_sink_init_stage[idx] == SINK_INIT_STAGE_AUX_RELAY) {
|
||||
g_sink_init_stage[idx] = SINK_INIT_STAGE_DELAY;
|
||||
g_sink_init_north_relay_tick[idx] = rt_tick_get() +
|
||||
rt_tick_from_millisecond(SINK_INIT_NORTH_RELAY_DELAY_MS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 北向可能已推进到CC或电压查询,此处只更新南向完成状态。 */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_sink.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.19
|
||||
当前版本号 : V1.1.23
|
||||
主要功能 : 北向数据sink请求数据填充及发送,命令字定义。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
+101
-949
File diff suppressed because it is too large
Load Diff
+921
-2487
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,57 @@
|
||||
# 修改日志
|
||||
|
||||
## V1.1.23 - 2026-09-11
|
||||
|
||||
### 负载初始化继电器时序调整
|
||||
|
||||
- 负载初始化先单独下发辅助继电器 `FU_REL_ON (0x01 0x02)`。
|
||||
- 只有收到匹配回码后,等待 `30ms` 才打开北向负载继电器。
|
||||
- 北向继电器打开后,再继续下发电流、模式、V_On等初始化参数。
|
||||
- 辅助继电器回码失败时只重发当前初始化阶段,不提前打开北向继电器。
|
||||
- 协议板版本号更新为 `V1.1.23`,固件版本寄存器更新为 `0x0127`。
|
||||
|
||||
### 待验证
|
||||
|
||||
- 上电初始化日志中确认先收到 `01 02`,约30ms后才出现北向继电器打开。
|
||||
- 辅助继电器无回码时确认北向继电器保持关闭。
|
||||
|
||||
## V1.1.22 - 2026-09-11
|
||||
|
||||
### 增加纹波滤波调试打印
|
||||
|
||||
- 记录每个通道主继电器闭合的 tick 和忽略帧配置。
|
||||
- 打印忽略帧的序号、原始纹波值及继电器闭合后的经过时间。
|
||||
- 打印实际进入滤波的帧序号、原始值、滤波值及经过时间。
|
||||
- 协议板版本号更新为 `V1.1.22`,固件版本寄存器更新为 `0x0126`。
|
||||
- 待验证:确认宏调整后忽略帧数量和实际进入滤波的时间同步变化。
|
||||
|
||||
## V1.1.21 - 2026-09-11
|
||||
|
||||
### 继电器切换纹波滤波
|
||||
|
||||
- 主继电器闭合回码成功后,忽略 `RIPPLE_RELAY_IGNORE_P1_COUNT` 个新P1采样帧;当前值为 `2U`,可在 `chrg_north.h` 中调整。
|
||||
- 后续纹波持续使用三点中值滤波,滤除单帧尖峰;连续异常纹波仍会正常显示。
|
||||
- LCD和上位机纹波寄存器统一使用滤波后的纹波值。
|
||||
- 协议板版本号更新为 `V1.1.21`,固件版本寄存器更新为 `0x0125`。
|
||||
|
||||
### 验证记录
|
||||
|
||||
- 待硬件验证:继电器闭合瞬间出现约500mV尖峰时,LCD和上位机不显示该尖峰;忽略2帧后再累计3帧并更新为稳定纹波。
|
||||
- 待硬件验证:持续三帧以上的高纹波仍能在LCD和上位机显示。
|
||||
|
||||
## V1.1.20 - 2026-09-10
|
||||
|
||||
### D+/D-上位机显示单位修正
|
||||
|
||||
- 上位机读取各通道 `D+`、`D-` 保持寄存器时,返回值由内部原始值放大 `10` 倍,适配上位机按 `0.001V` 解析。
|
||||
- LCD显示、北向回码解析及内部控制值保持原有 `0.01V` 单位,不受影响。
|
||||
- 增加16位寄存器上限保护,放大结果超过 `65535` 时返回 `65535`。
|
||||
- 协议板版本号更新为 `V1.1.20`,固件版本寄存器更新为 `0x0124`。
|
||||
|
||||
### 验证记录
|
||||
|
||||
- 待硬件验证:D+或D-内部值为 `260` 时,LCD继续显示 `2.60V`,上位机读取值为 `2600` 并显示 `2.600V`。
|
||||
|
||||
## V1.1.19 - 2026-09-10
|
||||
|
||||
### 短路测试绕过 V_ON 门槛
|
||||
|
||||
@@ -20,6 +20,21 @@
|
||||
- 上位机必须从偏移 0 开始以 `STX/1024` 发送;第一个 STX 是头区,真正 body 从第二个 STX 开始。
|
||||
- YMODEM 最后一帧的 `0x1A` 补齐仅属于传输层,不能计入文件大小、`raw_size` 或 `pkg_size`。
|
||||
|
||||
### YMODEM 1K 帧字节数
|
||||
|
||||
`STX/1024` 中的 `1024` 指数据区长度,不是串口线上完整帧长度。每个完整 STX 数据帧固定为 **1029 字节**:
|
||||
|
||||
```text
|
||||
STX 1 字节
|
||||
PacketNo 1 字节
|
||||
~PacketNo 1 字节
|
||||
Data 1024 字节
|
||||
CRC16 2 字节
|
||||
总计 1029 字节
|
||||
```
|
||||
|
||||
因此,UPK 首数据块和后续固件数据块的有效数据均为 1024 字节,实际串口发送时均应连续发送 1029 字节。YMODEM 元数据使用 SOH 帧,完整帧为 133 字节(128 字节数据区 + 5 字节控制/校验字段)。
|
||||
|
||||
界面中的“表头尺寸 `1024 (ymodem1k)`”应改名为“YMODEM 首数据块/头区尺寸”,并固定为 1024;UPK 逻辑头固定为 96,不能让用户修改。
|
||||
|
||||
## 3. 输入、分区与版本
|
||||
|
||||
@@ -56,8 +56,8 @@ CRC 覆盖 `Data` 的全部固定长度字节(128 或 1024),并按 **高
|
||||
1. 元数据包必须使用 `SOH`,`PacketNo=0x00`,反码为 `0xFF`。
|
||||
2. 首个文件数据包使用 `PacketNo=0x01`;每得到 ACK 后序号加 1,按 8 位自然回绕。
|
||||
3. 本 Boot 的 `.upk` 使用 1K 首数据块布局,因此文件数据包必须使用 `STX`(1024 字节);最后一包不足 1024 字节时仍应补齐到 1024 字节,建议补 `0x1A`。
|
||||
4. Boot 校验包号、包号反码、帧长度与 CRC。任一校验失败会回复 NAK。
|
||||
5. 收到 NAK 时,必须重发**原完整帧**,包号不得递增。该 Boot 不将“前一帧重复包”当作成功帧,因此不能依赖重复包自动 ACK。
|
||||
4. Boot 校验包号、包号反码、帧长度与 CRC。任一校验失败会立即回复 NAK;当前 Boot 随后会重置 YMODEM 包号和流程。
|
||||
5. 对于业务层处理失败产生的 NAK,可以重发**原完整帧**,包号不得递增。对于 CRC、包号或帧长度错误产生的 NAK,不能只重发当前帧,必须重新进入 Boot 并从元数据包开始完整传输。
|
||||
|
||||
## 5. 元数据包规则
|
||||
|
||||
@@ -171,7 +171,7 @@ WAIT_END_ACK
|
||||
| 事件 | 上位机处理 |
|
||||
| --- | --- |
|
||||
| 收到 ACK | 仅推进到下一协议状态;数据包 ACK 后才递增包号 |
|
||||
| 收到明确 NAK | 重发当前完整帧;建议最多连续 3 次 |
|
||||
| 收到明确 NAK | 业务层 NAK 可重发当前完整帧;协议校验 NAK 应重新进入 Boot,从元数据包开始传输 |
|
||||
| 等待 ACK 超时 | 标记“传输结果不确定”,停止本次会话;重新进入 Boot 后从元数据包开始完整传输 |
|
||||
| 明确 NAK 重发耗尽 | 发送 CAN 两次,标记升级传输失败 |
|
||||
| 收到 CAN | 立即停止,标记 Boot 取消升级 |
|
||||
@@ -180,7 +180,7 @@ WAIT_END_ACK
|
||||
|
||||
Boot 对单个 CAN 会进入取消流程并回 ACK;上位机仍建议按标准发送两个 CAN,并接受可能出现的 ACK。
|
||||
|
||||
> **当前 Boot 的可靠性限制:** 成功接收一个数据包后,Boot 已把期望包号加一;若该包的 ACK 在串口上丢失,上位机重发同一包会被 Boot 判为“重复包”并回复 NAK,而不是再次回复 ACK。因此“ACK 超时后无条件重发当前包”不能可靠恢复。本文规则可在直连、稳定的串口环境中正常升级;若要支持 ACK 丢失后的可靠自动重发,需要修改 Boot,使其收到“期望包号减一”的重复帧且 CRC 正确时直接回复 ACK、不再次写入数据。
|
||||
> **当前 Boot 的可靠性限制:** 成功接收一个数据包后,Boot 已把期望包号加一;若该包的 ACK 在串口上丢失,上位机重发同一包会被 Boot 判为“重复包”并回复 NAK,同时触发 YMODEM 重置。因此“ACK 超时后无条件重发当前包”不能可靠恢复,必须重新进入 Boot 并从元数据包开始传输。若要支持当前会话内的可靠自动重发,需要修改 Boot,使其保留期望包号,并对 CRC 正确的重复帧直接回复 ACK、不再次写入数据。
|
||||
|
||||
`WAIT_*_ACK` 的建议超时为 3~10 秒,元数据后的 `WAIT_C_DATA`、结束阶段的 `WAIT_C_END` 建议为 10 秒。上位机可将串口接收设计为持续缓存并按字节解析,忽略调试文本或仅识别 `C/ACK/NAK/CAN` 控制字符,避免因分段到达造成误判。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user