From 7bc616cf9b7513e3049790d8e2b4578cea89c5d8 Mon Sep 17 00:00:00 2001 From: wandering1 <1624155937@qq.com> Date: Sat, 29 Aug 2026 09:45:54 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BA=86main=20=E5=87=BD?= =?UTF-8?q?=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/app_main.c | 81 +++++++++++++++++++++++++- App/task/net_task.c | 4 +- App/task/net_task.h | 2 +- Drivers/BSP/RS485/rs485.c | 97 ++++++++++++++++++++----------- Drivers/BSP/RS485/rs485.h | 34 ++++++++--- MDK-ARM/STM32F407-Demo.uvprojx | 5 ++ MDK-ARM/build_log.txt | 97 ++++++++++++++++--------------- STM32F407-Demo.ioc | 2 +- Src/freertos.c | 28 +++++---- Src/main.c | 103 ++------------------------------- rx_100k.bin | Bin 102400 -> 0 bytes test/ch395f_test.h | 4 +- test/ch395f_test_task.c | 22 ++----- test/ch395f_test_task.h | 3 +- test/net_test_task.c | 2 +- test/net_test_task.h | 2 +- test/sd2506_test.h | 2 +- test/sd2506_test_task.c | 2 +- test/storage_test.h | 2 +- test/storage_test_task.c | 2 +- test/test_config.c | 50 ++++++++++++++++ test/test_config.h | 2 +- 22 files changed, 311 insertions(+), 235 deletions(-) delete mode 100644 rx_100k.bin create mode 100644 test/test_config.c diff --git a/App/app_main.c b/App/app_main.c index 70a414ec..d300dadf 100644 --- a/App/app_main.c +++ b/App/app_main.c @@ -6,23 +6,102 @@ * 创建日期:2026-07-19 * 修改记录: * v1.0 2026-07-19 王建锋 创建初始版本 + * v1.1 2026-08-29 王建锋 将原 main.c 中各外设初始化统一收归 app_main_init, + * 并按"时间子系统优先"的顺序编排启动流程 */ #include "app_main.h" #include "app_cfg.h" +#include "main.h" /* ST_DIR4_GPIO_Port / ST_DIR4_Pin 等 CubeMX 宏 */ +#include "usart.h" /* huart5 */ +#include "rs485.h" +#include "sd2506.h" +#include "sys_clock.h" +#include "gd5f2gq5ue.h" +#include "tpafe5160.h" + #define DBG_TAG "[APP]" #include "dbg_log.h" +/* g_rs485 由 rs485.c 定义,经 rs485.h 的 extern 引用;接收缓冲内聚于句柄 rx_buf */ + /* * 函数功能:应用层初始化 * 入口参数:无 * 返 回 值:0 - 成功,-1 - 失败 * 限定条件:CubeMX 外设初始化已完成 - * 函数说明:在 CubeMX 外设初始化之后、FreeRTOS 调度器启动之前调用 + * 函数说明:在 CubeMX 外设初始化之后、FreeRTOS 调度器启动之前调用。 + * 启动顺序以"时间子系统优先"为原则,使后续所有日志均带时间戳: + * 1) 时间子系统(SD2506 RTC → 墙钟基准) + * 2) RS-485 + * 3) GD5F NAND + * 4) TPAFE5160 ADC + * 5) SD2506 诊断信息 + * 6) 触发首次 ADC 转换 */ int app_main_init(void) { + /* + * 1) 时间子系统初始化(尽早完成,后续所有日志带时间戳) + * sd2506_init() 从 RTC 读取初始时间 + * sys_clock_init() 将 RTC 时间转为 Unix epoch,建立墙钟基准 + */ + sd2506_init(); + sys_clock_init(); + + /* 2) RS-485 初始化(UART5 + PD0 方向控制),初始化即自动开启接收 */ + rs485_init(&g_rs485, &huart5, ST_DIR4_GPIO_Port, ST_DIR4_Pin); + DBG_INFO("RS485 init: OK (UART5, DE=PD0)"); + + /* 3) GD5F 初始化测试 */ + int ret = gd5f2gq5ue_init(); + DBG_INFO("NAND init: %s", + (ret == GD5F_OK) ? "OK" : + (ret == GD5F_ERROR) ? "ERROR" : + (ret == GD5F_BUSY_TIMEOUT) ? "BUSY TIMEOUT" : + (ret == GD5F_ECC_ERROR) ? "ECC ERROR" : + (ret == GD5F_PROGRAM_FAIL) ? "PROGRAM FAIL" : + (ret == GD5F_ERASE_FAIL) ? "ERASE FAIL" : + (ret == GD5F_ID_MISMATCH) ? "ID MISMATCH" : "UNKNOWN"); + + /* 4) TPAFE5160 ADC 测试 */ + int tp_ret = tpafe5160_init(); + DBG_INFO("ADC init: %s", + (tp_ret == TPAFE5160_OK) ? "OK" : "TIMEOUT"); + + /* 5) SD2506 RTC 诊断信息 */ + { + /* 读取 ID */ + uint8_t sd_id[8]; + sd2506_get_id(sd_id); + DBG_INFO("SD2506 ID: %02X%02X%02X%02X%02X%02X%02X%02X", + sd_id[0], sd_id[1], sd_id[2], sd_id[3], + sd_id[4], sd_id[5], sd_id[6], sd_id[7]); + + /* 读取当前时间 */ + sd2506_time_t sd_time; + sd2506_get_time(&sd_time); + DBG_INFO("SD2506 time: %04d-%02d-%02d %02d:%02d:%02d (week %d)", + sd_time.year, sd_time.month, sd_time.day, + sd_time.hour, sd_time.minute, sd_time.second, + sd_time.week); + + /* 读取温度 */ + int8_t sd_temp; + sd2506_get_temperature(&sd_temp); + DBG_INFO("SD2506 temp: %d C", sd_temp); + + /* 读取电池电压 */ + uint16_t sd_vbat; + sd2506_get_battery_voltage(&sd_vbat); + DBG_INFO("SD2506 battery: %d.%02d V", + sd_vbat / 1000, (sd_vbat % 1000) / 10); + } + + /* 6) 启动第一次转换(CubeMX 已配置 BUSY EXTI 中断) */ + tpafe5160_start_conv_irq(); + DBG_INFO("App init OK"); return 0; } diff --git a/App/task/net_task.c b/App/task/net_task.c index 772cdc10..c9283240 100644 --- a/App/task/net_task.c +++ b/App/task/net_task.c @@ -31,7 +31,7 @@ volatile uint8_t g_net_ready = 0; * 返 回 值:0 - 成功,-1 - 失败 * 函数说明:net_init → MAC 打印 → PHY 强制 100M 全双工 → 置 g_net_ready。 * NET 层模式由 netTask 调用;硬件层模式(阶段 1~5)netTask 不创建, - * 由 ch395fTestTask 调用后独占 CH395F。 + * 由 testTask 调用后独占 CH395F。 */ int net_stack_bring_up(void) { @@ -89,7 +89,7 @@ int net_task_init(void) * 函数说明:启动后先调用 net_stack_bring_up() 初始化 CH395F 协议栈, * 再进入轮询循环处理网络事件。 * 仅 NET 层测试模式(阶段 6~10)会创建本任务; - * 硬件层模式下 netTask 不创建,CH395F 由 ch395fTestTask 独占。 + * 硬件层模式下 netTask 不创建,CH395F 由 testTask 独占。 */ void net_task_func(void const *arg) { diff --git a/App/task/net_task.h b/App/task/net_task.h index da32062c..243d27be 100644 --- a/App/task/net_task.h +++ b/App/task/net_task.h @@ -18,7 +18,7 @@ extern "C" { /* CH395F 协议栈一次性初始化(net_init + MAC 打印 + PHY 配置 + g_net_ready 置位)。 * 返回 0 成功 / -1 失败。NET 层模式由 netTask 调用;硬件层模式(阶段 1~5) - * netTask 不创建,由 ch395fTestTask 调用后独占 CH395F。 */ + * netTask 不创建,由 testTask 调用后独占 CH395F。 */ int net_stack_bring_up(void); int net_task_init(void); diff --git a/Drivers/BSP/RS485/rs485.c b/Drivers/BSP/RS485/rs485.c index faee6b23..317fdb58 100644 --- a/Drivers/BSP/RS485/rs485.c +++ b/Drivers/BSP/RS485/rs485.c @@ -14,27 +14,10 @@ #include "rs485.h" -/* ======================== 内部辅助函数 ======================== */ +/* ======================== 全局实例 ======================== */ -/* - * 函数功能:DWT 微秒级延时 - * 入口参数:us - 延时微秒数 uint32_t 1 - N - * 返回值:无 - * 限定条件:无(首次调用自动初始化 DWT CYCCNT) - * 函数说明:利用 Cortex-M4 DWT CYCCNT 实现精确微秒延时,168MHz 下 1us = 168 计数。 - * 首次调用时自动使能 DWT 和 CYCCNT,后续只读 CYCCNT 寄存器,不影响其他模块。 - */ -static void delay_us(uint32_t us) -{ - if (!(CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)) { - CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; - DWT->CYCCNT = 0; - DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; - } - uint32_t start = DWT->CYCCNT; - uint32_t ticks = us * (SystemCoreClock / 1000000uL); - while ((DWT->CYCCNT - start) < ticks) { ; } -} +/* RS-485 全局实例(接收缓冲内聚于句柄的 rx_buf 字段) */ +rs485_handle_t g_rs485; /* ======================== 方向控制宏 ======================== */ @@ -51,7 +34,8 @@ static void delay_us(uint32_t us) * dir_pin - 方向控制 GPIO 引脚号(如 GPIO_PIN_0) uint16_t * 返回值:无 * 限定条件:UART 和 GPIO 须先由 CubeMX 完成初始化 - * 函数说明:初始化后默认处于接收状态(DE 引脚拉低) + * 函数说明:初始化后默认处于接收状态(DE 引脚拉低), + * 并自动启动 IDLE 中断接收,无需再手动调用 rs485_receive_start。 */ void rs485_init(rs485_handle_t *p_handle, UART_HandleTypeDef *p_huart, @@ -64,6 +48,9 @@ void rs485_init(rs485_handle_t *p_handle, p_handle->rx_size = 0; RS485_DIR_RX(p_handle); + + /* 自动开启 IDLE 中断接收(后续在回调中重新开启) */ + (void)rs485_receive_start(p_handle); } /* @@ -76,14 +63,15 @@ void rs485_init(rs485_handle_t *p_handle, * HAL_TIMEOUT - 发送超时 * HAL_ERROR - 发送错误 * 限定条件:须在主循环或 FreeRTOS 任务中调用,不可在 UART 中断中调用 - * 函数说明:发送前拉高 DE,等待 50us 确保 RS485 收发器驱动使能稳定后再启动 UART 发送。 + * 函数说明:发送前拉高 DE,等待 HAL 时基延时确保 RS485 收发器驱动使能稳定后再启动 + * UART 发送(HAL 时基最小粒度 1ms,此处延时 1ms,远大于 50us 的 DE 建立时间)。 * HAL_UART_Transmit 内部等待 TC(发送完成)标志,确保最后一字节完全移出后 * 再拉低 DE 切回接收状态。 */ HAL_StatusTypeDef rs485_transmit(rs485_handle_t *p_handle, - const uint8_t *p_data, - uint16_t len, - uint32_t timeout) + const uint8_t *p_data, + uint16_t len, + uint32_t timeout) { HAL_StatusTypeDef status = HAL_OK; @@ -93,7 +81,8 @@ HAL_StatusTypeDef rs485_transmit(rs485_handle_t *p_handle, RS485_DIR_TX(p_handle); - delay_us(50); + /* DE 建立延时:HAL 时基为 1ms 粒度,1ms 已充分覆盖收发器驱动使能稳定时间 */ + HAL_Delay(1); status = HAL_UART_Transmit(p_handle->huart, (uint8_t *)p_data, @@ -108,22 +97,19 @@ HAL_StatusTypeDef rs485_transmit(rs485_handle_t *p_handle, /* * 函数功能:启动中断方式接收(IDLE 空闲帧检测) * 入口参数:p_handle - RS-485 句柄指针 rs485_handle_t*(非空) - * p_buf - 接收缓冲区 uint8_t*(非空) - * buf_size - 缓冲区大小 uint16_t * 返回值:HAL_OK - 启动成功 HAL_StatusTypeDef * HAL_ERROR - 启动失败 * 限定条件:UART 须已开启全局中断(NVIC 使能) - * 函数说明:使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收。 + * 函数说明:使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收, + * 接收缓冲固定使用句柄内部的 rx_buf(RS485_RX_BUF_SIZE)。 * 当 UART 总线空闲超过 1 个字符时间后硬件触发 IDLE 中断, * HAL 自动调用 HAL_UARTEx_RxEventCallback 并返回已接收字节数。 * 用户须在回调中重新调用本函数重新开启接收。 */ -HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *p_handle, - uint8_t *p_buf, - uint16_t buf_size) +HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *p_handle) { p_handle->rx_size = 0; - return HAL_UARTEx_ReceiveToIdle_IT(p_handle->huart, p_buf, buf_size); + return HAL_UARTEx_ReceiveToIdle_IT(p_handle->huart, p_handle->rx_buf, RS485_RX_BUF_SIZE); } /* @@ -150,3 +136,48 @@ uint16_t rs485_rx_get_size(const rs485_handle_t *p_handle) { return p_handle->rx_size; } + +/* ======================== HAL 回调(UART5 / RS-485 专属) ======================== */ + +/* + * 应用层接收钩子默认实现(弱符号,可被应用重定义)。 + * 在中断上下文调用,仅做占位,业务解析由应用提供。 + */ +__weak void rs485_on_rx(uint8_t *buf, uint16_t size) +{ + (void)buf; + (void)size; +} + +/* + * HAL UART 扩展接收回调(IDLE 空闲帧中断触发)。 + * 当 RS-485 总线空闲超过 1 个字符时间后触发,由 HAL 自动调用。 + * 注意:回调按实例分发,仅处理本驱动绑定的 UART,不写死 UART5。 + */ +void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) +{ + if (huart == g_rs485.huart) { + rs485_rx_set_size(&g_rs485, Size); + + /* 通知应用处理本次接收(中断上下文,应尽快返回) */ + rs485_on_rx(g_rs485.rx_buf, Size); + + /* 重新开启接收 */ + rs485_receive_start(&g_rs485); + } +} + +/* + * HAL UART 错误回调(ORE/NE/FE/PE 等)。 + * 读 SR + DR 清除错误标志后重新开启接收,避免中断锁死。 + */ +void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) +{ + if (huart == g_rs485.huart) { + /* STM32F4 通过读 SR + DR 清除 ORE/NE/FE/PE 错误标志 */ + (void)huart->Instance->SR; + (void)huart->Instance->DR; + /* 重新开启接收 */ + rs485_receive_start(&g_rs485); + } +} diff --git a/Drivers/BSP/RS485/rs485.h b/Drivers/BSP/RS485/rs485.h index 4a1f0996..18964d5c 100644 --- a/Drivers/BSP/RS485/rs485.h +++ b/Drivers/BSP/RS485/rs485.h @@ -24,6 +24,7 @@ extern "C" { * 常量定义 */ #define RS485_TIMEOUT_DEFAULT 1000U /* 默认发送超时(ms) */ +#define RS485_RX_BUF_SIZE 256U /* 接收缓冲区大小 */ /* * RS-485 句柄结构体 @@ -34,6 +35,7 @@ typedef struct { GPIO_TypeDef *dir_port; /* 方向控制 GPIO 端口 */ uint16_t dir_pin; /* 方向控制 GPIO 引脚号 */ volatile uint16_t rx_size; /* 最近一次接收的字节数 */ + uint8_t rx_buf[RS485_RX_BUF_SIZE]; /* 接收缓冲区 */ } rs485_handle_t; /* @@ -48,7 +50,8 @@ typedef struct { * dir_pin - 方向控制 GPIO 引脚号(如 GPIO_PIN_0) * 返回值:无 * 限定条件:UART 和 GPIO 须先由 CubeMX 完成初始化 - * 函数说明:初始化后默认处于接收状态(DE 引脚拉低) + * 函数说明:初始化后默认处于接收状态(DE 引脚拉低),并自动启动 IDLE + * 中断接收,无需再手动调用 rs485_receive_start。 */ void rs485_init(rs485_handle_t *p_handle, UART_HandleTypeDef *p_huart, @@ -73,18 +76,16 @@ HAL_StatusTypeDef rs485_transmit(rs485_handle_t *p_handle, /* * 函数功能:启动中断方式接收(IDLE 空闲帧检测) - * 入口参数:handle - RS-485 句柄指针 - * buf - 接收缓冲区 - * buf_size - 缓冲区大小 + * 入口参数:handle - RS-485 句柄指针 * 返回值:HAL_OK / HAL_ERROR * 限定条件:UART 须已开启全局中断,NVIC 中须使能对应 UART 中断 * 函数说明:使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收, - * 收到完整帧后在 RxEventCallback 中通知用户。 - * 用户须在回调中重新调用本函数重新开启接收 + * 接收缓冲固定使用句柄内部的 rx_buf(RS485_RX_BUF_SIZE)。 + * 当 UART 总线空闲超过 1 个字符时间后硬件触发 IDLE 中断, + * HAL 自动调用 HAL_UARTEx_RxEventCallback 并返回已接收字节数。 + * 用户须在回调中重新调用本函数重新开启接收。 */ -HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *p_handle, - uint8_t *p_buf, - uint16_t buf_size); +HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *p_handle); /* * 函数功能:将 RS-485 句柄与 HAL 回调关联 @@ -103,6 +104,21 @@ void rs485_rx_set_size(rs485_handle_t *p_handle, uint16_t size); */ uint16_t rs485_rx_get_size(const rs485_handle_t *p_handle); +/* + * 全局 RS-485 实例(由 rs485.c 定义,应用层通过 extern 引用)。 + * 接收缓冲已内聚到 rs485_handle_t 的 rx_buf 字段,随实例统一管理。 + */ +extern rs485_handle_t g_rs485; + +/* + * 应用层接收钩子:RS-485 收到完整帧(IDLE 空闲帧)后由驱动回调调用, + * 传入本次接收缓冲区与有效字节数。默认弱实现为空,应用可重定义此函数 + * 处理业务数据。 + * 注意:此函数在 UART 中断上下文执行,应尽快拷贝数据后返回,不要在内部 + * 调用阻塞式 API(如 rs485_transmit 会切换 DE 并等待 TC)。 + */ +void rs485_on_rx(uint8_t *buf, uint16_t size); + #ifdef __cplusplus } #endif diff --git a/MDK-ARM/STM32F407-Demo.uvprojx b/MDK-ARM/STM32F407-Demo.uvprojx index ec454e3a..8c990ee5 100644 --- a/MDK-ARM/STM32F407-Demo.uvprojx +++ b/MDK-ARM/STM32F407-Demo.uvprojx @@ -2014,6 +2014,11 @@ 1 ..\test\ch395f_test_task.c + + test_config.c + 1 + ..\test\test_config.c + net_test_task.c 1 diff --git a/MDK-ARM/build_log.txt b/MDK-ARM/build_log.txt index c8e36657..88bb6005 100644 --- a/MDK-ARM/build_log.txt +++ b/MDK-ARM/build_log.txt @@ -1,76 +1,77 @@ *** Using Compiler 'V5.06 update 7 (build 960)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin' Rebuild target 'STM32F407-Demo' assembling startup_stm32f407xx.s... -compiling crc.c... compiling ringbuf.c... -compiling stm32f4xx_it.c... -compiling app_main.c... -compiling dma.c... +compiling crc.c... compiling stm32f4xx_hal_flash_ramfunc.c... -compiling i2c.c... -compiling sys_clock.c... -compiling stm32f4xx_hal_timebase_tim.c... -compiling stm32f4xx_hal_gpio.c... -compiling stm32f4xx_hal_dma_ex.c... -compiling stm32f4xx_hal_dma.c... compiling stm32f4xx_hal_flash_ex.c... -compiling stm32f4xx_hal_pwr.c... -compiling spi.c... +compiling i2c.c... +compiling app_main.c... +compiling stm32f4xx_hal_gpio.c... +compiling dma.c... +compiling stm32f4xx_hal_dma_ex.c... compiling stm32f4xx_hal_msp.c... -compiling stm32f4xx_hal_rcc.c... -compiling stm32f4xx_hal_flash.c... compiling gpio.c... -compiling usart.c... -compiling stm32f4xx_hal_tim_ex.c... -compiling net_task.c... -compiling freertos.c... +compiling spi.c... +compiling stm32f4xx_it.c... compiling stm32f4xx_hal_rcc_ex.c... +compiling stm32f4xx_hal_flash.c... +compiling usart.c... +compiling stm32f4xx_hal_timebase_tim.c... +compiling sys_clock.c... +compiling net_task.c... compiling rs485_task.c... -compiling main.c... -compiling adc_task.c... compiling time_sync.c... -compiling lftpd_string.c... -compiling croutine.c... +compiling adc_task.c... +compiling stm32f4xx_hal_rcc.c... +compiling main.c... +compiling freertos.c... +compiling stm32f4xx_hal_tim_ex.c... compiling stm32f4xx_hal_tim.c... -compiling list.c... +compiling lftpd_string.c... +compiling stm32f4xx_hal_dma.c... +compiling croutine.c... compiling event_groups.c... -compiling queue.c... -compiling stream_buffer.c... -compiling timers.c... -compiling tasks.c... -compiling heap_4.c... -compiling port.c... -compiling stm32f4xx_hal_pwr_ex.c... -compiling journal.c... -compiling map.c... -compiling ff.c... +compiling list.c... compiling stm32f4xx_hal.c... -compiling system_stm32f4xx.c... -compiling lftpd_io.c... -compiling stm32f4xx_hal_cortex.c... -compiling stm32f4xx_hal_i2c_ex.c... +compiling stm32f4xx_hal_pwr_ex.c... +compiling stream_buffer.c... +compiling queue.c... +compiling timers.c... compiling stm32f4xx_hal_exti.c... +compiling tasks.c... +compiling stm32f4xx_hal_pwr.c... +compiling stm32f4xx_hal_cortex.c... +compiling heap_4.c... +compiling map.c... +compiling journal.c... +compiling port.c... +compiling stm32f4xx_hal_i2c_ex.c... +compiling stm32f4xx_hal_i2c.c... +compiling ff.c... compiling rs485.c... -compiling tpafe5160.c... +compiling system_stm32f4xx.c... compiling sd2506.c... -compiling ch395f.c... -compiling nand_ftl.c... -compiling stm32f4xx_hal_spi.c... -compiling lftpd_inet.c... compiling gd5f2gq5ue.c... -compiling net_select.c... +compiling ch395f.c... +compiling stm32f4xx_hal_spi.c... +compiling lftpd_io.c... +compiling nand_ftl.c... compiling stm32f4xx_hal_uart.c... +compiling net_select.c... +compiling tpafe5160.c... +compiling lftpd_inet.c... compiling lftpd.c... compiling net_socket.c... -compiling stm32f4xx_hal_i2c.c... compiling cmsis_os2.c... compiling ch395f_test_task.c... -compiling net_test_task.c... compiling gd5f_test_task.c... -compiling storage_test_task.c... +compiling test_config.c... compiling sd2506_test_task.c... +compiling net_test_task.c... +compiling storage_test_task.c... linking... -Program Size: Code=64436 RO-data=3936 RW-data=420 ZI-data=51868 +Program Size: Code=59916 RO-data=2552 RW-data=412 ZI-data=51868 FromELF: creating hex file... ".\STM32F407-Demo\STM32F407-Demo.axf" - 0 Error(s), 0 Warning(s). -Build Time Elapsed: 00:00:14 +Build Time Elapsed: 00:00:16 diff --git a/STM32F407-Demo.ioc b/STM32F407-Demo.ioc index bebe7630..a1904de8 100644 --- a/STM32F407-Demo.ioc +++ b/STM32F407-Demo.ioc @@ -72,7 +72,7 @@ Dma.USART1_TX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphData FREERTOS.FootprintOK=true FREERTOS.IPParameters=Tasks01,configENABLE_FPU,FootprintOK,configTOTAL_HEAP_SIZE,Queues01 FREERTOS.Queues01=netMsgQueue,8,net_msg_t,0,Dynamic,NULL,NULL -FREERTOS.Tasks01=defaultTask,24,512,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL;netTask,24,1024,StartNetTask,Default,NULL,Dynamic,NULL,NULL;ftpTask,24,1024,StartFtpTask,As weak,NULL,Dynamic,NULL,NULL;ch395fTestTask,16,4096,StartCh395fTestTask,As weak,NULL,Dynamic,NULL,NULL +FREERTOS.Tasks01=defaultTask,24,512,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL;netTask,24,1024,StartNetTask,Default,NULL,Dynamic,NULL,NULL;ftpTask,24,1024,StartFtpTask,As weak,NULL,Dynamic,NULL,NULL;testTask,16,4096,start_test_task,As weak,NULL,Dynamic,NULL,NULL FREERTOS.configENABLE_FPU=1 FREERTOS.configTOTAL_HEAP_SIZE=30720 File.Version=6 diff --git a/Src/freertos.c b/Src/freertos.c index 516c6106..90a0d5db 100644 --- a/Src/freertos.c +++ b/Src/freertos.c @@ -84,10 +84,10 @@ const osThreadAttr_t ftpTask_attributes = { .stack_size = 1024 * 4, .priority = (osPriority_t) osPriorityNormal, }; -/* Definitions for ch395fTestTask */ -osThreadId_t ch395fTestTaskHandle; -const osThreadAttr_t ch395fTestTask_attributes = { - .name = "ch395fTestTask", +/* Definitions for testTask */ +osThreadId_t testTaskHandle; +const osThreadAttr_t testTask_attributes = { + .name = "testTask", .stack_size = 4096 * 4, .priority = (osPriority_t) osPriorityBelowNormal, }; @@ -105,7 +105,7 @@ const osMessageQueueAttr_t netMsgQueue_attributes = { void StartDefaultTask(void *argument); void StartNetTask(void *argument); void StartFtpTask(void *argument); -void StartCh395fTestTask(void *argument); +void start_test_task(void *argument); void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */ @@ -148,11 +148,9 @@ void MX_FREERTOS_Init(void) { /* creation of ftpTask */ ftpTaskHandle = osThreadNew(StartFtpTask, NULL, &ftpTask_attributes); - - - /* creation of ch395fTestTask */ - ch395fTestTaskHandle = osThreadNew(StartCh395fTestTask, NULL, &ch395fTestTask_attributes); + /* creation of testTask */ + testTaskHandle = osThreadNew(start_test_task, NULL, &testTask_attributes); /* USER CODE BEGIN RTOS_THREADS */ #ifdef ENABLE_NET_LAYER_TESTS @@ -243,22 +241,22 @@ __weak void StartFtpTask(void *argument) /* USER CODE END StartFtpTask */ } -/* USER CODE BEGIN Header_StartCh395fTestTask */ +/* USER CODE BEGIN Header_start_test_task */ /** -* @brief Function implementing the ch395fTestTask thread. +* @brief Function implementing the testTask thread. * @param argument: Not used * @retval None */ -/* USER CODE END Header_StartCh395fTestTask */ -__weak void StartCh395fTestTask(void *argument) +/* USER CODE END Header_start_test_task */ +__weak void start_test_task(void *argument) { - /* USER CODE BEGIN StartCh395fTestTask */ + /* USER CODE BEGIN start_test_task */ /* Infinite loop */ for(;;) { osDelay(1); } - /* USER CODE END StartCh395fTestTask */ + /* USER CODE END start_test_task */ } /* Private application code --------------------------------------------------*/ diff --git a/Src/main.c b/Src/main.c index 7e40511f..033fcf51 100644 --- a/Src/main.c +++ b/Src/main.c @@ -59,10 +59,7 @@ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ -/* RS-485 通信实例(UART5: PC12=TX, PD2=RX, PD0=DE) */ -rs485_handle_t g_rs485; -#define RS485_RX_BUF_SIZE 256 -uint8_t g_rs485_rx_buf[RS485_RX_BUF_SIZE]; +/* RS-485 实例与接收缓冲已收归 rs485.c(见 rs485.h 的 extern 导出) */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ @@ -117,71 +114,8 @@ int main(void) /* USER CODE BEGIN 2 */ HAL_Delay(100); - /* - * 时间子系统初始化(尽早完成,后续所有日志带时间戳) - * sd2506_init() 从 RTC 读取初始时间 - * sys_clock_init() 将 RTC 时间转为 Unix epoch,建立墙钟基准 - */ + /* 应用层初始化(时间子系统优先,详见 app_main_init) */ app_main_init(); - sd2506_init(); - sys_clock_init(); - - /* RS-485 初始化(UART5 + PD0 方向控制) */ - rs485_init(&g_rs485, &huart5, ST_DIR4_GPIO_Port, ST_DIR4_Pin); - DBG_INFO("RS485 init: OK (UART5, DE=PD0)"); - - /* 启动第一次 RS-485 接收 */ - rs485_receive_start(&g_rs485, g_rs485_rx_buf, RS485_RX_BUF_SIZE); - - /* GD5F 初始化测试 */ - int ret = gd5f2gq5ue_init(); - DBG_INFO("NAND init: %s", - (ret == GD5F_OK) ? "OK" : - (ret == GD5F_ERROR) ? "ERROR" : - (ret == GD5F_BUSY_TIMEOUT) ? "BUSY TIMEOUT" : - (ret == GD5F_ECC_ERROR) ? "ECC ERROR" : - (ret == GD5F_PROGRAM_FAIL) ? "PROGRAM FAIL" : - (ret == GD5F_ERASE_FAIL) ? "ERASE FAIL" : - (ret == GD5F_ID_MISMATCH) ? "ID MISMATCH" : "UNKNOWN"); - - /* TPAFE5160 ADC 测试 */ - int tp_ret = tpafe5160_init(); - DBG_INFO("ADC init: %s", - (tp_ret == TPAFE5160_OK) ? "OK" : "TIMEOUT"); - - /* SD2506 RTC 诊断信息 */ - { - /* 读取 ID */ - uint8_t sd_id[8]; - sd2506_get_id(sd_id); - DBG_INFO("SD2506 ID: %02X%02X%02X%02X%02X%02X%02X%02X", - sd_id[0], sd_id[1], sd_id[2], sd_id[3], - sd_id[4], sd_id[5], sd_id[6], sd_id[7]); - - /* 读取当前时间 */ - sd2506_time_t sd_time; - sd2506_get_time(&sd_time); - DBG_INFO("SD2506 time: %04d-%02d-%02d %02d:%02d:%02d (week %d)", - sd_time.year, sd_time.month, sd_time.day, - sd_time.hour, sd_time.minute, sd_time.second, - sd_time.week); - - /* 读取温度 */ - int8_t sd_temp; - sd2506_get_temperature(&sd_temp); - DBG_INFO("SD2506 temp: %d C", sd_temp); - - /* 读取电池电压 */ - uint16_t sd_vbat; - sd2506_get_battery_voltage(&sd_vbat); - DBG_INFO("SD2506 battery: %d.%02d V", - sd_vbat / 1000, (sd_vbat % 1000) / 10); - } - - /* 启动第一次转换(CubeMX 已配置 BUSY EXTI 中断) */ - tpafe5160_start_conv_irq(); - - /* CH395F 测试已全部移至 ch395fTestTask */ /* USER CODE END 2 */ /* Init scheduler */ @@ -252,37 +186,10 @@ void SystemClock_Config(void) /* USER CODE BEGIN 4 */ /* - * HAL UART 扩展接收回调(IDLE 空闲帧中断触发) - * 当 RS-485 总线空闲超过 1 个字符时间后触发 + * RS-485 的 HAL UART 回调(HAL_UARTEx_RxEventCallback / HAL_UART_ErrorCallback) + * 已收归 rs485.c 实现,本文件不再定义它们。如需处理接收到的 RS-485 数据, + * 请重定义 rs485.h 中的弱钩子 rs485_on_rx(uint8_t *buf, uint16_t size)。 */ -void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) -{ - if (huart->Instance == UART5) { - rs485_rx_set_size(&g_rs485, Size); - - /* TODO: 在此处处理接收到的 RS-485 数据 - * g_rs485_rx_buf[0 .. Size-1] 为有效数据 - * 例如:rs485_transmit(&g_rs485, g_rs485_rx_buf, Size, 0); - */ - - /* 重新开启接收 */ - rs485_receive_start(&g_rs485, g_rs485_rx_buf, RS485_RX_BUF_SIZE); - } -} - -/* - * HAL UART 错误回调 - */ -void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) -{ - if (huart->Instance == UART5) { - /* STM32F4 通过读 SR + DR 清除 ORE/NE/FE/PE 错误标志 */ - (void)huart->Instance->SR; - (void)huart->Instance->DR; - /* 重新开启接收 */ - rs485_receive_start(&g_rs485, g_rs485_rx_buf, RS485_RX_BUF_SIZE); - } -} /* USER CODE END 4 */ /** diff --git a/rx_100k.bin b/rx_100k.bin deleted file mode 100644 index db15ba9928a4e1345de7b1a4ab7a23a3d6794720..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102400 zcmeI*g}Rhg7zWUpQ>1i*w6wI8N+T)V-Q6IHNOwu6(%qfXpmaCVU1B1joO8Gjo^=WH z%*_Aq{l&Wi!I03f@Q4^OW5tdW_k(!x6C_NOI7!lE$y20El{(FbY15_8kTFx{kFsRV zmOV$#Tp#DolQ&=f0tG)QRJcgdVxNBYdGQh@OO-BDw%ixxD^#phxyqMSt5vU2vsUdo zb?en{(6CYCCQX|)Z_%<<>o#rMweQfeQ|B&SyLIo;vsdr0`h5LO-*5YU*MGpkL4$`3 z9X5Q#$Wf!mj2$=r`w0^#O`bA!+VmMSXU+cM$2oK7&0nx^(c&dbmn~nha@FcJYuByc zuyNDoEnBy3-?8(jUAy<}-M9b1!9zd)a`?#6W5-XNJazia*>mSFT)cGo%GGPXUcYhk z*6llY@7;g!@X_NZPoF*i?ZxkZ{Q1}4|GfP7)$2F^{r@&HDmviv`~Lm@{r^4xJpaA_ zy#Jklod2AEo&Vi`-2dEv-T&1;)PK~!)c@2!)qmB$)&KQB^ndif^#Alf^?&uh_5aO3 znEx>UV*bbclld?6Z|48ZKbrqE|7!l%{ImIQ^Y7;W?LXN6u>WHJ$NrQ3FZ*xy|Li~7 z|Fr*V|JVMr{crp4_W$J{$bXQ3A^$`EiToG&H}ZevAIX1`ek&VT2>^WXXJ{CEC4|DFHNf9JpR-}&$Scm6y7o&U~%=fCsc`S1L9 z{yYDj|IUBszw_Vu@BDZEJO7>k&VT2>^WXXJ{CEC4|DFHNf9JpR-}&$Scm6y7o&U~% z=fCsc`S1L9{yYDj|IUBszw_Vu@BDZEJO7>k&VT2>^WXXJ{CEC4|DFHNf9JpR-}&$S zcm6y7o&U~%=fCsc`S1L9{yYDj|IUBszw_Vu@BDZEJO7>k&VT2>^WXXJ{CEC4|DFHN zf9JpR-}&$Scm6y7o&U~%j}8PwLc{p){CEC4|DFHNf9JpR-}&$Scm6y7o&U~%=fCsc z`S1L9{yYDj|IUBszw_Vu@BDZEJO7>k&VT2>^WXXJ{CEC4|DFHNf9JpR-}&$Scm6y7 zo&U~%=fCsc`S1L9{yYDj|IUBszw_Vu@BDZEJO7>k&VT2>^WXXJ{CEC4|DFHNf9JpR z-}&$Scm6y7o&U~%=fCsc`S1L9{yYDj|IUBszw_Vu@BDZEJO7>k&VT2>^WXXJ{CEC4 z|DFHNf9JpR-}&$Scm6y7o&U~%=fCsc`S1L9{yYDj|IUBszw_Vu@BDZEJO7>k&VLVv sgocGj@Zb6G{CEC4|DFHNf9JpR-}&$Scm6y7o&U~%=fCsc-&6nn9V+8PssI20 diff --git a/test/ch395f_test.h b/test/ch395f_test.h index e1b789f8..90194433 100644 --- a/test/ch395f_test.h +++ b/test/ch395f_test.h @@ -38,8 +38,8 @@ extern "C" { * 阶段使能开关(取消注释即启用对应阶段) * * 构建模式互斥(详见 docs/CH395F_Test_Guide.md「构建模式与执行顺序」): - * 硬件层模式(阶段 1~5):netTask 不创建,ch395fTestTask 独占 CH395F - * NET 层模式 (阶段 6~11):完整网络栈,netTask 轮询 + ch395fTestTask 监听循环 + * 硬件层模式(阶段 1~5):netTask 不创建,testTask 独占 CH395F + * NET 层模式 (阶段 6~11):完整网络栈,netTask 轮询 + testTask 监听循环 * * 注意:同层内可多选(Phase 6~10 共享 testTask 循环); * Phase 4 (DHCP) 会改变 IP,必须独立运行; diff --git a/test/ch395f_test_task.c b/test/ch395f_test_task.c index 46e84203..212f0d20 100644 --- a/test/ch395f_test_task.c +++ b/test/ch395f_test_task.c @@ -1345,13 +1345,12 @@ static void phase5_run(void) { TEST_REPORT("Phase 5"); } #endif -void StartCh395fTestTask(void *argument) +/* + * CH395F 测试套件入口(由 test_config.c 的 start_test_task 统一调度)。 + * 此处只负责 CH395F 自身的硬件层 / NET 层逻辑,套件选择已上移到 test_config.c。 + */ +void ch395f_test_run(void) { - (void)argument; - - DBG_INFO("Test task started, suite=%s", TEST_SUITE_NAME); - -#if defined(TEST_SUITE_CH395F) #if defined(ENABLE_HW_LAYER_TESTS) /* 硬件层模式(阶段 1~5):netTask 未创建,由本任务完成一次性协议栈 * 初始化并独占 CH395F —— 无 net_poll() 并发读取中断,无 SPI 并发事务 */ @@ -1391,16 +1390,5 @@ void StartCh395fTestTask(void *argument) #else net_layer_test_main(); #endif -#endif /* TEST_SUITE_CH395F */ -#elif defined(TEST_SUITE_STORAGE) - storage_test_run(); -#elif defined(TEST_SUITE_GD5F) - gd5f_test_run(); -#elif defined(TEST_SUITE_RTC) - sd2506_test_run(); #endif - - for (;;) { - osDelay(1000); - } } diff --git a/test/ch395f_test_task.h b/test/ch395f_test_task.h index 66bf1669..aa839584 100644 --- a/test/ch395f_test_task.h +++ b/test/ch395f_test_task.h @@ -5,7 +5,8 @@ extern "C" { #endif -void StartCh395fTestTask(void *argument); +void start_test_task(void *argument); +void ch395f_test_run(void); #ifdef __cplusplus } diff --git a/test/net_test_task.c b/test/net_test_task.c index 3017277b..43e8257c 100644 --- a/test/net_test_task.c +++ b/test/net_test_task.c @@ -1,6 +1,6 @@ /***************************************************************************** * 模块名称:CH395F NET 层测试(Phase 6~11) - * 模块功能:基于 BSD Socket API(单连接模式)的 NET 层测试,由 ch395fTestTask + * 模块功能:基于 BSD Socket API(单连接模式)的 NET 层测试,由 testTask * 任务内的 net_layer_test_main() / net_layer_client_test_main() 事件 * 循环驱动,需 PC 配合。 * 包含 Phase 6(TCP Echo) / 7(TCP Client) / 8(大文件) / 9(Select) / diff --git a/test/net_test_task.h b/test/net_test_task.h index f5ed5c95..6a583a2a 100644 --- a/test/net_test_task.h +++ b/test/net_test_task.h @@ -6,7 +6,7 @@ extern "C" { #endif /* NET 层测试事件循环入口(定义于 net_test_task.c)。 - * 由 ch395fTestTask 在 NET 层构建模式下调用,内部创建单连接 TCP 监听 + * 由 testTask 在 NET 层构建模式下调用,内部创建单连接 TCP 监听 * 并驱动 Phase 6/8~11 依次执行,连接断开后自动重新 listen。 */ void net_layer_test_main(void); diff --git a/test/sd2506_test.h b/test/sd2506_test.h index 153084af..9c494d0d 100644 --- a/test/sd2506_test.h +++ b/test/sd2506_test.h @@ -37,7 +37,7 @@ extern sd2506_test_stats_t g_sd2506_test_stats; g_sd2506_test_stats.failed); \ } while (0) -/* 测试入口:由 StartCh395fTestTask 经 TEST_SUITE_RTC 调度,顺序执行 Phase 1~3 */ +/* 测试入口:由 start_test_task 经 TEST_SUITE_RTC 调度,顺序执行 Phase 1~3 */ void sd2506_test_run(void); #ifdef __cplusplus diff --git a/test/sd2506_test_task.c b/test/sd2506_test_task.c index 4212ab4e..583d5d1c 100644 --- a/test/sd2506_test_task.c +++ b/test/sd2506_test_task.c @@ -10,7 +10,7 @@ * * 当前测试:Phase 1 基本读写(init / 读 / 写 / 回读一致 / 走时), * 结束后自动恢复板子原始时间。 - * 入口:sd2506_test_run()(由 StartCh395fTestTask 经 TEST_SUITE_RTC 调度) + * 入口:sd2506_test_run()(由 start_test_task 经 TEST_SUITE_RTC 调度) * 创建日期:2026-08-28 ******************************************************************************/ diff --git a/test/storage_test.h b/test/storage_test.h index e0d6b94d..e501960c 100644 --- a/test/storage_test.h +++ b/test/storage_test.h @@ -1,7 +1,7 @@ /* * 模块名称:Storage Test Suite * 模块功能:FTL + FatFS 存储测试的声明与断言宏。实现见 storage_test_task.c, - * 统一由 ch395fTestTask 调度;正常产品构建下由 defaultTask 调用, + * 统一由 testTask 调度;正常产品构建下由 defaultTask 调用, * 行为与原 defaultTask 内联逻辑一致。 * 适用平台:STM32F4 系列 * 作者:王建锋 diff --git a/test/storage_test_task.c b/test/storage_test_task.c index 373a79cf..468e55a9 100644 --- a/test/storage_test_task.c +++ b/test/storage_test_task.c @@ -1,6 +1,6 @@ /****************************************************************************** * 模块名称:Storage Test Task - * 模块功能:FTL + FatFS 存储测试,从 defaultTask 迁入,统一由 ch395fTestTask + * 模块功能:FTL + FatFS 存储测试,从 defaultTask 迁入,统一由 testTask * 调度运行。正常产品构建下由 defaultTask 调用,行为与原内联逻辑一致。 * 作者:王建锋 * 创建日期:2026-08-26 diff --git a/test/test_config.c b/test/test_config.c new file mode 100644 index 00000000..8adad1ee --- /dev/null +++ b/test/test_config.c @@ -0,0 +1,50 @@ +/****************************************************************************** + * 模块名称:统一测试任务调度器(Test Config) + * 模块功能:所有测试任务的唯一入口。FreeRTOS 的 testTask 仅调用本文件 + * 的 start_test_task(),由本文件根据 test_config.h 中启用的 + * TEST_SUITE_* 宏,将测试分发到对应套件的运行函数。 + * + * 各套件运行函数(ch395f_test_run / storage_test_run / gd5f_test_run + * / sd2506_test_run)各自实现具体测试逻辑,本文件只负责"选哪个跑", + * 不掺杂任何具体测试细节,使测试入口界限清晰、易于维护。 + * 作者:王建锋 + * 创建日期:2026-08-29 + ******************************************************************************/ + +#define DBG_TAG "[TEST_CFG]" +#include "cmsis_os.h" +#include "dbg_log.h" + +#include "test_config.h" + +#include "ch395f_test_task.h" +#include "storage_test.h" +#include "gd5f_test.h" +#include "sd2506_test.h" + +/* + * 测试任务统一入口(FreeRTOS start_test_task 线程函数)。 + * 根据编译期选中的 TEST_SUITE_* 调度对应套件,其余时间挂起。 + */ +void start_test_task(void *argument) +{ + (void)argument; + + DBG_INFO("Test task started, suite=%s", TEST_SUITE_NAME); + +#if defined(TEST_SUITE_CH395F) + ch395f_test_run(); +#elif defined(TEST_SUITE_STORAGE) + storage_test_run(); +#elif defined(TEST_SUITE_GD5F) + gd5f_test_run(); +#elif defined(TEST_SUITE_RTC) + sd2506_test_run(); +#else + DBG_INFO("No test suite selected (normal product build)"); +#endif + + for (;;) { + osDelay(1000); + } +} diff --git a/test/test_config.h b/test/test_config.h index f16839e7..8bc5f89d 100644 --- a/test/test_config.h +++ b/test/test_config.h @@ -1,7 +1,7 @@ /* * 模块名称:统一测试套件选择 * 模块功能:集中选择当前构建要运行的测试套件。所有测试统一由 - * ch395fTestTask(StartCh395fTestTask)调度,defaultTask 在测试 + * testTask(start_test_task)调度,defaultTask 在测试 * 构建下空闲,正常产品构建下仅运行存储挂载/测试。 * 适用平台:STM32F4 系列 * 作者:王建锋