/* * 模块名称:Application Main Entry * 模块功能:应用初始化流程编排、各模块启动、主循环 * 适用平台:STM32F407ZGTx * 作者:王建锋 * 创建日期:2026-07-19 * 修改记录: * v1.0 2026-07-19 王建锋 创建初始版本 * v1.1 2026-08-29 王建锋 将原 main.c 中各外设初始化统一收归 app_main_init, * 并按"时间子系统优先"的顺序编排启动流程 * v1.2 2026-09-14 王建锋 新增自检埋点(RTC/NAND/ADC 失败 → sys_log 自检记录)+ syslog_mcu_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" #include "sys_log.h" #define DBG_TAG "[APP]" #include "dbg_log.h" /* g_rs485 由 rs485.c 定义,经 rs485.h 的 extern 引用;接收缓冲内聚于句柄 rx_buf */ /* * 函数功能:应用层初始化 * 入口参数:无 * 返 回 值:0 - 成功,-1 - 失败 * 限定条件:CubeMX 外设初始化已完成 * 函数说明:在 CubeMX 外设初始化之后、FreeRTOS 调度器启动之前调用。 * 启动顺序以"时间子系统优先"为原则,使后续所有日志均带时间戳: * 1) 时间子系统(SD2506 RTC → 墙钟基准) * 2) RS-485 * 3) GD5F NAND * 4) TPAFE5160 ADC * 5) SD2506 诊断信息 * 6) 触发首次 ADC 转换 */ int app_main_init(void) { /* 日志引擎初始化(创建待发队列;须先于任何 syslog_post) */ (void)syslog_mcu_init(); /* * 1) 时间子系统初始化(尽早完成,后续所有日志带时间戳) * sd2506_init() 从 RTC 读取初始时间 * sys_clock_init() 将 RTC 时间转为 Unix epoch,建立墙钟基准 */ sd2506_init(); if (sys_clock_init() != 0) { syslog_post(SYSLOG_SELFTEST, "时钟芯片异常"); } /* 2) RS-485 初始化(UART4 + PD0 方向控制),初始化即自动开启接收 */ rs485_init(&g_rs485, &huart4, ST_DIR4_GPIO_Port, ST_DIR4_Pin); DBG_INFO("RS485 init: OK (UART4, DE=PA15)"); /* 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"); if (ret != GD5F_OK) { syslog_post(SYSLOG_SELFTEST, "NAND异常"); } /* 4) TPAFE5160 ADC 测试 */ int tp_ret = tpafe5160_init(); DBG_INFO("ADC init: %s", (tp_ret == TPAFE5160_OK) ? "OK" : "TIMEOUT"); if (tp_ret != TPAFE5160_OK) { syslog_post(SYSLOG_SELFTEST, "ADC异常"); } /* 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; } /* * 函数功能:应用主循环 * 入口参数:无 * 返 回 值:无 * 限定条件:FreeRTOS 调度器启动后不再返回 * 函数说明:空闲任务可调用的应用层处理入口 */ void app_main_run(void) { for (;;) { /* 应用层空闲处理 */ } }