Merge pull request 'Feature' (#2) from feature into master

Reviewed-on: chrg/chrg#2
This commit is contained in:
yhf
2026-08-31 08:18:11 +00:00
54 changed files with 9677 additions and 2576 deletions
+53 -2
View File
@@ -166,6 +166,56 @@ void MX_USART_DeInit (void)
HAL_UART_DeInit(&huart2);
}
static void boot_JumpToAPP (void)
{
static uint32_t _stack_addr; /* APP 栈顶地址 */
static uint32_t _reset_handler; /* APP reset handler 地址 */
typedef void(*APP_MAIN_FUNC)(void);
APP_MAIN_FUNC APP_Main;
_stack_addr = *(volatile uint32_t *)BASE_APPLICATION;
_reset_handler = *(volatile uint32_t *)(BASE_APPLICATION + 4);
/* 设置所有时钟到默认状态,使用HSI时钟 */
HAL_RCC_DeInit();
/* 关闭全局中断 */
__disable_irq();
/* 关闭滴答定时器,复位到默认值 */
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
/* 关闭所有中断,清除所有中断挂起标志 */
for (uint8_t i = 0; i < 8; i++) {
NVIC->ICER[i] = 0xFFFFFFFF;
NVIC->ICPR[i] = 0xFFFFFFFF;
}
/* 外设 deinit */
HAL_DeInit();
MX_USART_DeInit();
MX_DMA_DeInit();
/* 设置主堆栈指针 */
__set_MSP(_stack_addr);
/* 在 RTOS 工程,这条语句很重要,设置为特权级模式,使用 MSP 指针 */
__set_CONTROL(0);
/* 设置中断向量表 */
SCB->VTOR = BASE_APPLICATION;
/* 跳转到 APP ,首地址是 MSP ,地址 +4 是复位中断服务程序地址 */
APP_Main = (APP_MAIN_FUNC)_reset_handler;
APP_Main();
/* 复位或跳转成功的话,不会执行到这里 */
while (1) {
}
}
int main (void)
{
@@ -190,9 +240,10 @@ int main (void)
VERSION_MAIN, VERSION_SUB, VERSION_FIX, BUILD_TIMESTAMP);
#endif
APP_Init();
boot_JumpToAPP();
while (1) {
APP_Running();
//APP_Running();
}
return -1;
+6 -6
View File
@@ -32,18 +32,18 @@
#define GPO_PIN_CH1_P2 GET_PIN(C, 1) // P2 connect K5 for GND/PGND
// 北向继电器2组
#define GPO_PIN_CH2_P0 GET_PIN(A, 5) // P0
#define GPO_PIN_CH2_P1 GET_PIN(A, 4) // P1
#define GPO_PIN_CH2_P0 GET_PIN(A, 5) // P0 //SINK D+D- CC
#define GPO_PIN_CH2_P1 GET_PIN(A, 4) // P1 //SOURCE D+D- CC
#define GPO_PIN_CH2_P2 GET_PIN(A, 1) // P2
// 北向继电器3组
#define GPO_PIN_CH3_P0 GET_PIN(C, 5) // P0
#define GPO_PIN_CH3_P1 GET_PIN(C, 4) // P1
#define GPO_PIN_CH3_P0 GET_PIN(C, 5) // P0 //SINK D+D- CC
#define GPO_PIN_CH3_P1 GET_PIN(C, 4) // P1 //SOURCE D+D- CC
#define GPO_PIN_CH3_P2 GET_PIN(A, 7) // P2
// 北向继电器4组
#define GPO_PIN_CH4_P0 GET_PIN(B, 15) // P0
#define GPO_PIN_CH4_P1 GET_PIN(B, 14) // P1
#define GPO_PIN_CH4_P0 GET_PIN(B, 15) // P0 //SINK D+D- CC
#define GPO_PIN_CH4_P1 GET_PIN(B, 14) // P1 //SOURCE D+D- CC
#define GPO_PIN_CH4_P2 GET_PIN(B, 13) // P2
// 北向通信口选通 U14
File diff suppressed because it is too large Load Diff
+3 -20
View File
@@ -1,7 +1,7 @@
/****************************************************************************
文件名称 : chrg_comm.h
完成日期 :
当前版本号 : V1.0
当前版本号 : V1.1.9
主要功能 : 实现对外通讯协议 MODBUS 服务端,以独立线程等待处理响应请求数据。
版本历史 : 创建原始版本
说明 :
@@ -19,23 +19,8 @@
#define MB_HANDLERS_MAX (16)
typedef struct
{
//北向协议设置
rt_uint8_t proto_changed;
rt_uint8_t group_changed;
rt_uint16_t pro_volt_changed;
rt_uint16_t pro_curr_changed;
//南向功率设置
rt_uint8_t volt_changed;
rt_uint8_t curr_changed;
rt_uint8_t ccset_changed;
rt_uint8_t cvmode_changed;
} sink_proto_diff_t;
static void chrg_sink_get_proto_diff(struct chrg_switch_t *pReal,
struct chrg_switch_t *pShadow,
sink_proto_diff_t *pDiff,
rt_uint8_t *pNoChange);
/* 北向Source协议设置成功后,通知COM保存本通道的PD/非PD类别。 */
extern void chrg_comm_source_protocol_ack(rt_uint8_t ch, rt_uint8_t protocol);
typedef enum {
MB_REG_READ, /*!< Read register values and pass to protocol stack. */
@@ -228,8 +213,6 @@ extern void chrg_comm_thread_entry (void *data);
extern rt_uint8_t chrg_com_sink_on(rt_uint8_t ch, struct chrg_switch_t *pSW, rt_uint8_t *enable);
extern rt_uint8_t chrg_com_source_on(rt_uint8_t ch, rt_uint8_t protoCmd, struct chrg_switch_t *pSW, rt_uint8_t *enable);
extern void chrg_sink_diff_send_reg(eIDX_SOU_CH ch, sink_proto_diff_t *pDiff, struct chrg_switch_t *pReal);
#endif
+30 -32
View File
@@ -37,26 +37,6 @@ struct chrg_lcd_t chrglcd = {
// 55 41 00 0D 0A 停止
// 55 41 01 0D 0A 运行
void chrg_sou_work(eIDX_SOU_CH ch,struct chrg_switch_t *pSW)
{
struct chrg_south_t *pSOU = &chrgsouth;
if(pSW->id == ID_SOURCE){
chrg_set_sou_reg(ch, REG_WORK, WORK_START);
// rt_thread_mdelay(50);
pSW->source.Set_CV_Flag = 1;
pSW->source.Set_Pro_Flag = 1;
pSW->source.On_Flag = 1;
pSW->sub = IDX_SET_SOURCE_PD;
}
else if(pSW->id == ID_SINK) {
pSW->sink.On_work = 1;
pSW->sub=IDX_SET_SINK_PD;
}
pSOU->online[ch] = 1;
chrg_nor_sw_rel((eIDX_NOR_CH)ch, pSW->id);
rt_thread_mdelay(50);
}
void chrg_sou_stop(eIDX_SOU_CH ch,struct chrg_switch_t *pSW,struct chrg_north_t *pNOR)
{
struct chrg_south_t *pSOU = &chrgsouth;
@@ -64,7 +44,6 @@ void chrg_sou_stop(eIDX_SOU_CH ch,struct chrg_switch_t *pSW,struct chrg_north_t
return;
}
if(pSW->id == ID_SOURCE){
pSW->source.Stop_step_flag = 0;
pSW->source.On_Flag = 0;
pSW->sub = IDX_GET_SOURCE_VC;
}
@@ -82,7 +61,6 @@ int chrg_pro_set(struct chrg_switch_t *pSW, rt_uint8_t protocol){
if (pSW->id == ID_SOURCE) {
// Source端
pSW->source.protocol = protocol;
pSW->source.LCD_Set_Pro_Flag = 1;
} else if (pSW->id == ID_SINK) {
// Sink端
pSW->sink.protocol = protocol;
@@ -211,7 +189,6 @@ static int chrg_lcd_parse (rt_uint8_t *recv, rt_uint16_t len)
}
pNOR->enable[ch] = 1;
rt_kprintf("ch=%d\n",ch);
chrg_sou_work((eIDX_SOU_CH)ch,pSW);
pSW->continue_flag = 0;
}
//关闭
@@ -235,14 +212,16 @@ static int chrg_lcd_parse (rt_uint8_t *recv, rt_uint16_t len)
Recv_Data = recv[LCD_IDX_VAL+1]<<8 | recv[LCD_IDX_VAL]; // 拼接16位电压值
pSW = &pNOR->sw[ch];
// 按角色存入source/sink
pSW->source.vc.set_voltage = Recv_Data; // 电源侧电压(mV)
pSW->source.pd_set.mm.max_vol = Recv_Data; // 电源协议目标电压(mV)
pSW->source.set_volt = Recv_Data; // 当前准备写入功率板的电压目标
pSW->sink.loadv = Recv_Data; // 负载侧电压(mV,)
pSW->source.Set_Pro_Flag = 1;
// 写入电压寄存器
if(pSW->id==ID_SINK) {
chrg_set_sou_reg((eIDX_SOU_CH)ch, REG_VOLTAGE_OUT+1, Recv_Data);
/* Sink保留原直接设置方式;Source电压必须统一经过RUNING状态补偿后下发。 */
if (pSW->id == ID_SINK) {
chrg_set_sou_reg((eIDX_SOU_CH)ch, REG_VOLTAGE_OUT + 1, Recv_Data);
} else if (pSW->source.On_Flag == 1) {
pSW->source.work_mode = SOURCE_WORK_RUNING;
(void)chrg_source_work_state(ch, pSW);
}
else chrg_set_sou_reg((eIDX_SOU_CH)ch, REG_VOLTAGE_OUT+1, 5000);
break;
}
@@ -255,9 +234,9 @@ static int chrg_lcd_parse (rt_uint8_t *recv, rt_uint16_t len)
Recv_Data = recv[LCD_IDX_VAL+1]<<8 | recv[LCD_IDX_VAL]; // 拼接16位电流值
pSW = &pNOR->sw[ch];
//按角色存入source/sink
pSW->source.vc.set_current = Recv_Data; // 电源侧电流(mA)
pSW->source.pd_set.mm.max_cur = Recv_Data; // 电源协议最大电流(mA)
pSW->source.set_curr = Recv_Data; // 当前准备写入功率板的电流目标
pSW->sink.loadc = Recv_Data; // 负载侧电流(mA)
pSW->source.Set_Pro_Flag = 1;
// rt_kprintf("cur=%d",Recv_Data);
// 写入电流寄存器
for(int i = 0;i<10;i++){
@@ -390,7 +369,9 @@ void chrg_lcd_thread_entry (void *data)
return ;
}
#if LCD_RX_ENABLE
int len = 0;
#endif
struct chrg_tty_t *pTTY = RT_NULL;
struct chrg_lcd_t *pLCD = &chrglcd;
pTTY = chrg_tty_create(pLCD->devname, 921600, 0, -1, 1);
@@ -398,8 +379,10 @@ void chrg_lcd_thread_entry (void *data)
LOG_E("tty can't create.");
return ;
}
#if LCD_RX_ENABLE
/* LCD接收功能开启时,最多等待100ms屏幕回传数据。 */
chrg_tty_set_recv_tmo(pTTY, 100);
#endif
if (chrg_tty_connect(pTTY) != RT_EOK) {
chrg_tty_destory(pTTY);
return;
@@ -407,6 +390,12 @@ void chrg_lcd_thread_entry (void *data)
pLCD->tty = pTTY;
#if LCD_RX_ENABLE
/*
* 保留原LCD接收及控制解析流程,需要恢复屏幕控制时只需将
* LCD_RX_ENABLE改为1。接收关闭时本段不参与编译,避免chrg_tty_recv
* 在等待回传期间持有TTY锁并阻塞chrg_lcd_send。
*/
while (1) {
rt_memset(pLCD->rx_buf, 0, SIZE_BUF_TTY);
len = chrg_tty_recv(pTTY, pLCD->rx_buf, sizeof(pLCD->rx_buf));
@@ -420,6 +409,15 @@ void chrg_lcd_thread_entry (void *data)
chrg_lcd_parse(pLCD->rx_buf, len);
}
}
#else
/*
* 仅发送模式仍保留LCD线程和串口实例。线程低频休眠且不访问TTY,
* 量测解析中的LCD发送可以直接取得TTY锁,不再受100ms接收超时影响。
*/
while (1) {
rt_thread_mdelay(1000);
}
#endif
}
+3 -1
View File
@@ -18,6 +18,9 @@
#define THR_NAME_LCD "thr.lcd"
#define DEV_NAME_LCD "uart2"
/* LCD发送保持启用;当前产品不使用屏幕回传控制,关闭接收可避免接收线程持有TTY锁阻塞量测上报。 */
#define LCD_RX_ENABLE 0
#define LCD_FRAME_HEAD 0x55
@@ -45,7 +48,6 @@ extern void chrg_lcd_thread_entry (void *data);
extern rt_uint8_t On_Flag;
extern rt_uint8_t Flag_start;
extern void chrg_sou_work(eIDX_SOU_CH ch,struct chrg_switch_t *pSW);
extern void chrg_sou_stop(eIDX_SOU_CH ch,struct chrg_switch_t *pSW,struct chrg_north_t *pNOR);
extern void chrg_set_eload_sink(eIDX_SOU_CH ch,struct chrg_switch_t *pSW);
extern void chrg_set_eload_source(eIDX_SOU_CH ch,struct chrg_switch_t *pSW);
File diff suppressed because it is too large Load Diff
+34 -6
View File
@@ -19,15 +19,20 @@
#define THR_NAME_NORTH "thr.nor"
#define DEV_NAME_NORTH "uart3"
#define LEN_FRAME_HEAD (3) // [帧长, 0x00, id]
#define LEN_FRAME_HEAD (4) // [帧长, 0x00, id, 命令]
#define MIN_FRAME_LENGTH (5) // 帧最短5字节
#define WORK_MIN_VOLT 3000 // 工作电压下限,单位mV
#define DEBUG_NORTH 0x00 // 0 = 关闭,1 = 开启
#define NORTH_FRAME_DEBUG 0x00 // 北向UART原始收发帧
#define NORTH_SOURCE_DEBUG 0x01 // Source协议解析及组帧
#define NORTH_SINK_DEBUG 0x00 // Sink协议解析及组帧
#define SOUTH_FRAME_DEBUG 0x00 // 南向UART原始收发帧
#define SOUTH_COMMAND_DEBUG 0x01 // 南向寄存器写命令
#define COMM_FRAME_DEBUG 0x00 // COM UART原始收发帧
#define COMM_DEBUG 0x00 // COM寄存器读写过程
#define COMM_TRIM_DEBUG 0x00 // COM校准参数解析
#define LCD_OPEN 0x01 // 0为关闭屏幕显示 1为打开
#define TRIM_NORTH 0x00 // 0 = 关闭, 1 = 开启
#define SINK_TEST_DEBUG 0x00 // 0 = 关闭,1 = 开启
#define PRO_TEST_DEBUG 0x00 //
#define DEBUG_SOUTH 0x00 // 0 = 关闭,1 = 开启
// 北向4通路索引 U14 ->
typedef enum {
IDX_NOR_CH1 = IDX_CH1, // J3
@@ -95,7 +100,6 @@ struct chrg_trim {
rt_int16_t trim_source_curr_b; // 校准电源电流值b mA
rt_int16_t trim_zero; // 校准飘零值 mV/mA
rt_uint8_t trim_mode; // 校准模式, 0-默认值,1-校准电压,2-校准电流,3-校准电源电流
rt_uint8_t trim_step;
rt_uint8_t trim_enable_flag; //0就是默认写用户区,1则写出场数据区
};
@@ -105,6 +109,7 @@ struct chrg_north_t {
struct chrg_tty_t *tty;
struct rt_ringbuffer *rb;
struct pickup_info_t frame;
rt_uint32_t config_version[TOTAL_NOR_CHS]; // COM配置版本,用于识别等待期间到达的旧回码
struct chrg_trim trim[TOTAL_NOR_CHS];
rt_uint8_t rx_buf[SIZE_BUF_TTY];
rt_uint8_t free_flag;
@@ -112,11 +117,34 @@ struct chrg_north_t {
rt_uint8_t manual; // 手动插入命令
eIDX_NOR_CH idx; // 当前通路
struct chrg_switch_t sw[TOTAL_NOR_CHS];
rt_uint8_t north_mode; // 0-正常模式, 1-校准模式
};
extern struct chrg_north_t chrgnorth;
/*****************************************************************
函数名称: chrg_source_parse
函数描述: 解析Source的0x20电压电流回码并驱动电源状态机
输入参数: frame_data:已通过CRC校验的完整回码 idx:对应通道
pSW:通道控制结构体 pNOR:北向控制结构体
输出参数: 更新Source目标电压、电流和工作状态
返回说明: 0:回码正常 <0:参数错误、Source切换错误或功率命令提交失败
其它说明: 仅由北向轮询线程在确认回码角色、命令和通道匹配后调用
*****************************************************************/
extern int chrg_source_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx,
struct chrg_switch_t *pSW, struct chrg_north_t *pNOR);
/*****************************************************************
函数名称: chrg_sink_parse
函数描述: 解析Sink的0x20电压电流回码并驱动负载状态机
输入参数: frame_data:已通过CRC校验的完整回码 idx:对应通道
pSW:通道控制结构体 pNOR:北向控制结构体
输出参数: 更新Sink协议量测值和工作状态
返回说明: -
其它说明: 仅由北向轮询线程在确认回码角色、命令和通道匹配后调用
*****************************************************************/
extern void chrg_sink_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx,
struct chrg_switch_t *pSW, struct chrg_north_t *pNOR);
/*****************************************************************
函数名称: chrg_north_switch
函数描述: 北向通道选择
File diff suppressed because it is too large Load Diff
+34 -2
View File
@@ -1,7 +1,7 @@
/****************************************************************************
文件名称 : chrg_roll_nor.h
完成日期 :
当前版本号 : V1.0
当前版本号 : V1.1.9
主要功能 : 实现北向通信轮巡请求命令。以独立线程处理。
版本历史 : 创建原始版本
说明 :
@@ -41,6 +41,20 @@ enum {
IDX_SET_SINK_WORK_STATE,
IDX_SET_SINK_STOP_TEST,//停止负载测试
IDX_SET_SINK_STORP_WAIT,
/* Source北向事务状态,追加在末尾以保持原有sub数值不变。 */
IDX_SET_SOURCE_RESET, // PD与非PD协议跨类切换前发送Source复位
IDX_WAIT_SOURCE_PROTOCOL, // 0xD0应答后的协议生效等待
/* Sink北向事务状态追加在末尾,避免改变已有sub数值。 */
IDX_SET_SINK_PD_ONLY, // 仅重发协议,协议应答后直接查询协商电压
IDX_WAIT_SINK_CC, // CC设置应答后的非阻塞稳定等待
IDX_SET_SINK_CC_BEFORE_PD, // 先设置CC,稳定后再设置协议
IDX_WAIT_SINK_CC_BEFORE_PD, // 等待CC稳定后进入协议设置
IDX_WAIT_SINK_PD_ACK, // 协议回码确认后的非发送过渡状态
#if 0
IDX_SET_SINK_PD_BEFORE_CC, // 先设置协议,协议回码后再设置CC
#endif
};
struct chrg_rollnor_t {
@@ -80,8 +94,26 @@ extern struct chrg_rollnor_t chrgrollnor;
extern void chrg_roll_nor_thread_entry (void *data);
extern int sink_fill_pd_buf(rt_uint8_t group,rt_uint8_t pd_val, rt_uint16_t pd_volt, rt_uint16_t pd_curr, rt_uint8_t *buf);
extern void chrg_roll_trim_set(rt_uint8_t ch, struct chrg_north_t *pNOR);
extern void roll_nor_set(void);
/*****************************************************************
函数名称: chrg_roll_nor_source_cc_close_register
函数描述: 将Source通道登记到本轮共享CC_CLOSE等待屏障
输入参数: ch:北向通道编号
输出参数: -
返回说明: -
其它说明: 仅需要在协议切换入口为IDX_SET_SOURCE_CC_CLOSE时调用
*****************************************************************/
/*****************************************************************
函数名称: chrg_roll_nor_source_switch_reset
函数描述: 清理指定Source通道的CC_CLOSE及协议等待记录
输入参数: ch:北向通道编号
输出参数: -
返回说明: -
其它说明: 停止、角色切换或新配置覆盖旧切换状态时调用
*****************************************************************/
extern void chrg_roll_nor_source_switch_reset(rt_uint8_t ch);
#define sink_time 3
#endif
File diff suppressed because it is too large Load Diff
+58 -6
View File
@@ -12,11 +12,13 @@
#include <rtthread.h>
struct chrg_trim;
#define THR_NAME_ROLL_SOU "thr.rollsou"
// 单通道批量下发缓存:保存当前需要同步的寄存器列表
#define SOU_COM_BATCH_REG_MAX 16
/* 为连续提交初始化、普通启动和动态启动命令预留足够空间。 */
#define SOU_COM_BATCH_REG_MAX 32
typedef struct
{
rt_uint16_t reg_cnt; // 当前待下发寄存器数量
@@ -24,6 +26,8 @@ typedef struct
rt_uint16_t val_list[SOU_COM_BATCH_REG_MAX]; // 对应寄存器值数组
rt_uint8_t cur_idx; // 当前下发到第几条
rt_bool_t pending; // 本通道有待下发批量指令
rt_int8_t result; // 0:执行中/无结果 1:成功 -1:失败取消
rt_tick_t next_send_tick; // 非0时下一条命令不得早于该tick发送
} sou_com_batch_ch_t;
// COM批量下发总控结构体
@@ -46,9 +50,10 @@ struct chrg_rollsou_t {
rt_uint16_t reg; // LCD 触发时,寄存器地址
rt_uint16_t value; // LCD 触发时,寄存器值
rt_uint8_t *updata_data;//南向升级的数据
rt_uint16_t leng;
rt_uint8_t send_flag; //发送标志位
rt_uint8_t updata_buf[YMODEM_STX_SIZE];/* 南向升级帧缓存,避免上层缓冲区被提前覆盖 */
rt_uint16_t leng; /* 当前待发送升级帧的实际长度 */
rt_int16_t updata_result;/* 最近一次升级帧发送结果 */
rt_uint8_t send_flag; /* 1:升级帧待发送或正在发送,0:允许提交下一帧 */
rt_uint8_t mode;// 0 为正常轮询,1为升级,2为校准
};
@@ -82,9 +87,56 @@ extern void chrg_set_sou_reg_com (eIDX_SOU_CH idx, rt_uint16_t reg, rt_uint16_t
*****************************************************************/
extern void chrg_roll_sou_thread_entry (void *data);
extern void chrg_send_sou_upadata_data (rt_uint8_t *buf,rt_uint16_t leng);
extern void chrg_sou_com_sou_set(void);
/*****************************************************************
函数名称: chrg_send_sou_upadata_data
函数描述: 将一帧升级数据复制到南向升级缓存并唤醒升级发送分支
输入参数: buf:升级帧数据 leng:升级帧长度
输出参数: -
返回说明: 0:提交成功 -1:参数错误 -2:上一帧尚未发送 -3:互斥锁超时
其它说明: 数据在函数内完成复制,调用者返回后可以立即复用原缓冲区
*****************************************************************/
extern int chrg_send_sou_upadata_data(const rt_uint8_t *buf, rt_uint16_t leng);
extern int chrg_sou_com_batch_add_reg(eIDX_SOU_CH ch, rt_uint16_t reg, rt_uint16_t val);
extern int chrg_sou_com_batch_submit(eIDX_SOU_CH ch, const rt_uint16_t *regs,
const rt_uint16_t *vals, rt_uint8_t count);
/*****************************************************************
函数名称: chrg_sou_com_batch_cancel
函数描述: 取消指定通道尚未完成的南向COM批次
输入参数: ch:南向功率板通道
输出参数: -
返回说明: 0:批次已取消 <0:参数或互斥锁错误
其它说明: 已发送到功率板的当前命令无法撤回,但其后续未发送命令将被清除;
当前命令的迟到回码会按批次已变更处理,不再推进旧批次
*****************************************************************/
extern int chrg_sou_com_batch_cancel(eIDX_SOU_CH ch);
extern rt_bool_t chrg_sou_com_batch_is_pending(eIDX_SOU_CH ch);
/*****************************************************************
函数名称: chrg_sou_com_batch_get_result
函数描述: 获取指定通道最近一次南向COM批次的执行结果
输入参数: ch:南向功率板通道
输出参数: -
返回说明: 1:全部命令收到匹配回码 0:执行中/无结果 -1:失败取消 -2:参数或锁错误
其它说明: 用于区分pending清零是正常完成还是重试耗尽后的失败取消
*****************************************************************/
extern int chrg_sou_com_batch_get_result(eIDX_SOU_CH ch);
/*****************************************************************
函数名称: chrg_sou_measure_once_submit
函数描述: 请求南向线程优先查询指定通道的一帧P1量测数据
输入参数: ch:南向功率板通道
输出参数: -
返回说明: 0:请求成功或已存在同通道请求 <0:参数或互斥锁错误
其它说明: 只登记一次性请求,实际切通道、发送0x03和解析仍由南向线程完成
*****************************************************************/
extern int chrg_sou_measure_once_submit(eIDX_SOU_CH ch);
/*****************************************************************
函数名称: chrg_sou_trim_submit
函数描述: 根据校准类型组装功率板校准指令并提交到南向COM队列
输入参数: ch:南向功率板通道 pTrim:已解析的校准参数
输出参数: -
返回说明: 0:提交成功 <0:参数、校准模式或队列提交失败
其它说明: 实际发送、应答校验和重试由RUN_COM分支统一管理
*****************************************************************/
extern int chrg_sou_trim_submit(eIDX_SOU_CH ch, const struct chrg_trim *pTrim);
#endif
+105 -43
View File
@@ -23,6 +23,8 @@
#define DBG_LEVEL DBG_LOG
#include <rtdbg.h>
#define SOUTH_FRAME_TIMEOUT_MS 100
#define MB_ACK_HEAD_SIZE 3 // modbus 响应头3字节
struct chrg_south_t chrgsouth = {
@@ -157,6 +159,9 @@ int chrg_south_send (rt_uint8_t *data, rt_size_t length)
struct chrg_tty_t *pTTY = chrgsouth.tty;
if (RT_NULL != pTTY) {
#if SOUTH_FRAME_DEBUG
LOG_HEX("sendS", 32, data, length);
#endif
ret = chrg_tty_send(pTTY, data, length);
}
return ret;
@@ -183,7 +188,9 @@ static int chrg_south_frame_head (struct rt_ringbuffer *rb, rt_uint8_t *head, eI
len_rb = rt_ringbuffer_data_len(rb);
if (len_rb < MB_ACK_HEAD_SIZE) { // 帧头3字节
#if SOUTH_FRAME_DEBUG
rt_kprintf("len_rb=:%d",len_rb);
#endif
return -1;
}
@@ -249,10 +256,70 @@ static int chrg_south_frame_head (struct rt_ringbuffer *rb, rt_uint8_t *head, eI
返回说明: <0: 错误 >0:帧长度
其它说明: -
*****************************************************************/
static void chrg_south_frame_reset(struct pickup_info_t *pFrame, rt_bool_t release)
{
if (RT_NULL == pFrame) {
return;
}
if (release && (RT_NULL != pFrame->pMB)) {
if (RT_NULL != pFrame->pMB->payload) {
rt_free(pFrame->pMB->payload);
}
rt_free(pFrame->pMB);
}
pFrame->last_tick = 0;
pFrame->length = 0;
pFrame->findhead = 0;
pFrame->len_msg = 0;
pFrame->pMB = RT_NULL;
}
static int chrg_south_frame_append(struct rt_ringbuffer *rb,
struct pickup_info_t *pFrame)
{
rt_size_t remaining;
rt_size_t copied;
if ((RT_NULL == rb)||(RT_NULL == pFrame)||(RT_NULL == pFrame->pMB)||
(RT_NULL == pFrame->pMB->payload)||(pFrame->len_msg <= 0)||
(pFrame->length > (rt_size_t)pFrame->len_msg)) {
return -1;
}
remaining = (rt_size_t)pFrame->len_msg - pFrame->length;
if (0 == remaining) {
return 1;
}
copied = rt_ringbuffer_data_len(rb);
if (copied > remaining) {
copied = remaining;
}
if (copied > 0) {
copied = rt_ringbuffer_get(rb,
&pFrame->pMB->payload[pFrame->length], copied);
pFrame->length += copied;
pFrame->last_tick = rt_tick_get();
}
return (pFrame->length == (rt_size_t)pFrame->len_msg) ? 1 : 0;
}
static void chrg_south_frame_dispatch(struct pickup_info_t *pFrame)
{
struct mb_msg_t *pMB = pFrame->pMB;
chrg_south_frame_reset(pFrame, RT_FALSE);
chrg_thread_mb_send(IDX_THR_SOUTH, pMB);
}
static int chrg_south_pickup_frame (struct rt_ringbuffer *rb,
struct pickup_info_t *pFrame)
{
int cnt = 0;
int status = 0;
rt_size_t len_rb = 0;
if ((RT_NULL == rb)||(RT_NULL == pFrame)) {
@@ -263,63 +330,55 @@ static int chrg_south_pickup_frame (struct rt_ringbuffer *rb,
if (0 == pFrame->findhead) {
pFrame->len_msg = chrg_south_frame_head(rb, pFrame->head, ID_ELOAD);
if (pFrame->len_msg > 0) {
if ((pFrame->len_msg < MB_ACK_HEAD_SIZE)||
(pFrame->len_msg >= SIZE_BUF_TTY)) {
LOG_E("invalid msg length: %d", pFrame->len_msg);
chrg_south_frame_reset(pFrame, RT_TRUE);
return -3;
}
pFrame->pMB = (struct mb_msg_t *)rt_malloc(sizeof(struct mb_msg_t));
if (RT_NULL == pFrame->pMB) {
LOG_E("malloc mb failed.");
chrg_south_frame_reset(pFrame, RT_FALSE);
return -2;
}
pFrame->pMB->length = pFrame->len_msg;
if (pFrame->pMB->length >= SIZE_BUF_TTY) {
rt_free(pFrame->pMB);
pFrame->pMB = RT_NULL;
LOG_E("too long msg.");
return -3;
}
pFrame->pMB->payload = RT_NULL;
pFrame->pMB->payload = (rt_uint8_t *)rt_malloc(pFrame->len_msg);
if (RT_NULL == pFrame->pMB->payload) {
LOG_E("malloc buf failed.");
chrg_south_frame_reset(pFrame, RT_TRUE);
return -4;
}
rt_memcpy(pFrame->pMB->payload, pFrame->head, MB_ACK_HEAD_SIZE);
len_rb = rt_ringbuffer_data_len(rb);
if (len_rb >= pFrame->len_msg - MB_ACK_HEAD_SIZE) {
rt_ringbuffer_get(rb, &pFrame->pMB->payload[MB_ACK_HEAD_SIZE],
pFrame->len_msg - MB_ACK_HEAD_SIZE);
chrg_thread_mb_send(IDX_THR_SOUTH, pFrame->pMB);
pFrame->length = 0;
pFrame->len_msg = 0;
cnt++;
} else {
rt_ringbuffer_get(rb, &pFrame->pMB->payload[MB_ACK_HEAD_SIZE], len_rb);
pFrame->length = MB_ACK_HEAD_SIZE + len_rb;
pFrame->length = MB_ACK_HEAD_SIZE;
pFrame->findhead = 1;
pFrame->last_tick = rt_tick_get();
status = chrg_south_frame_append(rb, pFrame);
if (status > 0) {
chrg_south_frame_dispatch(pFrame);
cnt++;
} else if (status < 0) {
chrg_south_frame_reset(pFrame, RT_TRUE);
return -5;
} else {
break;
}
}
} else {
len_rb = rt_ringbuffer_data_len(rb);
int len_need = pFrame->len_msg - MB_ACK_HEAD_SIZE;
if (len_rb >= len_need) {
rt_ringbuffer_get(rb, &pFrame->pMB->payload[pFrame->length], len_need);
chrg_thread_mb_send(IDX_THR_SOUTH, pFrame->pMB);
pFrame->length = 0;
pFrame->findhead = 0;
pFrame->len_msg = 0;
status = chrg_south_frame_append(rb, pFrame);
if (status > 0) {
chrg_south_frame_dispatch(pFrame);
cnt++;
} else if (status < 0) {
chrg_south_frame_reset(pFrame, RT_TRUE);
return -5;
} else {
rt_ringbuffer_get(rb, &pFrame->pMB->payload[pFrame->length], len_rb);
pFrame->length += len_rb;
pFrame->last_tick = rt_tick_get();
break;
}
}
@@ -373,6 +432,13 @@ void chrg_south_thread_entry (void *data)
}
while (1) {
if (pSOU->frame.findhead &&
((rt_tick_t)(rt_tick_get() - pSOU->frame.last_tick) >=
rt_tick_from_millisecond(SOUTH_FRAME_TIMEOUT_MS))) {
chrg_south_frame_reset(&pSOU->frame, RT_TRUE);
LOG_W("partial frame timeout");
}
rt_memset(pSOU->rx_buf, 0, sizeof(pSOU->rx_buf));
len = chrg_tty_recv(pTTY, pSOU->rx_buf, sizeof(pSOU->rx_buf));
if (len <= 0) {
@@ -387,21 +453,17 @@ void chrg_south_thread_entry (void *data)
rt_uint8_t resp_byte;
while (rt_ringbuffer_data_len(pSOU->rb) > 0) {
rt_ringbuffer_getchar(pSOU->rb, &resp_byte);
if (resp_byte == ACK || resp_byte == NAK || resp_byte == ACK_C) {
if (resp_byte == ACK || resp_byte == NAK ||
resp_byte == ACK_C || resp_byte == YM_CAN) {
chrg_eload_set_ymodem_resp(resp_byte);
}
}
continue;
}
//LOG_HEX("recvS", 32, pSOU->rx_buf, len);
if (1 == pSOU->frame.findhead) {
if (rt_tick_get() >= pSOU->frame.last_tick + 100) { // 100ms
pSOU->frame.findhead = 0; // reset
//LOG_E("timeo\r\n");
}
}
#if SOUTH_FRAME_DEBUG
LOG_HEX("recvS", 32, pSOU->rx_buf, len);
#endif
chrg_south_pickup_frame(pSOU->rb, &pSOU->frame);
}
+24 -16
View File
@@ -146,32 +146,40 @@ rt_err_t chrg_thread_evt_send (eIDX_THRS idx, rt_uint32_t data)
返回说明: 0: OK , !=0 : FAILED
其它说明: -
*****************************************************************/
static void chrg_thread_mb_free(void *data)
{
struct mb_msg_t *pMB = (struct mb_msg_t *)data;
if (RT_NULL == pMB) {
return;
}
if (RT_NULL != pMB->payload) {
rt_free(pMB->payload);
}
rt_free(pMB);
}
rt_err_t chrg_thread_mb_send (eIDX_THRS idx, void *data)
{
rt_err_t ret = RT_EOK;
rt_err_t ret;
if (idx >= TOTAL_THRS) {
if ((idx >= TOTAL_THRS)||(RT_NULL == data)) {
chrg_thread_mb_free(data);
return -RT_ERROR;
}
struct chrg_thread_t *pTHR = &chrgthr[idx];
if (RT_NULL != pTHR->mb) {
if (RT_NULL == pTHR->mb) {
LOG_E("mb '%s' is not ready.", pTHR->name);
chrg_thread_mb_free(data);
return -RT_ERROR;
}
ret = rt_mb_send(pTHR->mb, (rt_uint32_t)data);
if (RT_EOK != ret) {
if (ret == -RT_EFULL) {
LOG_E("mb full, drop message. [%d]", ret);
if (RT_NULL != data) {
struct mb_msg_t *pMB = (struct mb_msg_t *)data;
if (RT_NULL != pMB->payload) {
rt_free(pMB->payload);
}
rt_free(pMB);
}
} else {
LOG_E("mb send failed. [%d]", ret);
}
}
LOG_E("mb send failed, drop message. [%d]", ret);
chrg_thread_mb_free(data);
}
return ret;
+14 -1
View File
@@ -12,6 +12,19 @@
#include <rtthread.h>
/*
* Channel polling mode:
* 1 - multi-channel hardware, advance the polling channel index;
* 0 - single-channel hardware, keep polling channel 0.
*/
#define CHRG_MULTI_CHANNEL 1
#if CHRG_MULTI_CHANNEL
#define CHRG_CHANNEL_NEXT(index) do { (index)++; } while (0)
#else
#define CHRG_CHANNEL_NEXT(index) do { } while (0)
#endif
// 4路选通
typedef enum {
IDX_CH1 = 0, // 通路1
@@ -88,7 +101,7 @@ struct vc_pd_t {
rt_uint8_t group_num; // 挡位数量
rt_uint8_t src_type; // 源类型
rt_uint8_t pps_type; // PPS类型
struct vc_mm_t mm[2]; // 电压电流极值
struct vc_mm_t mm; // 电压电流极值
};
/* 邮件内容 */
+112 -16
View File
@@ -18,7 +18,29 @@
#include "chrg_regs.h"
#include "chrg_utils.h"
#include "chrg_south.h"
#define ELOAD_VALID_VOLTAGE_MIN_MV 2000U
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);
/* 每通道P1量测更新序号;32位读写在STM32F405上为原子访问。 */
static volatile rt_uint32_t g_eload_sample_seq[TOTAL_SOU_CHS] = {0};
/*****************************************************************
函数名称: chrg_eload_get_sample_seq
函数描述: 获取指定南向通道P1量测数据的更新序号
输入参数: idx:南向功率板通道
输出参数: -
返回说明: 当前通道量测序号,通道非法时返回0
其它说明: 卸载确认记录命令下发前序号,只接受序号变化后的新量测
*****************************************************************/
rt_uint32_t chrg_eload_get_sample_seq(rt_uint8_t idx)
{
if (idx >= TOTAL_SOU_CHS) {
return 0;
}
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};
@@ -32,10 +54,31 @@ static rt_uint8_t g_eload_ymodem_ready = 0; // 应答就绪标志(1=有新应
函数描述: 存储南向板返回的ymodem应答字节(由chrg_roll_sou在RUN_UPDATA调用)
输入参数: resp: 南向ymodem应答 (ACK=0x06 / NAK=0x15 / 'C'=0x43)
*****************************************************************/
#define ELOAD_YMODEM_RESP_DEPTH 8
static rt_uint8_t g_ymodem_resp_queue[ELOAD_YMODEM_RESP_DEPTH];
static rt_uint8_t g_ymodem_resp_read = 0;
static rt_uint8_t g_ymodem_resp_write = 0;
static rt_uint8_t g_ymodem_resp_count = 0;
void chrg_eload_set_ymodem_resp(rt_uint8_t resp)
{
rt_base_t level = rt_hw_interrupt_disable();
/* 队列已满时丢弃周期性的C,保留更关键的ACK/NAK/CAN。 */
if (g_ymodem_resp_count >= ELOAD_YMODEM_RESP_DEPTH) {
if (resp == ACK_C) {
rt_hw_interrupt_enable(level);
return;
}
g_ymodem_resp_read = (g_ymodem_resp_read + 1) % ELOAD_YMODEM_RESP_DEPTH;
g_ymodem_resp_count--;
}
g_ymodem_resp_queue[g_ymodem_resp_write] = resp;
g_ymodem_resp_write = (g_ymodem_resp_write + 1) % ELOAD_YMODEM_RESP_DEPTH;
g_ymodem_resp_count++;
g_eload_ymodem_resp = resp;
g_eload_ymodem_ready = 1;
rt_hw_interrupt_enable(level);
}
/*****************************************************************
@@ -46,11 +89,17 @@ void chrg_eload_set_ymodem_resp(rt_uint8_t resp)
rt_uint8_t chrg_eload_get_ymodem_resp(void)
{
rt_uint8_t resp = 0;
if (g_eload_ymodem_ready) {
resp = g_eload_ymodem_resp;
g_eload_ymodem_ready = 0;
g_eload_ymodem_resp = 0;
rt_base_t level = rt_hw_interrupt_disable();
if (g_ymodem_resp_count > 0) {
resp = g_ymodem_resp_queue[g_ymodem_resp_read];
g_ymodem_resp_read = (g_ymodem_resp_read + 1) % ELOAD_YMODEM_RESP_DEPTH;
g_ymodem_resp_count--;
}
g_eload_ymodem_ready = (g_ymodem_resp_count > 0);
g_eload_ymodem_resp = g_eload_ymodem_ready ?
g_ymodem_resp_queue[g_ymodem_resp_read] : 0;
rt_hw_interrupt_enable(level);
return resp;
}
@@ -60,8 +109,15 @@ rt_uint8_t chrg_eload_get_ymodem_resp(void)
*****************************************************************/
void chrg_eload_clear_ymodem_resp(void)
{
rt_base_t level = rt_hw_interrupt_disable();
g_ymodem_resp_read = 0;
g_ymodem_resp_write = 0;
g_ymodem_resp_count = 0;
g_eload_ymodem_resp = 0;
g_eload_ymodem_ready = 0;
rt_memset(g_ymodem_resp_queue, 0, sizeof(g_ymodem_resp_queue));
rt_hw_interrupt_enable(level);
}
static int memcmp_8bytes(const rt_uint8_t *buf1, const rt_uint8_t *buf2)
@@ -116,9 +172,20 @@ int chrg_eload_read_regs (rt_uint8_t addr, rt_uint16_t reg, rt_uint16_t len)
u16_to_u8v(value, &buf[4]);
crc = mb_crc16(buf, 6);
u16_to_u8v(swap_u16(crc), &buf[6]);
rt_kprintf("addr = %d,reg = %02x,value = %02x\n",addr,reg,value);
#if SOUTH_COMMAND_DEBUG
rt_kprintf("south write: addr=%d reg=0x%04x value=0x%04x\n",
addr, reg, value);
#endif
return chrg_south_send(buf, 8);
}
}
/* Read the version first so a newly powered south board is not queried with
* the long measurement frame before its Modbus interface is ready. */
int chrg_eload_read_version (rt_uint8_t addr)
{
return chrg_eload_read_regs(addr, MODBUSRTU_SW_VERSION_REG,
MODBUSRTU_SW_VERSION_LEN);
}
/*****************************************************************
函数名称: chrg_eload_send_ymodem_data
@@ -233,6 +300,24 @@ int chrg_eload_refresh (rt_uint8_t addr, rt_uint8_t part)
return ret;
}
int chrg_eload_parse_version (rt_uint8_t idx, rt_uint8_t *data, rt_uint16_t len)
{
rt_uint16_t version;
/* A one-register Modbus 0x03 response is 7 bytes including CRC16. */
if ((idx >= TOTAL_SOU_CHS) || (data == RT_NULL) ||
(len != (MODBUSRTU_SW_VERSION_LEN * 2U + 5U)) ||
(data[0] != ID_ELOAD) || (data[1] != MB_REGISTER_RD) ||
(data[2] != 2U) || (mb_crc16(data, len) != 0U)) {
return -1;
}
version = u8v_to_u16(&data[3]);
/* HOLD_REG_CH0_VERSION is the per-channel south board version register. */
usRegHoldBuf[HOLD_REG_CH0_VERSION + idx * TOTAL_HOLD_CH_REGS] = version;
return 0;
}
/*****************************************************************
函数名称: chrg_eload_parse
函数描述: 解析源载返回数据
@@ -276,9 +361,25 @@ int chrg_eload_parse (rt_uint8_t idx, rt_uint8_t pt, rt_uint8_t *data, rt_uint16
pLOAD->vpkn = swap_u16(pP1->Vpkn);
pLOAD->vpp = swap_u16(pP1->Vpp);
pLOAD->Ripple = swap_u16(pP1->Ripple);
pSW->Now_voltage = pLOAD->voltage;
/* 保留功率板返回的真实电流,供卸载保护判断使用。 */
pSW->Now_current = pLOAD->current;
if(idx == 0)
/*
* 低于2V时直接清零量测结果。只清理量测字段,保留工作状态、
* 故障、模式及测试结果,避免影响通道状态判断。
*/
if (pLOAD->voltage < ELOAD_VALID_VOLTAGE_MIN_MV) {
pLOAD->voltage = 0;
pLOAD->current = 0;
pLOAD->vpkp = 0;
pLOAD->vpkn = 0;
pLOAD->vpp = 0;
pLOAD->Ripple = 0;
pSW->VZ = 0;
pSW->VF = 0;
}
pSW->Now_voltage = pLOAD->voltage;
/* 电压、电流均更新完成后再发布序号,避免状态机读取到半更新数据。 */
g_eload_sample_seq[idx]++;
#if LCD_OPEN
// for(int i = 0;i<4;i++){
// if(pNOR->sw[i].change_flag == 0x01){
@@ -338,17 +439,12 @@ void Show_Curr(rt_uint8_t idx, struct chrg_eload_t *pLOAD, char *tmp, rt_uint8_t
}
void Show_Ripple(rt_uint8_t idx, struct chrg_eload_t *pLOAD, char *tmp, rt_uint8_t online,struct chrg_switch_t *pSW)
{
rt_int32_t ripple_rand = rand() % 11; // 生成0到10之间的随机数
if(online == 0){
if ((online == 0) ||
(pSW->Now_voltage < ELOAD_VALID_VOLTAGE_MIN_MV)) {
snprintf(tmp, 36, "status.CH%d_Ripple.val=0",idx+1);
return;
}else{
if(pSW->Now_voltage<200){
snprintf(tmp, 36, "status.CH%d_Ripple.val=%d",idx+1, ripple_rand);
}else{
}
snprintf(tmp, 36, "status.CH%d_Ripple.val=%d",idx+1, pLOAD->Ripple);
}
}
}
void Show_DZF(rt_uint8_t idx, struct chrg_eload_t *pLOAD, char *tmp, rt_uint8_t online,rt_uint32_t vzf)
{
+31
View File
@@ -164,6 +164,10 @@ typedef enum {
TOTAL_MB_R
} eIDX_MB_PART;
/* South board firmware version register: one 16-bit register at 0x0301. */
#define MODBUSRTU_SW_VERSION_REG 0x0301U
#define MODBUSRTU_SW_VERSION_LEN 1U
#define SIZE_P1_RD 19 // 读19个寄存器
#define SIZE_P2_RD 28 // 读28个寄存器
@@ -239,6 +243,15 @@ struct chrg_eload_t {
*****************************************************************/
extern int chrg_eload_read_regs (rt_uint8_t addr, rt_uint16_t reg, rt_uint16_t len);
/*****************************************************************
Function: chrg_eload_read_version
Description: Request the south board firmware version register.
Input: addr: south board address
Output: -
Return: <0: error, >0: sent length
*****************************************************************/
extern int chrg_eload_read_version (rt_uint8_t addr);
/*****************************************************************
函数名称: chrg_eload_write_reg
函数描述: 向南向发送写单个寄存器
@@ -268,6 +281,24 @@ extern int chrg_eload_refresh (rt_uint8_t addr, rt_uint8_t part);
其它说明: -
*****************************************************************/
extern int chrg_eload_parse (rt_uint8_t idx, rt_uint8_t pt, rt_uint8_t *data, rt_uint16_t len);
/*****************************************************************
Function: chrg_eload_parse_version
Description: Parse and store a valid south board firmware version.
Input: idx: channel, data: Modbus response, len: response length
Output: firmware version is stored at the channel version register
Return: 0: valid, <0: invalid response
*****************************************************************/
extern int chrg_eload_parse_version (rt_uint8_t idx, rt_uint8_t *data, rt_uint16_t len);
/*****************************************************************
函数名称: chrg_eload_get_sample_seq
函数描述: 获取指定南向通道P1量测数据的更新序号
输入参数: idx:南向功率板通道
输出参数: -
返回说明: 当前通道量测序号,通道非法时返回0
其它说明: 每成功解析一帧P1数据后递增,用于区分控制命令前后的新旧量测
*****************************************************************/
extern rt_uint32_t chrg_eload_get_sample_seq(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);
+6 -11
View File
@@ -41,14 +41,9 @@ int chrg_north_pkg_encode (eIDX_ID id, rt_uint8_t cmd, rt_uint8_t *data_in,
if (len_in > 0) {
rt_memcpy(&data_out[4], data_in, len_in);
}
data_out[len_in+4] = 0x2a;//calc_crc8(data_out, len_in+4);
// rt_kprintf("pro_data= \n");
data_out[len_in+4] = calc_crc8(data_out, len_in+4);//0x2a;
*len_out = 5+len_in;
// for(int i = 0; i < *len_out;i++)
// {
// rt_kprintf("%02x ",data_out[i]);
// }
// rt_kprintf("\n");
return 0;
}
@@ -81,7 +76,7 @@ int chrg_north_pkg_decode (rt_uint8_t *data, rt_uint16_t length, struct chrg_swi
struct get_vol_ack_t *pAck = (struct get_vol_ack_t *)data;
pS->vc.voltage = pAck->voltage;
pS->vc.version = pAck->version;
// ?
//
}
break;
@@ -89,9 +84,9 @@ int chrg_north_pkg_decode (rt_uint8_t *data, rt_uint16_t length, struct chrg_swi
struct get_pd_pro_ack_t *pAck = (struct get_pd_pro_ack_t *)data;
pS->pd_get[0].src_type = pAck->type;
pS->pd_get[0].pps_type = pAck->pps;
pS->pd_get[0].mm[0].max_vol = pAck->vmax;
pS->pd_get[0].mm[0].min_vol = pAck->vmin;
pS->pd_get[0].mm[0].max_cur = pAck->curpwr;
pS->pd_get[0].mm.max_vol = pAck->vmax;
pS->pd_get[0].mm.min_vol = pAck->vmin;
pS->pd_get[0].mm.max_cur = pAck->curpwr;
}
break;
+4 -47
View File
@@ -93,60 +93,17 @@ enum {
TOTAL_COIL_REGS // 继电器总数(24个)
};
#define TOTAL_INPUT_CH_REGS (10) // 单通道 输入寄存器
#define TOTAL_INPUT_CH_REGS (50) // 单通道输入寄存器,通道地址步长为50
#define TOTAL_INPUT_REGS TOTAL_INPUT_CH_REGS * 4
// 输入寄存器列表
// 每个通道占用50个地址,当前实际使用前4个寄存器,其余地址预留。
enum {
INPUT_REG_CH0_STA1 = INPUT_REG_START, // 通道0 工作状态1 定义同源载
INPUT_REG_CH0_STA2, // 通道0 工作状态2 定义同源载
INPUT_REG_CH0_FAULT1, // 通道0 故障状态1 定义同源载
INPUT_REG_CH0_FAULT2, // 通道0 故障状态2 定义同源载
INPUT_REG_04, // 输入寄存器04
INPUT_REG_05, // 输入寄存器05
INPUT_REG_06, // 输入寄存器06
INPUT_REG_07, // 输入寄存器07
INPUT_REG_08, // 输入寄存器08
INPUT_REG_09, // 输入寄存器09
// add more TOTAL_INPUT_CH_REGS
INPUT_REG_CH0_FAULT2 // 通道0 故障状态2 定义同源载
INPUT_REG_CH1_STA1, // 通道1 工作状态1
INPUT_REG_CH1_STA2, // 通道1 工作状态2
INPUT_REG_CH1_FAULT1, // 通道1 故障状态1
INPUT_REG_CH1_FAULT2, // 通道1 故障状态2
INPUT_REG_14, // 输入寄存器14
INPUT_REG_15, // 输入寄存器15
INPUT_REG_16, // 输入寄存器16
INPUT_REG_17, // 输入寄存器17
INPUT_REG_18, // 输入寄存器18
INPUT_REG_19, // 输入寄存器19
INPUT_REG_CH2_STA1, // 通道2 工作状态1
INPUT_REG_CH2_STA2, // 通道2 工作状态2
INPUT_REG_CH2_FAULT1, // 通道2 故障状态1
INPUT_REG_CH2_FAULT2, // 通道2 故障状态2
INPUT_REG_24, // 输入寄存器24
INPUT_REG_25, // 输入寄存器25
INPUT_REG_26, // 输入寄存器26
INPUT_REG_27, // 输入寄存器27
INPUT_REG_28, // 输入寄存器28
INPUT_REG_29, // 输入寄存器29
INPUT_REG_CH3_STA1, // 通道3 工作状态1
INPUT_REG_CH3_STA2, // 通道3 工作状态2
INPUT_REG_CH3_FAULT1, // 通道3 故障状态1
INPUT_REG_CH3_FAULT2, // 通道3 故障状态2
INPUT_REG_34, // 输入寄存器34
INPUT_REG_35, // 输入寄存器35
INPUT_REG_36, // 输入寄存器36
INPUT_REG_37, // 输入寄存器37
INPUT_REG_38, // 输入寄存器38
INPUT_REG_39, // 输入寄存器39
INPUT_REG_40, // 输入寄存器40
TOTAL_INPUT_REGS // 输入寄存器总数
};
//AI修改,不一定准确
// ======================== 新寄存器映射 (基于0x06/0x10标准Modbus功能码) ========================
// 地址空间规划:
// 负载(Sink): 0x0000 + 通道号×29 + 参数偏移 (4通道×29=116个, 0x0000~0x0073)
File diff suppressed because it is too large Load Diff
+36 -12
View File
@@ -201,16 +201,40 @@ enum {
#define SINK_CMD_SET_AVS 0xE3 // AVS
/*
* 普通恒流负载允许执行WORK_START的最低设定电流,单位mA。
* 小于该值时北向仍完成协议握手,但南向保持WORK_STOP且不改写电流设定,
* 避免功率板在零电流或几十mA的小电流设定下启动电子负载产生冲击。
*/
#define SINK_LOAD_ENABLE_MIN_MA 100U
/* 主继电器闭合后的0V持续监控:由北向轮询线程每轮调用,掉电立即转掉电保护。 */
extern int chrg_sink_volt_low_protect(eIDX_SOU_CH idx, struct chrg_switch_t *pSW);
enum {
SINK_WORK_INIT =0,
SINK_WORK_WAIT,
SINK_WORK_VOLT_OK,
SINK_WORK_RUNING,
SINK_WORK_RUNING_2,
SINK_WORK_LOW,
SINK_WORK_STOP,
SINK_WORK_ON_TEST_CHANGE,
SINK_WORK_ON_TEST_SHOUT,
SINK_WORK_INIT = 0, // 启动入口:第一条南向命令只打开副继电器
SINK_WORK_INIT_AUX_WAIT, // 等待启动副继电器收到有效南向回码
SINK_WORK_WAIT, // 北向协议设置或电压查询等待状态
SINK_WORK_VOLT_OK, // 预留的电压达标状态
SINK_WORK_RUNING, // 电压稳定后提交继电器、电流和启动命令
SINK_WORK_LOW, // 运行电压过低,执行掉电安全处理
SINK_WORK_LOW_AUX_WAIT, // 等待掉电处理及副继电器恢复批次完成
SINK_WORK_LOW_MONITOR, // 副继电器已恢复,等待输入电压重新出现
SINK_WORK_STOP, // 用户主动停止:先停止负载并确认低电流
SINK_WORK_SWITCH, // 停止旧电源后进入负载INIT
SINK_WORK_PROTOCOL_UNLOAD, // 协议电压或电流变化:掉载但不切换继电器
SINK_WORK_UNLOAD_WAIT, // 等待软卸载完成并连续两次确认电流不大于200mA
SINK_WORK_ON_TEST_DYNA, // 动态负载测试启动状态
SINK_WORK_ON_TEST_SHORT, // 短路测试启动状态
SINK_WORK_ON_TEST_OCP, // OCP过流保护测试启动状态
SINK_WORK_HANDSHAKE_PREPARE, // 完整重握手:停止、清流、全关继电器后打开副继电器
SINK_WORK_HANDSHAKE_WAIT, // 南向低电流确认与北向协议/CC并行
SINK_WORK_LOAD_STANDBY, // 协议已就绪但主继电器未打开,低设定电流下保持停止
SINK_WORK_LOAD_STOP, // 运行中跨到低电流:只发送WORK_STOP关闭电子负载
SINK_WORK_LOAD_START, // 主继电器未打开的低电流待机恢复:等待北向电压稳定后进入RUNING
SINK_WORK_STOP_WAIT, // 关机:等待连续2次实际电流达到安全范围
SINK_WORK_STOP_RELAY, // 关机:低电流确认后提交关闭南向继电器
SINK_WORK_STOP_RELAY_WAIT // 关机:等待关闭南向继电器的回码
};
// sink 参数结构
@@ -234,11 +258,9 @@ struct chrg_sink_t {
rt_uint8_t work_mode; // 0=停止 1=工作 2=低电压
};
//纹波寄存器
#define ModbusRTU_Ripple_Value 0x35 //读取纹波
/******************** 负载测试 ************************* */
#define ModbusRTU_CAL_WriteEnable 0x34 //使能写入;0x4361代表使能写入;C+a ASCII码
#define ModbusRTU_Test_CMD 0x4361 //
@@ -384,7 +406,9 @@ extern void chrg_nor_sink_change_test(rt_uint8_t ch, struct chrg_switch_t *pSW);
extern void chrg_nor_sink_test_stop(rt_uint8_t ch,struct chrg_switch_t *pSW,rt_uint8_t *enable);
extern void chrg_nor_sink_test_run(rt_uint8_t ch, struct chrg_switch_t *pSW);
extern void chrg_sink_work(eIDX_SOU_CH idx, struct chrg_switch_t *pSW);
/* 判断普通负载的当前设定是否允许启动电子负载。 */
extern rt_bool_t chrg_sink_load_should_start(const struct chrg_switch_t *pSW);
extern int chrg_sink_work(eIDX_SOU_CH idx, struct chrg_switch_t *pSW);
#endif
+500 -80
View File
@@ -1,7 +1,7 @@
/****************************************************************************
文件名称 : chrg_source.c
完成日期 :
当前版本号 : V1.0
当前版本号 : V1.1.9
主要功能 : 北向数据source请求数据填充及发送。
版本历史 : 创建原始版本
说明 :
@@ -13,6 +13,395 @@
#include "chrg_utils.h"
#include "chrg_roll_nor.h"
#include "chrg_source.h"
#include "chrg_eload.h"
#include "chrg_roll_sou.h"
#include "chrg_rel.h"
#define SOURCE_VOLT_COMPENSATION_MV 200U
static int chrg_source_work_running(eIDX_SOU_CH idx,
struct chrg_switch_t *pSW);
static int chrg_source_work_full_reset(eIDX_SOU_CH idx,
struct chrg_switch_t *pSW);
static int chrg_source_work_full_reset_wait(eIDX_SOU_CH idx,
struct chrg_switch_t *pSW);
static int chrg_source_work_full_reset_relay(eIDX_SOU_CH idx,
struct chrg_switch_t *pSW);
static int chrg_source_work_full_reset_relay_wait(eIDX_SOU_CH idx,
struct chrg_switch_t *pSW);
static int chrg_source_work_init_wait(eIDX_SOU_CH idx,
struct chrg_switch_t *pSW);
/*****************************************************************
函数名称: chrg_source_init_submit
函数描述: 将电源模式初始化参数批量提交到南向功率板命令队列
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
输出参数: -
返回说明: 0:提交成功 <0:参数错误或队列提交失败
其它说明: INIT不写电压;电压统一由RUNING状态写入,避免多个入口重复控制
*****************************************************************/
int chrg_source_init_submit(rt_uint8_t idx, struct chrg_switch_t *pSW)
{
/* Source启动参数一次入队,最后发送WORK_START使功率板开始输出。 */
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
return -1;
}
rt_uint16_t regs[5] = {
REG_ELOAD,
REG_MODE,
REG_REL_ON,
REG_CURRENT_OUT + 1,
REG_WORK
};
rt_uint16_t vals[5] = {
ELOAD_SOURCE,
pSW->CV_mode,
0x03,
pSW->source.set_curr,
WORK_START
};
return chrg_sou_com_batch_submit(idx, regs, vals, 5);
}
/*****************************************************************
函数名称: chrg_source_work_init
函数描述: 执行电源INIT状态,初始化功率板并打开对应北向通道
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
输出参数: 更新电源运行标志、通道使能、在线状态及work_mode
返回说明: 0:初始化命令提交成功 非0:初始化失败
其它说明: 标准协议从pd_set准备目标并转入RUNING;快充协议清空旧电压后
进入WAIT,等待北向协商结果,INIT本身不写功率板电压
*****************************************************************/
static int chrg_source_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
{
struct chrg_south_t *pSOU = &chrgsouth;
struct chrg_north_t *pNOR = &chrgnorth;
int ret;
/* 最大电流是功率板启动保护值,快充回码到达后可再更新运行目标。 */
pSW->source.set_curr = pSW->source.pd_set.mm.max_cur;
if (pSW->source.protocol == PRO_NONE) {
pSW->source.set_volt = pSW->source.pd_set.mm.max_vol;
} else {
/* 禁止快充重新启动时沿用上一次协商电压。 */
pSW->source.set_volt = 0;
}
ret = chrg_source_init_submit(idx, pSW);
if (ret != 0) {
return ret;
}
pSW->source.On_Flag = 1;
pSW->source.qc_err = 0;
pNOR->enable[idx] = 1;
pSOU->online[idx] = 1;
chrg_nor_sw_rel((eIDX_NOR_CH)idx, ID_SOURCE);
/* 初始化批次必须全部收到南向回码后,才能继续协议设置或输出控制。 */
pSW->source.work_mode = SOURCE_WORK_INIT_WAIT;
return 0;
}
static int chrg_source_work_init_wait(eIDX_SOU_CH idx,
struct chrg_switch_t *pSW)
{
int result;
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
return -1;
}
if (chrg_sou_com_batch_is_pending(idx)) {
return 1;
}
result = chrg_sou_com_batch_get_result(idx);
if (result <= 0) {
/* 南向初始化失败时,保持北向协议不变并重发完整初始化批次。 */
pSW->source.work_mode = SOURCE_WORK_INIT;
return 1;
}
if (pSW->sub == IDX_SET_SOURCE_RESET) {
/* 复位后的初始化完成,才允许进入PD协议设置。 */
pSW->sub = IDX_SET_SOURCE_PD;
pSW->source.work_mode = SOURCE_WORK_WAIT;
return 0;
}
if (pSW->source.protocol == PRO_NONE) {
/* 标准协议不等待协商,初始化完成后直接写入目标电压。 */
pSW->source.work_mode = SOURCE_WORK_RUNING;
return chrg_source_work_running(idx, pSW);
}
pSW->source.work_mode = SOURCE_WORK_WAIT;
return 0;
}
/*****************************************************************
函数名称: chrg_source_work_wait
函数描述: 执行电源WAIT状态
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
输出参数: -
返回说明: 0:状态处理完成
其它说明: WAIT状态不下发命令,由北向解析函数判断目标电压是否变化
*****************************************************************/
static int chrg_source_work_wait(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
{
/* WAIT状态不产生南向命令,等待下一帧北向电压数据。 */
return 0;
}
/*****************************************************************
函数名称: chrg_source_work_running
函数描述: 执行电源RUNING状态,下发补偿后的最新目标电压
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
输出参数: -
返回说明: 0:命令提交成功 非0:命令提交失败
其它说明: 功率板设定值固定比目标高200mV,防止限压导致输出进入稳流模式;
目标最大值为48000mV,无需做uint16_t饱和处理
*****************************************************************/
static int chrg_source_work_running(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
{
/* 只对本次下发值补偿,不修改set_volt,防止多次执行时累计增加。 */
rt_uint16_t reg = REG_VOLTAGE_OUT + 1;
rt_uint16_t value = pSW->source.set_volt;
return chrg_sou_com_batch_submit(idx, &reg, &value, 1);
}
/*****************************************************************
函数名称: chrg_source_work_protocol_switch
函数描述: 执行电源协议或CC切换前的功率板输出清零
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
输出参数: 清零source.set_volt,并在命令入队成功后进入WAIT状态
返回说明: 0:清零命令提交成功 非0:状态或命令提交失败
其它说明: COM在进入本状态前必须将sub设置为协议、CC或组合事务入口;
本状态只管理南向清零,不修改北向sub,
标准协议同时按0V、模式、电流顺序入队,保证南向命令顺序固定
*****************************************************************/
static int chrg_source_work_protocol_switch(eIDX_SOU_CH idx,
struct chrg_switch_t *pSW)
{
rt_uint16_t regs[3];
rt_uint16_t vals[3];
rt_uint8_t count = 0;
int ret;
if ((pSW->sub != IDX_SET_SOURCE_PD) &&
(pSW->sub != IDX_SET_SOURCE_RESET)) {
return -1;
}
regs[count] = REG_VOLTAGE_OUT + 1;
vals[count++] = 0;
if (pSW->source.protocol == PRO_NONE) {
/* 标准协议切换时,模式和限流值必须排在0V命令之后生效。 */
regs[count] = REG_MODE;
vals[count++] = pSW->CV_mode;
regs[count] = REG_CURRENT_OUT + 1;
vals[count++] = pSW->source.pd_set.mm.max_cur;
}
/* 只有整批命令成功加入南向队列后,才允许北向继续协议切换。 */
ret = chrg_sou_com_batch_submit(idx, regs, vals, count);
if (ret != 0) {
return ret;
}
pSW->source.set_volt = 0;
pSW->source.work_mode = SOURCE_WORK_WAIT;
return 0;
}
static int chrg_source_work_full_reset(eIDX_SOU_CH idx,
struct chrg_switch_t *pSW)
{
rt_uint16_t reg = REG_WORK;
rt_uint16_t value = WORK_STOP;
/* Cancel stale south commands so the reset sequence starts from a known state. */
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
return -1;
}
if (chrg_sou_com_batch_cancel(idx) != 0) {
return -1;
}
if (chrg_sou_com_batch_submit(idx, &reg, &value, 1) != 0) {
return -1;
}
pSW->source.set_volt = 0;
pSW->source.work_mode = SOURCE_WORK_FULL_RESET_WAIT;
return 1;
}
static int chrg_source_work_full_reset_wait(eIDX_SOU_CH idx,
struct chrg_switch_t *pSW)
{
int result;
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
return -1;
}
if (chrg_sou_com_batch_is_pending(idx)) {
return 1;
}
result = chrg_sou_com_batch_get_result(idx);
if (result <= 0) {
pSW->source.work_mode = SOURCE_WORK_FULL_RESET;
return 1;
}
pSW->source.work_mode = SOURCE_WORK_FULL_RESET_RELAY;
return 1;
}
static int chrg_source_work_full_reset_relay(eIDX_SOU_CH idx,
struct chrg_switch_t *pSW)
{
rt_uint16_t reg = REG_REL_ON;
rt_uint16_t value = ALL_REL_OFF;
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
return -1;
}
if (chrg_sou_com_batch_submit(idx, &reg, &value, 1) != 0) {
return -1;
}
pSW->source.work_mode = SOURCE_WORK_FULL_RESET_RELAY_WAIT;
return 1;
}
static int chrg_source_work_full_reset_relay_wait(eIDX_SOU_CH idx,
struct chrg_switch_t *pSW)
{
int result;
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
return -1;
}
if (chrg_sou_com_batch_is_pending(idx)) {
return 1;
}
result = chrg_sou_com_batch_get_result(idx);
if (result <= 0) {
pSW->source.work_mode = SOURCE_WORK_FULL_RESET_RELAY;
return 1;
}
/* South relays are off; now disconnect D+/D- and CC before SOURCE_RESET. */
chrg_nor_sw_rel((eIDX_NOR_CH)idx, 0);
pSW->sub = IDX_SET_SOURCE_RESET;
pSW->source.work_mode = SOURCE_WORK_WAIT;
return 1;
}
/*****************************************************************
函数名称: chrg_source_work_stop
函数描述: 执行电源主动关机流程
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
输出参数: 清除目标电压、运行标志、通道使能和在线状态
返回说明: 0:停止成功 非0:停止命令提交失败
其它说明: 依次关闭功率板两路继电器、清零电压并发送WORK_STOP;
停止命令成功入队后立即关闭北向通道,不额外发送CC_CLOSE
*****************************************************************/
static int chrg_source_work_stop(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
{
struct chrg_south_t *pSOU = &chrgsouth;
struct chrg_north_t *pNOR = &chrgnorth;
int ret;
rt_uint16_t regs[3] = {REG_REL_ON, REG_VOLTAGE_OUT + 1, REG_WORK};
rt_uint16_t vals[3] = {ALL_REL_OFF, 0, WORK_STOP};
/* 先断开两路功率继电器,再清零输出并停止,避免关机瞬间继续向外供电。 */
ret = chrg_sou_com_batch_submit(idx, regs, vals, 3);
if (ret != 0) {
return ret;
}
pSW->source.set_volt = 0;
pSW->source.On_Flag = 0;
pSW->source.qc_err = 0;
pNOR->enable[idx] = 0;
pSOU->online[idx] = 0;
chrg_nor_sw_rel((eIDX_NOR_CH)idx, 0);
pSW->sub = IDX_SET_SOURCE_STOP_STATE;
pSW->source.work_mode = SOURCE_WORK_WAIT;
return 0;
}
/*****************************************************************
函数名称: chrg_source_work_switch
函数描述: 处理“负载切换到电源”的过渡状态
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
输出参数: 清除旧负载运行标志,设置电源北向入口和INIT状态
返回说明: 0:停止命令成功加入队列 非0:命令入队失败
其它说明: pSW->id已由COM更新为ID_SOURCE;先关闭旧负载继电器并提交
WORK_STOP,后续电源INIT使用同一通道队列,保证停止命令先执行
*****************************************************************/
static int chrg_source_work_switch(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
{
rt_uint16_t regs[3] = {REG_REL_ON, REG_VOLTAGE_OUT + 1, REG_WORK};
rt_uint16_t vals[3] = {ALL_REL_OFF, 0, WORK_STOP};
int ret;
ret = chrg_sou_com_batch_submit(idx, regs, vals, 3);
if (ret != 0) {
return ret;
}
/* 停止成功入队后,清除旧Sink运行标志。 */
pSW->sink.On_work = 0;
pSW->source.set_volt = 0;
/* 首次进入Source按“设置协议->连接CC”启动,不能沿用Sink的sub状态。 */
pSW->sub = IDX_SET_SOURCE_PD;
/* SWITCH只负责旧角色退出,后续启动统一交给Source INIT状态。 */
pSW->source.work_mode = SOURCE_WORK_INIT;
return 0;
}
/*****************************************************************
函数名称: chrg_source_work_state
函数描述: 电源工作状态机统一入口
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
输出参数: 根据source.work_mode执行对应状态动作
返回说明: 0:状态处理成功 <0:参数、状态或命令提交失败
其它说明: 支持INIT、WAIT、RUNING、STOP、SWITCH和PROTOCOL_SWITCH状态
*****************************************************************/
int chrg_source_work_state(rt_uint8_t idx, struct chrg_switch_t *pSW)
{
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
return -1;
}
/* 所有Source功率板控制统一从本状态机出口执行。 */
switch (pSW->source.work_mode) {
case SOURCE_WORK_INIT:
return chrg_source_work_init(idx, pSW);
case SOURCE_WORK_WAIT:
return chrg_source_work_wait(idx, pSW);
case SOURCE_WORK_RUNING:
return chrg_source_work_running(idx, pSW);
case SOURCE_WORK_STOP:
return chrg_source_work_stop(idx, pSW);
case SOURCE_WORK_SWITCH:
return chrg_source_work_switch(idx, pSW);
case SOURCE_WORK_PROTOCOL_SWITCH:
return chrg_source_work_protocol_switch(idx, pSW);
case SOURCE_WORK_FULL_RESET:
return chrg_source_work_full_reset(idx, pSW);
case SOURCE_WORK_FULL_RESET_WAIT:
return chrg_source_work_full_reset_wait(idx, pSW);
case SOURCE_WORK_FULL_RESET_RELAY:
return chrg_source_work_full_reset_relay(idx, pSW);
case SOURCE_WORK_FULL_RESET_RELAY_WAIT:
return chrg_source_work_full_reset_relay_wait(idx, pSW);
case SOURCE_WORK_INIT_WAIT:
return chrg_source_work_init_wait(idx, pSW);
default:
return -1;
}
}
rt_uint8_t Pro_Group_VCMM[11][8] = {
{0} // 11个挡位,8个参数(src, pps, vmin_H,vmin_L, vmax_H,vmax_L,cur_set_H,cur_set_L)
};
@@ -58,6 +447,18 @@ int source_get_pd (void)
return chrg_north_send(frame, len);
}
int source_reset (void)
{
rt_uint16_t len = 0;
rt_uint8_t data[8] = {0};
rt_uint8_t frame[16] = {0};
data[0] = 0x00;
chrg_north_pkg_encode(ID_SOURCE, SRC_CMD_RESET, data, 1, frame, &len);
return chrg_north_send(frame, len);
}
/*****************************************************************
函数名称: source_set_cc_lvl
函数描述: source 设置 cc 等级
@@ -96,11 +497,13 @@ int source_set_cc_choose (rt_uint8_t cc_set)
data[0] = cc_set;
chrg_north_pkg_encode(ID_SOURCE, SRC_CMD_SET_CC_CHOOSE, data, 1, frame, &len);
rt_kprintf("\n");
for(int i=0;i<len;i++){
rt_kprintf("%d ");
#if NORTH_SOURCE_DEBUG
rt_kprintf("source set cc frame:");
for (int i = 0; i < len; i++) {
rt_kprintf(" %02x", frame[i]);
}
rt_kprintf("\n");
#endif
return chrg_north_send(frame, len);
}
@@ -118,9 +521,13 @@ rt_uint8_t parse_mulit_gear_One(rt_uint16_t min_volt_mv,rt_uint16_t max_volt_mv,
Pro_Group_VCMM[0][4] = (max_volt_mv >> 8) & 0xFF; // vmax_H
Pro_Group_VCMM[0][5] = max_volt_mv & 0xFF; // vmax_L
Pro_Group_VCMM[0][6] = (max_curr_ma >> 8) & 0xFF; // cur_set_H
#if NORTH_SOURCE_DEBUG
rt_kprintf("H_C=%02x",Pro_Group_VCMM[0][6]);
#endif
Pro_Group_VCMM[0][7] = max_curr_ma & 0xFF; // cur_set_L
#if NORTH_SOURCE_DEBUG
rt_kprintf("L_C=%02x\n",Pro_Group_VCMM[0][7]);
#endif
return 0;
}
@@ -152,12 +559,12 @@ void parse_power_single_gear(rt_uint8_t protoCmd, rt_uint8_t *pData, rt_uint16_t
// rt_kprintf("%0x",pData[i]);
// }
// rt_kprintf("\n");
#if PRO_TEST_DEBUG
#if NORTH_SOURCE_DEBUG
rt_kprintf("one_gear");
rt_kprintf("min_volt_mv = %d\n",min_volt_mv);
rt_kprintf("max_volt_mv = %d\n",max_volt_mv);
rt_kprintf("prtect_curr= %04x",*protect_curr);
#endif
#endif
*pro_gear_idx = 1; // 单档协议固定1
// 按协议命令码赋值
switch (protoCmd)
@@ -264,7 +671,7 @@ void parse_pd_11group_pdo(rt_uint8_t *pdoData, rt_uint8_t pdo_group_num) {
// 电流/功率拆分
Pro_Group_VCMM[i][6] = (cur_power >> 8) & 0xFF; // cur_set_H
Pro_Group_VCMM[i][7] = cur_power & 0xFF; // cur_set_L
#if PRO_TEST_DEBUG
#if NORTH_SOURCE_DEBUG
// 调试打印
rt_kprintf("max_H=%d",Pro_Group_VCMM[i][4]);
rt_kprintf("max_L=%d",Pro_Group_VCMM[i][5]);
@@ -305,9 +712,13 @@ void parse_power_pdo_gear(rt_uint8_t protoCmd, rt_uint8_t *pData, rt_uint16_t re
rt_int16_t comp_volt_mv = 0; // 补偿电压(mV)
// 数据区索引:0=状态+通道,1=CC线,2=恒压恒流模式,3=PDO组数(bit12-15)
#if NORTH_SOURCE_DEBUG
rt_kprintf("pdata=%04x",pData[3]);
#endif
pdo_group_num = (pData[3] >> 4) & 0x0F; // Bit12-15提取组数
#if NORTH_SOURCE_DEBUG
rt_kprintf("num=%d\n",pdo_group_num);
#endif
*pro = PRO_PD0PSS;
*pro_gear_idx = pdo_group_num;
// 解析11组PDO(小端序,44字节)
@@ -316,13 +727,11 @@ void parse_power_pdo_gear(rt_uint8_t protoCmd, rt_uint8_t *pData, rt_uint16_t re
// 解析保留字段(20字节) + 保护电流 + 补偿电压
*protect_ma = u8v_to_u16(&pData[4 + 44 + 20]); // 67-68字节
comp_volt_mv = (rt_int16_t)u8v_to_u16(&pData[4 + 44 + 22]); // 69-70字节
// #if PRO_TEST_DEBUG
#if NORTH_SOURCE_DEBUG
rt_kprintf("project_curr=%d mA, add_volt=%d mV\n", *protect_ma, comp_volt_mv);
// #endif.
#endif
}
/*****************************************************************
函数名称: parse_mulit_gear_more
函数描述: 解析三-四挡位原始数据,填充8参数高低字节缓冲区(同步修改)
@@ -408,7 +817,7 @@ rt_uint8_t parse_mulit_gear_more(rt_uint8_t *pData, rt_uint8_t gear_num) {
Pro_Group_VCMM[i][5] = vmax_mv & 0xFF; // vmax_L
Pro_Group_VCMM[i][6] = (cur_power >> 8) & 0xFF; // cur_set_H
Pro_Group_VCMM[i][7] = cur_power & 0xFF; // cur_set_L
#if PRO_TEST_DEBUG
#if NORTH_SOURCE_DEBUG
// 调试打印
rt_kprintf("parse_mulit_gear_pd0 PDO[%d]:rc=0x%02X, pps=0x%02X,V_Min=%dmV,V_MAX=%dmV,C/P=%d\n",
i, Pro_Group_VCMM[i][0], Pro_Group_VCMM[i][1], vmin_mv, vmax_mv, cur_power);
@@ -443,7 +852,9 @@ void parse_multi_gear_more(rt_uint8_t protoCmd, rt_uint8_t *pData, rt_uint16_t r
return;
}
*pro_gear_idx = gear_num;
#if NORTH_SOURCE_DEBUG
rt_kprintf("pro_gear_idx = %d\n",gear_num);
#endif
// 解析保护电流和补偿电压(不同协议偏移不同)
switch (protoCmd)
{
@@ -462,7 +873,7 @@ void parse_multi_gear_more(rt_uint8_t protoCmd, rt_uint8_t *pData, rt_uint16_t r
}
*protect_ma = u8v_to_u16(&pData[4 + 16]); // 19-20字节
comp_volt_mv = (rt_int16_t)u8v_to_u16(&pData[4 + 18]);
#if PRO_TEST_DEBUG
#if NORTH_SOURCE_DEBUG
for(int i = 0;i<30;i++){
rt_kprintf("data[%d]=%02x",i,pData[i]);
}
@@ -524,7 +935,7 @@ rt_uint8_t parse_ufcs_gear_more(rt_uint8_t *pData, rt_uint8_t gear_num) {
Pro_Group_VCMM[i][5] = vmax_mv & 0xFF;
Pro_Group_VCMM[i][6] = (cur_ma >> 8) & 0xFF;
Pro_Group_VCMM[i][7] = cur_ma & 0xFF;
#if PRO_TEST_DEBUG
#if NORTH_SOURCE_DEBUG
// ================= 打印格式 =================
rt_kprintf("parse_ufcs_gear_more PDO[%d]:PPS/AVS,V_Min=%dmV,V_MAX=%dmV,Max_Current=%dmA\n",
i, vmin_mv, vmax_mv, cur_ma);
@@ -568,10 +979,10 @@ void parse_power_ufcs(rt_uint8_t *pData, rt_uint16_t reqLen, uint8_t *pro_gear_i
// rt_kprintf("data[%d]=%02x",i,pData[i]);
// }
comp_volt_mv = 0;//(rt_int16_t)u8v_to_u16(&pData[3 + 14]);
//#if PRO_TEST_DEBUG
#if NORTH_SOURCE_DEBUG
rt_kprintf("parse_power_ufcs:gear=%d,protect=%dmA,comp=%dmV\n",
gear_num,*protect_ma, comp_volt_mv);
//#endif
#endif
// 调用下面的循环解析
parse_ufcs_gear_more(&pData[4], gear_num);
@@ -705,6 +1116,8 @@ rt_uint8_t pd_fill_single_group_need_src_com(rt_uint8_t *data, rt_uint8_t start_
rt_uint8_t idx = start_idx;
struct chrg_src_t *source = &psw->source;
const struct vc_pd_t *pd = &source->pd_set;
const struct vc_mm_t *mm = &pd->mm;
// 1. src + pps(2字节)
data[idx++] = 0x00;
data[idx++] = 0x00;
@@ -715,23 +1128,23 @@ rt_uint8_t pd_fill_single_group_need_src_com(rt_uint8_t *data, rt_uint8_t start_
data[idx++] = 0x13;
data[idx++] = 0x88;
// 4. 电流/功率(高+低,直接取已拆分好的值)
data[idx++] = source->protective_curr >> 8;
data[idx++] = source->protective_curr & 0xFF;
data[idx++] = mm->max_cur >> 8;
data[idx++] = mm->max_cur & 0xFF;
// 5. 保留位6字节(直接填0)
memset(&data[idx], 0x00, 6);
idx+=6;
data[idx++] = source->src;
data[idx++] = source->pps;
rt_kprintf("src = %d pps = %d\n",source->src,source->pps);
data[idx++] = pd->src_type;
data[idx++] = pd->pps_type;
//rt_kprintf("src = %d pps = %d\n", pd->src_type, pd->pps_type);
// 2. 最小电压(高+低,直接取已拆分好的值)
data[idx++] = source->min_vol >> 8;
data[idx++] = source->min_vol & 0xFF;
data[idx++] = mm->min_vol >> 8;
data[idx++] = mm->min_vol & 0xFF;
// 3. 最大电压(高+低,直接取已拆分好的值)
data[idx++] = source->max_vol >> 8;
data[idx++] = source->max_vol & 0xFF;
data[idx++] = mm->max_vol >> 8;
data[idx++] = mm->max_vol & 0xFF;
// 4. 电流/功率(高+低,直接取已拆分好的值)
data[idx++] = source->protective_curr >> 8;
data[idx++] = source->protective_curr & 0xFF;
data[idx++] = mm->max_cur >> 8;
data[idx++] = mm->max_cur & 0xFF;
// 5. 保留位6字节(直接填0)
memset(&data[idx], 0x00, 6);
idx+=6;
@@ -742,28 +1155,30 @@ rt_uint8_t pd_fill_single_group_no_src_com(rt_uint8_t *data, rt_uint8_t start_id
rt_uint8_t idx = start_idx;
struct chrg_src_t *source = &psw->source;
const struct vc_mm_t *mm = &source->pd_set.mm;
// 1. src + pps(2字节)
data[idx++] = 0x00;
data[idx++] = 0x00;
// 2. 最小电压(高+低,直接取已拆分好的值)
data[idx++] = source->min_vol >> 8;
data[idx++] = source->min_vol & 0xFF;
data[idx++] = 0x13;//mm->min_vol >> 8;
data[idx++] = 0x18;//mm->min_vol & 0xFF;
// 3. 最大电压(高+低,直接取已拆分好的值)
data[idx++] = source->max_vol >> 8;
data[idx++] = source->max_vol & 0xFF;
data[idx++] = mm->max_vol >> 8;
data[idx++] = mm->max_vol & 0xFF;
// 4. 电流/功率(高+低,直接取已拆分好的值)
data[idx++] = source->protective_curr >> 8;
data[idx++] = source->protective_curr & 0xFF;
data[idx++] = mm->max_cur >> 8;
data[idx++] = mm->max_cur & 0xFF;
// 5. 保留位6字节(直接填0)
memset(&data[idx], 0x00, 6);
idx+=6;
return idx - start_idx; // 返回填充的总字节数
}
rt_uint8_t pd_fill_single_group_FCP_AFC(rt_uint8_t *data, rt_uint8_t start_idx,struct chrg_switch_t *psw){
rt_uint8_t pd_fill_single_group_AFC(rt_uint8_t *data, rt_uint8_t start_idx,struct chrg_switch_t *psw){
rt_uint8_t idx = start_idx;
struct chrg_src_t *source = &psw->source;
const struct vc_mm_t *mm = &source->pd_set.mm;
// 1. src + pps(2字节)
data[idx++] = 0x00;
data[idx++] = 0x00;
@@ -774,8 +1189,8 @@ rt_uint8_t pd_fill_single_group_FCP_AFC(rt_uint8_t *data, rt_uint8_t start_idx,s
data[idx++] = 0x13;
data[idx++] = 0x88;
// 4. 电流/功率(高+低,直接取已拆分好的值)
data[idx++] = source->protective_curr >> 8;
data[idx++] = source->protective_curr & 0xFF;
data[idx++] = mm->max_cur >> 8;
data[idx++] = mm->max_cur & 0xFF;
// 5. 保留位6字节(直接填0)
memset(&data[idx], 0x00, 6);
idx+=6;
@@ -783,14 +1198,14 @@ rt_uint8_t pd_fill_single_group_FCP_AFC(rt_uint8_t *data, rt_uint8_t start_idx,s
data[idx++] = 0x00;
data[idx++] = 0x00;
// 2. 最小电压(高+低,直接取已拆分好的值)
data[idx++] = source->max_vol >> 8;
data[idx++] = source->max_vol & 0xFF;
data[idx++] = mm->max_vol >> 8;
data[idx++] = mm->max_vol & 0xFF;
// 3. 最大电压(高+低,直接取已拆分好的值)
data[idx++] = source->max_vol >> 8;
data[idx++] = source->max_vol & 0xFF;
data[idx++] = mm->max_vol >> 8;
data[idx++] = mm->max_vol & 0xFF;
// 4. 电流/功率(高+低,直接取已拆分好的值)
data[idx++] = source->protective_curr >> 8;
data[idx++] = source->protective_curr & 0xFF;
data[idx++] = mm->max_cur >> 8;
data[idx++] = mm->max_cur & 0xFF;
// 5. 保留位6字节(直接填0)
memset(&data[idx], 0x00, 6);
idx+=6;
@@ -801,6 +1216,7 @@ rt_uint8_t pd_fill_single_group_UFCS(rt_uint8_t *data, rt_uint8_t start_idx,stru
rt_uint8_t idx = start_idx;
struct chrg_src_t *source = &psw->source;
const struct vc_mm_t *mm = &source->pd_set.mm;
// 1. src + pps(2字节)
data[idx++] = 0x00;
data[idx++] = 0x00;
@@ -811,8 +1227,8 @@ rt_uint8_t pd_fill_single_group_UFCS(rt_uint8_t *data, rt_uint8_t start_idx,stru
data[idx++] = 0x13;
data[idx++] = 0x88;
// 4. 电流/功率(高+低,直接取已拆分好的值)
data[idx++] = source->protective_curr >> 8;
data[idx++] = source->protective_curr & 0xFF;
data[idx++] = mm->max_cur >> 8;
data[idx++] = mm->max_cur & 0xFF;
// 5. 保留位6字节(直接填0)
memset(&data[idx], 0x00, 6);
idx+=6;
@@ -820,48 +1236,47 @@ rt_uint8_t pd_fill_single_group_UFCS(rt_uint8_t *data, rt_uint8_t start_idx,stru
data[idx++] = 0x00;
data[idx++] = 0x00;
// 2. 最小电压(高+低,直接取已拆分好的值)
data[idx++] = source->min_vol >> 8;
data[idx++] = source->min_vol & 0xFF;
data[idx++] = mm->min_vol >> 8;
data[idx++] = mm->min_vol & 0xFF;
// 3. 最大电压(高+低,直接取已拆分好的值)
data[idx++] = source->max_vol >> 8;
data[idx++] = source->max_vol & 0xFF;
data[idx++] = mm->max_vol >> 8;
data[idx++] = mm->max_vol & 0xFF;
// 4. 电流/功率(高+低,直接取已拆分好的值)
data[idx++] = source->protective_curr >> 8;
data[idx++] = source->protective_curr & 0xFF;
data[idx++] = mm->max_cur >> 8;
data[idx++] = mm->max_cur & 0xFF;
// 5. 保留位6字节(直接填0)
memset(&data[idx], 0x00, 6);
idx+=6;
return idx - start_idx; // 返回填充的总字节数
}
int source_set_pd_com(rt_uint8_t pro,rt_uint8_t pro_gear_idx)
static rt_uint8_t chrg_source_fill_AFC_three_gears(rt_uint8_t *data,
rt_uint8_t start_idx, struct chrg_switch_t *psw)
{
rt_uint16_t len = 0;
rt_uint8_t data[150] = {0};
rt_uint8_t frame[150] = {0};
rt_uint8_t send_len = 0; //数据长度
rt_uint8_t max_group_idx = 0; //挡位索引
data[0] = pro; //协议
rt_uint8_t idx = 1;
for(rt_uint8_t i = 0;i<pro_gear_idx;i++){
rt_uint8_t fill_len = pd_fill_single_group_com(data,idx,i);
if (fill_len == 0) {
rt_kprintf("Error: fill group %d failed\n", i);
return -1;
}
idx += fill_len; // 偏移到下一组起始位置
}
send_len = idx; // 总填充字节数
static const rt_uint16_t fixed_voltages[] = {5000U, 9000U, 12000U, 20000U};
const struct vc_mm_t *mm = &psw->source.pd_set.mm;
rt_uint8_t idx = start_idx;
rt_uint8_t gear;
chrg_north_pkg_encode(ID_SOURCE, SRC_CMD_SET_PROTOCOL, data, send_len, frame, &len);
// for(rt_uint8_t i=0;i<len+5;i++){
// rt_kprintf("%02x",data[i]);
// }
// rt_kprintf("idx=%d",idx);
return chrg_north_send(frame, len);
for (gear = 0; gear < (sizeof(fixed_voltages) / sizeof(fixed_voltages[0]));
gear++) {
/* FCP固定电压档不使用PD源类型和PPS类型。 */
data[idx++] = 0x00;
data[idx++] = 0x00;
data[idx++] = fixed_voltages[gear] >> 8;
data[idx++] = fixed_voltages[gear] & 0xFF;
data[idx++] = fixed_voltages[gear] >> 8;
data[idx++] = fixed_voltages[gear] & 0xFF;
data[idx++] = mm->max_cur >> 8;
data[idx++] = mm->max_cur & 0xFF;
memset(&data[idx], 0x00, 6);
idx += 6;
}
return idx - start_idx;
}
int source_set_pd_new_com(rt_uint8_t pro, struct chrg_switch_t *pSW)
int source_set_pro(rt_uint8_t pro, struct chrg_switch_t *pSW)
{
rt_uint16_t len = 0;
rt_uint8_t data[150] = {0};
@@ -872,19 +1287,25 @@ int source_set_pd_new_com(rt_uint8_t pro, struct chrg_switch_t *pSW)
rt_uint8_t idx = 1; //从data[1]开始填充
rt_uint8_t fill_len = 0;
rt_uint8_t protocal = pSW->source.protocol;
if(protocal == 0x0A){
if(protocal == PRO_PD0PSS){
fill_len = pd_fill_single_group_need_src_com(data, idx, pSW);
}else if(protocal == 0x03||protocal == 0x07||protocal == 0x08 ){
}else if(protocal == PRO_SCPB||protocal == PRO_QC30||protocal == PRO_QC20 ||protocal == PRO_FCP ){
fill_len = pd_fill_single_group_no_src_com(data, idx, pSW);
}else if(protocal == 0x0C){
}else if(protocal == PRO_UFCS){
fill_len = pd_fill_single_group_UFCS(data, idx, pSW);
}else{
fill_len = pd_fill_single_group_FCP_AFC(data, idx, pSW);
fill_len = chrg_source_fill_AFC_three_gears(data, idx, pSW);
}
idx += fill_len;
send_len = idx; // 总填充字节数
chrg_north_pkg_encode(ID_SOURCE, SRC_CMD_SET_PROTOCOL, data, send_len, frame, &len);
rt_kprintf("idx = %d ",idx);
#if NORTH_SOURCE_DEBUG
rt_kprintf("source protocol frame:");
for (rt_uint16_t i = 0; i < len; i++) {
rt_kprintf(" %02x", frame[i]);
}
rt_kprintf("\n");
#endif
// for(rt_uint8_t i=0;i<idx;i++){
// rt_kprintf("%02x",data[i]);
// }
@@ -892,4 +1313,3 @@ int source_set_pd_new_com(rt_uint8_t pro, struct chrg_switch_t *pSW)
return chrg_north_send(frame, len);
}
+36 -21
View File
@@ -1,7 +1,7 @@
/****************************************************************************
文件名称 : chrg_source.c
完成日期 :
当前版本号 : V1.0
当前版本号 : V1.1.9
主要功能 : 北向数据source请求数据填充及发送,命令字定义。
版本历史 : 创建原始版本
说明 :
@@ -25,6 +25,8 @@ struct chrg_switch_t;
#define SRC_CMD_SET_CC_CHOOSE 0x17
#define SRC_CMD_RESET 0x18
#define SRC_CMD_SET_PROTOCOL 0xD0
#define PROTOCOL_NONE 0x00 // 无快充
@@ -137,39 +139,46 @@ struct set_qc_ack_t {
struct src_vc_t {
rt_uint16_t voltage; // 读取 0.01V
rt_uint16_t set_voltage; // 设置电压 mV
rt_uint16_t set_current; // 设置电流 mA
rt_uint16_t version; // 版本号
};
#define PD_GEAR_ARRAY_LEN 4 // 非5V挡位最多4个,数组长度设为4
// source 参数结构
struct chrg_src_t {
rt_uint16_t voltage; // 当前电压 mV
rt_uint16_t current; // 当前电流 mA
eSRC_PRO protocol; // 协议类型
rt_uint8_t src; // 源类型
rt_uint8_t pps; // PPS类型
rt_uint8_t pro_gear_idx; // 挡位
rt_uint16_t min_vol; // 最小电压 mV
rt_uint16_t max_vol; // 最大电压 mV
rt_uint8_t vol_lvl; // CC线电平
rt_uint8_t cc_set; // cc线选择 //0代表1+2,1代表cc1,2代表cc2
rt_uint16_t protective_curr; // 保护电流
rt_uint8_t CC_Set; // CC线选择:0=CC1+CC2,1=CC1,2=CC2
rt_uint8_t Now_State; // 当前状态
rt_uint8_t On_Flag; // 启动总标志(0/1)
rt_uint8_t Set_CV_Flag; // 电压/电流切换标志(0/1)
rt_uint8_t Set_Pro_Flag; // 设置协议标志位(0/1/2)0代表没设置协议,1代表设置了但还没执行,2代表设置了并执行
rt_uint8_t LCD_Set_Pro_Flag; // LCD设置协议标志位
rt_uint8_t Work_step_flag; // 工作步骤标志位
rt_uint8_t Stop_step_flag; // 停止步骤标志位
rt_uint8_t change_sink_Flag; // 从source切换到sink标志位
rt_uint8_t work_mode; // 0=停止 1=工作 2=低电压
struct src_vc_t vc; // 读取数据
rt_uint8_t work_mode;
rt_uint8_t qc_err; // Source板0x20回码错误码,bit2表示协议/CC切换失败
rt_uint16_t set_volt; // 北向解析后准备写入功率板的目标电压(mV)
rt_uint16_t set_curr; // 北向解析后准备写入功率板的目标电流(mA)
struct src_vc_t vc; // 北向回读数据
struct vc_pd_t pd_get[2]; // 读取PD协议数据
struct vc_pd_t pd_set[2]; // 设置PD协议数据
struct vc_pd_t pd_set; // COM设置的协议挡位、类型和电压电流范围
};
// 电源工作状态机:COM只切换状态,具体功率板指令由状态处理函数下发
enum {
SOURCE_WORK_INIT = 0, // 初始化功率板并启动输出
SOURCE_WORK_WAIT, // 参数未变化,不下发功率板指令
SOURCE_WORK_RUNING, // 协商电压变化,下发一次新电压
SOURCE_WORK_LOW, // 电压过低,停止功率板输出
SOURCE_WORK_STOP, // 主动停止并关闭通道
SOURCE_WORK_SWITCH, // 停止旧负载后进入电源INIT
SOURCE_WORK_PROTOCOL_SWITCH, // 协议/CC切换前清零功率板输出
SOURCE_WORK_FULL_RESET, // Submit output clear and stop commands
SOURCE_WORK_FULL_RESET_WAIT, // Wait for output clear and stop
SOURCE_WORK_FULL_RESET_RELAY, // Submit south relay-off command
SOURCE_WORK_FULL_RESET_RELAY_WAIT,// Wait before disconnecting north relay
SOURCE_WORK_INIT_WAIT, // Wait for Source init batch completion
SOURCE_WORK_ON_TEST_DYNA,
SOURCE_WORK_ON_TEST_SHORT,
};
/*****************************************************************
函数名称: source_get_vc
函数描述: source电压电流查询请求
@@ -190,6 +199,8 @@ extern int source_get_vc (rt_uint16_t vol, rt_uint16_t cur);
*****************************************************************/
extern int source_get_pd (void);
extern int source_reset (void);
/*****************************************************************
函数名称: source_set_cc_lvl
函数描述: source 设置 cc 等级
@@ -248,7 +259,11 @@ extern void parse_power_single_gear(rt_uint8_t protoCmd, rt_uint8_t *pData, rt_u
extern void parse_power_pdo_gear(rt_uint8_t protoCmd, rt_uint8_t *pData, rt_uint16_t reqLen,uint8_t *pro_gear_idx,uint8_t *pro,rt_uint16_t *protect_ma);
extern void parse_multi_gear_more(rt_uint8_t protoCmd, rt_uint8_t *pData, rt_uint16_t reqLen,uint8_t *pro_gear_idx,uint8_t *pro,rt_uint16_t *protect_ma);
extern void parse_power_ufcs(rt_uint8_t *pData, rt_uint16_t reqLen, uint8_t *pro_gear_idx, uint8_t *pro,rt_uint16_t *protect_ma);
extern int source_set_pd_new_com(rt_uint8_t pro, struct chrg_switch_t *pSW);
extern int source_set_pro(rt_uint8_t pro, struct chrg_switch_t *pSW);
/* 提交 Source 功率板初始化参数;北向协议设置完成后调用。 */
extern int chrg_source_init_submit(rt_uint8_t idx, struct chrg_switch_t *pSW);
extern int chrg_source_work_state(rt_uint8_t idx, struct chrg_switch_t *pSW);
#endif
+6 -6
View File
@@ -75,12 +75,12 @@ rt_uint16_t mb_crc16 (rt_uint8_t *pucFrame, rt_uint16_t usLen)
rt_uint8_t ucCRCLo = 0xFF;
int iIndex;
if(usLen==8){
for(int i = 0;i<usLen;i++){
rt_kprintf("%02x ",pucFrame[i]);
}
rt_kprintf("\n");
}
// if(usLen==8){
// for(int i = 0;i<usLen;i++){
// rt_kprintf("%02x ",pucFrame[i]);
// }
// rt_kprintf("\n");
// }
while ( usLen-- ) {
iIndex = ucCRCLo ^ *(pucFrame++);
+2 -2
View File
@@ -132,7 +132,7 @@
<UseTargetDll>1</UseTargetDll>
<UseExternalTool>0</UseExternalTool>
<RunIndependent>0</RunIndependent>
<UpdateFlashBeforeDebugging>0</UpdateFlashBeforeDebugging>
<UpdateFlashBeforeDebugging>1</UpdateFlashBeforeDebugging>
<Capability>1</Capability>
<DriverSelection>4096</DriverSelection>
</Flash1>
@@ -275,7 +275,7 @@
</OCR_RVCT3>
<OCR_RVCT4>
<Type>1</Type>
<StartAddress>0x8040000</StartAddress>
<StartAddress>0x8000000</StartAddress>
<Size>0x40000</Size>
</OCR_RVCT4>
<OCR_RVCT5>
+9
View File
@@ -0,0 +1,9 @@
*** Using Compiler 'V6.16', folder: 'D:\keil mdk 2\ARM\ARMCLANG\Bin'
Build target 'chrg'
compiling chrg_roll_nor.c...
linking...
Program Size: Code=146668 RO-data=15332 RW-data=9328 ZI-data=15968
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:02
@@ -0,0 +1,9 @@
*** Using Compiler 'V6.16', folder: 'D:\keil mdk 2\ARM\ARMCLANG\Bin'
Build target 'chrg'
compiling chrg_sink.c...
linking...
Program Size: Code=147156 RO-data=15312 RW-data=9328 ZI-data=15984
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:02
+18
View File
@@ -0,0 +1,18 @@
*** Using Compiler 'V6.16', folder: 'D:\keil mdk 2\ARM\ARMCLANG\Bin'
Build target 'chrg'
compiling chrg_north_pkg.c...
compiling chrg_lcd.c...
compiling chrg_thread.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=146988 RO-data=15312 RW-data=9328 ZI-data=15984
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:03
+21
View File
@@ -0,0 +1,21 @@
*** Using Compiler 'V6.16', folder: 'D:\keil mdk 2\ARM\ARMCLANG\Bin'
Build target 'chrg'
compiling chrg_rel.c...
compiling chrg_vcom.c...
compiling chrg_north_pkg.c...
compiling chrg_lcd.c...
compiling chrg_thread.c...
compiling chrg_south.c...
compiling chrg_eload.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=146964 RO-data=15312 RW-data=9328 ZI-data=15984
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:02
@@ -0,0 +1,21 @@
*** Using Compiler 'V6.16', folder: 'D:\keil mdk 2\ARM\ARMCLANG\Bin'
Build target 'chrg'
compiling chrg_vcom.c...
compiling chrg_thread.c...
compiling chrg_north_pkg.c...
compiling chrg_lcd.c...
compiling chrg_rel.c...
compiling chrg_eload.c...
compiling chrg_sink.c...
compiling chrg_south.c...
compiling chrg_source.c...
compiling chrg_north.c...
compiling chrg_roll_nor.c...
compiling chrg_roll_sou.c...
compiling chrg_comm.c...
linking...
Program Size: Code=147032 RO-data=15312 RW-data=9328 ZI-data=15984
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:03
+21
View File
@@ -0,0 +1,21 @@
*** Using Compiler 'V6.16', folder: 'D:\keil mdk 2\ARM\ARMCLANG\Bin'
Build target 'chrg'
compiling chrg_rel.c...
compiling chrg_north_pkg.c...
compiling chrg_thread.c...
compiling chrg_vcom.c...
compiling chrg_lcd.c...
compiling chrg_eload.c...
compiling chrg_sink.c...
compiling chrg_source.c...
compiling chrg_south.c...
compiling chrg_north.c...
compiling chrg_roll_nor.c...
compiling chrg_roll_sou.c...
compiling chrg_comm.c...
linking...
Program Size: Code=146976 RO-data=15312 RW-data=9328 ZI-data=15984
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:03
@@ -0,0 +1,9 @@
*** Using Compiler 'V6.16', folder: 'D:\keil mdk 2\ARM\ARMCLANG\Bin'
Build target 'chrg'
compiling chrg_comm.c...
linking...
Program Size: Code=147096 RO-data=15312 RW-data=9328 ZI-data=15984
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:02
+9
View File
@@ -0,0 +1,9 @@
*** Using Compiler 'V6.16', folder: 'D:\keil mdk 2\ARM\ARMCLANG\Bin'
Build target 'chrg'
compiling chrg_sink.c...
linking...
Program Size: Code=147104 RO-data=15312 RW-data=9328 ZI-data=16000
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:01
+3
View File
@@ -1 +1,4 @@
LOAD %L INCREMENTAL
BS HardFault_Handler
BS rt_assert_handler
G
+2
View File
@@ -0,0 +1,2 @@
Load "D:\\HUACE_Project\\3_Code\\HCDF_MID_405_Charger\\chrg_V.3.0\\apps\\chrg\\build\\keil\\Obj\\chrg.axf"
Erase Done.Programming Done.Verify OK.Flash Load finished at 18:22:08
+18
View File
@@ -0,0 +1,18 @@
*** Using Compiler 'V6.16', folder: 'D:\Program Files\Keil_v5\ARM\ARMCLANG\Bin'
Build target 'chrg'
compiling chrg_roll_nor.c...
compiling chrg_north.c...
compiling chrg_south.c...
compiling chrg_comm.c...
compiling chrg_roll_sou.c...
compiling chrg_lcd.c...
compiling chrg_thread.c...
compiling chrg_sink.c...
compiling chrg_north_pkg.c...
compiling chrg_eload.c...
linking...
Program Size: Code=141040 RO-data=15212 RW-data=8544 ZI-data=13968
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:06
+130
View File
@@ -0,0 +1,130 @@
*** Using Compiler 'V6.16', folder: 'D:\Program Files\Keil_v5\ARM\ARMCLANG\Bin'
Rebuild target 'chrg'
compiling main.c...
compiling chrg_switch.c...
compiling chrg_wdt.c...
compiling chrg_gpio.c...
compiling chrg_tmr.c...
compiling chrg_fal.c...
compiling chrg_tty.c...
compiling chrg_led.c...
compiling chrg_vcom.c...
compiling chrg_rel.c...
compiling chrg_roll_nor.c...
compiling chrg_north.c...
compiling chrg_south.c...
compiling chrg_comm.c...
compiling chrg_roll_sou.c...
compiling chrg_lcd.c...
compiling chrg_thread.c...
compiling chrg_source.c...
compiling chrg_sink.c...
compiling chrg_north_pkg.c...
compiling chrg_eload.c...
compiling chrg_utils.c...
compiling syscall_mem.c...
compiling syscalls.c...
compiling cctype.c...
compiling cstdlib.c...
compiling cstring.c...
compiling ctime.c...
compiling cunistd.c...
compiling cwchar.c...
compiling device.c...
compiling hwtimer.c...
compiling completion_comm.c...
compiling completion_up.c...
compiling condvar.c...
compiling dataqueue.c...
compiling pipe.c...
compiling ringblk_buf.c...
compiling ringbuffer.c...
compiling waitqueue.c...
compiling workqueue.c...
compiling dev_pin.c...
compiling dev_serial.c...
compiling dev_watchdog.c...
compiling stm32f4xx_hal_msp.c...
compiling board.c...
compiling drv_flash_f4.c...
compiling drv_gpio.c...
compiling drv_tim.c...
compiling drv_usart.c...
compiling drv_usbd.c...
compiling drv_wdt.c...
compiling drv_common.c...
compiling fal.c...
compiling fal_flash.c...
compiling fal_partition.c...
compiling fal_rtt.c...
compiling shell.c...
compiling msh_parse.c...
compiling cmd.c...
compiling msh.c...
compiling clock.c...
compiling components.c...
compiling cpu_up.c...
compiling defunct.c...
compiling idle.c...
compiling ipc.c...
compiling irq.c...
compiling kservice.c...
compiling memheap.c...
compiling mempool.c...
compiling object.c...
compiling scheduler_comm.c...
compiling scheduler_up.c...
compiling thread.c...
compiling timer.c...
compiling rt_vsnprintf_tiny.c...
compiling kerrno.c...
compiling kstring.c...
compiling rt_vsscanf.c...
compiling kstdio.c...
compiling atomic_arm.c...
compiling div0.c...
compiling showmem.c...
assembling context_rvds.S...
compiling cpuport.c...
compiling usbdevice.c...
compiling cdc_vcom.c...
compiling usbdevice_core.c...
assembling startup_stm32f405xx.s...
compiling system_stm32f4xx.c...
compiling stm32f4xx_hal_gpio.c...
compiling stm32f4xx_hal_flash.c...
compiling stm32f4xx_hal_usart.c...
compiling stm32f4xx_hal_rng.c...
compiling stm32f4xx_hal_uart.c...
compiling stm32f4xx_hal_wwdg.c...
compiling stm32f4xx_hal_tim.c...
compiling stm32f4xx_hal_cryp_ex.c...
compiling stm32f4xx_hal_pwr.c...
compiling stm32f4xx_hal_rcc.c...
compiling stm32f4xx_hal_hcd.c...
compiling stm32f4xx_ll_usb.c...
compiling stm32f4xx_hal_pccard.c...
compiling stm32f4xx_hal_flash_ex.c...
compiling stm32f4xx_hal_flash_ramfunc.c...
compiling stm32f4xx_hal_tim_ex.c...
compiling stm32f4xx_hal_lptim.c...
compiling stm32f4xx_hal_cec.c...
compiling stm32f4xx_hal_cryp.c...
compiling stm32f4xx_hal.c...
compiling stm32f4xx_hal_iwdg.c...
compiling stm32f4xx_hal_pcd_ex.c...
compiling stm32f4xx_hal_pcd.c...
compiling stm32f4xx_hal_crc.c...
compiling stm32f4xx_hal_dma_ex.c...
compiling stm32f4xx_hal_cortex.c...
compiling stm32f4xx_hal_dma.c...
compiling stm32f4xx_hal_rcc_ex.c...
compiling stm32f4xx_hal_pwr_ex.c...
compiling ulog.c...
compiling console_be.c...
linking...
Program Size: Code=139712 RO-data=15040 RW-data=8544 ZI-data=13704
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:29
+130
View File
@@ -0,0 +1,130 @@
*** Using Compiler 'V6.16', folder: 'D:\Program Files\Keil_v5\ARM\ARMCLANG\Bin'
Rebuild target 'chrg'
compiling main.c...
compiling chrg_switch.c...
compiling chrg_wdt.c...
compiling chrg_gpio.c...
compiling chrg_tmr.c...
compiling chrg_fal.c...
compiling chrg_tty.c...
compiling chrg_led.c...
compiling chrg_vcom.c...
compiling chrg_rel.c...
compiling chrg_roll_nor.c...
compiling chrg_north.c...
compiling chrg_south.c...
compiling chrg_comm.c...
compiling chrg_roll_sou.c...
compiling chrg_lcd.c...
compiling chrg_thread.c...
compiling chrg_source.c...
compiling chrg_sink.c...
compiling chrg_north_pkg.c...
compiling chrg_eload.c...
compiling chrg_utils.c...
compiling syscall_mem.c...
compiling syscalls.c...
compiling cctype.c...
compiling cstdlib.c...
compiling cstring.c...
compiling ctime.c...
compiling cunistd.c...
compiling cwchar.c...
compiling device.c...
compiling hwtimer.c...
compiling completion_comm.c...
compiling completion_up.c...
compiling condvar.c...
compiling dataqueue.c...
compiling pipe.c...
compiling ringblk_buf.c...
compiling ringbuffer.c...
compiling waitqueue.c...
compiling workqueue.c...
compiling dev_pin.c...
compiling dev_serial.c...
compiling dev_watchdog.c...
compiling stm32f4xx_hal_msp.c...
compiling board.c...
compiling drv_flash_f4.c...
compiling drv_gpio.c...
compiling drv_tim.c...
compiling drv_usart.c...
compiling drv_usbd.c...
compiling drv_wdt.c...
compiling drv_common.c...
compiling fal.c...
compiling fal_flash.c...
compiling fal_partition.c...
compiling fal_rtt.c...
compiling shell.c...
compiling msh_parse.c...
compiling cmd.c...
compiling msh.c...
compiling clock.c...
compiling components.c...
compiling cpu_up.c...
compiling defunct.c...
compiling idle.c...
compiling ipc.c...
compiling irq.c...
compiling kservice.c...
compiling memheap.c...
compiling mempool.c...
compiling object.c...
compiling scheduler_comm.c...
compiling scheduler_up.c...
compiling thread.c...
compiling timer.c...
compiling rt_vsnprintf_tiny.c...
compiling kerrno.c...
compiling kstring.c...
compiling rt_vsscanf.c...
compiling kstdio.c...
compiling atomic_arm.c...
compiling div0.c...
compiling showmem.c...
assembling context_rvds.S...
compiling cpuport.c...
compiling usbdevice.c...
compiling cdc_vcom.c...
compiling usbdevice_core.c...
assembling startup_stm32f405xx.s...
compiling system_stm32f4xx.c...
compiling stm32f4xx_hal_gpio.c...
compiling stm32f4xx_hal_flash.c...
compiling stm32f4xx_hal_usart.c...
compiling stm32f4xx_hal_rng.c...
compiling stm32f4xx_hal_uart.c...
compiling stm32f4xx_hal_wwdg.c...
compiling stm32f4xx_hal_tim.c...
compiling stm32f4xx_hal_cryp_ex.c...
compiling stm32f4xx_hal_pwr.c...
compiling stm32f4xx_hal_rcc.c...
compiling stm32f4xx_hal_hcd.c...
compiling stm32f4xx_ll_usb.c...
compiling stm32f4xx_hal_pccard.c...
compiling stm32f4xx_hal_flash_ex.c...
compiling stm32f4xx_hal_flash_ramfunc.c...
compiling stm32f4xx_hal_tim_ex.c...
compiling stm32f4xx_hal_lptim.c...
compiling stm32f4xx_hal_cec.c...
compiling stm32f4xx_hal_cryp.c...
compiling stm32f4xx_hal.c...
compiling stm32f4xx_hal_iwdg.c...
compiling stm32f4xx_hal_pcd_ex.c...
compiling stm32f4xx_hal_pcd.c...
compiling stm32f4xx_hal_crc.c...
compiling stm32f4xx_hal_dma_ex.c...
compiling stm32f4xx_hal_cortex.c...
compiling stm32f4xx_hal_dma.c...
compiling stm32f4xx_hal_rcc_ex.c...
compiling stm32f4xx_hal_pwr_ex.c...
compiling ulog.c...
compiling console_be.c...
linking...
Program Size: Code=140360 RO-data=15152 RW-data=8544 ZI-data=13712
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:29
+130
View File
@@ -0,0 +1,130 @@
*** Using Compiler 'V6.16', folder: 'D:\Program Files\Keil_v5\ARM\ARMCLANG\Bin'
Rebuild target 'chrg'
compiling main.c...
compiling chrg_switch.c...
compiling chrg_wdt.c...
compiling chrg_gpio.c...
compiling chrg_tmr.c...
compiling chrg_fal.c...
compiling chrg_tty.c...
compiling chrg_led.c...
compiling chrg_vcom.c...
compiling chrg_rel.c...
compiling chrg_roll_nor.c...
compiling chrg_north.c...
compiling chrg_south.c...
compiling chrg_comm.c...
compiling chrg_roll_sou.c...
compiling chrg_lcd.c...
compiling chrg_thread.c...
compiling chrg_source.c...
compiling chrg_sink.c...
compiling chrg_north_pkg.c...
compiling chrg_eload.c...
compiling chrg_utils.c...
compiling syscall_mem.c...
compiling syscalls.c...
compiling cctype.c...
compiling cstdlib.c...
compiling cstring.c...
compiling ctime.c...
compiling cunistd.c...
compiling cwchar.c...
compiling device.c...
compiling hwtimer.c...
compiling completion_comm.c...
compiling completion_up.c...
compiling condvar.c...
compiling dataqueue.c...
compiling pipe.c...
compiling ringblk_buf.c...
compiling ringbuffer.c...
compiling waitqueue.c...
compiling workqueue.c...
compiling dev_pin.c...
compiling dev_serial.c...
compiling dev_watchdog.c...
compiling stm32f4xx_hal_msp.c...
compiling board.c...
compiling drv_flash_f4.c...
compiling drv_gpio.c...
compiling drv_tim.c...
compiling drv_usart.c...
compiling drv_usbd.c...
compiling drv_wdt.c...
compiling drv_common.c...
compiling fal.c...
compiling fal_flash.c...
compiling fal_partition.c...
compiling fal_rtt.c...
compiling shell.c...
compiling msh_parse.c...
compiling cmd.c...
compiling msh.c...
compiling clock.c...
compiling components.c...
compiling cpu_up.c...
compiling defunct.c...
compiling idle.c...
compiling ipc.c...
compiling irq.c...
compiling kservice.c...
compiling memheap.c...
compiling mempool.c...
compiling object.c...
compiling scheduler_comm.c...
compiling scheduler_up.c...
compiling thread.c...
compiling timer.c...
compiling rt_vsnprintf_tiny.c...
compiling kerrno.c...
compiling kstring.c...
compiling rt_vsscanf.c...
compiling kstdio.c...
compiling atomic_arm.c...
compiling div0.c...
compiling showmem.c...
assembling context_rvds.S...
compiling cpuport.c...
compiling usbdevice.c...
compiling cdc_vcom.c...
compiling usbdevice_core.c...
assembling startup_stm32f405xx.s...
compiling system_stm32f4xx.c...
compiling stm32f4xx_hal_gpio.c...
compiling stm32f4xx_hal_flash.c...
compiling stm32f4xx_hal_usart.c...
compiling stm32f4xx_hal_rng.c...
compiling stm32f4xx_hal_uart.c...
compiling stm32f4xx_hal_wwdg.c...
compiling stm32f4xx_hal_tim.c...
compiling stm32f4xx_hal_cryp_ex.c...
compiling stm32f4xx_hal_pwr.c...
compiling stm32f4xx_hal_rcc.c...
compiling stm32f4xx_hal_hcd.c...
compiling stm32f4xx_ll_usb.c...
compiling stm32f4xx_hal_pccard.c...
compiling stm32f4xx_hal_flash_ex.c...
compiling stm32f4xx_hal_flash_ramfunc.c...
compiling stm32f4xx_hal_tim_ex.c...
compiling stm32f4xx_hal_lptim.c...
compiling stm32f4xx_hal_cec.c...
compiling stm32f4xx_hal_cryp.c...
compiling stm32f4xx_hal.c...
compiling stm32f4xx_hal_iwdg.c...
compiling stm32f4xx_hal_pcd_ex.c...
compiling stm32f4xx_hal_pcd.c...
compiling stm32f4xx_hal_crc.c...
compiling stm32f4xx_hal_dma_ex.c...
compiling stm32f4xx_hal_cortex.c...
compiling stm32f4xx_hal_dma.c...
compiling stm32f4xx_hal_rcc_ex.c...
compiling stm32f4xx_hal_pwr_ex.c...
compiling ulog.c...
compiling console_be.c...
linking...
Program Size: Code=139960 RO-data=15064 RW-data=8544 ZI-data=13704
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:27
+9
View File
@@ -0,0 +1,9 @@
*** Using Compiler 'V6.16', folder: 'D:\Program Files\Keil_v5\ARM\ARMCLANG\Bin'
Build target 'chrg'
compiling chrg_north.c...
linking...
Program Size: Code=140256 RO-data=15160 RW-data=8544 ZI-data=13704
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:02
@@ -0,0 +1,121 @@
# Source 状态机改造与角色切换维护计划
## 1. 改造目标
将电源(Source)控制整理为与负载(Sink)类似的独立状态机,但保留两者业务差异:
- 北向协议板只负责角色/CC 线选择、协议设置及周期读取协议板电压电流。
- 功率板角色、模式、电压、电流、继电器和启停全部由 `chrg_source.c` 管理。
- 所有 Source 南向寄存器命令统一使用 `chrg_sou_com_batch_submit()`,不再散落调用 `chrg_set_sou_reg()`。
- Source 不判断带载电流。协议板返回电压有效则进入 `RUNNING`;启动后持续无电压则回到 `WAIT`。
- 协议、协议电压或协议电流发生变化时,重新进入 `INIT`。
- Source/Sink 不停机切换时,必须先停止旧角色,确认完成后再初始化新角色。
## 2. 当前已完成的修改
当前工作区已完成第一阶段,尚未形成完整状态机:
1. `apps/chrg/applications/utils/chrg_source.c`
- 新增 `chrg_source_init_submit(rt_uint8_t idx, struct chrg_switch_t *pSW)`。
- 通过一个批次下发 `REG_ELOAD`、`REG_MODE`、`REG_VOLTAGE_OUT + 1`、`REG_CURRENT_OUT + 1` 和 `REG_WORK = WORK_STOP`。
2. `apps/chrg/applications/utils/chrg_source.h`
- 增加上述函数声明。
3. `apps/chrg/applications/thread/chrg_roll_nor.c`
- Source 协议设置流程进入 `IDX_GET_SOURCE_VC` 后提交南向初始化批次。
- 仅当批次提交成功时设置 `source.On_Flag = 1`。
注意:当前仍有旧 Source 路径在 `chrg_north.c`、`chrg_roll_nor.c` 和 `chrg_lcd.c` 中直接调用 `chrg_set_sou_reg()`。在完成后续步骤前,新旧逻辑会同时存在,不能作为最终版本发布。
## 3. 目标状态机
在 `chrg_source.h` 中增加明确的 Source 状态:
```c
typedef enum {
SOURCE_WORK_STOP = 0,
SOURCE_WORK_WAIT,
SOURCE_WORK_INIT,
SOURCE_WORK_START,
SOURCE_WORK_RUNNING,
SOURCE_WORK_STOPPING,
SOURCE_WORK_FAULT
} source_work_mode_t;
```
在 `chrg_src_t` 中增加每通道状态及参数快照:`work_mode`、`last_protocol`、`last_voltage`、`last_current`、`zero_volt_count`、`retry_count`。参数快照只能在对应命令确认完成后更新。
状态动作:
| 状态 | 动作 | 后续状态 |
|---|---|---|
| `INIT` | 批量设置 Source 角色、模式、电压、电流及继电器,保持停止 | `START` |
| `START` | 批量下发 `REG_WORK = WORK_START` | `WAIT` |
| `WAIT` | 北向周期读取协议板 VC | 有电压进入 `RUNNING` |
| `RUNNING` | 更新 VC;检测协议/电压/电流变化 | 变化进入 `INIT` |
| `STOPPING` | 批量停止输出、关闭功率板继电器 | `STOP` |
| `STOP` | 清理使能并断开北向继电器 | 保持 |
建议电压大于 `WORK_MIN_VOLT` 即视为有效。电压为零连续 3 次再由 `RUNNING` 回到 `WAIT`,避免单帧异常造成状态抖动。
## 4. COM 端改造
修改 `chrg_mb_write_sys()`:
- 当目标角色为 Source 且当前未工作时,只设置 `pSW->sub = IDX_SET_SOURCE_CC_SET`,由北向依次完成 CC 和协议设置;协议应答完成后才进入 `SOURCE_WORK_INIT`。
- 同角色下,比较协议、协议电压、协议电流。任一变化则进入 `SOURCE_WORK_INIT`;相同参数不得重复初始化。
- 不要在收到 `SYS_REG_ROLE_SWITCH` 时立即覆盖实际角色。应保存 `target_role`,在参数生效时启动切换流程。
- 切换期间返回 `MB_EX_SLAVE_BUSY`,或者只更新影子参数并等待本次切换完成。
角色切换顺序:
```text
Source -> Sink: Source STOPPING -> STOP -> 切换角色/继电器 -> Sink INIT
Sink -> Source: Sink STOP -> 切换角色/继电器 -> 北向 CC/协议 -> Source INIT
```
禁止 Source 和 Sink 的功率板继电器、工作命令在同一通道同时有效。
## 5. 北向流程改造
精简 `chrg_roll_nor_set()` 的 Source 分支,只保留:
1. `IDX_SET_SOURCE_CC_SET`:设置 CC 线,成功后进入 `IDX_SET_SOURCE_PD`。
2. `IDX_SET_SOURCE_PD`:设置协议,应答成功后设置 `SOURCE_WORK_INIT`。
3. `IDX_GET_SOURCE_VC`:读取协议板电压电流。
删除 Source 分支中的 `IDX_SET_SOURCE_ID`、`IDX_SET_SOURCE_CV`、`IDX_SER_SOURCE_VOLT`、`IDX_SER_SOURCE_CURR`、`IDX_SET_SOURCE_WORK` 南向设置动作。校准、控制台和 Sink 分支不在本次范围内。
`chrg_north.c` 只解析 Source VC:更新 `source.vc`、`Now_voltage`、`Now_current`,并根据电压推进 `WAIT/RUNNING`。移除 `chrg_source_standard_output()`、`chrg_source_fast_output()` 和旧的分步停机控制,避免解析函数直接下发南向命令。
## 6. 南向完成确认
`chrg_sou_com_batch_submit()` 返回成功仅表示入队成功,不表示功率板已经执行。需要为每通道增加批次完成序号或完成事件:
- `INIT` 批次全部应答匹配后才能进入 `START`。
- `START` 应答成功后才能进入 `WAIT`。
- `STOPPING` 批次完成后才能断开北向继电器和修改实际角色。
- CRC 错误、寄存器不匹配或超时不得推进状态;达到重试上限后进入 `FAULT`。
## 7. 推荐实施顺序
1. 增加 Source 状态枚举、参数快照及 `chrg_source_work()`。
2. 将 INIT、START、STOPPING 的南向动作全部迁移到 `chrg_source.c`。
3. 增加南向批次完成通知,再改为应答驱动状态转换。
4. 精简北向 Source 子状态,只保留 CC、协议和 VC。
5. 修改 COM 同角色参数差异及跨角色切换。
6. 清理 `chrg_lcd.c` 中重复的 Source 启停和角色寄存器写入。
7. 编译并在硬件验证后删除旧字段和旧函数。
## 8. 验证清单
- Keil 编译 `apps/chrg/chrg.uvprojx`,确认无未定义符号和头文件循环依赖。
- 单通道验证 Source 首次启动、停止、相同参数重复生效。
- 分别改变协议、协议电压和协议电流,确认只执行一次重新 INIT。
- 模拟协议板电压持续为零,确认进入 WAIT 且不会反复提交相同批次。
- 验证 Source -> Sink、Sink -> Source,示波器确认切换期间无输出重叠。
- 四通道同时运行并交叉切换,检查南向队列饥饿、响应错配、超时和缓存串通道。
- 回归 Sink 正常负载、动态测试、无电流重启及低压处理。
## 9. 接手注意事项
开始修改前先执行 `git status --short` 和 `git diff`。当前 `chrg_north.c` 还包含此前 Sink 连续确认次数改为 3 的修改及注释清理,不能在 Source 重构时回退。不要提交 Keil `build/`、`Obj/`、AXF、BIN 或 MAP 等生成文件。
@@ -0,0 +1,101 @@
# Source CC_CLOSE 协议切换修改说明
## 修改目标
修正 Source 北向协议板的命令顺序,避免在 CC 保持 Attached 时直接重配
`0xD0`。多通道同时切换时采用共享等待屏障,使保护时间并行发生,不按
通道串行累计。
## 本轮实施步骤
### 第一步:统一状态命名
断开 CC 的命令状态命名为 `IDX_SET_SOURCE_CC_CLOSE`,等待状态命名为
`IDX_WAIT_SOURCE_CC_CLOSE`。`CC_CLOSE` 固定发送 `0x17=0x03`,不覆盖
COM 保存的目标 `CC_Set`。
### 第二步:调整停止态启动顺序
Source 从停止状态启动以及 Sink 切换为 Source 时,不发送 `CC_CLOSE`,
直接按以下顺序执行:
```text
IDX_SET_SOURCE_PD
-> IDX_WAIT_SOURCE_PROTOCOL
-> IDX_SET_SOURCE_CC_SET
-> IDX_GET_SOURCE_VC
```
即先设置协议,收到 `0xD0` ACK 并完成保护等待后,再连接目标 CC。
### 第三步:识别必须断开 CC 的切换
COM 参数生效时,满足以下任一条件进入 `CC_CLOSE`:
- 新协议为 PD/PPS 或 PD3.1/AVS,并且协议或 CC 线与上次不同。
- 上次协议为 PD/PPS 或 PD3.1/AVS,本次切换为非 PD 协议。
其它协议配置变化从 `IDX_SET_SOURCE_PD` 开始。标准协议仅改变电压、电流
时直接更新功率板,不重复下发 `0xD0`。
### 第四步:执行 CC_CLOSE 命令链
COM先确定北向`sub`,协议或CC发生变化时进入
`SOURCE_WORK_PROTOCOL_SWITCH`,不在COM中调用发送函数。北向轮询线程
执行该Source工作状态,负责向南向功率板写入0V;标准协议还会在同一批
命令中依次写模式和电流。提交成功后清零`set_volt`并进入
`SOURCE_WORK_WAIT`,随后按已经选定的`sub`继续执行。
需要断开 CC 的通道按以下顺序执行:
```text
IDX_SET_SOURCE_CC_CLOSE 发送 0x17=0x03
-> IDX_WAIT_SOURCE_CC_CLOSE 等待共享保护时间
-> IDX_SET_SOURCE_PD 发送 0xD0
-> IDX_WAIT_SOURCE_PROTOCOL 等待协议 ACK 后保护时间
-> IDX_SET_SOURCE_CC_SET 发送 0x17=目标 CC
-> IDX_GET_SOURCE_VC 恢复 0x20 查询
```
每条设置命令仍需收到角色、命令、长度和 CRC 均正确的回码后才能推进
`sub`;错误回码继续沿用现有丢弃和有限重发逻辑。
### 第五步:多通道共享 CC_CLOSE 等待
使用 `pending_mask` 和 `acked_mask` 管理本轮参与切换的 Source 通道。
所有已登记通道都收到 `0x17` ACK 后,只启动一次 300 ms 保护等待。
一个通道和四个通道的保护等待本身均为 300 ms;四通道只额外产生必要的
命令收发时间,不会累计为四次 300 ms。
### 第六步:握手稳定确认(本轮不修改)
本轮不增加“连续两次 `0x20` 电压稳定后才进入 RUNNING”的新逻辑,继续
使用现有 `chrg_source_parse()` 电压误差和重试规则。
### 第七步:配置覆盖保护
继续使用 `config_version` 防止 COM 新配置被旧回码推进。停止、角色切换
或不再需要 `CC_CLOSE` 时,会把通道移出共享等待屏障,避免残留状态影响
下一次启动。
### 第八步:完整失败恢复(本轮不修改)
本轮不增加握手总超时、再次 detach、整套流程最多重试两轮以及故障上报。
单条北向命令仍使用现有的三次发送机制。完整恢复流程待单独验证后实施。
## 时间参数
| 参数 | 当前值 | 说明 |
|---|---:|---|
| `SOURCE_CC_CLOSE_WAIT_MS` | 300 ms | 从本轮最后一个有效 `CC_CLOSE` ACK 开始 |
| `SOURCE_PROTOCOL_WAIT_MS` | 100 ms | 每通道收到 `0xD0` ACK 后并行等待 |
| `NORTH_RESPONSE_TIMEOUT_MS` | 50 ms | 单次北向回码等待 |
| `NORTH_REQUEST_MAX_RETRIES` | 2 | 首次发送外最多重发两次 |
## 建议验证顺序
1. 单通道停止态启动 PD,确认发送顺序为 `D0 -> 17(目标CC) -> 20`。
2. 单通道 PD 改协议或 CC,确认顺序为 `17(03) -> 等待 -> D0 -> 17(目标CC) -> 20`。
3. 单通道 PD 切换 QC/FCP/标准,确认切换前先发送 `17(03)`。
4. 四通道连续生效,确认四路 `17(03)` 均回码后共享一次约 300 ms 等待。
5. 连续执行 20 至 30 轮协议切换,检查是否仍出现 Source 芯片 PD 状态异常。
+2519
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
+310
View File
@@ -0,0 +1,310 @@
param(
[string]$OutputDirectory = 'D:\HC-PMP-SW\Power_ControlPannel\MP_Control_sw_405\拖拽式平台\docs'
)
$ErrorActionPreference = 'Stop'
function New-Criteria {
param([int]$VoltageToleranceMv, [int]$CurrentToleranceMa)
[ordered]@{
VoltageToleranceMv = $VoltageToleranceMv
CurrentToleranceMa = $CurrentToleranceMa
ShortVoltageMinMv = 0
ShortVoltageMaxMv = 1000
ShortCurrentMinMa = 0
ShortCurrentMaxMa = 1000
OcpVoltageMinMv = 0
OcpVoltageMaxMv = 5000
OcpCurrentMinMa = 4500
OcpCurrentMaxMa = 5500
DynamicVpkPlusMinMv = 0
DynamicVpkPlusMaxMv = 65535
DynamicVpkMinusMinMv = 0
DynamicVpkMinusMaxMv = 65535
}
}
function New-DmpItem {
param(
[string]$Name,
[int]$Channel,
[string]$Protocol,
[int]$VoltageMv,
[int]$ProtocolCurrentMa,
[int]$LoadCurrentMa,
[int]$VoltageToleranceMv,
[int]$CurrentToleranceMa,
[int]$QueryDelayMs,
[string]$OutputAction = 'Start',
[int]$Gear = 0,
[int]$CcSelection = -1,
[string]$SinkFunction = 'StandardLoad'
)
[ordered]@{
Id = [guid]::NewGuid().ToString()
Name = $Name
Channel = $Channel
Direction = 'Sink'
OutputAction = $OutputAction
Protocol = $Protocol
Mode = 'ConstantCurrent'
PdoType = 'Fpdo'
SinkFunction = $SinkFunction
Gear = $Gear
CcSelection = if ($CcSelection -ge 0) { $CcSelection } elseif ($Channel -eq 2) { 1 } else { 0 }
MinVoltageMv = 3300
VoltageMv = $VoltageMv
CurrentMa = $ProtocolCurrentMa
LoadVoltageMv = $VoltageMv
LoadCurrentMa = $LoadCurrentMa
VonVoltageMv = 100
ShortHoldTimeMs = 1000
HoldAfterTest = $false
OcpStartCurrentMa = 1000
OcpEndCurrentMa = 5000
OcpStepCurrentMa = 100
OcpStepTimeMs = 10
OcpRecoveryTimeMs = 1000
OcpStopVoltageMv = 4000
OcpRecoveryWithLoad = $true
DynamicCurrent1Ma = 1000
DynamicTime1 = 100
DynamicCurrent2Ma = 5000
DynamicTime2 = 100
DynamicRiseSlope = 1
DynamicFallSlope = 1
ApplyDelayMs = 500
QueryDelayMs = $QueryDelayMs
DurationMs = 1000
StopOnFault = $true
Criteria = New-Criteria $VoltageToleranceMv $CurrentToleranceMa
Status = 'Pending'
Result = ''
Verdict = ''
MeasuredVoltageMv = $null
MeasuredCurrentMa = $null
QueryTime = $null
Measurements = @()
}
}
function New-PortConfig {
param(
[string]$Port,
[int]$Channel,
[string]$Protocol,
[int]$VoltageMv,
[int]$ProtocolCurrentMa,
[int]$LoadCurrentMa,
[int]$VoltageToleranceMv,
[int]$CurrentToleranceMa,
[int]$Gear = 0
)
[pscustomobject]@{
Port = $Port
Channel = $Channel
Protocol = $Protocol
VoltageMv = $VoltageMv
ProtocolCurrentMa = $ProtocolCurrentMa
LoadCurrentMa = $LoadCurrentMa
VoltageToleranceMv = $VoltageToleranceMv
CurrentToleranceMa = $CurrentToleranceMa
Gear = $Gear
}
}
function Add-SingleTest {
param(
[System.Collections.Generic.List[object]]$Items,
[string]$Prefix,
[pscustomobject]$Config,
[int]$CcSelection = -1
)
$voltage = $Config.VoltageMv / 1000
$current = $Config.LoadCurrentMa / 1000
$Items.Add((New-DmpItem "$Prefix-$($Config.Port)-$voltage`V-$current`A" $Config.Channel $Config.Protocol `
$Config.VoltageMv $Config.ProtocolCurrentMa $Config.LoadCurrentMa `
$Config.VoltageToleranceMv $Config.CurrentToleranceMa 10000 'Start' $Config.Gear $CcSelection))
$Items.Add((New-DmpItem "$Prefix-$($Config.Port)-停止" $Config.Channel $Config.Protocol `
$Config.VoltageMv $Config.ProtocolCurrentMa $Config.LoadCurrentMa 0 0 1000 'Stop' $Config.Gear $CcSelection))
}
function Add-SequencedPortTest {
param(
[System.Collections.Generic.List[object]]$Items,
[string]$Face,
[int]$CcSelection,
[pscustomobject]$Case,
[string]$Port,
[int]$Channel
)
$sinkFunction = if ($Case.SinkFunction) { $Case.SinkFunction } else { 'StandardLoad' }
$namePrefix = "$Face-$($Case.Label)-$Port"
$start = New-DmpItem "$namePrefix-启动" $Channel $Case.Protocol $Case.Voltage `
$Case.ProtocolCurrent $Case.LoadCurrent $Case.VTol $Case.ITol 5000 'Start' 0 $CcSelection $sinkFunction
if ($sinkFunction -eq 'ShortCircuit') {
$start.Criteria.ShortVoltageMinMv = 0
$start.Criteria.ShortVoltageMaxMv = 3000
$start.Criteria.ShortCurrentMinMa = 0
$start.Criteria.ShortCurrentMaxMa = 65535
}
$Items.Add($start)
$Items.Add((New-DmpItem "$namePrefix-停止" $Channel $Case.Protocol $Case.Voltage `
$Case.ProtocolCurrent $Case.LoadCurrent 0 0 5000 'Stop' 0 $CcSelection $sinkFunction))
}
function Add-CombinationTest {
param(
[System.Collections.Generic.List[object]]$Items,
[string]$Prefix,
[object[]]$Configs
)
foreach ($config in $Configs) {
$Items.Add((New-DmpItem "$Prefix-$($config.Port)-配置" $config.Channel $config.Protocol `
$config.VoltageMv $config.ProtocolCurrentMa $config.LoadCurrentMa 0 0 100 'Start' $config.Gear))
}
for ($index = 0; $index -lt $Configs.Count; $index++) {
$config = $Configs[$index]
$delay = if ($index -eq 0) { 10000 } else { 1000 }
$Items.Add((New-DmpItem "$Prefix-$($config.Port)-验证" $config.Channel $config.Protocol `
$config.VoltageMv $config.ProtocolCurrentMa $config.LoadCurrentMa `
$config.VoltageToleranceMv $config.CurrentToleranceMa $delay 'Start' $config.Gear))
}
foreach ($config in $Configs) {
$Items.Add((New-DmpItem "$Prefix-$($config.Port)-停止" $config.Channel $config.Protocol `
$config.VoltageMv $config.ProtocolCurrentMa $config.LoadCurrentMa 0 0 1000 'Stop' $config.Gear))
}
}
function Write-Plan {
param([string]$FileName, [string]$Name, [System.Collections.Generic.List[object]]$Items)
$plan = [ordered]@{
ProductId = 'DMP'
Name = $Name
Communication = [ordered]@{
PortName = 'COM6'
BaudRate = 115200
DataBits = 8
Parity = 'None'
StopBits = 1
SlaveAddress = 1
TimeoutMs = 500
RetryCount = 2
}
Items = $Items
}
$path = Join-Path $OutputDirectory $FileName
$json = $plan | ConvertTo-Json -Depth 20
[System.IO.File]::WriteAllText($path, $json, [System.Text.UTF8Encoding]::new($false))
Get-Item -LiteralPath $path
}
$c1 = 1
$c2 = 2
$a1 = 3
# 1. C1/C2同时插入,但依次对单个通道带载。先测A面(CC1),再测B面(CC2)。
$items = [System.Collections.Generic.List[object]]::new()
$dualCases = @(
[pscustomobject]@{ Label = '5V3A'; Protocol = 'Standard'; Voltage = 5000; ProtocolCurrent = 3000; LoadCurrent = 3000; VTol = 240; ITol = 300; SinkFunction = 'StandardLoad' },
[pscustomobject]@{ Label = '5V3.8A过载'; Protocol = 'Standard'; Voltage = 5000; ProtocolCurrent = 3000; LoadCurrent = 3800; VTol = 0; ITol = 0; SinkFunction = 'StandardLoad' },
[pscustomobject]@{ Label = '5V0A空载'; Protocol = 'Standard'; Voltage = 5000; ProtocolCurrent = 3000; LoadCurrent = 0; VTol = 240; ITol = 0; SinkFunction = 'StandardLoad' },
[pscustomobject]@{ Label = '5V-QC2.0'; Protocol = 'Qc20'; Voltage = 5000; ProtocolCurrent = 3000; LoadCurrent = 0; VTol = 240; ITol = 0; SinkFunction = 'StandardLoad' },
[pscustomobject]@{ Label = '5V短路'; Protocol = 'Standard'; Voltage = 5000; ProtocolCurrent = 3000; LoadCurrent = 0; VTol = 0; ITol = 0; SinkFunction = 'ShortCircuit' },
[pscustomobject]@{ Label = '5V0A短路恢复'; Protocol = 'Standard'; Voltage = 5000; ProtocolCurrent = 3000; LoadCurrent = 0; VTol = 240; ITol = 0; SinkFunction = 'StandardLoad' },
[pscustomobject]@{ Label = '9V3A'; Protocol = 'Pdo'; Voltage = 9000; ProtocolCurrent = 3000; LoadCurrent = 3000; VTol = 440; ITol = 300; SinkFunction = 'StandardLoad' },
[pscustomobject]@{ Label = '15V3A'; Protocol = 'Pdo'; Voltage = 15000; ProtocolCurrent = 3000; LoadCurrent = 3000; VTol = 740; ITol = 300; SinkFunction = 'StandardLoad' },
[pscustomobject]@{ Label = '20V2.25A'; Protocol = 'Pdo'; Voltage = 20000; ProtocolCurrent = 2250; LoadCurrent = 2250; VTol = 790; ITol = 225; SinkFunction = 'StandardLoad' },
[pscustomobject]@{ Label = '20V0A空载'; Protocol = 'Pdo'; Voltage = 20000; ProtocolCurrent = 2250; LoadCurrent = 0; VTol = 790; ITol = 0; SinkFunction = 'StandardLoad' },
[pscustomobject]@{ Label = '20V2.82A过载'; Protocol = 'Pdo'; Voltage = 20000; ProtocolCurrent = 2250; LoadCurrent = 2820; VTol = 0; ITol = 0; SinkFunction = 'StandardLoad' }
)
foreach ($face in @(
[pscustomobject]@{ Name = 'A面'; CcSelection = 1 },
[pscustomobject]@{ Name = 'B面'; CcSelection = 2 }
)) {
foreach ($case in $dualCases) {
Add-SequencedPortTest $items $face.Name $face.CcSelection $case 'C1' $c1
Add-SequencedPortTest $items $face.Name $face.CcSelection $case 'C2' $c2
}
}
Write-Plan '01_C1-C2双口同时插入测试.json' '01 C1/C2双口同时插入、依次单口负载测试' $items
# 2. A1单口:5V标准,9V/12V使用QC2.0。
$items = [System.Collections.Generic.List[object]]::new()
$a1Cases = @(
[pscustomobject]@{ Label = '264VAC'; Protocol = 'Standard'; Voltage = 5000; Current = 3000; VTol = 240; ITol = 300 },
[pscustomobject]@{ Label = '264VAC'; Protocol = 'Qc20'; Voltage = 9000; Current = 2000; VTol = 440; ITol = 200 },
[pscustomobject]@{ Label = '264VAC'; Protocol = 'Qc20'; Voltage = 12000; Current = 1500; VTol = 590; ITol = 150 },
[pscustomobject]@{ Label = '90VAC'; Protocol = 'Standard'; Voltage = 5000; Current = 3000; VTol = 240; ITol = 300 },
[pscustomobject]@{ Label = '90VAC'; Protocol = 'Qc20'; Voltage = 12000; Current = 1500; VTol = 590; ITol = 150 }
)
foreach ($case in $a1Cases) {
Add-SingleTest $items $case.Label (New-PortConfig 'A1' $a1 $case.Protocol $case.Voltage `
$case.Current $case.Current $case.VTol $case.ITol)
}
Add-SingleTest $items 'SCP-10V2.25A' (New-PortConfig 'A1' $a1 'Scp' 10000 2250 2250 490 225)
Write-Plan '02_A1单口测试.json' '02 A1单口测试' $items
# 3. C1/C2单口多协议。先测A面(CC1),再测B面(CC2)。
# PPS3-5没有规格值,仅做9V空载握手,避免未确认的大电流带载。
$items = [System.Collections.Generic.List[object]]::new()
$multiProtocolCases = @(
[pscustomobject]@{ Label = '标准5V3A'; Protocol = 'Standard'; Gear = 0; Voltage = 5000; ProtocolCurrent = 3000; LoadCurrent = 3000; VTol = 240; ITol = 300 },
[pscustomobject]@{ Label = 'PDO9V3A'; Protocol = 'Pdo'; Gear = 0; Voltage = 9000; ProtocolCurrent = 3000; LoadCurrent = 3000; VTol = 440; ITol = 300 },
[pscustomobject]@{ Label = 'PDO15V3A'; Protocol = 'Pdo'; Gear = 0; Voltage = 15000; ProtocolCurrent = 3000; LoadCurrent = 3000; VTol = 740; ITol = 300 },
[pscustomobject]@{ Label = 'PDO20V2.25A'; Protocol = 'Pdo'; Gear = 0; Voltage = 20000; ProtocolCurrent = 2250; LoadCurrent = 2250; VTol = 790; ITol = 225 },
[pscustomobject]@{ Label = 'PPS1-9V4.5A'; Protocol = 'Pps'; Gear = 1; Voltage = 9000; ProtocolCurrent = 4500; LoadCurrent = 4500; VTol = 450; ITol = 225 },
[pscustomobject]@{ Label = 'PPS2-19V2A'; Protocol = 'Pps'; Gear = 2; Voltage = 19000; ProtocolCurrent = 2000; LoadCurrent = 2000; VTol = 950; ITol = 150 },
[pscustomobject]@{ Label = 'PPS3-9V空载握手'; Protocol = 'Pps'; Gear = 3; Voltage = 9000; ProtocolCurrent = 1000; LoadCurrent = 0; VTol = 450; ITol = 100 },
[pscustomobject]@{ Label = 'PPS4-9V空载握手'; Protocol = 'Pps'; Gear = 4; Voltage = 9000; ProtocolCurrent = 1000; LoadCurrent = 0; VTol = 450; ITol = 100 },
[pscustomobject]@{ Label = 'PPS5-9V空载握手'; Protocol = 'Pps'; Gear = 5; Voltage = 9000; ProtocolCurrent = 1000; LoadCurrent = 0; VTol = 450; ITol = 100 }
)
$avsCases = @(
[pscustomobject]@{ Label = 'AVS-9V3A'; Protocol = 'Avs'; Gear = 0; Voltage = 9000; ProtocolCurrent = 3000; LoadCurrent = 3000; VTol = 150; ITol = 300 },
[pscustomobject]@{ Label = 'AVS-20V2.25A'; Protocol = 'Avs'; Gear = 0; Voltage = 20000; ProtocolCurrent = 2250; LoadCurrent = 2250; VTol = 650; ITol = 225 }
)
$cPorts = @([pscustomobject]@{ Name = 'C1'; Channel = $c1 }, [pscustomobject]@{ Name = 'C2'; Channel = $c2 })
foreach ($face in @(
[pscustomobject]@{ Name = 'A面'; CcSelection = 1 },
[pscustomobject]@{ Name = 'B面'; CcSelection = 2 }
)) {
foreach ($case in $multiProtocolCases) {
foreach ($port in $cPorts) {
Add-SingleTest $items "$($face.Name)-$($case.Label)" (New-PortConfig $port.Name $port.Channel $case.Protocol `
$case.Voltage $case.ProtocolCurrent $case.LoadCurrent $case.VTol $case.ITol $case.Gear) $face.CcSelection
}
}
foreach ($case in $avsCases) {
Add-SingleTest $items "$($face.Name)-$($case.Label)" (New-PortConfig 'C1' $c1 $case.Protocol `
$case.Voltage $case.ProtocolCurrent $case.LoadCurrent $case.VTol $case.ITol $case.Gear) $face.CcSelection
}
}
Write-Plan '03_C1-C2单口多协议测试.json' '03 C1/C2单口多协议A/B面测试(含PPS1~5、AVS)' $items
# 4. 两口组合:只有20V项目使用PDO,其余5V均为标准协议。
$items = [System.Collections.Generic.List[object]]::new()
Add-CombinationTest $items '组合1-C1+C2' @(
(New-PortConfig 'C1' $c1 'Pdo' 20000 1500 1500 990 150),
(New-PortConfig 'C2' $c2 'Standard' 5000 3000 3000 240 300)
)
Add-CombinationTest $items '组合2-C1+A1' @(
(New-PortConfig 'C1' $c1 'Pdo' 20000 1500 1500 990 150),
(New-PortConfig 'A1' $a1 'Standard' 5000 3000 3000 240 300)
)
Add-CombinationTest $items '组合3-C2+A1' @(
(New-PortConfig 'C2' $c2 'Standard' 5000 1500 1500 240 150),
(New-PortConfig 'A1' $a1 'Standard' 5000 1500 1500 240 150)
)
Write-Plan '04_两口组合输出测试.json' '04 两口组合输出测试' $items
# 5. 三口组合:C1为PD 20V,C2/A1为标准5V。
$items = [System.Collections.Generic.List[object]]::new()
Add-CombinationTest $items '三口组合-C1+C2+A1' @(
(New-PortConfig 'C1' $c1 'Pdo' 20000 1500 1500 990 150),
(New-PortConfig 'C2' $c2 'Standard' 5000 1500 1500 240 150),
(New-PortConfig 'A1' $a1 'Standard' 5000 1500 1500 240 150)
)
Write-Plan '05_C1-C2-A1三口组合输出测试.json' '05 C1/C2/A1三口组合输出测试' $items
+190
View File
@@ -0,0 +1,190 @@
#ifndef __DigtalPower_ModbusRTU_REG_List_H__
#define __DigtalPower_ModbusRTU_REG_List_H__
#include "USART1_Modbus_RTU.h"
#include "dac.h"
#define ModbusRTU_SW_Version 0x0301; //01是电源代号,02是负载代号,03是非节能源载代号,04是节能电源代号;低字节01是版本号,V0.1
//ModbusRTU 从站地址//工作状态及运行参数显示
#define ModbusRTU_Power_Status 0x00 //R,工作状态指示,00 预充电;01就绪/停止 02 缓启动;03 运行;04 故障:03 03 00 00 00 01 85 E8
#define ModbusRTU_Relay_Status 0x01 //bit0=0 主继电器断开 bit0=1 主继电器闭合;;;bit1=0 滤波继电器断开 bit1=1 滤波继电器闭合
#define ModbusRTU_Fault_Status 0x02 //故障状态寄存器
#define ModbusRTU_Flash_Status 0x03 //flash存储状态
#define ModbusRTU_Role_ModeFlag 0x04 //0x04 源载指令,默认是电子负载,1是supply,2是eload
//故障寄存器
/*****************************故障类型*****************/
#define F_NOERR 0x0000//无故障
#define F_SW_VIN_UVP 0x0001//输入欠压
#define F_SW_VIN_OVP 0x0002//输入过压
#define F_SW_VOUT_UVP 0x0004//输出欠压
#define F_SW_VOUT_OVP 0x0008//输出过压
#define F_SW_IOUT_OCP 0x0010//输出过流
#define F_SW_SHORT 0x0020//输出短路
#define F_SW_OTP 0x0040//过温保护
//电源控制指令
#define ModbusRTU_PowerCmd 0x05 //05 W 0x01 开机,0x02 关机,0x03故障复位;0xAA 存储数据到flash;0xBB 恢复默认参数
#define ModbusRTU_WorkMode 0x06 //06 WR 0x01 恒压,0x02 恒流,0x03开环,04 恒功率,05恒阻
#define ModbusRTU_Volt 0x07 //07-08 WR 设置输出电压 uint32,0.001V, 0~60V,默认5V,查询电压也是这个指令
#define ModbusRTU_Current 0x09 //09-0A WR 设置输出电流 uint32 ,0.001A,, 0~60A,默认值1A,查询电压也是这个指令
#define ModbusRTU_ShortTest_VoltShort 0x0B //无论short测试成功或者失败,都给出短路恒流值的时候的电压
#define ModbusRTU_ShortTest_CurrentShort 0x0C //无论测试成功或者失败,都给出短路恒流值的时候的电压
#define ModbusRTU_OCPTest_VoltOCP 0x0D //无论short测试成功或者失败,都给出短路恒流值的时候的电压
#define ModbusRTU_OCPTest_CurrentOCP 0x0E //无论测试成功或者失败,都给出短路恒流值的时候的电压
#define ModbusRTU_DUT_Vpkp 0x0F //量测正峰值
#define ModbusRTU_DUT_Vpkn 0x10 //量测负峰值
#define ModbusRTU_DUT_Vpp 0x11 //量测峰峰值
//纹波寄存器
#define ModbusRTU_Ripple_Value 0x12 //读取纹波
#define ModbusRTU_Temp 0x1A //WR 11,当前内部温度读取点
#define ModbusADDR_SW_Version 0x1B //10,12地址,读取版本号,03代表buckboost半桥,01是版本号
#define ModbusADDR_SlaveID_Modify 0x1C //11,13地址,修订SlaveID
#define Line_Compensation 0X1D //1F 14d地址,线损补偿,正负5V,1mv,精度0.001,放大1000倍,5000
#define Eload_Start_VON 0x20 //10 16寄存器存储电子负载启动电压,负载检测到电压值为启动电压,才开启电子负载;
#define Eload_Stop_Volt 0x21 //11 17寄存器存储电子负载关闭电压;
#define Eload_Slew_Rate 0x22 //12 18寄存器存储电子负载上升斜率参数;
#define ModbusRTU_CPower 0x24 //36-37 功率值
#define ModbusRTU_CResistor 0x26 //38 电阻值
//6.3.1电源控制参数
#define ModbusRTU_VoltLimit 0x28 //0x29 40-41 0x2A 42寄存器输出电压限值,默认是6.0V,可以微调到6.5V;
#define ModbusRTU_CurrentLimit_H 0x2A //42~43WR 输出电流限值
#define ModbusRTU_CurrentLimit_L 0x2B //42~43WR 输出电流限值
#define ModbusRTU_Volt_CAL_K 0x2C //2C~2D 电压校准K值,被放大Q16倍,再移动16回去;使用两个字节
#define ModbusRTU_Volt_CAL_K_L 0x2D
#define ModbusRTU_Volt_CAL_B 0x2E //2E 电压校准B值
#define ModbusRTU_Current_CAL_K 0x2F //2F-30 电流校准K值
#define ModbusRTU_Current_CAL_K_L 0x30
#define ModbusRTU_Current_CAL_B 0x31 //31 电流校准B值
#define ModbusRTU_SourceCurrent_CAL_K 0x32 //32-33 电流校准K值
#define ModbusRTU_SourceCurrent_CAL_K_L 0x33
#define ModbusRTU_SourceCurrent_CAL_B 0x34 //34 电流校准B值
#define ModbusRTU_SourceSink_Current_Offset 0x35 //电源的电流上报offset
//#define ModbusRTU_Sink_Current_Offset 0x33 //负载的电流上报offset
#define ModbusRTU_CALI_CRC 0x36 //校准偏移6参数的校验值;使用CRC16-Modbus校验;
#define ModbusRTU_CAL_WriteEnable 0x37 //使能写入FLASH;下次调用使用这个参数;是个魔数:0x4361 (C+a)
#define ModbusRTU_CAL_WriteRecovery 0x38 //使能写入出厂数据区域;0x5763
#define ModbusRTU_CAL_ReadRecovery 0x39 //使能读出;将出厂数据读到当前的bank中,并更新6个参数
//short测试
#define ModbusRTU_ShortTest_CMD_MODE_FLAG 0x40 //16位;0x0101; 01启动,低字节的01,保持电流,为0是释放电流; 20260601新增一个低字节的bit7=0用于是恢复以前的状态,bit7=1是将卸载电流归零;
#define ModbusRTU_ShortTest_Hold_Time 0x41 //单位是ms,最大65535ms,给0是立即释放,给一个时间值,是保持这个时间不变;
//#define ModbusRTU_ShortTest_CurrentShort 0x42 //无论测试成功或者失败,都给出短路恒流值的时候的电压
//OCP测试
#define ModbusRTU_OCPTest_CMD_MODE_FLAG 0x43 //16位;0x0101; 01启动,低字节的01,保持电流,为0是释放电流; 20260601新增一个低字节的bit7=0用于是恢复以前的状态,bit7=1是将卸载电流归零;
#define ModbusRTU_OCPTest_StartCurrent 0x44 //起始电流
#define ModbusRTU_OCPTest_StopCurrent 0x45 //终止电流
#define ModbusRTU_OCPTest_StepCurrent 0x46 //每一步的电流
#define ModbusRTU_OCPTest_Step_Hold_Time 0x47 //每一步的保持时间;默认10ms;范围1ms到100ms;
#define ModbusRTU_OCPTest_Vtrig_Stop 0x48 //达到触发OCP流点的电压值;
#define ModbusRTU_OCPTest_Hold_Time 0x49
//#define ModbusRTU_OCPTest_VoltOCP 0x49 //无论short测试成功或者失败,都给出短路恒流值的时候的电压
//#define ModbusRTU_OCPTest_CurrentOCP 0x4A //无论测试成功或者失败,都给出短路恒流值的时候的电压
//DYNA 电子负载的动态测试模式,也叫动态负载或瞬态测试。在该模式下,负载会按设定的斜率、频率和占空比,在两个电流值(如高负载和低负载)之间周期性跳变,用来测试电源的瞬态响应、恢复时间等特性。
#define ModbusRTU_DYNA_CMD_MODE_FLAG 0x4B //动态测试 CMD启动、退出、 以及模式:Continuous、PULSE、Toggle;LSB8 BIT7 短路测试时候的电流:保持/归零;bit1 过流; bit0 成功/失败
#define ModbusRTU_DYNA_L1 0x4C //动态测试电流1
#define ModbusRTU_DYNA_L2 0x4D //动态测试电流2
#define ModbusRTU_DYNA_T1 0x4E //动态测试电流1的时间
#define ModbusRTU_DYNA_T2 0x4F //动态测试电流2的时间
#define ModbusRTU_DYNA_Rise_Slew_Rate 0x50 //动态测试上升斜率
#define ModbusRTU_DYNA_Fall_Slew_Rate 0x51 //动态测试下降斜率
#define ModbusRTU_DUT_ValueReset 0x5D //复位数值
#define ModbusRTU_SYS_Reset 0x61 //系统复位指令,如果异常过压,通常发指令,让系统复位
//#define ModbusRTU_Volt_Kp 0x30 //48-49 RW 电压环kp
//#define ModbusRTU_Volt_Ki 0x32 //50-51WR 电压环ki
//#define ModbusRTU_Curr_Kp 0x34 //52-53WR 电流环kp
//#define ModbusRTU_Curr_Ki 0x36 //54-55WR 电流环ki
//#define ModbusRTU_CP_Kp 0x38 //56-57 RW 功率环kp
//#define ModbusRTU_CP_Ki 0x3A //58-59 WR 功率环ki
//#define ModbusRTU_CR_Kp 0x3C //60-61 WR 电阻环kp
//#define ModbusRTU_CR_Ki 0x3E //62-63 WR 电阻环ki
//112,0x70寄存器,改为当前内部温度读取点;
#define ModbusRTU_TempLimit 0x71 //WR 温度限值
#define ModbusRTU_FANSpeed 0x72 //风速控制,上位机可以设定;自动模式下,温度高于一个值,最大风速跑,低于则最小风速跑
#define SMU_Relay_ON 0x0001 //源载主继电器
#define SMU_EL_PB15_EMI_Bypass_ON 0x0002 //旁路滤波继电器
//定义电流保护值的关系:Y(VDAC) = K*X(I-real)+B
#define Init_OCP_VALUE 12000 //12A
//正向:
#define K_COEFF_FWD_Q16 (9960)
#define B_Intercept_FWD (1846)
//反向:
#define K_COEFF_REV_Q16 (-9960)
#define B_Intercept_REV (1846)
//结构体
//6.2.1工作状态及运行参数显示 PowerStatusAndParaShow
typedef struct {
uint16_t Power_Status;
uint16_t Relay_Status;
uint16_t Fault_Status;
uint16_t Flash_Status;
uint32_t InputVolt;
uint32_t InputCurr;
uint32_t OutputVolt;
uint32_t OutputCurr;
uint32_t OutputPower;
uint16_t statusRsv1; //预留位
uint16_t statusRsv2;
}S_PowerStatusAndParaShow;
extern S_PowerStatusAndParaShow PowerStatusAndParaShow;
//6.2.2电源控制指令PowerControlCmd
typedef struct{
uint16_t PowerCmd;
uint16_t WorkMode;
uint32_t Vout;
uint32_t Iout;
uint8_t Remote_Power_ON_Flag; //开关机指示
uint8_t Remote_Power_Reset_Flag; //复位指示
}S_PowerControlCmd;
extern S_PowerControlCmd PowerControlCmd;
//6.3.1电源控制参数
typedef struct{
uint32_t VoutLimit;
uint32_t IoutLimit;
uint16_t DutyLimit;
uint16_t FrequnceLimit;
float VoltKp;
float VoltKi;
float CurrKp;
float CurrKi;
}S_PowerControlPara;
extern uint8_t Power_OnOff_Flag,Power_OnOff_Flag;
extern S_PowerControlPara PowerControlPara;
//Modbus 参数初始化
extern void Modbus_Para_Init(void);
#endif
+238
View File
@@ -0,0 +1,238 @@
# 修改日志
## V1.1.9 - 2026-08-25
### Source 复位后的初始化流程
- 从其他协议切换到 PD 时复位加入断开CC,D+D-,GND逻辑,等断开后再复位,再初始化
- 增加 PD 切换到非 PD 协议时的完整复位;PD/非PD跨类别切换统一执行复位。
- PD切PD、非PD切非PD以及仅切换CC线时不复位。
- 新增 `SOURCE_WORK_INIT_WAIT`,复位回码后重新执行 Source 初始化,并等待南向初始化批次完成。
- 加入了读取版本号
## V1.1.8 - 2026-08-24
### 修改主题
修复了source部分的PD协议长时间运行后会出不来的问题
对应芯海3221/source版本V_1.07
### Source协议复位切换
- 新增`SOURCE_RESET`命令:发送`06 00 02 18 00 0E`,校验回码`05 00 02 18 16`。
- 首次发送协议不复位;PD与非PD跨类别切换时先复位。
- PD切PD、非PD切非PD以及仅切换CC线时不复位。
- 删除`CC_CLOSE`状态及其共享等待屏障。
- 协议设置回码有效后更新`last_pd_pro`,避免协议尚未生效时错误判断。
### 验证记录
- 使用1-2,3-4测试自举例程测试俩百次正常
- git diff --check`:通过。
- 旧`CC_CLOSE`状态、宏和调用引用:已检查清理。
- Keil编译:按当前要求未执行,待现场烧录后验证复位回码和协议切换时序。
## V1.1.7 - 2026-08-08
### 修改主题
并行执行Sink完整握手中的南向低电流确认与北向协议/CC设置。
### 主要修改
- 南向安全批次完成并收到辅助继电器回码、建立量测基线后,立即允许北向设置协议和CC线。
- 南向实际电流连续两次不大于 `100mA` 的确认过程与北向协议/CC设置并行执行。
- 北向进入 `GET_SINK_VC` 后,只有低电流确认完成且CC后的 `200ms` 查询保护时间到期,才发送第一条 `0x20`。
- 电压稳定后再发送 `ALL_REL_ON -> 目标电流 -> WORK_START`,防止协议协商期间提前带载。
### 涉及文件
- `apps/chrg/applications/thread/chrg_roll_nor.c`
- `apps/chrg/applications/utils/chrg_sink.c`
- `apps/chrg/applications/utils/chrg_sink.h`
### 编译验证
- Keil MDK 编译结果:`0 Error(s), 0 Warning(s)`。
## V1.1.5 - 2026-08-08
### 修改主题
协议电压和协议电流变化统一采用软卸载重发协议流程。
### 主要修改
- 协议类型、CC线和协议组号变化仍进入完整握手并切换南向继电器。
- 协议电压、协议电流单独变化或同时变化时,只发送 `WORK_STOP`,不关闭南向继电器。
- 软卸载不再额外发送 `CURRENT=0`,仅通过实际电流连续两次不大于 `100mA`确认电子负载已停止。
- 协议重新生效且电压稳定后,由RUNNING先写入实际负载电流,再发送 `WORK_START`。
### 涉及文件
- `apps/chrg/applications/thread/chrg_comm.c`
- `apps/chrg/applications/utils/chrg_sink.c`
### 编译验证
- Keil MDK 编译结果:`0 Error(s), 0 Warning(s)`。
## V1.1.4 - 2026-08-07
### 修改主题
调整负载低电流启动时的继电器和工作命令顺序。
### 主要修改
- 设定电流为 `0A` 或低于 `100mA` 时,协议握手仍正常执行。
- 电压达到目标后发送 `ALL_REL_ON`,确保主继电器打开。
- 主继电器打开后继续发送 `WORK_STOP` 和 `CURRENT=0`,保持电子负载不带载。
- 已经处于运行状态切换到低电流时,沿用原有停止流程,不重复切换继电器。
### 涉及文件
- `apps/chrg/applications/utils/chrg_sink.c`
### 编译验证
- Keil MDK 编译结果:`0 Error(s), 0 Warning(s)`。
## V1.1.3 - 2026-08-07
### 修改主题
并行执行Sink南向初始化与北向握手,并优化握手查询和RUNING继电器时序。
### 主要修改
- `INIT`将 `FU_REL_ON -> CURRENT=0 -> MODE -> VON` 作为一个有序南向批次提交。
- 南向初始化批次成功入队后立即打开北向Sink继电器、设置 `enable=1` 并开始协议握手。
- `SINK_WORK_INIT_AUX_WAIT`改为后台监控南向初始化,不再阻塞北向协议、CC和电压查询。
- 南向初始化失败重试时保留当前北向 `sub`,不重复拉回协议设置起点。
- 协议或CC有效回码后,首条 `0x20` 等待 `200ms`;电压未稳定时后续每 `100ms` 查询一次。
- 一帧通过CRC、ID、命令和配置版本校验的电压达到目标后立即进入 `RUNING`,不再等待第二帧。
- 进入稳定运行后立即解除查询节流,恢复北向正常轮询速度。
- `RUNING`删除重复的 `FU_REL_ON`,调整为 `ALL_REL_ON -> 目标负载值 -> WORK_START`。
### 涉及文件
- `apps/chrg/applications/utils/chrg_sink.c`
- `apps/chrg/applications/thread/chrg_roll_nor.c`
- `apps/chrg/applications/thread/chrg_north.c`
### 编译验证
- Keil MDK 编译结果:`0 Error(s), 0 Warning(s)`。
### 硬件验证
- 待确认南向初始化命令与北向协议/CC设置并行执行且互不重置状态。
- 待确认首条和后续 `0x20` 间隔分别约为 `200ms` 和 `100ms`。
- 待确认进入 `RUNING` 时不再发送 `FU_REL_ON`,主继电器不会被重复断开。
## V1.1.2 - 2026-08-07
### 修改主题
降低Sink协议握手阶段的北向电压电流查询频率。
### 主要修改
- 新增 `SINK_HANDSHAKE_QUERY_INTERVAL_MS`,设置为 `200ms`。
- Sink协议或CC设置收到有效回码后,不立即发送或连续快速发送 `0x20` 查询。
- CC路径的 `200ms` 从有效 `0x17` 回码时刻开始计时,包含原有 `50ms` CC稳定保护。
- 协议握手、软恢复等待和掉电恢复监控阶段的 `0x20` 查询按每 `200ms` 一次执行。
- 北向量测连续两次达到稳定条件后解除节流,`RUNING` 和低电流待机恢复正常查询频率。
- 仅重发协议的 `IDX_SET_SINK_PD_ONLY` 路径同样启动 `200ms` 查询等待。
- 设置协议和CC命令仍然按有效回码、超时和原有重试机制处理。
### 涉及文件
- `apps/chrg/applications/thread/chrg_roll_nor.c`
### 编译验证
- Keil MDK 编译结果:`0 Error(s), 0 Warning(s)`。
### 硬件验证
- 待观察协议/CC设置后 `0x20` 的发送间隔是否稳定为不小于 `200ms`。
- 待验证电压连续两次稳定后是否恢复正常量测频率。
## V1.1.1 - 2026-08-07
### 修改主题
增加普通负载最低带载电流控制,低电流时保持协议在线但关闭电子负载。
### 主要修改
- 新增 `SINK_LOAD_ENABLE_MIN_MA`,恒流负载设定低于 `100mA` 时禁止发送 `WORK_START`。
- 最低带载门限只判断南向负载电流 `loadc`,不影响北向协议电流 `pro_loadc` 和协议握手。
- 首次启动或完整重握手后为低电流时,发送 `WORK_STOP -> CURRENT=0` 并保持主继电器关闭。
- 运行中由有效电流降至低电流时,发送 `WORK_STOP -> CURRENT=0`,保持协议、CC和继电器不变。
- 运行中低电流待机恢复有效电流时,只发送目标电流和 `WORK_START`,不重新握手或切换继电器。
- 主继电器未打开的低电流待机使用独立 `SINK_WORK_LOAD_START` 恢复入口,避免被 `RUNING` 状态去重。
- 低电流待机期间仅修改协议电压时不重复卸载,并保持原有主继电器状态语义。
- 将 COM 端运行电流跨门限判断封装为 `chrg_comm_handle_sink_load_current()`,避免生效分支继续膨胀。
- 北向解析将两种低电流待机状态作为稳定状态,不因实际电流为零反复进入 `RUNING`。
- 低电流待机恢复有效电流时,`SINK_WORK_LOAD_START`/`SINK_WORK_LOAD_RESUME` 只作为待启动标记,必须等北向实际电压稳定后才下发 `WORK_START`。
### 涉及文件
- `apps/chrg/applications/utils/chrg_sink.h`
- `apps/chrg/applications/utils/chrg_sink.c`
- `apps/chrg/applications/thread/chrg_comm.c`
- `apps/chrg/applications/thread/chrg_north.c`
### 编译验证
- Keil MDK 编译结果:`0 Error(s), 0 Warning(s)`。
### 硬件验证
- 待验证 `20V/3A -> 20V/0A -> 20V/3A` 的南向命令顺序和协议保持情况。
- 待验证首次以低于 `100mA` 的电流启动时,北向握手正常且南向不执行 `WORK_START`。
## V1.1.0 - 2026-08-07
### 修改主题
负载启动、掉电恢复、协议重握手和协议电压软切换时序调整。
### 主要修改
- 负载启动时先向南向发送 `FU_REL_ON`,收到有效回码后才打开北向 Sink 继电器。
- 剩余的负载初始化命令在副继电器确认后入队,北向协议握手与南向初始化并行执行。
- `RUNING` 阶段的南向命令继续追加到同一队列,保持初始化配置、继电器、目标电流/电压和 `WORK_START` 的顺序。
- 掉电恢复时执行 `WORK_STOP -> CURRENT=0 -> ALL_REL_OFF -> FU_REL_ON`,副继电器恢复后等待输入电压重新出现。
- 掉电恢复检测到电压后重新设置协议和 CC,不能使用掉电前的电压样本直接进入 `RUNING`。
- 协议类型、CC、协议组号或协议电流变化进入完整重握手,关闭主副继电器后重新打开副继电器。
- 仅协议电压变化使用软卸载,只发送 `WORK_STOP` 和 `CURRENT=0`,不切换继电器。
- 软卸载恢复时只发送目标电流/电压和 `WORK_START`,不再发送继电器命令。
- 保留连续两次实际电流不大于 `100mA` 的安全确认,以及连续两次稳定电压确认。
- 暂时保持南向主副继电器之间的固定延时为屏蔽状态。
### 涉及文件
- `apps/chrg/applications/utils/chrg_sink.h`
- `apps/chrg/applications/utils/chrg_sink.c`
- `apps/chrg/applications/thread/chrg_comm.c`
- `apps/chrg/applications/thread/chrg_roll_nor.c`
- `apps/chrg/applications/thread/chrg_north.c`
### 编译验证
- Keil MDK 编译结果:`0 Error(s), 0 Warning(s)`。
- 尚未完成硬件验证,需重点观察南向命令顺序、北向协议握手时刻、掉电恢复和协议电压软切换。
### 后续记录格式
后续每次修改按以下格式追加:
```text
## Vx.y.z - YYYY-MM-DD
### 修改主题
### 主要修改
### 涉及文件
### 编译验证
### 硬件验证
```
+111
View File
@@ -0,0 +1,111 @@
静态排查后,暂未看到明确的 ABBA 型互斥锁环。当前现象更像“内存破坏/资源泄漏后线程停滞”或“状态机无限重试”,而不是整个 RTOS 调度器死锁。
另外,代码中使用的是 STM32 内部 IWDG,不是外部独立看门狗。
**可疑点**
1. **高风险:南北向分包接收存在确定的越界写和泄漏路径**
[north](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_north.c:548) 和 [south](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_south.c:309) 在续接分包时计算:
```text
len_need = len_msg - 帧头长度
```
但此时 `pFrame->length` 已经包含之前收到的数据,正确的剩余长度应基于 `len_msg - pFrame->length`。当前代码却从 `payload[pFrame->length]` 开始写入整个“帧头后的总长度”。
例如总长 21 字节,首批已存 8 字节,下一次仍可能从偏移 8 写入 18 字节,最终写到偏移 26,越过 21 字节堆块。这会破坏相邻堆块、邮箱消息甚至 RT-Thread 内核对象,最终表现为随机线程卡死、互斥量异常或堆分配失败。
同时,分包超时路径只清除了 `findhead`:
- [chrg_north.c:627](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_north.c:627)
- [chrg_south.c:399](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_south.c:399)
没有释放 `pMB/payload`,也没有清除 `length/len_msg`。而且没有新数据时会提前 `continue`,超时检查根本不会执行。串口噪声、丢字节或正常分包都可能不断积累泄漏。
此外,payload 分配失败时只返回,没有释放刚分配的 `pMB`:
- [chrg_north.c:518](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_north.c:518)
- [chrg_south.c:280](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_south.c:280)
这是目前最符合“运行时间越长越容易出现”的可疑点。
2. **高风险:看门狗喂法无法覆盖业务线程死锁**
主线程每秒无条件喂狗:[main.c:36](D:/proj/char/chrg_v/apps/chrg/applications/main.c:36)。
北向轮询线程又在每轮无条件喂同一只狗:[chrg_roll_nor.c:421](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_roll_nor.c:421)。
因此即使 `thr.comm`、`thr.sou`、`thr.rollsou`、LCD 线程全部停止工作,只要主线程或北向轮询线程仍能调度,IWDG 就永远不会复位。这只是在检测“CPU/调度器是否完全停止”,没有检测业务线程是否健康。
驱动最终调用的是 `HAL_IWDG_Refresh()`:[drv_wdt.c:40](D:/proj/char/chrg_v/rt-thread/bsp/stm32/libraries/HAL_Drivers/drivers/drv_wdt.c:40)。代码中没有找到外部 WDI 引脚翻转或外部看门狗驱动。
3. **高风险:当前新增的南向批处理可能永久停在 `RUN_COM`**
南向批处理遇到 CRC 错误或应答超时后,不增加重试次数、不设置截止时间,也不清除任务:
- CRC 错误:[chrg_roll_sou.c:608](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_roll_sou.c:608)
- 应答超时:[chrg_roll_sou.c:627](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_roll_sou.c:627)
线程会一直重发同一个寄存器,`pending` 永远不清除,`run` 永远保持 `RUN_COM`,正常南向轮询无法恢复。这属于业务状态机死锁,调度器仍正常运行,所以看门狗不会复位。
这套批处理逻辑是当前工作区相对 `HEAD` 新增的,优先级很高。
4. **高风险:南向共享状态的互斥保护实际无效**
[chrg_set_sou_reg](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_roll_sou.c:435) 先在锁外写入:
```text
pROLL->ch
pROLL->reg
pROLL->value
```
随后互斥量只保护 `pROLL->run`。消费者也只在锁内读取 `run`,实际使用 `ch/reg/value` 时已经离开锁。
多个生产者包括 LCD、Modbus 和状态机可能交叉覆盖这些字段,形成“通道来自命令 A、寄存器来自命令 B、值来自命令 C”的组合。
批处理数组 `g_sou_com_batch` 同样由生产者和 `thr.rollsou` 同时读写,却没有共同的锁:[chrg_roll_sou.c:394](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_roll_sou.c:394)。
5. **中高风险:先切换 `RUN_COM`,再填充批处理数据**
[chrg_sink_diff_send_reg](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_comm.c:2338) 先调用 `chrg_sou_com_sou_set()` 将状态切到 `RUN_COM`,然后才追加寄存器。
`chrg_sink_work()` 也是相同顺序:[chrg_sink.c:541](D:/proj/char/chrg_v/apps/chrg/applications/utils/chrg_sink.c:541)。
如果消费者在状态切换后看到尚未填充的批次,会认为没有任务并切回自动模式;随后加入的 `pending` 数据可能一直无人处理。当前线程优先级降低了部分窗口概率,但没有从同步机制上消除竞态。
6. **中高风险:应答邮箱没有请求、通道或序号关联**
邮箱消息只有 `length + payload`:[chrg_def.h:95](D:/proj/char/chrg_v/apps/chrg/applications/utils/chrg_def.h:95)。
南北轮询线程默认“收到的下一帧就是刚才请求的响应”。南向批处理只检查 CRC,任何延迟到达的旧响应都可能让当前批次 `cur_idx++`:[chrg_roll_sou.c:574](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_roll_sou.c:574)。
在超时、重发、通道切换或邮箱积压后,请求与响应很容易错位,最终造成状态机停在错误步骤或无限重试。
7. **中风险:所有业务互斥量都是永久等待**
TTY、南北轮询互斥量统一使用 `RT_WAITING_FOREVER`。例如:
- [chrg_tty.c:457](D:/proj/char/chrg_v/apps/chrg/applications/bsp/chrg_tty.c:457)
- [chrg_comm.c:2246](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_comm.c:2246)
- [chrg_roll_nor.c:439](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_roll_nor.c:439)
目前没有发现确定的反向加锁环,但一旦锁所有者因堆破坏、状态机卡死或设备写阻塞而不再释放,其他线程会永久挂起,没有超时和故障上报。
8. **中风险:串口 RingBuffer 写入结果被忽略**
[chrg_north.c:623](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_north.c:623) 和 [chrg_south.c:383](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_south.c:383) 没有检查 `rt_ringbuffer_put()` 实际写入长度。
缓冲区满时会静默丢字节,随后触发分包超时、泄漏和上述越界路径,是长期运行后出现问题的重要放大器。
**优先判断**
最可能的两条故障链是:
1. 串口分包 → 长度计算错误/超时泄漏 → 堆损坏或耗尽 → 某些业务线程永久等待;主线程继续喂狗。
2. 南向某条命令超时或响应错位 → `RUN_COM` 无限重发 → 南向业务永久停止;主线程和北向线程继续喂狗。
现场故障尚能进入 Shell 时,优先保存 `list_thread`、`list_mutex`、`list_mailbox`、`free` 输出,并检查是否持续打印 `com batch timeout, resend current reg`。这几项可以直接区分锁等待、堆耗尽和状态机无限重试。
未修改任何文件。
+36
View File
@@ -0,0 +1,36 @@
# 测试日志
## V1.1.8 - 2026-08-24
### 测试对象
Source协议切换复位逻辑。
### 验证记录
| 编号 | 测试项 | 预期结果 | 当前结果 |
| --- | --- | --- | --- |
| 1 | 首次发送Source协议 | 直接发送协议,不发送`SOURCE_RESET` | 静态检查通过 |
| 2 | PD切换到非PD | 先复位,再发送协议 | 静态检查通过 |
| 3 | 非PD切换到PD | 先复位,再发送协议 | 静态检查通过 |
| 4 | PD切PD | 不复位,直接发送协议 | 静态检查通过 |
| 5 | 非PD切非PD | 不复位,直接发送协议 | 静态检查通过 |
| 6 | 仅切换CC线 | 不复位 | 静态检查通过 |
| 7 | 复位命令帧 | 发送`06 00 02 18 00 0E` | 静态检查通过 |
| 8 | 复位回码 | 收到`05 00 02 18 16`后推进状态 | 待硬件验证 |
### 静态验证
- 已执行`git diff --check`,无格式错误。
- 已检查复位命令、状态映射、回码长度校验和`last_pd_pro`更新路径。
- Keil编译及硬件实测未执行。
### 待补充现场信息
- 板卡编号:
- 测试连接方式:
- 测试开始/结束时间:
- 复位发送日志:
- 复位回码日志:
- 协议切换结果:
- 最终结论:
+325
View File
@@ -0,0 +1,325 @@
# 程序流程与函数说明
## 1. 文档范围
本文按当前源码(2026-07-19)说明 `apps/chrg/applications/` 的自研函数、运行流程和函数级调用关系,并补充 `apps/boot/` 的启动主链。`rt-thread/`、`libs/`、CubeMX 生成代码、HAL 中断模板以及调试 shell 命令的内部库调用不展开。调用关系由源码静态分析得到;通过 `INIT_*_EXPORT`、线程入口、回调和函数指针发生的调用会单独标明。
## 2. 上电与初始化流程
```mermaid
flowchart TD
R["芯片复位"] --> B["Boot main()"]
B --> SI["System_Init()"]
SI --> AI["APP_Init()"]
AI --> AR["APP_Running()"]
AR --> CK["boot_CheckAndHandle()"]
CK -->|APP 有效| JA["boot_JumpToAPP()"]
CK -->|需要升级| RX["recvDataHandler()"]
RX --> YH["ymodemHandler()"]
YH --> BP["boot_ProtocolDataHandle()"]
BP --> FM["FM_* 擦写/校验函数"]
FM --> JA
JA --> RTT["RT-Thread 启动"]
RTT --> INIT["INIT_PREV/DEVICE/ENV/APP_EXPORT"]
INIT --> TI["chrg_thread_init()"]
TI --> TC["chrg_thread_create() x 6"]
TC --> MAIN["main() 空闲循环"]
```
`main()` 不是业务入口。GPIO、FAL、定时器、串口、继电器和看门狗由 RT-Thread 自动初始化段调用;`chrg_thread_init()` 再创建六个常驻线程。初始化失败目前不会阻止后续线程继续创建,排障时必须查看启动日志。
## 3. 运行期线程与数据流
| 线程入口 | 职责 | 主要输入 | 主要输出 |
|---|---|---|---|
| `chrg_north_thread_entry` | 接收协议板/Sink/Source 北向帧 | 北向 UART ringbuffer | 更新 `chrgnorth.sw[]`,投递帧 |
| `chrg_south_thread_entry` | 接收功率板 Modbus 响应 | 南向 UART ringbuffer | 投递响应到轮询/通信模块 |
| `chrg_comm_thread_entry` | 上位机 Modbus、寄存器映射和业务命令 | mailbox、Modbus 回调 | 修改目标状态,生成南北向命令 |
| `chrg_lcd_thread_entry` | HMI 报文解析和状态显示 | LCD 串口 | 修改配置、刷新页面 |
| `chrg_roll_nor_thread_entry` | 分时驱动四路 Sink/Source 协议板 | event、通道状态 | 查询/设置协议板,运行 Sink 状态机 |
| `chrg_roll_sou_thread_entry` | 串行执行功率板寄存器读写 | event、批命令队列 | Modbus RTU 请求与完成状态 |
```mermaid
flowchart LR
PC["上位机"] --> MB["Modbus 回调 func* / mb_reg_*_cb"]
LCD["HMI"] --> LP["chrg_lcd_parse()"]
MB --> CM["chrg_comm_parse_msg()"]
LP --> ST["chrgnorth.sw[] 目标状态"]
CM --> ST
RN["chrg_roll_nor_thread_entry()"] --> SET["chrg_roll_nor_set()"]
ST --> SET
SET --> SK["sink/source 设置函数"]
SK --> NTX["chrg_north_send()"]
DEV["协议板"] --> NRX["chrg_north_thread_entry()"]
NRX --> FD["chrg_north_frame_dispatch()"]
FD --> SP["chrg_sink_parse() / Source 解析"]
SP --> SW["chrg_sink_work()"]
SW --> SR["chrg_set_sou_reg()"]
CM --> SR
SR --> RS["chrg_roll_sou_thread_entry()"]
RS --> STX["chrg_south_send()"]
PWR["功率板"] --> SRX["chrg_south_thread_entry()"]
SRX --> SD["chrg_south_frame_dispatch()"]
SD --> RS
```
## 4. Sink 工作状态机
```mermaid
stateDiagram-v2
[*] --> INIT
INIT --> WAIT: 下发停止/安全继电器状态
WAIT --> RUNING: 电压正常且接近目标
RUNING --> WAIT: 电压正常但电流连续偏低
RUNING --> LOW: 电压连续低于 WORK_MIN_VOLT
WAIT --> LOW: 电压连续过低
LOW --> WAIT: 电压恢复并重新准备
RUNING --> OFF: 停止工作
WAIT --> OFF: 停止工作
```
函数级主链:`chrg_roll_nor_thread_entry()` → `chrg_roll_nor_set()` → `sink_get_vc()` → 北向响应 → `chrg_north_frame_dispatch()` → `chrg_sink_parse()` → `chrg_sink_work()` → `chrg_sink_work_init()` / `chrg_sink_work_volt_runing()` / `chrg_sink_nor_work_low()` / `chrg_sink_nor_work_off()`。继电器动作由 `chrg_sink_change_ON()`、`chrg_sink_SHOUT_ON()`、`chrg_nor_sw_rel()` 完成,功率板命令最终经 `chrg_set_sou_reg()` 交给南向轮询线程。
## 5. 函数说明:入口与线程基础设施
### `main.c`
| 函数 | 说明 |
|---|---|
| `show_app_version()` | 打印 RT-Thread 版本和固件编译时间,无输入和返回值。 |
| `main()` | 设置 shell 提示符后进入 1 秒延时循环;业务线程由自动初始化段提前创建。 |
### `thread/chrg_thread.c`
| 函数 | 说明 |
|---|---|
| `chrg_thread_evt_send()` | 向指定线程发送事件位;线程或事件对象无效时返回错误。 |
| `chrg_thread_mb_free()` | 释放邮箱消息及其 `payload`,仅供本文件失败路径使用。 |
| `chrg_thread_mb_send()` | 向指定线程邮箱转移消息所有权;发送失败时自动释放消息。 |
| `chrg_thread_mq_send()` | 向指定线程消息队列复制定长消息。 |
| `chrg_thread_create()` | 按 `chrgthr[]` 配置创建 IPC 对象、线程并启动线程。 |
| `chrg_thread_init()` | 遍历六个线程配置并创建;由 `INIT_APP_EXPORT` 隐式调用。 |
## 6. 函数说明:通信线程
### `thread/chrg_north.c`
| 函数 | 说明 |
|---|---|
| `chrg_compare()` | 计算两个有符号量的绝对差值。 |
| `chrg_source_stop()` | 按步骤停止 Source 输出并处理继电器/状态复位。 |
| `chrg_source_standard_output()` | 执行 Source 标准输出控制流程。 |
| `chrg_source_fast_output()` | 执行 Source 快充协议输出流程。 |
| `chrg_source_setting()` | 根据 Source 当前配置选择和推进设置过程。 |
| `chrg_sink_parse()` | 解析 Sink 电压、电流及状态,做低压/无流判定并调用 `chrg_sink_work()`。 |
| `chrg_north_handle_Seting_Volt()` | 解析北向设置电压类响应并更新通道状态。 |
| `chrg_north_switch()` | 选择当前北向物理通道。 |
| `chrg_north_send()` | 通过北向 TTY 发送一帧数据。 |
| `chrg_north_frame_head()` | 从 ringbuffer 搜索合法帧头。 |
| `chrg_north_frame_reset()` | 重置组帧上下文,并按参数决定是否释放缓存。 |
| `chrg_north_frame_append()` | 将接收字节追加到当前帧缓存。 |
| `chrg_north_frame_dispatch()` | 校验完整帧并分派到 Source/Sink 业务解析。 |
| `chrg_north_pickup_frame()` | 驱动“找帧头—收帧体—分派”状态机。 |
| `chrg_north_thread_entry()` | 北向接收线程主循环,从 UART ringbuffer 持续提取帧。 |
| `north_ch()` / `north_diag()` | FinSH 调试命令:切换通道、查看诊断计数。 |
### `thread/chrg_south.c`
| 函数 | 说明 |
|---|---|
| `chrg_south_switch_lv1()` / `chrg_south_switch_lv2_1()` / `chrg_south_switch_lv2_2()` | 控制级联选择线,完成南向通道硬件选通。 |
| `chrg_south_switch()` | 校验通道并组合调用三级选择函数。 |
| `chrg_south_send()` | 通过南向 TTY 发送 Modbus RTU 帧。 |
| `chrg_south_frame_head()` | 从 ringbuffer 识别目标地址和功能码。 |
| `chrg_south_frame_reset()` | 清理南向组帧状态和动态缓存。 |
| `chrg_south_frame_append()` | 追加南向接收字节。 |
| `chrg_south_frame_dispatch()` | 校验 CRC 后将响应投递给消费者。 |
| `chrg_south_pickup_frame()` | 推进南向组帧状态机。 |
| `chrg_south_thread_entry()` | 南向接收线程主循环。 |
| `south_ch()` | FinSH 南向通道调试命令。 |
### `thread/chrg_roll_nor.c`
| 函数 | 说明 |
|---|---|
| `sink_fill_pd_buf()` | 按协议类型把组号、电压、电流编码为 Sink 参数字节。 |
| `chrg_nor_source_stop()` | 分步骤停止 Source,关闭继电器并清理切换标志。 |
| `chrg_roll_nor_sw_uart()` | 在指定通道选择 Sink 或 Source UART。 |
| `chrg_roll_nor_sink_pro_set()` | 组装并发送 Sink 快充协议设置。 |
| `chrg_roll_nor_source_pro_set()` | 按设置来源选择 Source 协议下发函数。 |
| `chrg_roll_nor_parse()` | 根据角色和子命令生成一次北向查询/设置动作。 |
| `chrg_roll_nor_cmd()` | 北向命令参数检查接口;当前仅做空指针检查。 |
| `chrg_roll_nor_set()` | 北向轮询核心状态机,推进每通道 Source/Sink 子步骤。 |
| `chrg_roll_nor_thread_entry()` | 轮询四个北向通道,等待响应并控制超时/重试。 |
| `sink()` / `source()` | FinSH 手工配置 Sink/Source 的调试入口。 |
| `chrg_trim_crc()` | 计算校准数据 CRC。 |
| `chrg_trim_set_volt()` / `chrg_trim_set_curr()` / `chrg_trim_set_source_curr()` | 写入电压、电流及 Source 电流校准值。 |
| `chrg_trim_set_zero()` | 执行零点校准设置。 |
| `chrg_roll_trim_set()` | 按校准类型分派具体校准函数。 |
### `thread/chrg_roll_sou.c`
| 函数 | 说明 |
|---|---|
| `chrg_sou_com_batch_submit()` | 提交一批南向连续写寄存器命令。 |
| `chrg_sou_com_batch_add_reg()` | 向当前批次追加通道、寄存器和值。 |
| `chrg_set_sou_reg()` | 提交单个异步寄存器写命令。 |
| `chrg_set_sou_reg_com()` | 将寄存器写入合并批次。 |
| `sou_com_batch_next()` | 在锁保护下取下一条批命令。 |
| `sou_com_batch_complete()` | 标记批命令完成并推进队列。 |
| `sou_com_batch_cancel()` | 取消指定通道批命令。 |
| `sou_com_batch_pending_locked()` | 判断锁内是否还有待处理批命令。 |
| `sou_single_command_finish()` | 结束单命令,恢复期望运行状态。 |
| `sou_com_response_matches()` | 判断响应是否匹配当前请求。 |
| `sou_msg_free()` | 释放南向邮箱消息。 |
| `sou_com_command_failed()` | 统一处理超时/协议错误和批次回滚。 |
| `chrg_roll_sou_thread_entry()` | 串行发送南向命令、等待响应并处理重试。 |
| `south_send()` / `south_run()` | FinSH 发送寄存器和启停调试命令。 |
## 7. 函数说明:业务与协议
### `utils/chrg_sink.c`
| 函数 | 说明 |
|---|---|
| `sink_get_vc()` / `sink_get_pd()` | 生成 Sink 电压电流/协议查询帧。 |
| `sink_set_cc_line()` / `sink_set_cc_lvl()` | 设置 CC 线选择和电平。 |
| `sink_set_pd()` | 编码并发送 Sink 快充协议参数。 |
| `chrg_sink_work_init()` | 初始化工作步骤并下发停止/安全继电器命令。 |
| `chrg_sink_work_volt_runing()` | 在电压满足条件时推进 RUNING 动作。 |
| `chrg_sink_nor_work_low()` | 处理持续低压状态并复位运行条件。 |
| `chrg_sink_nor_work_off()` | 执行 Sink 停机收尾。 |
| `chrg_sink_change_ON()` / `chrg_sink_SHOUT_ON()` | 控制换向和短接相关继电器步骤。 |
| `chrg_sink_work()` | 根据 `work_mode` 分派 Sink 工作状态。 |
### `utils/chrg_source.c`
| 函数组 | 说明 |
|---|---|
| `source_get_vc()` / `source_get_pd()` | 生成 Source 电参/协议查询帧。 |
| `source_set_cc_lvl()` / `source_set_cc_choose()` | 配置 Source CC 电平和选择方式。 |
| `parse_mulit_gear_One()` / `parse_power_single_gear()` | 解析单组固定档快充能力。 |
| `parse_pd_11group_pdo()` / `parse_power_pdo_gear()` | 解析 PDO/PPS 多档能力。 |
| `parse_mulit_gear_more()` / `parse_multi_gear_more()` | 解析多组多档协议能力。 |
| `parse_ufcs_gear_more()` / `parse_power_ufcs()` | 解析 UFCS 档位。 |
| `pd_fill_single_group()` | 通用单组协议参数编码。 |
| `source_set_pd()` | 按协议、电压和电流生成 Source 设置帧。 |
| `pd_fill_single_group_com()` | 按通信寄存器档位编码单组参数。 |
| `pd_fill_single_group_need_src_com()` / `pd_fill_single_group_no_src_com()` | 分别编码需要/不需要 Source 参数的协议。 |
| `pd_fill_single_group_FCP_AFC()` / `pd_fill_single_group_UFCS()` | 编码 FCP/AFC 和 UFCS 专用参数。 |
| `source_set_pd_com()` / `source_set_pd_new_com()` | 根据寄存器配置或完整通道状态下发 Source 协议。 |
### `utils/chrg_eload.c`
| 函数组 | 说明 |
|---|---|
| `chrg_eload_set_ymodem_resp()` / `chrg_eload_get_ymodem_resp()` / `chrg_eload_clear_ymodem_resp()` | 设置、读取和清除电子负载升级响应标志。 |
| `memcmp_8bytes()` | 比较固定 8 字节标识。 |
| `chrg_eload_read_regs()` / `chrg_eload_write_reg()` / `chrg_eload_write_More_reg()` | 生成电子负载 Modbus 读、单写和多写请求。 |
| `chrg_eload_send_ymodem_data()` | 转发 YModem 升级数据。 |
| `chrg_write_cv()` | 写入电子负载 CV 参数。 |
| `chrg_eload_send_relay()` | 下发电子负载继电器动作。 |
| `chrg_eload_refresh()` | 刷新电子负载测量状态。 |
| `chrg_eload_parse()` | 解析电子负载响应并更新通道数据。 |
| `snp_ch()` | 选择电子负载通道。 |
| `Show_Volt()` / `Show_Curr()` / `Show_Ripple()` / `Show_DZF()` | 计算或刷新对应测量显示项。 |
| `Sta_compute()` | 汇总测量状态。 |
| `LCD_SHOW()` | 将电子负载测量结果推送到 LCD。 |
### `utils/chrg_north_pkg.c` 与 `utils/chrg_utils.c`
| 函数 | 说明 |
|---|---|
| `chrg_north_pkg_encode()` / `chrg_north_pkg_decode()` | 编码和解码北向协议包,并校验长度/校验值。 |
| `mb_crc16()` | 计算 Modbus CRC16。 |
| `_crc8()` / `calc_crc8()` | 单字节推进及整段 CRC8 计算。 |
| `u16_to_u8v()` / `u16_to_u8v_com()` / `u8v_to_u16()` | 16 位整数与字节序列互转。 |
| `u32_to_u8v()` / `u8v_to_u32()` | 32 位整数与字节序列互转。 |
| `swap_u16()` / `swap_u32()` | 交换 16/32 位整数端序。 |
## 8. 函数说明:上位机、LCD 与板级封装
### `thread/chrg_comm.c`
| 函数组 | 说明 |
|---|---|
| `chrg_shadow_sync()` / `chrg_shadow_init()` | 同步/初始化 Modbus 寄存器影子数据。 |
| `mb_set_bits()` / `mb_get_bits()` | 在 Modbus 位缓冲区写入/读取指定位段。 |
| `mb_reg_input_cb()` / `mb_reg_holding_cb()` / `mb_reg_test_cb()` | 输入、保持和测试寄存器回调。 |
| `mb_ymodem_updata_cb()` | 处理升级寄存器数据。 |
| `mb_reg_coils_cb()` / `mb_reg_discrete_cb()` | 线圈与离散输入回调。 |
| `funcReadCoils()` / `funcReadDiscreteInputs()` / `funcReadHoldingRegister()` / `funcReadInputRegister()` | 实现对应 Modbus 读功能。 |
| `funcWriteCoil()` / `funcWriteHoldingRegister()` / `funcWriteMultipleCoils()` / `funcWriteMultipleHoldingRegister()` | 校验并执行对应写功能。 |
| `sink_proto_lookup()` / `src_proto_lookup()` / `src_type_lookup()` | 将寄存器枚举映射为内部协议/Source 类型。 |
| `parse_load_no_group()` / `parse_load_with_group()` | 解析无组号/带组号的负载协议参数。 |
| `chrg_com_source_on()` | 根据通信配置启动 Source 流程。 |
| `funcWriteProtoCal()` / `funcSinkTest()` / `funcTrimELoad()` | 处理协议校准、Sink 测试和电子负载校准命令。 |
| `funYmodemUpadata()` | 推进固件升级命令。 |
| `chrg_comm_parse_msg()` | 解析通信线程邮箱消息并分派功能码。 |
| `chrg_comm_updata_north()` | 将实时北向状态同步到寄存器区。 |
| `chrg_comm_thread_entry()` | 初始化 Modbus 从站并循环处理消息/状态同步。 |
| `chrg_mb_write_sink()` / `chrg_mb_write_src()` / `chrg_mb_write_sys()` | 将保持寄存器变化写入 Sink、Source 和系统状态。 |
| `chrg_sink_get_proto_diff()` | 比较目标与实际 Sink 协议参数。 |
| `chrg_sink_diff_send_reg()` | 仅发送存在差异的 Sink 寄存器。 |
| `set_ymodem_update_channel()` / `mb_error()` / `rs485snd()` | 分别设置升级通道、转换错误码和提供 RS485 调试命令。 |
### `thread/chrg_lcd.c`
| 函数组 | 说明 |
|---|---|
| `chrg_sou_work()` / `chrg_sou_stop()` | 启动/停止指定功率通道。 |
| `chrg_pro_set()` | 应用 LCD 输入的快充协议配置。 |
| `chrg_set_eload_sink()` / `chrg_set_eload_source()` | 配置电子负载的 Sink/Source 角色。 |
| `chrg_set_CV()` / `chrg_set_CC()` / `chrg_roll_set_cv()` | 设置 CV、CC 及轮询相关目标值。 |
| `chrg_lcd_parse()` | 解析 HMI 命令并修改对应通道配置。 |
| `chrg_lcd_send()` | 向 HMI 发送数据。 |
| `chrg_lcd_thread_entry()` | LCD 串口收发与周期刷新主循环。 |
| `lcdsend()` | FinSH LCD 原始发送调试命令。 |
### `bsp/`
| 模块 | 函数说明 |
|---|---|
| `chrg_fal.c` | `chrg_fal_read()`、`chrg_fal_write()`、`chrg_fal_erase()`、`chrg_fal_erase_all()` 封装分区访问;`chrg_fal_init()` 初始化 FAL。 |
| `chrg_gpio.c` | `chrg_gpio_mode_set()`、`chrg_gpio_get()`、`chrg_gpio_set()` 封装 GPIO;`chrg_gpios_init()` 初始化引脚。 |
| `chrg_rel.c` | `chrg_nor_sw_rel()` 控制北向继电器;`chrg_nor_rel_init()` 初始化;`rel_test()` 用于 shell 测试。 |
| `chrg_switch.c` | `chrg_switch_ch()` 驱动通道译码选择线。 |
| `chrg_vcom.c` | `chrg_vcom_init()` 初始化 USB 虚拟串口;`chrg_vcom_console_init()` 注册控制台。 |
| `chrg_wdt.c` | `chrg_wdt_feed()` 喂狗;`chrg_wdt_init()` 初始化并启动看门狗。 |
| `chrg_tmr.c` | `chrg_tmr_get_count()`、`chrg_tmr_start()`、`chrg_tmr_stop()`、`chrg_tmr_release()`、`chrg_tmr_open()` 管理软件秒定时器;`chrg_tmr_1s_callback()` 计时;`chrg_tmrs_init()` 初始化;`uptime()`、`sec_tmr()` 为 shell 命令。 |
| `chrg_led.c` | `chrg_led_get()`、`chrg_led_set()`、`chrg_led_toggle()`、`chrg_led_pulsing()`、`chrg_led_flashing()` 控制 LED;`chrg_led_timer_set_on()`、`chrg_led_timer_set_off()`、`chrg_led_timer_start()`、`chrg_led_timer_delete()`、`chrg_led_timer_timeout_callback()`、`chrg_led_show()` 管理闪烁时序;`chrg_leds_init()` 初始化。 |
| `chrg_tty.c` | `chrg_tty_send_comp_hook()`、`chrg_tty_recv_ind_hook()` 为驱动回调;`chrg_tty_cal_byte_tmo()`、`chrg_tty_mode_set()`、`chrg_tty_dev_open()`、`chrg_tty_config()` 配置串口;`chrg_tty_connect()`、`chrg_tty_disconn()`、`chrg_tty_destory()` 管理连接;`chrg_tty_set_recv_tmo()`、`chrg_tty_set_byte_tmo()` 设置超时;`chrg_tty_recv()`、`chrg_tty_send()`、`chrg_tty_break_recv()`、`chrg_tty_send_then_recv()` 完成阻塞式收发。 |
## 9. Bootloader 函数级主链
```mermaid
flowchart TD
M["main()"] --> SI["System_Init()"]
M --> GPIO["MX_GPIO_Init() / MX_DMA_Init() / MX_USART_Init()"]
M --> AI["APP_Init()"]
AI --> DTI["DT_Init()"]
AI --> YI["ymodem_init()"]
AI --> FI["FM_Init()"]
M --> AR["APP_Running()"]
AR --> RD["recvDataHandler()"]
RD --> DPR["DT_PollingReceive()"]
RD --> YH["ymodemHandler()"]
YH --> BPD["boot_ProtocolDataHandle()"]
AR --> BCH["boot_CheckAndHandle()"]
BCH --> BCF["boot_CheckFirmware()"]
BCH --> BAU["boot_AutoUpdate()"]
BAU --> FMR["FM_ReadFirmwareHead()"]
BAU --> FMV["FM_VerifyFirmware()"]
BAU --> FMU["FM_UpdateToAPP()"]
BCH --> J["boot_JumpToAPP()"]
```
Boot 辅助模块职责:`firmware.c` 的 `FM_*` 函数负责分区头、擦写、CRC 校验、版本和搬运;`ymodem.c` 的 `ymodemHandler()`、`ymodemConfig()` 负责升级协议状态机;`transfer.c` 的 `DT_Init()`、`DT_Send()`、`DT_PollingReceive()` 负责串口帧传输;`drv_timer.c` 提供启动、重启、暂停、注销、处理和用户数据绑定;`bsp_uart.c`/`bsp_uart_port.c` 提供 UART、DMA、中断及接收完成回调。
## 10. 阅读与调试顺序
1. 启动异常先看 `chrg_thread_init()` 和各 `INIT_*_EXPORT` 初始化返回值。
2. 北向无数据依次跟踪 `chrg_north_thread_entry()`、`chrg_north_frame_head()`、`chrg_north_pickup_frame()`、`chrg_north_frame_dispatch()`。
3. Sink 不启动依次检查 `chrg_sink_parse()` 的电压/电流判定、`work_mode`、`chrg_sink_work()` 和 `chrg_set_sou_reg()`。
4. 功率板命令未生效依次检查 `chrg_set_sou_reg()`、`chrg_roll_sou_thread_entry()`、`chrg_south_send()` 和南向响应匹配。
5. 上位机写入未生效依次检查 Modbus `funcWrite*()`、`chrg_mb_write_*()`、共享状态和两个轮询线程。
+1 -1
View File
@@ -890,7 +890,7 @@ static void fal(rt_uint8_t argc, char **argv) {
{
if (write_data[index] != read_data[index])
{
rt_kprintf("%d %d %02x %02x.\n", i, index, write_data[index], read_data[index]);
// rt_kprintf("%d %d %02x %02x.\n", i, index, write_data[index], read_data[index]);
}
}
@@ -2237,6 +2237,7 @@ static struct rt_thread usb_thread;
/* internal of the message queue: every message is associated with a pointer,
* so in order to recveive USBD_MQ_MAX_MSG messages, we have to allocate more
* than USBD_MQ_MSG_SZ*USBD_MQ_MAX_MSG memory. */
rt_align(RT_ALIGN_SIZE)
static rt_uint8_t usb_mq_pool[(USBD_MQ_MSG_SZ+sizeof(void*))*USBD_MQ_MAX_MSG];
/**