短路测试增加先下发V_ON为500mv的逻辑。让充电头一带电就打嗝
切换协议和CC线时,将V_ON设置顺序调整,避免指令被清楚 feat: 发布V1.1.19版本,优化短路测试与电压恢复逻辑 1. 更新所有文件版本号到V1.1.19,固件版本寄存器改为0x0123 2. 新增短路测试最低启动电压宏,设置为500mV,绕过普通V_ON门槛 3. 调整南向COM单次最大发送条数为8条,优化通信批次 4. 重构电压稳定确认逻辑,新增自动停止后恢复确认计数 5. 优化协议软卸载与完整握手流程,统一下发WORK_STOP和V_ON命令 6. 新增修改日志文档,补充本次更新说明与验证项 7. 新增UPK打包规则与YMODEM上位机实现文档
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_comm.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.15
|
||||
当前版本号 : V1.1.19
|
||||
主要功能 : 实现对外通讯协议 MODBUS 服务端,以独立线程等待处理响应请求数据。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "stm32f4xx_hal.h"
|
||||
|
||||
#define HOLD_REG_FIRMWARE_VERSION 0x0300U /* 协议板固件版本,只读 */
|
||||
#define CHRG_FIRMWARE_VERSION 0x011FU /* 当前协议板版本:V1.1.15 */
|
||||
#define CHRG_FIRMWARE_VERSION 0x0123U /* 当前协议板版本:V1.1.19 */
|
||||
|
||||
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.15编码为0x011F,Modbus响应按高字节在前返回01 1F。
|
||||
* 当前版本V1.1.19编码为0x0123,Modbus响应按高字节在前返回01 23。
|
||||
* 该特殊地址只支持一次读取一个寄存器,避免与普通连续寄存器混用。
|
||||
*/
|
||||
if (regAddress == HOLD_REG_FIRMWARE_VERSION) {
|
||||
@@ -2589,7 +2589,13 @@ static eMBException chrg_comm_apply_sink_effect(rt_uint8_t ch,
|
||||
protocol_voltage_only = diff_info.pro_voltage_changed &&
|
||||
!full_handshake_change && !protocol_current_change;
|
||||
von_changed = (pReal->sink.volt_on != pShadow->sink.volt_on);
|
||||
if ((sink_work == 0x01) && (old_on_work == 1U) && von_changed) {
|
||||
/* 完整握手或协议软卸载会先清理本通道批次,V_ON由对应状态机在
|
||||
* WORK_STOP之后重新加入;普通参数变化仍在这里立即下发。 */
|
||||
if ((sink_work == 0x01) && (old_on_work == 1U) && von_changed &&
|
||||
!full_handshake_change && !protocol_voltage_only &&
|
||||
!protocol_current_change &&
|
||||
(pReal->sink.test.test_mode != SINK_TEST_SHORT) &&
|
||||
(pShadow->sink.test.test_mode != SINK_TEST_SHORT)) {
|
||||
rt_uint16_t reg = Eload_Start_V_ON;
|
||||
rt_uint16_t val = (pShadow->sink.volt_on <= 500U) ?
|
||||
500U : pShadow->sink.volt_on;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_comm.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.15
|
||||
当前版本号 : V1.1.19
|
||||
主要功能 : 实现对外通讯协议 MODBUS 服务端,以独立线程等待处理响应请求数据。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_north.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.14
|
||||
当前版本号 : V1.1.19
|
||||
主要功能 : 实现北向通信交互,包括接收命令解析,发送请求命令,切换通路。以独立线程处理。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -28,7 +28,10 @@
|
||||
#endif
|
||||
|
||||
/* 南向COM批次中单通道连续收到有效回码后的最大发送条数。 */
|
||||
#define SOU_COM_BURST_MAX 10U
|
||||
#define SOU_COM_BURST_MAX 8U
|
||||
|
||||
/* 自动停止带载后,电压恢复时需要连续确认的新P1采样帧数。 */
|
||||
#define SINK_LOAD_RESTART_CONFIRM_COUNT 3U
|
||||
|
||||
#define THR_NAME_NORTH "thr.nor"
|
||||
#define DEV_NAME_NORTH "uart3"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_sink.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.14
|
||||
当前版本号 : V1.1.19
|
||||
主要功能 : 北向数据sink请求数据填充及发送。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -41,10 +41,12 @@ static rt_tick_t g_sink_unload_query_tick[TOTAL_SOU_CHS] = {0};
|
||||
static rt_uint8_t g_sink_unload_confirm_count[TOTAL_SOU_CHS] = {0};
|
||||
/* 记录各通道短路测试最近一次WORK_START的发送时间。 */
|
||||
static rt_tick_t g_sink_short_start_tick[TOTAL_SOU_CHS] = {0};
|
||||
#if SINK_VON_VOLTAGE_SOURCE == SINK_VON_VOLTAGE_FROM_PROTOCOL
|
||||
/* 只消费新的协议板0x20电压回码,避免同一帧重复计入稳定次数。 */
|
||||
/* 只消费新的V_On电压采样,避免同一帧重复计入稳定确认。 */
|
||||
static rt_uint32_t g_sink_von_voltage_seq[TOTAL_SOU_CHS] = {0};
|
||||
#endif
|
||||
/* 协议切换期间清零,避免旧电压样本累计成启动确认。 */
|
||||
static rt_uint8_t g_sink_von_stable_count[TOTAL_SOU_CHS] = {0};
|
||||
/* 自动停止带载后的恢复确认计数,独立于首次握手的电压确认计数。 */
|
||||
static rt_uint8_t g_sink_load_restart_confirm_count[TOTAL_SOU_CHS] = {0};
|
||||
|
||||
enum {
|
||||
SINK_UNLOAD_NEXT_RUNNING = 0,
|
||||
@@ -447,9 +449,15 @@ static int chrg_sink_work_load_stop(eIDX_SOU_CH idx,
|
||||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||||
return -1;
|
||||
}
|
||||
/* 自动停止优先于同通道残留启动批次,禁止STOP后继续发送WORK_START。 */
|
||||
if (chrg_sou_com_batch_cancel(idx) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (chrg_sou_com_batch_submit(idx, ®, &val, 1U) != 0) {
|
||||
return -1;
|
||||
}
|
||||
g_sink_von_stable_count[idx] = 0U;
|
||||
g_sink_load_restart_confirm_count[idx] = 0U;
|
||||
pSW->sink.work_mode = SINK_WORK_LOAD_STANDBY;
|
||||
return 0;
|
||||
}
|
||||
@@ -665,15 +673,23 @@ static int chrg_sink_work_switch(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
*****************************************************************/
|
||||
static int chrg_sink_work_protocol_unload(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
{
|
||||
rt_uint16_t reg = REG_WORK;
|
||||
rt_uint16_t value = WORK_STOP;
|
||||
rt_uint16_t regs[2] = {REG_WORK, Eload_Start_V_ON};
|
||||
rt_uint16_t values[2];
|
||||
|
||||
if (chrg_sou_com_batch_submit(idx, ®, &value, 1U) != 0) {
|
||||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||||
return -1;
|
||||
}
|
||||
values[0] = WORK_STOP;
|
||||
values[1] = (pSW->sink.volt_on <= 500U) ? 500U : pSW->sink.volt_on;
|
||||
|
||||
if (chrg_sou_com_batch_submit(idx, regs, values, 2U) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* WORK_STOP回码只确认命令接收;还需连续读取两帧合格的实际电流。 */
|
||||
chrg_sink_unload_confirm_reset(idx);
|
||||
g_sink_von_stable_count[idx] = 0U;
|
||||
g_sink_load_restart_confirm_count[idx] = 0U;
|
||||
pSW->sink.work_mode = SINK_WORK_UNLOAD_WAIT;
|
||||
return 0;
|
||||
}
|
||||
@@ -683,31 +699,35 @@ static int chrg_sink_work_protocol_unload(eIDX_SOU_CH idx, struct chrg_switch_t
|
||||
函数描述: 执行协议或CC完整重握手前的南向安全断开和副继电器恢复
|
||||
输入参数: idx:南向功率板通道 pSW:当前通道控制结构体
|
||||
输出参数: 命令提交成功后进入SINK_WORK_HANDSHAKE_WAIT
|
||||
返回说明: 0:四条命令提交成功 <0:参数或命令提交失败
|
||||
其它说明: 命令顺序固定为WORK_STOP、CURRENT=1000mA、ALL_REL_OFF、FU_REL_ON;
|
||||
WORK_STOP已关闭电子负载,1000mA仅为功率板停止阶段保存的电流设定值;
|
||||
返回说明: 0:两条命令提交成功 <0:参数或命令提交失败
|
||||
其它说明: 命令顺序固定为WORK_STOP、Eload_Start_V_ON;
|
||||
WORK_STOP已关闭电子负载,V_ON随后更新到功率板;
|
||||
主副继电器全部断开并确认回码后再单独打开副继电器;
|
||||
北向Sink继电器保持接通,低电流确认完成后才允许重新握手
|
||||
*****************************************************************/
|
||||
static int chrg_sink_work_handshake_prepare(eIDX_SOU_CH idx,
|
||||
struct chrg_switch_t *pSW)
|
||||
{
|
||||
rt_uint16_t reg = REG_WORK;
|
||||
rt_uint16_t value = WORK_STOP;
|
||||
rt_uint16_t regs[2] = {REG_WORK, Eload_Start_V_ON};
|
||||
rt_uint16_t values[2];
|
||||
|
||||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||||
return -1;
|
||||
}
|
||||
values[0] = WORK_STOP;
|
||||
values[1] = (pSW->sink.volt_on <= 500U) ? 500U : pSW->sink.volt_on;
|
||||
/* 新CC/协议事务必须抢占本通道尚未发送的旧启动和设定命令。 */
|
||||
if (chrg_sou_com_batch_cancel(idx) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (chrg_sou_com_batch_submit(idx, ®, &value, 1U) != 0) {
|
||||
if (chrg_sou_com_batch_submit(idx, regs, values, 2U) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 协议或CC切换先停止电子负载,连续2次确认低电流后再操作继电器。 */
|
||||
chrg_sink_unload_confirm_reset(idx);
|
||||
g_sink_von_stable_count[idx] = 0U;
|
||||
g_sink_load_restart_confirm_count[idx] = 0U;
|
||||
pSW->sink.work_mode = SINK_WORK_HANDSHAKE_WAIT;
|
||||
return 0;
|
||||
}
|
||||
@@ -719,7 +739,7 @@ static int chrg_sink_work_handshake_prepare(eIDX_SOU_CH idx,
|
||||
full_handshake:RT_TRUE为完整重握手 RT_FALSE为协议参数软卸载
|
||||
输出参数: 确认成功后将sink.work_mode切换为SINK_WORK_WAIT
|
||||
返回说明: 0:继续等待或确认成功 <0:状态查询或优先量测请求失败
|
||||
其它说明: 软卸载只要求WORK_STOP收到匹配回码后建立量测基线;完整重握手
|
||||
其它说明: 软卸载要求WORK_STOP和V_ON收到匹配回码后建立量测基线;完整重握手
|
||||
还要求CURRENT=1000mA、ALL_REL_OFF和FU_REL_ON回码成功,但保持北向Sink继电器接通
|
||||
*****************************************************************/
|
||||
static int chrg_sink_work_current_wait(eIDX_SOU_CH idx,
|
||||
@@ -831,13 +851,14 @@ static int chrg_sink_TEST_DYNA_ON(rt_uint8_t ch, struct chrg_switch_t *pSW)
|
||||
*****************************************************************/
|
||||
static int chrg_sink_TEST_SHORT_ON(rt_uint8_t ch, struct chrg_switch_t *pSW)
|
||||
{
|
||||
rt_uint16_t regs[3] = {ModbusRTU_ShortTest_Hold_Time,ModbusRTU_ShortTest_CMD_MODE_FLAG, REG_WORK};
|
||||
rt_uint16_t vals[3] = {0,0,0};
|
||||
rt_uint16_t regs[4] = {Eload_Start_V_ON, ModbusRTU_ShortTest_Hold_Time,
|
||||
ModbusRTU_ShortTest_CMD_MODE_FLAG, REG_WORK};
|
||||
rt_uint16_t vals[4] = {SINK_SHORT_TEST_VON_MV, 0, 0, 0};
|
||||
/* 外部工程固定短路测试保持60秒且不带载。 */
|
||||
vals[0] = 60000;
|
||||
vals[1] = ModbusRTU_DYNA_CMD_MODE_RUN_NO_CURR;
|
||||
vals[2] = WORK_START;
|
||||
if (chrg_sou_com_batch_submit((eIDX_SOU_CH)ch, regs, vals, 3) == 0) {
|
||||
vals[1] = 60000;
|
||||
vals[2] = ModbusRTU_DYNA_CMD_MODE_RUN_NO_CURR;
|
||||
vals[3] = WORK_START;
|
||||
if (chrg_sou_com_batch_submit((eIDX_SOU_CH)ch, regs, vals, 4) == 0) {
|
||||
g_sink_short_start_tick[ch] = rt_tick_get();
|
||||
return 0;
|
||||
}
|
||||
@@ -897,10 +918,10 @@ static rt_uint16_t chrg_sink_von_voltage_get(const struct chrg_switch_t *pSW)
|
||||
int chrg_sink_volt_judge(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
{
|
||||
rt_uint8_t stable_confirm_count;
|
||||
rt_uint32_t voltage_seq;
|
||||
static rt_uint8_t volt_low[TOTAL_SOU_CHS] = {0};
|
||||
static rt_uint8_t no_curr[TOTAL_SOU_CHS] = {0};
|
||||
static rt_uint8_t volt_set_ok[TOTAL_SOU_CHS] = {0};
|
||||
static rt_uint8_t volt_stable_count[TOTAL_SOU_CHS] = {0};
|
||||
static rt_tick_t running_start_tick[TOTAL_SOU_CHS] = {0};
|
||||
rt_uint16_t von_voltage;
|
||||
|
||||
@@ -908,18 +929,32 @@ int chrg_sink_volt_judge(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
return -1;
|
||||
}
|
||||
#if SINK_VON_VOLTAGE_SOURCE == SINK_VON_VOLTAGE_FROM_PROTOCOL
|
||||
if (pSW->Sink_voltage_seq == g_sink_von_voltage_seq[idx]) {
|
||||
voltage_seq = pSW->Sink_voltage_seq;
|
||||
#else
|
||||
voltage_seq = chrg_eload_get_sample_seq(idx);
|
||||
#endif
|
||||
if (voltage_seq == g_sink_von_voltage_seq[idx]) {
|
||||
return chrg_sink_work(idx, pSW);
|
||||
}
|
||||
g_sink_von_voltage_seq[idx] = voltage_seq;
|
||||
/* 卸载和协议重配尚未完成时,旧电压只能用于推进安全流程,不能触发WORK_START。 */
|
||||
if ((pSW->sink.work_mode == SINK_WORK_UNLOAD_WAIT) ||
|
||||
(pSW->sink.work_mode == SINK_WORK_HANDSHAKE_WAIT) ||
|
||||
((pSW->sink.work_mode != SINK_WORK_RUNING) &&
|
||||
(pSW->sink.work_mode != SINK_WORK_LOAD_STANDBY) &&
|
||||
(pSW->sub != IDX_GET_SINK_VC))) {
|
||||
g_sink_von_stable_count[idx] = 0U;
|
||||
g_sink_load_restart_confirm_count[idx] = 0U;
|
||||
return chrg_sink_work(idx, pSW);
|
||||
}
|
||||
g_sink_von_voltage_seq[idx] = pSW->Sink_voltage_seq;
|
||||
#endif
|
||||
von_voltage = chrg_sink_von_voltage_get(pSW);
|
||||
stable_confirm_count = chrg_sink_voltage_confirm_count(
|
||||
pSW->sink.pro_loadv);
|
||||
|
||||
if ((pSW->sink.On_work == 1) && (pSW->sink.test.test_mode == 0)) {
|
||||
if (von_voltage <= WORK_MIN_VOLT) {
|
||||
volt_stable_count[idx] = 0;
|
||||
g_sink_von_stable_count[idx] = 0U;
|
||||
g_sink_load_restart_confirm_count[idx] = 0U;
|
||||
if (volt_set_ok[idx] == 1 && ++volt_low[idx] >= 50) {
|
||||
volt_set_ok[idx] = 0;
|
||||
no_curr[idx] = 0;
|
||||
@@ -933,47 +968,58 @@ int chrg_sink_volt_judge(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
pSW->change_flag = 0;
|
||||
if (pSW->sink.work_mode == SINK_WORK_LOW_MONITOR) {
|
||||
/* 副继电器恢复后首次重新检测到输入电压,只启动协议重握手。 */
|
||||
volt_stable_count[idx] = 0;
|
||||
g_sink_von_stable_count[idx] = 0U;
|
||||
no_curr[idx] = 0;
|
||||
pSW->sink.work_mode = SINK_WORK_WAIT;
|
||||
} else if ((pSW->sink.work_mode == SINK_WORK_LOW) ||
|
||||
(pSW->sink.work_mode == SINK_WORK_LOW_AUX_WAIT)) {
|
||||
/* 掉电安全批次完成前,不得进入RUNING。 */
|
||||
volt_stable_count[idx] = 0;
|
||||
g_sink_von_stable_count[idx] = 0U;
|
||||
no_curr[idx] = 0;
|
||||
} else if (von_voltage > pSW->sink.volt_on) {
|
||||
if ((pSW->sink.work_mode != SINK_WORK_RUNING) &&
|
||||
(pSW->sink.work_mode != SINK_WORK_LOAD_STANDBY)) {
|
||||
if (volt_stable_count[idx] < stable_confirm_count) {
|
||||
volt_stable_count[idx]++;
|
||||
if (g_sink_von_stable_count[idx] < stable_confirm_count) {
|
||||
g_sink_von_stable_count[idx]++;
|
||||
}
|
||||
if (volt_stable_count[idx] >= stable_confirm_count) {
|
||||
if (g_sink_von_stable_count[idx] >= stable_confirm_count) {
|
||||
/* 连续达到当前目标对应的确认帧数后进入RUNING。 */
|
||||
volt_stable_count[idx] = 0;
|
||||
g_sink_von_stable_count[idx] = 0U;
|
||||
pSW->sink.work_mode = SINK_WORK_RUNING;
|
||||
running_start_tick[idx] = rt_tick_get();
|
||||
no_curr[idx] = 0;
|
||||
}
|
||||
} else if (pSW->sink.work_mode == SINK_WORK_LOAD_STANDBY) {
|
||||
volt_stable_count[idx] = 0;
|
||||
no_curr[idx] = 0;
|
||||
if (chrg_sink_load_should_start(pSW)) {
|
||||
/* 因输入电压不足停止带载后,电压恢复时重新进入稳定确认。 */
|
||||
pSW->sink.work_mode = SINK_WORK_WAIT;
|
||||
/* 自动停止后只接受新的电压采样;达到恢复确认帧数才允许重启。 */
|
||||
if (g_sink_load_restart_confirm_count[idx] <
|
||||
SINK_LOAD_RESTART_CONFIRM_COUNT) {
|
||||
g_sink_load_restart_confirm_count[idx]++;
|
||||
}
|
||||
if (g_sink_load_restart_confirm_count[idx] >=
|
||||
SINK_LOAD_RESTART_CONFIRM_COUNT) {
|
||||
g_sink_load_restart_confirm_count[idx] = 0U;
|
||||
pSW->sink.work_mode = SINK_WORK_RUNING;
|
||||
running_start_tick[idx] = rt_tick_get();
|
||||
}
|
||||
} else {
|
||||
g_sink_load_restart_confirm_count[idx] = 0U;
|
||||
}
|
||||
} else if ((pSW->Now_current > 200) || (pSW->sink.loadc < 200)) {
|
||||
volt_stable_count[idx] = 0;
|
||||
g_sink_von_stable_count[idx] = 0U;
|
||||
no_curr[idx] = 0;
|
||||
} else if ((rt_tick_t)(rt_tick_get() - running_start_tick[idx]) >=
|
||||
rt_tick_from_millisecond(SINK_CURRENT_START_GRACE_MS)) {
|
||||
volt_stable_count[idx] = 0;
|
||||
g_sink_von_stable_count[idx] = 0U;
|
||||
if (++no_curr[idx] >= 2) {
|
||||
pSW->sink.work_mode = SINK_WORK_WAIT;
|
||||
no_curr[idx] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
volt_stable_count[idx] = 0;
|
||||
g_sink_von_stable_count[idx] = 0U;
|
||||
g_sink_load_restart_confirm_count[idx] = 0U;
|
||||
no_curr[idx] = 0;
|
||||
/* 配置电压源低于负载设置的V_On时,立即停止电子负载。 */
|
||||
if (pSW->sink.work_mode == SINK_WORK_RUNING) {
|
||||
@@ -985,7 +1031,7 @@ int chrg_sink_volt_judge(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
volt_low[idx] = 0;
|
||||
no_curr[idx] = 0;
|
||||
volt_set_ok[idx] = 0;
|
||||
volt_stable_count[idx] = 0;
|
||||
g_sink_von_stable_count[idx] = 0U;
|
||||
}
|
||||
return chrg_sink_work(idx, pSW);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_sink.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.14
|
||||
当前版本号 : V1.1.19
|
||||
主要功能 : 北向数据sink请求数据填充及发送,命令字定义。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -23,6 +23,8 @@ struct chrg_switch_t;
|
||||
#define SINK_TEST_DYNA 3
|
||||
/* 短路测试期间按该周期补发WORK_START,防止功率板因超时停止。 */
|
||||
#define SINK_SHORT_START_INTERVAL_MS 50U
|
||||
/* 短路测试不受普通V_ON门槛限制,功率板使用最低启动电压。 */
|
||||
#define SINK_SHORT_TEST_VON_MV 500U
|
||||
//短路测试结构体
|
||||
struct test_short {
|
||||
rt_uint16_t hold_time; // 短路测试时间
|
||||
@@ -212,8 +214,8 @@ enum {
|
||||
|
||||
/* Sink电压稳定确认参数,供chrg_sink_volt_judge使用。 */
|
||||
#define SINK_VOLT_5V_TARGET_MV 5000U
|
||||
#define SINK_VOLT_CONFIRM_NORMAL_COUNT 5U
|
||||
#define SINK_VOLT_CONFIRM_5V_COUNT 15U
|
||||
#define SINK_VOLT_CONFIRM_NORMAL_COUNT 3U
|
||||
#define SINK_VOLT_CONFIRM_5V_COUNT 12U
|
||||
#define SINK_CURRENT_START_GRACE_MS 200U
|
||||
|
||||
/* 主继电器闭合后的0V持续监控:由北向轮询线程每轮调用,掉电立即转掉电保护。 */
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
*** Using Compiler 'V6.16', folder: 'D:\keil mdk 2\ARM\ARMCLANG\Bin'
|
||||
Build target 'chrg'
|
||||
compiling chrg_north_pkg.c...
|
||||
compiling chrg_vcom.c...
|
||||
compiling chrg_thread.c...
|
||||
compiling chrg_lcd.c...
|
||||
compiling chrg_rel.c...
|
||||
compiling chrg_eload.c...
|
||||
compiling chrg_south.c...
|
||||
compiling chrg_sink.c...
|
||||
compiling chrg_north.c...
|
||||
compiling chrg_source.c...
|
||||
compiling chrg_roll_nor.c...
|
||||
compiling chrg_roll_sou.c...
|
||||
compiling chrg_comm.c...
|
||||
linking...
|
||||
Program Size: Code=151456 RO-data=15928 RW-data=9356 ZI-data=16052
|
||||
FromELF: creating hex file...
|
||||
After Build - User command #1: fromelf --bin .\build\keil\Obj\chrg.axf -o build/chrg.bin
|
||||
".\build\keil\Obj\chrg.axf" - 0 Error(s), 0 Warning(s).
|
||||
Build Time Elapsed: 00:00:05
|
||||
@@ -1,5 +1,60 @@
|
||||
# 修改日志
|
||||
|
||||
## V1.1.19 - 2026-09-10
|
||||
|
||||
### 短路测试绕过 V_ON 门槛
|
||||
|
||||
- 短路测试启动批次增加 `Eload_Start_V_ON=500mV`,保证5V输入时不因用户设置的6V V_ON而拒绝短路启动。
|
||||
- 短路测试期间忽略普通 V_ON 更新,保持功率板使用500mV短路启动门槛。
|
||||
- 退出短路测试时由初始化流程恢复用户设定的 V_ON。
|
||||
- 协议板版本号更新为 `V1.1.19`,固件版本寄存器更新为 `0x0123`。
|
||||
|
||||
### 验证记录
|
||||
|
||||
- 待硬件验证:V_ON=6V、输入PD5V时,短路模式仍能启动并按周期发送 `WORK_START`。
|
||||
- 待硬件验证:退出短路模式后,功率板恢复用户设定的 V_ON。
|
||||
|
||||
## V1.1.18 - 2026-09-10
|
||||
|
||||
### 修复 CC 切换时 V_ON 丢失
|
||||
|
||||
- 修复 V_ON 与 CC 线同时修改时,V_ON 命令先入队后被完整握手清队列取消的问题。
|
||||
- 协议软卸载和完整握手统一按 `WORK_STOP -> Eload_Start_V_ON` 顺序下发。
|
||||
- 握手或命令重试时会重新携带当前 V_ON,避免功率板继续使用旧阈值。
|
||||
- 协议板版本号更新为 `V1.1.18`,固件版本寄存器更新为 `0x0122`。
|
||||
|
||||
### 验证记录
|
||||
|
||||
- 待硬件验证:同时修改 V_ON 与 CC 线,确认功率板收到 `Eload_Start_V_ON`。
|
||||
- 待硬件验证:确认 CC 切换失败重试、协议电压切换和其他通道调度正常。
|
||||
|
||||
## V1.1.17 - 2026-09-10
|
||||
|
||||
### 协议切换期间禁止误启动
|
||||
|
||||
- 将 V_On 稳定确认计数提升为通道级状态,并在协议软卸载、完整握手和自动停止时清零。
|
||||
- `UNLOAD_WAIT`、`HANDSHAKE_WAIT` 以及协议配置未完成前,电压采样只推进安全流程,不允许进入 `RUNING` 或发送 `WORK_START`。
|
||||
- 协议/模式配置完成并回到 `IDX_GET_SINK_VC` 后,才重新累计 V_On 稳定确认帧,避免停止后约40ms因旧电压再次启动。
|
||||
- 协议板版本号更新为 `V1.1.17`,固件版本寄存器更新为 `0x0121`。
|
||||
|
||||
### 验证记录
|
||||
|
||||
- 待硬件验证:协议电压切换时确认 `WORK_STOP` 后、协议配置完成前不再出现 `WORK_START`。
|
||||
- 待硬件验证:确认协议切换、自动停止恢复和三个通道并行调度不受影响。
|
||||
|
||||
## V1.1.16 - 2026-09-09
|
||||
|
||||
### Sink 自动停止后的恢复保护
|
||||
|
||||
- 新增 `SINK_LOAD_RESTART_CONFIRM_COUNT`,位于 `chrg_north.h`,当前设为 `2U`。
|
||||
- 功率板电压作为 V_On 判定源时,仅消费新的 P1 采样帧,旧采样不再重复累计稳定次数。
|
||||
- 自动停止带载时取消本通道残留南向批次,再单独下发 `WORK_STOP`,避免残留 `WORK_START` 在停止后执行。
|
||||
- 自动恢复带载前必须收到连续 `2` 帧新的、满足 `V_On` 的电压采样。
|
||||
|
||||
### 验证记录
|
||||
|
||||
- 待硬件验证:触发 CH1 自动停止后,确认停止后 2 帧新P1到达前不再出现 `WORK_START`;同时确认其它通道南向命令正常调度。
|
||||
|
||||
## V1.1.15 - 2026-09-09
|
||||
|
||||
### 运行中 V_On 更新
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
# 协议板 Boot:UPK 打包规则
|
||||
|
||||
## 1. 适用范围
|
||||
|
||||
本文用于实现协议板 App 固件的 `.upk` 打包和解析工具,适配 `apps/boot` 当前 Boot。传输层 YMODEM 规则见[协议板Boot_YMODEM上位机实现规则.md](协议板Boot_YMODEM上位机实现规则.md)。
|
||||
|
||||
## 2. 1K 文件布局
|
||||
|
||||
当前 Boot 收到第一个文件数据帧时,只取其中前 96 字节作为 UPK 头,**会忽略该帧其余数据**。因此打包文件必须使用固定 1024 字节首数据块:
|
||||
|
||||
```text
|
||||
输出 .upk 文件
|
||||
偏移 0x000 ~ 0x05F : 96 字节 UPK 逻辑头
|
||||
偏移 0x060 ~ 0x3FF : 928 字节 0x00 填充
|
||||
偏移 0x400 起 : package body(未加密 BIN 或 AES 加密后的 body)
|
||||
```
|
||||
|
||||
- `.upk` 实际文件大小:`1024 + pkg_size`。
|
||||
- YMODEM 元数据包的文件大小必须为上述实际文件大小。
|
||||
- 上位机必须从偏移 0 开始以 `STX/1024` 发送;第一个 STX 是头区,真正 body 从第二个 STX 开始。
|
||||
- YMODEM 最后一帧的 `0x1A` 补齐仅属于传输层,不能计入文件大小、`raw_size` 或 `pkg_size`。
|
||||
|
||||
界面中的“表头尺寸 `1024 (ymodem1k)`”应改名为“YMODEM 首数据块/头区尺寸”,并固定为 1024;UPK 逻辑头固定为 96,不能让用户修改。
|
||||
|
||||
## 3. 输入、分区与版本
|
||||
|
||||
| 项目 | 规则 |
|
||||
| --- | --- |
|
||||
| 输入文件 | 仅协议板 App 裸 `bin`,例如 `apps/chrg/build/chrg.bin`;拒绝 `.hex`、`.elf`、已有 `.upk`。 |
|
||||
| `name[4]` | 固定 ASCII `upk\0`。 |
|
||||
| `part_name[16]` | 仅允许 `app`、`download`、`factory`,ASCII NUL 结尾;协议板常规升级默认 `app`,Boot 会修正为 `download` 后安装到 `app`。 |
|
||||
| `fw_old_ver[16]` | 目标设备当前版本,前 4 字节为数值 `major, minor, fix, build`,其余 `0x00`。 |
|
||||
| `fw_new_ver[16]` | 新固件版本,编码同上。 |
|
||||
| 版本输入 | 界面应分别提供“当前/旧版本”与“新版本”;不能只保留一个版本号,且不得写 ASCII 版本字符串。 |
|
||||
| `user_string[16]` | ASCII 水印最多 15 字节,NUL 结尾,其余 `0x00`。 |
|
||||
| `timestamp` | 当前 Unix 时间戳,`uint32` 小端。 |
|
||||
| 大小限制 | `raw_size <= 262144` 且 `pkg_size <= 262144`,即 App/download 分区各 256KB。 |
|
||||
|
||||
## 4. 加密、大小与 CRC
|
||||
|
||||
1. `raw_body` 为原始 `.bin`:`raw_size = len(raw_body)`,`raw_crc = crc32_boot(raw_body)`。
|
||||
2. 未加密:`package_body = raw_body`,`pkg_size = raw_size`,`pkg_crc = raw_crc`,`config[1]=0x00`。
|
||||
3. AES:`config[1]=0x01`,使用 AES-256-CBC;Key=`0123456789ABCDEF0123456789ABCDEF`,IV=`0123456789ABCDEF`。加密前 body 必须补齐到 16 字节整数倍;`pkg_size`、`pkg_crc`对应加密后的 body。Key、IV 必须与 Boot 编译配置一致。
|
||||
4. `config[0]`、`config[2]`、`config[3]` 固定 `0x00`。
|
||||
5. `head_crc = crc32_boot(逻辑头前 92 字节)`;最后 4 字节按小端写入 `head_crc`。
|
||||
6. 所有 `uint32` 字段按 STM32 小端序写入。
|
||||
|
||||
`crc32_boot()` 必须与 `apps/boot/application/func/utils.c` 的 `crc32_step(0xFFFFFFFF, data, size)` 完全一致;不能直接使用未校验的库默认 CRC32。
|
||||
|
||||
## 5. 96 字节逻辑头字段
|
||||
|
||||
```text
|
||||
0x00 name[4]
|
||||
0x04 config[4]
|
||||
0x08 fw_old_ver[16]
|
||||
0x18 fw_new_ver[16]
|
||||
0x28 user_string[16]
|
||||
0x38 part_name[16]
|
||||
0x48 raw_size uint32 little-endian
|
||||
0x4C pkg_size uint32 little-endian
|
||||
0x50 timestamp uint32 little-endian
|
||||
0x54 raw_crc uint32 little-endian
|
||||
0x58 pkg_crc uint32 little-endian
|
||||
0x5C head_crc uint32 little-endian
|
||||
```
|
||||
|
||||
## 6. 打包完成前的强制自检
|
||||
|
||||
1. 重新解析刚生成的 `.upk`。
|
||||
2. 校验总长度是否为 `1024 + pkg_size`,并检查 `0x60~0x3FF` 全部为 `0x00`。
|
||||
3. 校验 `name`、分区名、版本字段、大小限制和 `head_crc`。
|
||||
4. 校验 `pkg_crc`;未加密时还必须校验 `raw_crc`。加密时使用相同 Key/IV 解密后校验 `raw_crc`。
|
||||
5. 解析页显示 `raw_size`、`pkg_size`、全部 CRC、加密状态、分区、旧/新版本和时间戳;任一项异常时禁止输出成功文件。
|
||||
|
||||
## 7. 当前样本
|
||||
|
||||
工程中的 `apps/chrg/chrg.upk` 已验证:实际长度 `155816`,`pkg_size=154792`,两者相差 1024,符合本规则。
|
||||
|
||||
## 8. 代码依据
|
||||
|
||||
- `apps/boot/application/include/firmware.h`
|
||||
- `apps/boot/application/func/firmware.c`
|
||||
- `apps/boot/application/func/app.c`
|
||||
- `apps/boot/application/func/utils.c`
|
||||
@@ -16,8 +16,9 @@
|
||||
| 启动依据 | 等待 Boot 发出 ASCII `C`(`0x43`)后再开始传输 |
|
||||
| Boot 上电等待 | 首次等待主机开始约 5 秒;超时后可能跳转 App |
|
||||
| 传输中的帧间等待 | Boot 约 10 秒;上位机不得使相邻有效帧间隔达到 10 秒 |
|
||||
| 单帧发送方式 | 一个完整 YMODEM 帧必须连续写入串口;不得把同一帧拆开并在中间产生明显空闲间隔 |
|
||||
|
||||
Boot 每约 1 秒发送一次 `C`。若没有收到 `C`,上位机不可直接发送 YMODEM 首帧;应提示设备未进入 Boot,或重新复位/触发其进入 Boot。
|
||||
Boot 每约 1 秒发送一次 `C`。若没有收到 `C`,上位机不可直接发送 YMODEM 首帧;应提示设备未进入 Boot,或重新复位/触发其进入 Boot。Boot 的接收层按 UART 收帧处理,不会为上位机重组被空闲间隔拆断的 YMODEM 包。
|
||||
|
||||
## 3. YMODEM 常量与帧格式
|
||||
|
||||
@@ -54,7 +55,7 @@ CRC 覆盖 `Data` 的全部固定长度字节(128 或 1024),并按 **高
|
||||
|
||||
1. 元数据包必须使用 `SOH`,`PacketNo=0x00`,反码为 `0xFF`。
|
||||
2. 首个文件数据包使用 `PacketNo=0x01`;每得到 ACK 后序号加 1,按 8 位自然回绕。
|
||||
3. 数据包正常使用 `STX`(1024 字节);最后一包不足 1024 字节时仍应补齐到 1024 字节,建议补 `0x1A`。
|
||||
3. 本 Boot 的 `.upk` 使用 1K 首数据块布局,因此文件数据包必须使用 `STX`(1024 字节);最后一包不足 1024 字节时仍应补齐到 1024 字节,建议补 `0x1A`。
|
||||
4. Boot 校验包号、包号反码、帧长度与 CRC。任一校验失败会回复 NAK。
|
||||
5. 收到 NAK 时,必须重发**原完整帧**,包号不得递增。该 Boot 不将“前一帧重复包”当作成功帧,因此不能依赖重复包自动 ACK。
|
||||
|
||||
@@ -79,10 +80,12 @@ protocol_v1.2.upk\0 123456\0 [其余填 0]
|
||||
Boot 在接收数据后按 UPK 格式处理,而不是把它当作裸固件。
|
||||
|
||||
- 头部标识必须为 `UPK_IDENTIFIER=0x006B7075`(`"upk"`)。
|
||||
- UPK 头为 1 字节对齐、总计 96 字节,包含版本、目标分区、原始/包体大小、CRC 等字段。
|
||||
- 工程当前启用 AES-256-CBC 解密;上位机职责仅为原样传输既有打包工具产生的 `.upk`,无需也不得自行改变加密、CRC 或头内容。
|
||||
- UPK 逻辑头为 1 字节对齐、总计 96 字节,包含版本、目标分区、原始/包体大小、CRC 等字段。
|
||||
- 工程启用了 AES-256-CBC 解密组件,但不强制加密;`config[1]=0` 的未加密包和 `config[1]=1` 的 AES-256-CBC 包均可被当前 Boot 处理。
|
||||
- Boot 根据 UPK 头确定下载与安装流程;当前配置会先写 download 分区,再更新 app 分区。
|
||||
|
||||
打包输出的 `.upk` 必须符合[协议板Boot_UPK打包规则.md](协议板Boot_UPK打包规则.md),特别是 1024 字节首数据块布局。YMODEM 元数据中的文件大小使用该 `.upk` 的实际字节数。
|
||||
|
||||
## 7. 完整正常时序
|
||||
|
||||
```text
|
||||
@@ -91,9 +94,9 @@ PC -> Boot: SOH, 00, FF, 元数据, CRC
|
||||
Boot -> PC : ACK
|
||||
Boot -> PC : C (必须等待此 C)
|
||||
|
||||
PC -> Boot: STX/SOH, 01, FE, 数据块, CRC
|
||||
PC -> Boot: STX, 01, FE, 数据块, CRC
|
||||
Boot -> PC : ACK
|
||||
PC -> Boot: STX/SOH, 02, FD, 数据块, CRC
|
||||
PC -> Boot: STX, 02, FD, 数据块, CRC
|
||||
Boot -> PC : ACK
|
||||
... (直至全部 .upk 数据发送完成)
|
||||
|
||||
@@ -168,15 +171,17 @@ WAIT_END_ACK
|
||||
| 事件 | 上位机处理 |
|
||||
| --- | --- |
|
||||
| 收到 ACK | 仅推进到下一协议状态;数据包 ACK 后才递增包号 |
|
||||
| 收到 NAK | 立即重发当前完整帧,不改变包号和文件偏移 |
|
||||
| 单帧等待超时 | 重发当前完整帧;建议最多连续 3 次 |
|
||||
| 重发次数耗尽 | 发送 CAN 两次,标记升级传输失败 |
|
||||
| 收到明确 NAK | 重发当前完整帧;建议最多连续 3 次 |
|
||||
| 等待 ACK 超时 | 标记“传输结果不确定”,停止本次会话;重新进入 Boot 后从元数据包开始完整传输 |
|
||||
| 明确 NAK 重发耗尽 | 发送 CAN 两次,标记升级传输失败 |
|
||||
| 收到 CAN | 立即停止,标记 Boot 取消升级 |
|
||||
| 用户取消 | 发送 CAN 两次,停止发送后续字节 |
|
||||
| 无 C | 不开始发送,提示设备未进入 Boot 或串口参数/连线错误 |
|
||||
|
||||
Boot 对单个 CAN 会进入取消流程并回 ACK;上位机仍建议按标准发送两个 CAN,并接受可能出现的 ACK。
|
||||
|
||||
> **当前 Boot 的可靠性限制:** 成功接收一个数据包后,Boot 已把期望包号加一;若该包的 ACK 在串口上丢失,上位机重发同一包会被 Boot 判为“重复包”并回复 NAK,而不是再次回复 ACK。因此“ACK 超时后无条件重发当前包”不能可靠恢复。本文规则可在直连、稳定的串口环境中正常升级;若要支持 ACK 丢失后的可靠自动重发,需要修改 Boot,使其收到“期望包号减一”的重复帧且 CRC 正确时直接回复 ACK、不再次写入数据。
|
||||
|
||||
`WAIT_*_ACK` 的建议超时为 3~10 秒,元数据后的 `WAIT_C_DATA`、结束阶段的 `WAIT_C_END` 建议为 10 秒。上位机可将串口接收设计为持续缓存并按字节解析,忽略调试文本或仅识别 `C/ACK/NAK/CAN` 控制字符,避免因分段到达造成误判。
|
||||
|
||||
## 10. 成功判定与日志
|
||||
|
||||
Reference in New Issue
Block a user