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:
2026-10-29 18:45:59 +08:00
parent 27a700b0d8
commit f5161e1567
6 changed files with 43 additions and 31 deletions
+32 -20
View File
@@ -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(那本账的语义是"软复位自愈次数")。
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* 模块名称:Console Single-Writer Logging — 控制台单写者日志(USART1 调试串口)
* 模块名称:Console Single-Writer Logging — 控制台单写者日志(RS232#1 / UART5)
* 模块功能:调试控制台单写者环形缓冲的公共 API:所有任务/上下文(含 printf)只把
* 已格式化整行文本入环形缓冲,写者任务(defaultTask)为唯一
* HAL_UART_Transmit 发送点(行级原子 + 指针可控)
@@ -47,10 +47,10 @@ dhara 失败类 +84;RO 另 +208,全是该失败类名表)→ `ER_IROM1`
<!-- MEM_SNAPSHOT:BEGIN generated by scripts/check_mem_numbers.py -->
| 区域 | 用量 | 容量 | 占比 |
|---|---|---|---|
| ER_IROM1 | 264,580 B (258.38 KB) | 1,048,576 B (1024 KB) | 25.2% |
| ER_IROM1 | 264,584 B (258.38 KB) | 1,048,576 B (1024 KB) | 25.2% |
| RW_IRAM1 | 81,536 B (79.62 KB) | 131,072 B (128 KB) | 62.2% |
| RW_CCM | 57,376 B (56.03 KB) | 65,280 B (64 KB) | 87.9% |
| **Flash (ROM 合计)** | **266,456 B (260.2 KB)** | 1,048,576 B (1024 KB) | **25.4%** |
| **Flash (ROM 合计)** | **266,460 B (260.2 KB)** | 1,048,576 B (1024 KB) | **25.4%** |
<!-- MEM_SNAPSHOT:END -->
各区的容量与常量来源:
+1 -1
View File
@@ -15,7 +15,7 @@
<!-- MEM_BUDGET:BEGIN generated by scripts/ram_baseline.py -->
| 区域 | 用量 | 容量 | 占比 | 门禁(≤92%) |
|---|---|---|---|---|
| ER_IROM1 (Flash) | 264,580 B | 1,048,576 B | 25.2% | 参考 |
| ER_IROM1 (Flash) | 264,584 B | 1,048,576 B | 25.2% | 参考 |
| RW_CCM | 57,376 B | 65,280 B | 87.9% | PASS |
| UNINIT_CCM | 48 B | 256 B | 18.8% | 参考 |
| RW_IRAM1 | 81,536 B | 131,072 B | 62.2% | PASS |
+1 -1
View File
@@ -11,4 +11,4 @@ date code ro rw zi er_irom1 er_pct iram1 iram1_pct ccm ccm_pct top_rwzi
2026-10-26 231712 25560 1520 136216 257272 24.5 80312 61.3 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4003;default_task.o=2736
2026-10-27 235372 26392 1572 136924 261764 25.0 81072 61.9 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055;default_task.o=2736
2026-10-28 236456 28124 1876 137084 264580 25.2 81536 62.2 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055;default_task.o=2736
2026-10-29 236456 28124 1876 137084 264580 25.2 81536 62.2 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055;default_task.o=2736
2026-10-29 236460 28124 1876 137084 264584 25.2 81536 62.2 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055;default_task.o=2736
1 date code ro rw zi er_irom1 er_pct iram1 iram1_pct ccm ccm_pct top_rwzi
11 2026-10-26 231712 25560 1520 136216 257272 24.5 80312 61.3 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4003;default_task.o=2736
12 2026-10-27 235372 26392 1572 136924 261764 25.0 81072 61.9 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055;default_task.o=2736
13 2026-10-28 236456 28124 1876 137084 264580 25.2 81536 62.2 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055;default_task.o=2736
14 2026-10-29 236456 236460 28124 1876 137084 264580 264584 25.2 81536 62.2 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055;default_task.o=2736
+6 -6
View File
@@ -1,15 +1,15 @@
{
"built_at": "2026-10-29T17:51:46+08:00",
"fingerprint": "d9848eb18efe7902c936a791c0b649900c0088d4f2c582e0a71d9998ba9ae0f4",
"built_at": "2026-10-29T18:43:32+08:00",
"fingerprint": "bfe075e7093727025c3ba21e3057445a6c23ec4b0193c7e14286cc6ca60f6f1f",
"fingerprint_files": 1452,
"fingerprint_source": "git-index",
"gated_regions": [
"RW_IRAM1",
"RW_CCM"
],
"git_head": "c51ac2e8ef09dbd51b1e81a82b73becc55ca1c3e",
"git_head": "27a700b0d81cde580d88f783d6cb661aac248516",
"map": "MDK-ARM/STM32F407-Demo/STM32F407-Demo.map",
"map_mtime": 1793267423,
"map_mtime": 1793270606,
"pct": {
"ER_IROM1": 25.23,
"RW_CCM": 87.89,
@@ -19,7 +19,7 @@
"regions": {
"ER_IROM1": {
"max": 1048576,
"size": 264580
"size": 264584
},
"RW_CCM": {
"max": 65280,
@@ -37,7 +37,7 @@
"schema": 2,
"scope_note": "\u540c\u7801\u51ed\u8bc1\uff1a\u6307\u7eb9\u8986\u76d6\u56fa\u4ef6\u4f53\u79ef\u76f8\u5173\u6e90\u7801\uff0c\u53e3\u5f84\u89c1\u672c\u811a\u672c docstring",
"sizes": {
"code": 236456,
"code": 236460,
"ro_data": 28124,
"rw_data": 1876,
"zi_data": 137084