整理了main 函数

This commit is contained in:
2026-08-29 09:45:54 +08:00
parent 9c990ead43
commit 7bc616cf9b
22 changed files with 311 additions and 235 deletions
+80 -1
View File
@@ -6,23 +6,102 @@
* 创建日期:2026-07-19 * 创建日期:2026-07-19
* 修改记录: * 修改记录:
* v1.0 2026-07-19 王建锋 创建初始版本 * v1.0 2026-07-19 王建锋 创建初始版本
* v1.1 2026-08-29 王建锋 将原 main.c 中各外设初始化统一收归 app_main_init,
* 并按"时间子系统优先"的顺序编排启动流程
*/ */
#include "app_main.h" #include "app_main.h"
#include "app_cfg.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]" #define DBG_TAG "[APP]"
#include "dbg_log.h" #include "dbg_log.h"
/* g_rs485 由 rs485.c 定义,经 rs485.h 的 extern 引用;接收缓冲内聚于句柄 rx_buf */
/* /*
* 函数功能:应用层初始化 * 函数功能:应用层初始化
* 入口参数:无 * 入口参数:无
* 返 回 值:0 - 成功,-1 - 失败 * 返 回 值:0 - 成功,-1 - 失败
* 限定条件:CubeMX 外设初始化已完成 * 限定条件: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) 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"); DBG_INFO("App init OK");
return 0; return 0;
} }
+2 -2
View File
@@ -31,7 +31,7 @@ volatile uint8_t g_net_ready = 0;
* 返 回 值:0 - 成功,-1 - 失败 * 返 回 值:0 - 成功,-1 - 失败
* 函数说明:net_init → MAC 打印 → PHY 强制 100M 全双工 → 置 g_net_ready。 * 函数说明:net_init → MAC 打印 → PHY 强制 100M 全双工 → 置 g_net_ready。
* NET 层模式由 netTask 调用;硬件层模式(阶段 1~5)netTask 不创建, * NET 层模式由 netTask 调用;硬件层模式(阶段 1~5)netTask 不创建,
* 由 ch395fTestTask 调用后独占 CH395F。 * 由 testTask 调用后独占 CH395F。
*/ */
int net_stack_bring_up(void) int net_stack_bring_up(void)
{ {
@@ -89,7 +89,7 @@ int net_task_init(void)
* 函数说明:启动后先调用 net_stack_bring_up() 初始化 CH395F 协议栈, * 函数说明:启动后先调用 net_stack_bring_up() 初始化 CH395F 协议栈,
* 再进入轮询循环处理网络事件。 * 再进入轮询循环处理网络事件。
* 仅 NET 层测试模式(阶段 6~10)会创建本任务; * 仅 NET 层测试模式(阶段 6~10)会创建本任务;
* 硬件层模式下 netTask 不创建,CH395F 由 ch395fTestTask 独占。 * 硬件层模式下 netTask 不创建,CH395F 由 testTask 独占。
*/ */
void net_task_func(void const *arg) void net_task_func(void const *arg)
{ {
+1 -1
View File
@@ -18,7 +18,7 @@ extern "C" {
/* CH395F 协议栈一次性初始化(net_init + MAC 打印 + PHY 配置 + g_net_ready 置位)。 /* CH395F 协议栈一次性初始化(net_init + MAC 打印 + PHY 配置 + g_net_ready 置位)。
* 返回 0 成功 / -1 失败。NET 层模式由 netTask 调用;硬件层模式(阶段 1~5) * 返回 0 成功 / -1 失败。NET 层模式由 netTask 调用;硬件层模式(阶段 1~5)
* netTask 不创建,由 ch395fTestTask 调用后独占 CH395F。 */ * netTask 不创建,由 testTask 调用后独占 CH395F。 */
int net_stack_bring_up(void); int net_stack_bring_up(void);
int net_task_init(void); int net_task_init(void);
+64 -33
View File
@@ -14,27 +14,10 @@
#include "rs485.h" #include "rs485.h"
/* ======================== 内部辅助函数 ======================== */ /* ======================== 全局实例 ======================== */
/* /* RS-485 全局实例(接收缓冲内聚于句柄的 rx_buf 字段) */
* 函数功能:DWT 微秒级延时 rs485_handle_t g_rs485;
* 入口参数: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) { ; }
}
/* ======================== 方向控制宏 ======================== */ /* ======================== 方向控制宏 ======================== */
@@ -51,7 +34,8 @@ static void delay_us(uint32_t us)
* dir_pin - 方向控制 GPIO 引脚号(如 GPIO_PIN_0) uint16_t * dir_pin - 方向控制 GPIO 引脚号(如 GPIO_PIN_0) uint16_t
* 返回值:无 * 返回值:无
* 限定条件:UART 和 GPIO 须先由 CubeMX 完成初始化 * 限定条件:UART 和 GPIO 须先由 CubeMX 完成初始化
* 函数说明:初始化后默认处于接收状态(DE 引脚拉低) * 函数说明:初始化后默认处于接收状态(DE 引脚拉低),
* 并自动启动 IDLE 中断接收,无需再手动调用 rs485_receive_start。
*/ */
void rs485_init(rs485_handle_t *p_handle, void rs485_init(rs485_handle_t *p_handle,
UART_HandleTypeDef *p_huart, UART_HandleTypeDef *p_huart,
@@ -64,6 +48,9 @@ void rs485_init(rs485_handle_t *p_handle,
p_handle->rx_size = 0; p_handle->rx_size = 0;
RS485_DIR_RX(p_handle); 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_TIMEOUT - 发送超时
* HAL_ERROR - 发送错误 * HAL_ERROR - 发送错误
* 限定条件:须在主循环或 FreeRTOS 任务中调用,不可在 UART 中断中调用 * 限定条件:须在主循环或 FreeRTOS 任务中调用,不可在 UART 中断中调用
* 函数说明:发送前拉高 DE,等待 50us 确保 RS485 收发器驱动使能稳定后再启动 UART 发送。 * 函数说明:发送前拉高 DE,等待 HAL 时基延时确保 RS485 收发器驱动使能稳定后再启动
* UART 发送(HAL 时基最小粒度 1ms,此处延时 1ms,远大于 50us 的 DE 建立时间)。
* HAL_UART_Transmit 内部等待 TC(发送完成)标志,确保最后一字节完全移出后 * HAL_UART_Transmit 内部等待 TC(发送完成)标志,确保最后一字节完全移出后
* 再拉低 DE 切回接收状态。 * 再拉低 DE 切回接收状态。
*/ */
HAL_StatusTypeDef rs485_transmit(rs485_handle_t *p_handle, HAL_StatusTypeDef rs485_transmit(rs485_handle_t *p_handle,
const uint8_t *p_data, const uint8_t *p_data,
uint16_t len, uint16_t len,
uint32_t timeout) uint32_t timeout)
{ {
HAL_StatusTypeDef status = HAL_OK; HAL_StatusTypeDef status = HAL_OK;
@@ -93,7 +81,8 @@ HAL_StatusTypeDef rs485_transmit(rs485_handle_t *p_handle,
RS485_DIR_TX(p_handle); RS485_DIR_TX(p_handle);
delay_us(50); /* DE 建立延时:HAL 时基为 1ms 粒度,1ms 已充分覆盖收发器驱动使能稳定时间 */
HAL_Delay(1);
status = HAL_UART_Transmit(p_handle->huart, status = HAL_UART_Transmit(p_handle->huart,
(uint8_t *)p_data, (uint8_t *)p_data,
@@ -108,22 +97,19 @@ HAL_StatusTypeDef rs485_transmit(rs485_handle_t *p_handle,
/* /*
* 函数功能:启动中断方式接收(IDLE 空闲帧检测) * 函数功能:启动中断方式接收(IDLE 空闲帧检测)
* 入口参数:p_handle - RS-485 句柄指针 rs485_handle_t*(非空) * 入口参数:p_handle - RS-485 句柄指针 rs485_handle_t*(非空)
* p_buf - 接收缓冲区 uint8_t*(非空)
* buf_size - 缓冲区大小 uint16_t
* 返回值:HAL_OK - 启动成功 HAL_StatusTypeDef * 返回值:HAL_OK - 启动成功 HAL_StatusTypeDef
* HAL_ERROR - 启动失败 * HAL_ERROR - 启动失败
* 限定条件:UART 须已开启全局中断(NVIC 使能) * 限定条件:UART 须已开启全局中断(NVIC 使能)
* 函数说明:使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收。 * 函数说明:使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收,
* 接收缓冲固定使用句柄内部的 rx_buf(RS485_RX_BUF_SIZE)。
* 当 UART 总线空闲超过 1 个字符时间后硬件触发 IDLE 中断, * 当 UART 总线空闲超过 1 个字符时间后硬件触发 IDLE 中断,
* HAL 自动调用 HAL_UARTEx_RxEventCallback 并返回已接收字节数。 * HAL 自动调用 HAL_UARTEx_RxEventCallback 并返回已接收字节数。
* 用户须在回调中重新调用本函数重新开启接收。 * 用户须在回调中重新调用本函数重新开启接收。
*/ */
HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *p_handle, HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *p_handle)
uint8_t *p_buf,
uint16_t buf_size)
{ {
p_handle->rx_size = 0; 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; 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);
}
}
+25 -9
View File
@@ -24,6 +24,7 @@ extern "C" {
* 常量定义 * 常量定义
*/ */
#define RS485_TIMEOUT_DEFAULT 1000U /* 默认发送超时(ms) */ #define RS485_TIMEOUT_DEFAULT 1000U /* 默认发送超时(ms) */
#define RS485_RX_BUF_SIZE 256U /* 接收缓冲区大小 */
/* /*
* RS-485 句柄结构体 * RS-485 句柄结构体
@@ -34,6 +35,7 @@ typedef struct {
GPIO_TypeDef *dir_port; /* 方向控制 GPIO 端口 */ GPIO_TypeDef *dir_port; /* 方向控制 GPIO 端口 */
uint16_t dir_pin; /* 方向控制 GPIO 引脚号 */ uint16_t dir_pin; /* 方向控制 GPIO 引脚号 */
volatile uint16_t rx_size; /* 最近一次接收的字节数 */ volatile uint16_t rx_size; /* 最近一次接收的字节数 */
uint8_t rx_buf[RS485_RX_BUF_SIZE]; /* 接收缓冲区 */
} rs485_handle_t; } rs485_handle_t;
/* /*
@@ -48,7 +50,8 @@ typedef struct {
* dir_pin - 方向控制 GPIO 引脚号(如 GPIO_PIN_0) * dir_pin - 方向控制 GPIO 引脚号(如 GPIO_PIN_0)
* 返回值:无 * 返回值:无
* 限定条件:UART 和 GPIO 须先由 CubeMX 完成初始化 * 限定条件:UART 和 GPIO 须先由 CubeMX 完成初始化
* 函数说明:初始化后默认处于接收状态(DE 引脚拉低) * 函数说明:初始化后默认处于接收状态(DE 引脚拉低),并自动启动 IDLE
* 中断接收,无需再手动调用 rs485_receive_start。
*/ */
void rs485_init(rs485_handle_t *p_handle, void rs485_init(rs485_handle_t *p_handle,
UART_HandleTypeDef *p_huart, UART_HandleTypeDef *p_huart,
@@ -73,18 +76,16 @@ HAL_StatusTypeDef rs485_transmit(rs485_handle_t *p_handle,
/* /*
* 函数功能:启动中断方式接收(IDLE 空闲帧检测) * 函数功能:启动中断方式接收(IDLE 空闲帧检测)
* 入口参数:handle - RS-485 句柄指针 * 入口参数:handle - RS-485 句柄指针
* buf - 接收缓冲区
* buf_size - 缓冲区大小
* 返回值:HAL_OK / HAL_ERROR * 返回值:HAL_OK / HAL_ERROR
* 限定条件:UART 须已开启全局中断,NVIC 中须使能对应 UART 中断 * 限定条件:UART 须已开启全局中断,NVIC 中须使能对应 UART 中断
* 函数说明:使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收, * 函数说明:使用 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, HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *p_handle);
uint8_t *p_buf,
uint16_t buf_size);
/* /*
* 函数功能:将 RS-485 句柄与 HAL 回调关联 * 函数功能:将 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); 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 #ifdef __cplusplus
} }
#endif #endif
+5
View File
@@ -2014,6 +2014,11 @@
<FileType>1</FileType> <FileType>1</FileType>
<FilePath>..\test\ch395f_test_task.c</FilePath> <FilePath>..\test\ch395f_test_task.c</FilePath>
</File> </File>
<File>
<FileName>test_config.c</FileName>
<FileType>1</FileType>
<FilePath>..\test\test_config.c</FilePath>
</File>
<File> <File>
<FileName>net_test_task.c</FileName> <FileName>net_test_task.c</FileName>
<FileType>1</FileType> <FileType>1</FileType>
+49 -48
View File
@@ -1,76 +1,77 @@
*** Using Compiler 'V5.06 update 7 (build 960)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin' *** Using Compiler 'V5.06 update 7 (build 960)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
Rebuild target 'STM32F407-Demo' Rebuild target 'STM32F407-Demo'
assembling startup_stm32f407xx.s... assembling startup_stm32f407xx.s...
compiling crc.c...
compiling ringbuf.c... compiling ringbuf.c...
compiling stm32f4xx_it.c... compiling crc.c...
compiling app_main.c...
compiling dma.c...
compiling stm32f4xx_hal_flash_ramfunc.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_flash_ex.c...
compiling stm32f4xx_hal_pwr.c... compiling i2c.c...
compiling spi.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_msp.c...
compiling stm32f4xx_hal_rcc.c...
compiling stm32f4xx_hal_flash.c...
compiling gpio.c... compiling gpio.c...
compiling usart.c... compiling spi.c...
compiling stm32f4xx_hal_tim_ex.c... compiling stm32f4xx_it.c...
compiling net_task.c...
compiling freertos.c...
compiling stm32f4xx_hal_rcc_ex.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 rs485_task.c...
compiling main.c...
compiling adc_task.c...
compiling time_sync.c... compiling time_sync.c...
compiling lftpd_string.c... compiling adc_task.c...
compiling croutine.c... compiling stm32f4xx_hal_rcc.c...
compiling main.c...
compiling freertos.c...
compiling stm32f4xx_hal_tim_ex.c...
compiling stm32f4xx_hal_tim.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 event_groups.c...
compiling queue.c... compiling list.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 stm32f4xx_hal.c... compiling stm32f4xx_hal.c...
compiling system_stm32f4xx.c... compiling stm32f4xx_hal_pwr_ex.c...
compiling lftpd_io.c... compiling stream_buffer.c...
compiling stm32f4xx_hal_cortex.c... compiling queue.c...
compiling stm32f4xx_hal_i2c_ex.c... compiling timers.c...
compiling stm32f4xx_hal_exti.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 rs485.c...
compiling tpafe5160.c... compiling system_stm32f4xx.c...
compiling sd2506.c... compiling sd2506.c...
compiling ch395f.c...
compiling nand_ftl.c...
compiling stm32f4xx_hal_spi.c...
compiling lftpd_inet.c...
compiling gd5f2gq5ue.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 stm32f4xx_hal_uart.c...
compiling net_select.c...
compiling tpafe5160.c...
compiling lftpd_inet.c...
compiling lftpd.c... compiling lftpd.c...
compiling net_socket.c... compiling net_socket.c...
compiling stm32f4xx_hal_i2c.c...
compiling cmsis_os2.c... compiling cmsis_os2.c...
compiling ch395f_test_task.c... compiling ch395f_test_task.c...
compiling net_test_task.c...
compiling gd5f_test_task.c... compiling gd5f_test_task.c...
compiling storage_test_task.c... compiling test_config.c...
compiling sd2506_test_task.c... compiling sd2506_test_task.c...
compiling net_test_task.c...
compiling storage_test_task.c...
linking... 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... FromELF: creating hex file...
".\STM32F407-Demo\STM32F407-Demo.axf" - 0 Error(s), 0 Warning(s). ".\STM32F407-Demo\STM32F407-Demo.axf" - 0 Error(s), 0 Warning(s).
Build Time Elapsed: 00:00:14 Build Time Elapsed: 00:00:16
+1 -1
View File
@@ -72,7 +72,7 @@ Dma.USART1_TX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphData
FREERTOS.FootprintOK=true FREERTOS.FootprintOK=true
FREERTOS.IPParameters=Tasks01,configENABLE_FPU,FootprintOK,configTOTAL_HEAP_SIZE,Queues01 FREERTOS.IPParameters=Tasks01,configENABLE_FPU,FootprintOK,configTOTAL_HEAP_SIZE,Queues01
FREERTOS.Queues01=netMsgQueue,8,net_msg_t,0,Dynamic,NULL,NULL 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.configENABLE_FPU=1
FREERTOS.configTOTAL_HEAP_SIZE=30720 FREERTOS.configTOTAL_HEAP_SIZE=30720
File.Version=6 File.Version=6
+13 -15
View File
@@ -84,10 +84,10 @@ const osThreadAttr_t ftpTask_attributes = {
.stack_size = 1024 * 4, .stack_size = 1024 * 4,
.priority = (osPriority_t) osPriorityNormal, .priority = (osPriority_t) osPriorityNormal,
}; };
/* Definitions for ch395fTestTask */ /* Definitions for testTask */
osThreadId_t ch395fTestTaskHandle; osThreadId_t testTaskHandle;
const osThreadAttr_t ch395fTestTask_attributes = { const osThreadAttr_t testTask_attributes = {
.name = "ch395fTestTask", .name = "testTask",
.stack_size = 4096 * 4, .stack_size = 4096 * 4,
.priority = (osPriority_t) osPriorityBelowNormal, .priority = (osPriority_t) osPriorityBelowNormal,
}; };
@@ -105,7 +105,7 @@ const osMessageQueueAttr_t netMsgQueue_attributes = {
void StartDefaultTask(void *argument); void StartDefaultTask(void *argument);
void StartNetTask(void *argument); void StartNetTask(void *argument);
void StartFtpTask(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) */ void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
@@ -148,11 +148,9 @@ void MX_FREERTOS_Init(void) {
/* creation of ftpTask */ /* creation of ftpTask */
ftpTaskHandle = osThreadNew(StartFtpTask, NULL, &ftpTask_attributes); ftpTaskHandle = osThreadNew(StartFtpTask, NULL, &ftpTask_attributes);
/* creation of ch395fTestTask */ /* creation of testTask */
ch395fTestTaskHandle = osThreadNew(StartCh395fTestTask, NULL, &ch395fTestTask_attributes); testTaskHandle = osThreadNew(start_test_task, NULL, &testTask_attributes);
/* USER CODE BEGIN RTOS_THREADS */ /* USER CODE BEGIN RTOS_THREADS */
#ifdef ENABLE_NET_LAYER_TESTS #ifdef ENABLE_NET_LAYER_TESTS
@@ -243,22 +241,22 @@ __weak void StartFtpTask(void *argument)
/* USER CODE END StartFtpTask */ /* 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 * @param argument: Not used
* @retval None * @retval None
*/ */
/* USER CODE END Header_StartCh395fTestTask */ /* USER CODE END Header_start_test_task */
__weak void StartCh395fTestTask(void *argument) __weak void start_test_task(void *argument)
{ {
/* USER CODE BEGIN StartCh395fTestTask */ /* USER CODE BEGIN start_test_task */
/* Infinite loop */ /* Infinite loop */
for(;;) for(;;)
{ {
osDelay(1); osDelay(1);
} }
/* USER CODE END StartCh395fTestTask */ /* USER CODE END start_test_task */
} }
/* Private application code --------------------------------------------------*/ /* Private application code --------------------------------------------------*/
+5 -98
View File
@@ -59,10 +59,7 @@
/* Private variables ---------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */ /* USER CODE BEGIN PV */
/* RS-485 通信实例(UART5: PC12=TX, PD2=RX, PD0=DE) */ /* RS-485 实例与接收缓冲已收归 rs485.c(见 rs485.h 的 extern 导出) */
rs485_handle_t g_rs485;
#define RS485_RX_BUF_SIZE 256
uint8_t g_rs485_rx_buf[RS485_RX_BUF_SIZE];
/* USER CODE END PV */ /* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/
@@ -117,71 +114,8 @@ int main(void)
/* USER CODE BEGIN 2 */ /* USER CODE BEGIN 2 */
HAL_Delay(100); HAL_Delay(100);
/* /* 应用层初始化(时间子系统优先,详见 app_main_init) */
* 时间子系统初始化(尽早完成,后续所有日志带时间戳)
* 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 */ /* USER CODE END 2 */
/* Init scheduler */ /* Init scheduler */
@@ -252,37 +186,10 @@ void SystemClock_Config(void)
/* USER CODE BEGIN 4 */ /* USER CODE BEGIN 4 */
/* /*
* HAL UART 扩展接收回调(IDLE 空闲帧中断触发) * RS-485 的 HAL UART 回调(HAL_UARTEx_RxEventCallback / HAL_UART_ErrorCallback)
* 当 RS-485 总线空闲超过 1 个字符时间后触发 * 已收归 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 */ /* USER CODE END 4 */
/** /**
BIN
View File
Binary file not shown.
+2 -2
View File
@@ -38,8 +38,8 @@ extern "C" {
* 阶段使能开关(取消注释即启用对应阶段) * 阶段使能开关(取消注释即启用对应阶段)
* *
* 构建模式互斥(详见 docs/CH395F_Test_Guide.md「构建模式与执行顺序」): * 构建模式互斥(详见 docs/CH395F_Test_Guide.md「构建模式与执行顺序」):
* 硬件层模式(阶段 1~5):netTask 不创建,ch395fTestTask 独占 CH395F * 硬件层模式(阶段 1~5):netTask 不创建,testTask 独占 CH395F
* NET 层模式 (阶段 6~11):完整网络栈,netTask 轮询 + ch395fTestTask 监听循环 * NET 层模式 (阶段 6~11):完整网络栈,netTask 轮询 + testTask 监听循环
* *
* 注意:同层内可多选(Phase 6~10 共享 testTask 循环); * 注意:同层内可多选(Phase 6~10 共享 testTask 循环);
* Phase 4 (DHCP) 会改变 IP,必须独立运行; * Phase 4 (DHCP) 会改变 IP,必须独立运行;
+5 -17
View File
@@ -1345,13 +1345,12 @@ static void phase5_run(void) {
TEST_REPORT("Phase 5"); TEST_REPORT("Phase 5");
} }
#endif #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) #if defined(ENABLE_HW_LAYER_TESTS)
/* 硬件层模式(阶段 1~5):netTask 未创建,由本任务完成一次性协议栈 /* 硬件层模式(阶段 1~5):netTask 未创建,由本任务完成一次性协议栈
* 初始化并独占 CH395F —— 无 net_poll() 并发读取中断,无 SPI 并发事务 */ * 初始化并独占 CH395F —— 无 net_poll() 并发读取中断,无 SPI 并发事务 */
@@ -1391,16 +1390,5 @@ void StartCh395fTestTask(void *argument)
#else #else
net_layer_test_main(); net_layer_test_main();
#endif #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 #endif
for (;;) {
osDelay(1000);
}
} }
+2 -1
View File
@@ -5,7 +5,8 @@
extern "C" { extern "C" {
#endif #endif
void StartCh395fTestTask(void *argument); void start_test_task(void *argument);
void ch395f_test_run(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
+1 -1
View File
@@ -1,6 +1,6 @@
/***************************************************************************** /*****************************************************************************
* 模块名称:CH395F NET 层测试(Phase 6~11) * 模块名称:CH395F NET 层测试(Phase 6~11)
* 模块功能:基于 BSD Socket API(单连接模式)的 NET 层测试,由 ch395fTestTask * 模块功能:基于 BSD Socket API(单连接模式)的 NET 层测试,由 testTask
* 任务内的 net_layer_test_main() / net_layer_client_test_main() 事件 * 任务内的 net_layer_test_main() / net_layer_client_test_main() 事件
* 循环驱动,需 PC 配合。 * 循环驱动,需 PC 配合。
* 包含 Phase 6(TCP Echo) / 7(TCP Client) / 8(大文件) / 9(Select) / * 包含 Phase 6(TCP Echo) / 7(TCP Client) / 8(大文件) / 9(Select) /
+1 -1
View File
@@ -6,7 +6,7 @@ extern "C" {
#endif #endif
/* NET 层测试事件循环入口(定义于 net_test_task.c)。 /* NET 层测试事件循环入口(定义于 net_test_task.c)。
* 由 ch395fTestTask 在 NET 层构建模式下调用,内部创建单连接 TCP 监听 * 由 testTask 在 NET 层构建模式下调用,内部创建单连接 TCP 监听
* 并驱动 Phase 6/8~11 依次执行,连接断开后自动重新 listen。 */ * 并驱动 Phase 6/8~11 依次执行,连接断开后自动重新 listen。 */
void net_layer_test_main(void); void net_layer_test_main(void);
+1 -1
View File
@@ -37,7 +37,7 @@ extern sd2506_test_stats_t g_sd2506_test_stats;
g_sd2506_test_stats.failed); \ g_sd2506_test_stats.failed); \
} while (0) } while (0)
/* 测试入口:由 StartCh395fTestTask 经 TEST_SUITE_RTC 调度,顺序执行 Phase 1~3 */ /* 测试入口:由 start_test_task 经 TEST_SUITE_RTC 调度,顺序执行 Phase 1~3 */
void sd2506_test_run(void); void sd2506_test_run(void);
#ifdef __cplusplus #ifdef __cplusplus
+1 -1
View File
@@ -10,7 +10,7 @@
* *
* 当前测试:Phase 1 基本读写(init / 读 / 写 / 回读一致 / 走时), * 当前测试:Phase 1 基本读写(init / 读 / 写 / 回读一致 / 走时),
* 结束后自动恢复板子原始时间。 * 结束后自动恢复板子原始时间。
* 入口:sd2506_test_run()(由 StartCh395fTestTask 经 TEST_SUITE_RTC 调度) * 入口:sd2506_test_run()(由 start_test_task 经 TEST_SUITE_RTC 调度)
* 创建日期:2026-08-28 * 创建日期:2026-08-28
******************************************************************************/ ******************************************************************************/
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
* 模块名称:Storage Test Suite * 模块名称:Storage Test Suite
* 模块功能:FTL + FatFS 存储测试的声明与断言宏。实现见 storage_test_task.c, * 模块功能:FTL + FatFS 存储测试的声明与断言宏。实现见 storage_test_task.c,
* 统一由 ch395fTestTask 调度;正常产品构建下由 defaultTask 调用, * 统一由 testTask 调度;正常产品构建下由 defaultTask 调用,
* 行为与原 defaultTask 内联逻辑一致。 * 行为与原 defaultTask 内联逻辑一致。
* 适用平台:STM32F4 系列 * 适用平台:STM32F4 系列
* 作者:王建锋 * 作者:王建锋
+1 -1
View File
@@ -1,6 +1,6 @@
/****************************************************************************** /******************************************************************************
* 模块名称:Storage Test Task * 模块名称:Storage Test Task
* 模块功能:FTL + FatFS 存储测试,从 defaultTask 迁入,统一由 ch395fTestTask * 模块功能:FTL + FatFS 存储测试,从 defaultTask 迁入,统一由 testTask
* 调度运行。正常产品构建下由 defaultTask 调用,行为与原内联逻辑一致。 * 调度运行。正常产品构建下由 defaultTask 调用,行为与原内联逻辑一致。
* 作者:王建锋 * 作者:王建锋
* 创建日期:2026-08-26 * 创建日期:2026-08-26
+50
View File
@@ -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);
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
* 模块名称:统一测试套件选择 * 模块名称:统一测试套件选择
* 模块功能:集中选择当前构建要运行的测试套件。所有测试统一由 * 模块功能:集中选择当前构建要运行的测试套件。所有测试统一由
* ch395fTestTask(StartCh395fTestTask)调度,defaultTask 在测试 * testTask(start_test_task)调度,defaultTask 在测试
* 构建下空闲,正常产品构建下仅运行存储挂载/测试。 * 构建下空闲,正常产品构建下仅运行存储挂载/测试。
* 适用平台:STM32F4 系列 * 适用平台:STM32F4 系列
* 作者:王建锋 * 作者:王建锋