feat(日志): 控制台迁到 RS232#1/UART5,USART1 让位给屏板链路
批 0 的第 2 项。USART1 是唯一 MCU 引脚直出的 TTL 通道,700 kbaud 的屏板 链路要用它,控制台必须先让开。 console_log.c 加一处端口收口块,换口只改这一段: CON_UART / CON_UART_IRQN / CON_UART_CLK_DISABLE/ENABLE / CON_UART_INIT 代码实际改动 4 处:con_tx_bounded 的 huart1.Instance(NULL 判据、counted 回退、赋值)与 con_uart_reinit 全函数体。其余是把描述当前行为的注释里的 USART1 换成「控制台串口」;历史变更记录(2026-10-02 / 10-24)里的 USART1 保持原样,那是当时的实况。 注意事项:UART5 在 APB1、USART1 在 APB2,时钟宏不能照抄; __HAL_RCC_UART5_CLK_ENABLE 定义在 stm32f4xx_hal_rcc_ex.h。 不改 UART 模式(2026-10-26 裁定:保持 UART_MODE_TX_RX,不动 RX 配置)。 MX_UART5_Init 在 Src/main.c:135,比 MX_USART1_UART_Init 晚几个初始化调用, 该窗口内的日志由 CON_UART.Instance == NULL 短路接住(记 dropped,不崩)。 构建:Code=236,460 RO=28,124 RW=1,876 ZI=137,084(Code 较迁移前 +4 B)。 台架验证(COM3 @115200,RS232#1 经 CN1.10/CN1.12): - 烧录回读 no difference found;8 个 required 锚点全中,无 forbidden; 启动到 net init: OK 用时 661 ms - 连续 10 分钟长稳:1218 行,零 [ERR]、零 dropped、零 tx_fault, 末行仍在正常 PROF 输出 - USART1 已无任何控制台写入(全文件 grep 只剩历史注释)
This commit is contained in:
+32
-20
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 模块名称:Console Single-Writer Logging — 控制台单写者日志(USART1)实现
|
||||
* 模块名称:Console Single-Writer Logging — 控制台单写者日志(RS232#1 / UART5)实现
|
||||
* 模块功能:控制台单写者日志的环形缓冲 + 唯一写者发送实现(API 见 console_log.h);
|
||||
* 兼载 MicroLIB printf 底层 fputc 重定向
|
||||
* 适用平台:STM32F407ZGTx(仅 MCU 端)
|
||||
@@ -99,6 +99,18 @@
|
||||
* 与当场直发逐字节相同。ISR / 调度器未启动两种上下文放行(不许等)。
|
||||
* 约束:不新增任务、不动态分配;环形缓冲为 BSS(SRAM1,非 CCM),无 DMA 可达性冲突。
|
||||
*/
|
||||
|
||||
/* ===== 控制台端口(单点收口)=====
|
||||
* 换口只改这一段:句柄 / IRQn / 初始化函数。时钟宏随句柄走——UART5 在 APB1、
|
||||
* USART1 在 APB2,别照抄;串口模式与波特率在 Src/usart.c 的 MX_*_Init 里,本模块不管。
|
||||
* 2026-10-29 批 0:USART1 让位给屏板链路(700 kbaud 只有它 MCU 引脚直出),控制台迁
|
||||
* RS232#1/UART5。缘由、端子与验收见 docs/任务规划/屏板链路.md 的批 0。 */
|
||||
#define CON_UART huart5
|
||||
#define CON_UART_IRQN UART5_IRQn
|
||||
#define CON_UART_CLK_DISABLE() __HAL_RCC_UART5_CLK_DISABLE()
|
||||
#define CON_UART_CLK_ENABLE() __HAL_RCC_UART5_CLK_ENABLE()
|
||||
#define CON_UART_INIT() MX_UART5_Init()
|
||||
|
||||
#define DBG_CON_RING_SIZE 4096U /* 环形缓冲字节数(必须为 2 的幂) */
|
||||
#define DBG_CON_CHUNK_MAX 256U /* 写者单次 HAL_UART_Transmit 字节上限 */
|
||||
#define DBG_CON_WAIT_MS 200U /* 缓冲满时生产者最长等待(ms),仍满则丢弃并计数 */
|
||||
@@ -140,7 +152,7 @@ static volatile uint8_t s_con_draining; /* 1 = 处于 drain 中(重入保
|
||||
static volatile uint8_t s_con_writer_up; /* 1 = 写者已注册(此后走环形缓冲) */
|
||||
static volatile uint8_t s_con_dwt_up; /* 1 = DWT CYCCNT 已使能(硬上界基准可用) */
|
||||
static TaskHandle_t s_con_writer_task; /* 写者任务句柄(自等保护用) */
|
||||
/* 行级单一所有者(道G task-23,O1 第二实例):USART1 数据寄存器同一时刻只允许
|
||||
/* 行级单一所有者(道G task-23,O1 第二实例):控制台串口数据寄存器同一时刻只允许
|
||||
* 一个上下文在逐字节轮询写入。NULL = 空闲。
|
||||
* ⚠ 这不是"锁",是**所有权凭证**:拿不到就当场让路,绝不排队等待(见
|
||||
* con_tx_try_claim 函数头:裸发一行 @115200 约 7.8 ms,把它包进临界区等于给
|
||||
@@ -228,7 +240,7 @@ static void con_dwt_ensure(void) {
|
||||
* 入口参数:u - USART 寄存器基址(调用方已判非 NULL) USART_TypeDef *
|
||||
* p_buf - 待发数据;len - 字节数
|
||||
* 返回值:HAL_OK - 已发出;HAL_TIMEOUT - 计数上界内未完成(本块放弃)
|
||||
* 限定条件:USART1 已初始化
|
||||
* 限定条件:控制台串口已初始化
|
||||
* 函数说明:刻意不用 HAL_UART_Transmit——理由见 CON_TX_GUARD_MAX 处注释
|
||||
* (tick 依赖不可信 + 其调用链污染所有任务的最坏栈链)
|
||||
*/
|
||||
@@ -258,12 +270,12 @@ static HAL_StatusTypeDef con_tx_counted(USART_TypeDef *u, const uint8_t *p_buf,
|
||||
* 函数功能:有界裸发送(不依赖 uwTick / HAL 超时)
|
||||
* 入口参数:p_buf - 待发数据;len - 字节数(调用方已限 ≤ DBG_CON_CHUNK_MAX)
|
||||
* 返回值:HAL_OK - 已全部写入发送寄存器;HAL_TIMEOUT - 有界上界内未完成
|
||||
* 限定条件:USART1 已初始化
|
||||
* 限定条件:控制台串口已初始化
|
||||
* 函数说明:寄存器级轮询 TXE/TC,超时判据用 DWT CYCCNT(CON_TX_TIMEOUT_CYC);
|
||||
* DWT 未使能时走 con_tx_counted(指令计数上界,2026-10-10 取代
|
||||
* HAL_UART_Transmit 回退)。本函数只做 TX,
|
||||
* 不触碰 RX/错误标志——僵尸通道自愈由调用方按返回值处理。
|
||||
* ⚠ USART1 未初始化(huart1.Instance == NULL,如 HAL_Init 早期或
|
||||
* ⚠ 控制台串口未初始化(CON_UART.Instance == NULL,如 HAL_Init 早期或
|
||||
* 断言/故障上报路径)时立即返回 HAL_ERROR:否则会解引用 NULL 去读写
|
||||
* 地址 0(flash 别名区)→ 在故障处理里再触发故障(2026-10-02 台架实测)。
|
||||
*/
|
||||
@@ -273,14 +285,14 @@ static HAL_StatusTypeDef con_tx_bounded(const uint8_t *p_buf, uint16_t len) {
|
||||
uint16_t i;
|
||||
|
||||
con_dwt_ensure();
|
||||
if (huart1.Instance == NULL) {
|
||||
return HAL_ERROR; /* USART1 未初始化:无可用通道,安全让位(不是超时,不记超时账) */
|
||||
if (CON_UART.Instance == NULL) {
|
||||
return HAL_ERROR; /* 控制台串口未初始化:无可用通道,安全让位(不是超时,不记超时账) */
|
||||
}
|
||||
if (s_con_dwt_up == 0U) {
|
||||
return con_tx_counted(huart1.Instance, p_buf, len);
|
||||
return con_tx_counted(CON_UART.Instance, p_buf, len);
|
||||
}
|
||||
|
||||
u = huart1.Instance;
|
||||
u = CON_UART.Instance;
|
||||
t0 = DWT->CYCCNT;
|
||||
for (i = 0U; i < len; i++) {
|
||||
while ((u->SR & USART_SR_TXE) == 0U) {
|
||||
@@ -299,7 +311,7 @@ static HAL_StatusTypeDef con_tx_bounded(const uint8_t *p_buf, uint16_t len) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:尝试取得"USART1 整行发送所有权"(**非阻塞**,道G task-23)
|
||||
* 函数功能:尝试取得"控制台串口整行发送所有权"(**非阻塞**,道G task-23)
|
||||
* 返回值:CON_TX_HELD 已持有(发完必须 con_tx_release)/ CON_TX_BYPASS 放行且不记账
|
||||
* / CON_TX_NO 别人正持有整行,调用方须让路
|
||||
* 限定条件:任意上下文(内部只有一次几条指令的临界区,绝不睡眠、绝不长期关中断)
|
||||
@@ -473,7 +485,7 @@ uint8_t dbg_console_writer_ready(void) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:USART1 僵尸通道自愈(清错误锁存 + 整外设重初始化)
|
||||
* 函数功能:控制台串口僵尸通道自愈(清错误锁存 + 整外设重初始化)
|
||||
* 函数说明:**RX 使能了却从不读 DR** → 线上任意一个字节或一个噪声沿使 RXNE 置位后无人读,
|
||||
* 下一个事件即锁存 ORE(常伴 NE/FE/PE);ORE 只能靠"先读 SR 再读 DR"清除 ⇒ 永不自愈。
|
||||
* 锁存后 HAL 轮询 TX 恒快速失败(控制台静默、系统不复位);发送器卡死状态则使 TXE
|
||||
@@ -484,13 +496,13 @@ uint8_t dbg_console_writer_ready(void) {
|
||||
* (详见 docs/子系统设计/控制台单写者日志设计说明.md §12)。
|
||||
*/
|
||||
static void con_uart_reinit(void) {
|
||||
__NVIC_ClearPendingIRQ(USART1_IRQn);
|
||||
__HAL_RCC_USART1_CLK_DISABLE();
|
||||
__HAL_RCC_USART1_CLK_ENABLE();
|
||||
huart1.gState = HAL_UART_STATE_RESET;
|
||||
huart1.RxState = HAL_UART_STATE_RESET;
|
||||
huart1.ErrorCode = HAL_UART_ERROR_NONE;
|
||||
(void)MX_USART1_UART_Init();
|
||||
__NVIC_ClearPendingIRQ(CON_UART_IRQN);
|
||||
CON_UART_CLK_DISABLE();
|
||||
CON_UART_CLK_ENABLE();
|
||||
CON_UART.gState = HAL_UART_STATE_RESET;
|
||||
CON_UART.RxState = HAL_UART_STATE_RESET;
|
||||
CON_UART.ErrorCode = HAL_UART_ERROR_NONE;
|
||||
(void)CON_UART_INIT();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -512,7 +524,7 @@ void dbg_console_drain(void) {
|
||||
return; /* 重入保护:写者自记录不触发嵌套 drain */
|
||||
}
|
||||
|
||||
/* 整行所有权(道G task-23):本函数按块直写 USART1->DR,若此刻别的应用上下文
|
||||
/* 整行所有权(道G task-23):本函数按块直写 CON_UART->DR,若此刻别的应用上下文
|
||||
* 还在未注册期那条裸发里发到自己一半(attach 就发生在 defaultTask 里,与别的
|
||||
* 任务裸发**可以**前后脚撞上),两边就会逐字节交错——那正是本卡要修的形态。
|
||||
* 拿不到就**本轮让位**:tail 不推进 => 环里一条不少,主循环 ≤50 ms 后再试,
|
||||
@@ -560,7 +572,7 @@ void dbg_console_drain(void) {
|
||||
|
||||
if (st != HAL_OK) {
|
||||
if (st == HAL_ERROR) {
|
||||
/* 2026-10-24 修复:USART1 **未初始化**(huart1.Instance == NULL,
|
||||
/* 2026-10-24 修复:控制台串口 **未初始化**(CON_UART.Instance == NULL,
|
||||
* 只可能出现在 HAL_Init 早期或断言/故障上报路径)与"僵尸通道"是两回事:
|
||||
* 这里**绝不做外设重初始化**——那会在 HAL 尚未就绪时跑 MspInit 重配
|
||||
* RCC/GPIO;也不计 tx_fault(那本账的语义是"软复位自愈次数")。
|
||||
|
||||
Reference in New Issue
Block a user