ate.c
源文件路径:
midware/debug/ate.c所属模块:midware/debug(设备中间件 - 板级调试/产线测试) 代码行数:219
1. 文件职责
本文件实现 EMS 主控板在产线 ATE(自动化测试设备)工位上的一种特殊工作模式:把 USART2(TTL 调试串口,PB10/PB11)与 UART4(外部 485 总线,PC12/PD2 配 PG9 收发使能)从"两个独立的标准串口"临时改造成一条位级透传(passthrough)通路,让测试工装接在 USART2 上就能直接与接到 UART4 上的逆变器/被控设备通信,而 EMS 自身不解析报文。
进入该模式后,EMS 的逆变器通信逻辑被挂起(midware/inverter/inverter.c 中多处 get_passthrough_flag() == FALSE 判断),LCD/LED 也切换到测试提示画面(hmi/ui/ui_main.c:778、hmi/led.c:388)。驱动链是:task_system_aux(midware/auxiliary/system_aux.c:2085)每 400 ms 调用一次 passthrough_detection(),由它判断进入/退出并做外设重配置;实际的数据搬运在两个外部中断服务函数里完成(EXTI2 在本文件,EXTI11 在 hardware/exti/exti.c:70)。
2. 关键数据结构与宏
本文件没有定义结构体/枚举,只有两个文件级静态变量作为状态载体。
| 名称 | 类型 | 说明 |
|---|---|---|
s_u8_passthrough_flag | static u8 | 透传模式开关。TRUE 表示当前处于模拟串口透传状态(ate.c:25)。只有本文件的 set_passthrough_flag() 写,get_passthrough_flag() 对外读 |
s_u32_passthrough_tick | static u32 | 透传活动时间戳(uCOS-II tick,1 tick = 1 ms)。进入透传时记一次,之后每次 UART4 侧 RX 下降/上升沿(PD2 的 EXTI2 中断)刷新一次(ate.c:26)。超时判据以此为基准 |
EXTI_11 / EXTI_2 | GD32 SPL 宏 | 外部中断线编号。EXTI_2(PD2,UART4_RX)在本文件配置并由本文件的 EXTI2_IRQHandler 服务;EXTI_11(PB11,USART2_RX)在本文件配置,但中断服务函数在 hardware/exti/exti.c:70 的 EXTI10_15_IRQHandler 中 |
RCU_GPIOB/GPIOC/GPIOD/GPIOG/SYSCFG | GD32 SPL 宏 | 透传所需外设时钟 |
3. 函数清单
| 函数名 | 作用域 | 说明 |
|---|---|---|
emulated_serial_passthrough | static(前置声明 ate.c:31,定义 ate.c:41) | 把 USART2 与 UART4 的 TX/RX 引脚重配置为普通 GPIO,并打开 EXTI2 / EXTI11 中断,建立位级硬件透传通路 |
EXTI2_IRQHandler | 全局(ISR,ate.c:84) | PD2(UART4_RX)边沿中断服务:清标志、刷新 s_u32_passthrough_tick、把 PD2 电平直接搬到 PB10(USART2_TX) |
set_passthrough_flag | static(前置声明 ate.c:32,定义 ate.c:105) | 写 s_u8_passthrough_flag,入参做 == TRUE 归一化 |
get_passthrough_flag | 全局(ate.c:117) | 读透传标志,供逆变器通信、LCD、LED 等多处查询 |
get_passthrough_timeout_flag | static(前置声明 ate.c:33,定义 ate.c:129) | 判断透传是否应退出:升级中 / 单板测试中 / 该机型不支持透传 → 立即退出;ATE 模式 → 不退出;否则按 10 s 无活动超时 |
passthrough_detection | 全局(ate.c:163) | 透传状态机主体:检测进入条件并重配置外设、进入;检测退出条件并恢复 9600 bps 标准串口 |
4. 核心逻辑解析
4.1 透传模式的定位
EMS 正常工作时,UART4 是它自己与逆变器通信的 485 口,USART2 是外部调试口。ATE 工位希望"绕过 EMS 直接测逆变器",于是本文件把两个外设都 usart_deinit() 掉,改成 GPIOD2→GPIOB10、GPIOB11→GPIOC12(+PG9) 两组输入捕获 + 输出翻转,使两条物理链路在电平上首尾相接,形成一条"USART2 ↔ UART4"的透明中继。整个过程不涉及任何协议解析,因此对 Modbus/厂商私有协议都通用。
4.2 进入条件与状态迁移
passthrough_detection()(ate.c:163)用一串 else if 做互斥判断,前四个分支都是空实现,即"不进入透传";只有第五个分支才真正进入:
进入条件(全部满足):
1. 不在逆变器固件升级中:Get_Status_Is_Updated_From_Server(UPDT_INV1/2/3) 均为 FALSE
2. 不在单板测试中:g_u8_single_board_test_enable == FALSE
3. 该机型/该并机模式下允许透传:passthrough_detection_flag() == TRUE
4. UART4 侧收到了数据:uart4_is_recv_async_data() == TRUE
5. 当前尚未处于透传:get_passthrough_flag() == FALSE
其中第 5 条内部还有一个机型相关的使能极性反转(ate.c:182-190):
get_board_type() == BOARD_EMS3_6_4_E时,要求g_t_inv_info.t_config_data.u8_passthrough_disenable_flag == TRUE才允许;- 其它机型则要求该标志为
FALSE才允许。
即同一个配置位 u8_passthrough_disenable_flag("透传禁用标志")在 EMS3.6-4 板型上语义被反过来了,名字与行为不一致。
进入动作(ate.c:191-200):置标志 → usart_deinit(UART4)、usart_deinit(USART2) → emulated_serial_passthrough() 重配引脚 → 清两侧缓冲区 → 记录 s_u32_passthrough_tick。
4.3 退出条件
get_passthrough_timeout_flag()(ate.c:129)按优先级返回:
| 优先级 | 条件 | 返回值 | 含义 |
|---|---|---|---|
| 1 | Get_Status_Is_Updated_From_Server(UPDT_INV1/INV2/INV3) | TRUE | 逆变器要升级了,强制退出,让 EMS 拿回 UART4 |
| 2 | g_u8_single_board_test_enable == TRUE | TRUE | 产线单板自检要占用串口,强制退出 |
| 3 | passthrough_detection_flag() == FALSE | TRUE | 机型/并机模式不支持透传(如并机走 UART4/USART3 时) |
| 4 | g_t_inv_info.t_control_parameter.u8_ate_mode_flag 非 0 | FALSE | ATE 模式常驻透传,从不超时 |
| 5 | 其它 | abs(s_u32_passthrough_tick - OSTimeGet()) > 10000 | 10 s(10000 tick @ 1000 Hz)无 UART4 侧活动即超时退出 |
退出动作(ate.c:207-217):清标志 → exti_interrupt_disable(EXTI_2/EXTI_11) → usart2_init(9600)、uart4_init(9600) 恢复标准串口(注意:波特率被硬编码为 9600)→ 清缓冲 → set_inverter_init()(置 g_t_inv_info.u8_init_flag = TRUE,让逆变器通信重新走一遍识别流程)。
4.4 中断与位级转发时序
进入透传时打开的是一对双边沿外部中断:
- PD2 / EXTI2 → PB10(
ate.c:84-96):EXTI2_IRQHandler中先exti_interrupt_flag_clear(EXTI_2),再s_u32_passthrough_tick = OSTimeGet(),最后PBout(10) = PDin(2)把 UART4 收到的电平直接驱动到 USART2_TX。进出中断用OSIntEnter()/OSIntExit()包裹(受SYSTEM_SUPPORT_OS控制)。 - PB11 / EXTI11 → PC12 + PG9(在
hardware/exti/exti.c:70-82):PCout(12) = PBin(11); PGout(9) = !PBin(11);把 USART2 收到的电平驱动到 UART4_TX,同时把 485 收发使能 PG9 取反——空闲电平为高时 DE=0(接收态),起始位拉低时 DE=1(发送态),用一个反相器实现自动方向切换。
时序特征:没有采样、没有滤波、没有去抖,纯组合逻辑式转发,因此透传速率完全取决于中断响应延迟,只能在 9600 bps 这类低速下可靠工作。s_u32_passthrough_tick 只由 UART4 侧(PD2)刷新,USART2 侧的 EXTI11 不刷新它,所以"只有工装不停发、逆变器一直不回话"的场景下 10 s 也会超时退出。
4.5 与 uCOS-II 任务/全局变量的配合
- 调用者:
task_system_aux(midware/auxiliary/system_aux.c:2055起的for(;;)),周期 400 ms。没有信号量/邮箱参与,纯轮询。 - 被读取的全局量:
g_t_inv_info.t_config_data.u8_passthrough_disenable_flag(机型使能,midware/inverter/inverter.h:470)g_t_inv_info.t_control_parameter.u8_ate_mode_flag(ATE 模式常驻,midware/inverter/inverter.h:1861;由 Modbus 寄存器REG_ATE_MODE_FLAG_E写入,见midware/interface/modbus/modbus.c:6969)g_u8_single_board_test_enable(单板测试,见board_test.c)
- 被写的全局量:通过
set_inverter_init()间接写g_t_inv_info.u8_init_flag。 - 对外被查询:
get_passthrough_flag()被midware/inverter/inverter.c:1086/1103/1114/1219/1237/1247、hmi/led.c:388、hmi/ui/ui_main.c:778读取,是"透传期间暂停业务通信 + 显示测试画面"的统一开关。
5. 对外接口
本文件导出
| 名称 | 类型 | 供谁使用 |
|---|---|---|
get_passthrough_flag(void) | 函数 | midware/inverter/inverter.c(挂起各厂商逆变器通信)、hmi/led.c、hmi/ui/ui_main.c |
passthrough_detection(void) | 函数 | midware/auxiliary/system_aux.c:2085(task_system_aux 周期调用) |
EXTI2_IRQHandler(void) | ISR | 由 GD32 中断向量表调用(EXTI2_IRQn) |
本文件调用的外部函数/变量
| 来源模块 | 使用内容 |
|---|---|
inverter.h / inverter.c | passthrough_detection_flag()、set_inverter_init()、g_t_inv_info |
net/upd_download.h | Get_Status_Is_Updated_From_Server(UPDT_INV1/2/3) |
net/server.h | 枚举 UPDT_INV1/INV2/INV3(net/server.h:188-196 的 ENUpdateType) |
system/board_init/board_init.h | get_board_type()、BOARD_EMS3_6_4_E |
hardware/usart2 | usart2_init()、usart2_clear_buffer() |
hardware/usart4 | uart4_init()、uart4_clear_buffer()、uart4_is_recv_async_data() |
board_test.h | g_u8_single_board_test_enable |
GD32 SPL(HALLIB/) | rcu_periph_clock_enable、gpio_mode_set、gpio_output_options_set、syscfg_exti_line_config、exti_init、exti_interrupt_flag_clear、exti_interrupt_disable、usart_deinit |
system/sys/chip.h | 位带宏 PBout(n)、PDin(n)(chip.h:100/107) |
| uCOS-II | OSTimeGet()、OSIntEnter()、OSIntExit()、SYSTEM_SUPPORT_OS |
6. 依赖关系
依赖
ate.h、usart2.h、usart4.h、includes.h(uCOS-II 总头)、inverter.h、inv_download.h、board_test.h、board_init.h(ate.c:13-20)。
被依赖
midware/auxiliary/system_aux.c(includeboard_test.h,并调用passthrough_detection())midware/inverter/inverter.c、hmi/led.c、hmi/ui/ui_main.c(调用get_passthrough_flag(),均通过ate.h或转包含)hardware/exti/exti.c的EXTI10_15_IRQHandler与本文件共享 EXTI11 中断线(配置在本文件,服务在 exti.c)
7. 备注与风险点
- 函数名与注释不符:
ate.c:122-128的注释块写的是get_passthrough_tick,实际函数名是get_passthrough_timeout_flag(ate.c:129)。 s_u8_passthrough_flag未加volatile:该变量被 ISR(间接)与任务上下文读写的语义边界存在,但真正在中断里写的只有s_u32_passthrough_tick(ISR 写、任务读),编译器优化下存在读到陈旧值的理论风险。s_u32_passthrough_tick只在 EXTI2 里刷新:单向活动(工装→设备)不会续期,10 s 后仍会超时退出,行为与"任意方向的透传活动都续期"的直觉不同。- 退出时波特率硬编码 9600(
ate.c:212-213),未保留进入前的波特率;若业务侧原本配置为其它速率,退出后需要靠set_inverter_init()触发的重新识别流程再调整。 u8_passthrough_disenable_flag在 EMS3.6-4 上语义反转(ate.c:183-190),标志名与含义相反,极易误配置。- 中断服务与初始化分居两个文件:EXTI11 的 SYSCFG/EXTI 配置在
ate.c:56-58,中断服务在hardware/exti/exti.c:70。改动其中一处时容易漏掉另一处。 ate.c直接操作裸 GPIO 位带(PBout(10) = PDin(2)),没有做"引脚当前是否仍被 USART 复用"的防御;若透传中发生复位流程不完整(例如升级抢占),可能残留半配置状态。emulated_serial_passthrough()中syscfg时钟使能注释写成"使能GPIOD中断时钟"(ate.c:47),实为RCU_SYSCFG,注释误导。- 所有进入/不进入的空分支都是
{ }而非注释说明,代码可读性差;这一写法本身无功能问题。