时间终于同步,存储成功

This commit is contained in:
2026-08-28 21:10:51 +08:00
parent 4e9ac0d9c3
commit 02a05a7a63
13 changed files with 606 additions and 78 deletions

View File

@@ -20,6 +20,7 @@
#include "test_config.h"
#include "storage_test.h"
#include "gd5f_test.h"
#include "sd2506_test.h"
#define DBG_TAG "[TEST_TASK]"
#include "dbg_log.h"
@@ -1395,6 +1396,8 @@ void StartCh395fTestTask(void *argument)
storage_test_run();
#elif defined(TEST_SUITE_GD5F)
gd5f_test_run();
#elif defined(TEST_SUITE_RTC)
sd2506_test_run();
#endif
for (;;) {

48
test/sd2506_test.h Normal file
View File

@@ -0,0 +1,48 @@
#ifndef SD2506_TEST_H
#define SD2506_TEST_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ============ Phase 使能开关(取消注释即启用,默认全开) ============ */
#define ENABLE_RTC_BASIC_TESTS /* Phase 1: 基本读写 / 走时 */
#define ENABLE_RTC_WRTC_PROBE_TESTS /* Phase 2: WRTC 解锁时序探测(定位正确时序) */
#define ENABLE_RTC_PERSIST_TESTS /* Phase 3: 跨重启持久化 */
/* ============ 测试统计(与 STORAGE/GD5F 套件一致的独立统计) ============ */
typedef struct {
uint16_t total;
uint16_t passed;
uint16_t failed;
} sd2506_test_stats_t;
extern sd2506_test_stats_t g_sd2506_test_stats;
#define SD2506_TEST_CHECK(cond, fmt, ...) do { \
g_sd2506_test_stats.total++; \
if (cond) { \
g_sd2506_test_stats.passed++; \
DBG_INFO("[PASS] " fmt, ##__VA_ARGS__); \
} else { \
g_sd2506_test_stats.failed++; \
DBG_ERROR("[FAIL] " fmt, ##__VA_ARGS__); \
} \
} while (0)
#define SD2506_TEST_REPORT(name) do { \
DBG_INFO("=== %s: %u/%u PASSED (failed=%u) ===", \
name, g_sd2506_test_stats.passed, g_sd2506_test_stats.total, \
g_sd2506_test_stats.failed); \
} while (0)
/* 测试入口:由 StartCh395fTestTask 经 TEST_SUITE_RTC 调度,顺序执行 Phase 1~3 */
void sd2506_test_run(void);
#ifdef __cplusplus
}
#endif
#endif /* SD2506_TEST_H */

137
test/sd2506_test_task.c Normal file
View File

@@ -0,0 +1,137 @@
/******************************************************************************
* 模块名称SD2506 RTC Test Suite
* 模块功能SD2506API-G RTC 驱动功能自测(黑盒,仅用公共 API
*
* 历史背景:本驱动曾出现"时间写不进"问题,根因是 sd2506.h 中寄存器宏写成
* "0x0FH"H 后缀。KEIL/ARMCC 不识别 H 整数后缀,将其编译为 0
* 导致 SD2506_REG_CTR1 实际等于 0秒寄存器sd2506_write_enable()
* 把 WRTC 写到了错误寄存器,写保护永不解除。修正为 "0x0FU" 后恢复。
* 详见 docs/SD2506_Trap_Records.md。
*
* 当前测试Phase 1 基本读写init / 读 / 写 / 回读一致 / 走时),
* 结束后自动恢复板子原始时间。
* 入口sd2506_test_run()(由 StartCh395fTestTask 经 TEST_SUITE_RTC 调度)
* 创建日期2026-08-28
******************************************************************************/
#include <string.h>
#include <stdint.h>
#include "sd2506_test.h"
#include "test_config.h"
#include "cmsis_os.h"
#include "sd2506.h"
#define DBG_TAG "[RTC_TEST]"
#include "dbg_log.h"
#ifdef TEST_SUITE_RTC
/* 全局测试统计(宏自动管理) */
sd2506_test_stats_t g_sd2506_test_stats;
/* ===================== Phase 1基本读写 ===================== */
#ifdef ENABLE_RTC_BASIC_TESTS
static void sd2506_phase_basic(void)
{
DBG_INFO("=== SD2506 Phase 1: basic read/write (public API) ===");
/* TC-RTC-001: init + 读取当前时间 */
int ret = sd2506_init();
SD2506_TEST_CHECK(ret == SD2506_OK, "sd2506_init() ret=%d (expect 0)", ret);
sd2506_time_t r;
ret = sd2506_get_time(&r);
SD2506_TEST_CHECK(ret == SD2506_OK, "sd2506_get_time() ret=%d (expect 0)", ret);
if (ret == SD2506_OK) {
DBG_INFO(" current RTC: %04u-%02u-%02u %02u:%02u:%02u wk=%u",
(unsigned int)r.year, (unsigned int)r.month, (unsigned int)r.day,
(unsigned int)r.hour, (unsigned int)r.minute,
(unsigned int)r.second, (unsigned int)r.week);
}
/* TC-RTC-002: 写固定时间,立即回读比对。
* 若 FAIL -> 先查 sd2506.h 寄存器宏后缀是否为 H曾因 0x0FH 被 KEIL 编译为 0
* 导致 SD2506_REG_CTR1 指向秒寄存器、WRTC 写错地址)。详见 docs/SD2506_Trap_Records.md。 */
sd2506_time_t t;
t.year = 2026; t.month = 8; t.day = 28; t.hour = 12; t.minute = 0; t.second = 0; t.week = 4;
ret = sd2506_set_time(&t);
SD2506_TEST_CHECK(ret == SD2506_OK, "sd2506_set_time() ret=%d (expect 0)", ret);
ret = sd2506_get_time(&r);
SD2506_TEST_CHECK(ret == SD2506_OK, "sd2506_get_time() after set ret=%d (expect 0)", ret);
if (ret == SD2506_OK) {
DBG_INFO(" set : %04u-%02u-%02u %02u:%02u:%02u",
(unsigned int)t.year, (unsigned int)t.month, (unsigned int)t.day,
(unsigned int)t.hour, (unsigned int)t.minute, (unsigned int)t.second);
DBG_INFO(" readback: %04u-%02u-%02u %02u:%02u:%02u",
(unsigned int)r.year, (unsigned int)r.month, (unsigned int)r.day,
(unsigned int)r.hour, (unsigned int)r.minute, (unsigned int)r.second);
}
int match = (r.year == t.year && r.month == t.month && r.day == t.day &&
r.hour == t.hour && r.minute == t.minute &&
(r.second == t.second || r.second == ((t.second + 1U) % 60U)));
SD2506_TEST_CHECK(match, "set==readback (in-session write takes effect)");
/* TC-RTC-003: 走时。写后等 3s应前进约 3 秒 */
if (ret == SD2506_OK) {
osDelay(3000);
sd2506_time_t r2;
int ret2 = sd2506_get_time(&r2);
if (ret2 == SD2506_OK) {
int adv = (r2.second + 60 * (r2.minute + 60 * (r2.hour + 24 * r2.day)))
- (r.second + 60 * (r.minute + 60 * (r.hour + 24 * r.day)));
if (adv < 0) adv += 60 * 60 * 24 * 32;
DBG_INFO(" 3s later: %04u-%02u-%02u %02u:%02u:%02u (advanced %d s)",
(unsigned int)r2.year, (unsigned int)r2.month, (unsigned int)r2.day,
(unsigned int)r2.hour, (unsigned int)r2.minute, (unsigned int)r2.second, adv);
SD2506_TEST_CHECK(adv >= 2 && adv <= 5, "RTC ticking forward (~3s)");
}
}
SD2506_TEST_REPORT("Phase 1 basic");
}
#endif /* ENABLE_RTC_BASIC_TESTS */
/* ===================== 套件入口 ===================== */
void sd2506_test_run(void)
{
DBG_INFO("SD2506 test suite started");
int ret = sd2506_init();
SD2506_TEST_CHECK(ret == SD2506_OK, "sd2506_init() ret=%d (expect 0)", ret);
/* 信息:读取 CTR1 默认状态(确认 WRTC 初始/可写能力,纯诊断) */
uint8_t c1 = 0x00U;
if (sd2506_read_ctr1(&c1) == SD2506_OK) {
DBG_INFO(" CTR1=0x%02X (WRTC2=CTR1.2=%u WRTC3=CTR1.7=%u)",
(unsigned int)c1,
(unsigned int)((c1 >> 2) & 1U),
(unsigned int)((c1 >> 7) & 1U));
}
/* 记录原始时间,测试结束恢复,避免把板子时间留在测试值 */
sd2506_time_t orig;
int have_orig = (sd2506_get_time(&orig) == SD2506_OK);
if (!have_orig) {
DBG_INFO(" WARN: cannot read original time; restore step will be skipped");
}
memset(&g_sd2506_test_stats, 0, sizeof(g_sd2506_test_stats));
#ifdef ENABLE_RTC_BASIC_TESTS
sd2506_phase_basic();
#endif
/* 恢复原始时间(用公共 API写保护逻辑已由 sd2506.c 正确处理) */
if (have_orig) {
int r = sd2506_set_time(&orig);
DBG_INFO(" restored original time (ret=%d)", r);
}
DBG_INFO("SD2506 test suite done");
for (;;) {
osDelay(1000);
}
}
#endif /* TEST_SUITE_RTC */

View File

@@ -26,8 +26,9 @@ extern "C" {
//#define TEST_SUITE_CH395F
//#define TEST_SUITE_STORAGE
//#define TEST_SUITE_GD5F
#define TEST_SUITE_RTC
#if defined(TEST_SUITE_CH395F) + defined(TEST_SUITE_STORAGE) + defined(TEST_SUITE_GD5F) > 1
#if defined(TEST_SUITE_CH395F) + defined(TEST_SUITE_STORAGE) + defined(TEST_SUITE_GD5F) + defined(TEST_SUITE_RTC) > 1
#error "测试套件互斥:一次构建只能启用一个 TEST_SUITE_*"
#endif
@@ -62,6 +63,11 @@ extern "C" {
#define TEST_SUITE_NAME "GD5F"
#endif
#ifdef TEST_SUITE_RTC
#include "sd2506_test.h"
#define TEST_SUITE_NAME "RTC"
#endif
#ifndef TEST_SUITE_NAME
#define TEST_SUITE_NAME "NONE"
#endif

View File

@@ -24,6 +24,7 @@ import socket
import struct
import sys
import time
import calendar
DEFAULT_MCU_IP = "192.168.1.100"
DEFAULT_PORT = 8888
@@ -44,8 +45,11 @@ def main():
while True:
try:
# 本地 wall-clock 的 epoch与电脑显示一致;板子按本地时间分解
local_epoch = int(time.mktime(time.localtime()))
# 本地 wall-clock 当作 UTC 算出的 epoch与电脑显示一致
# 注意:板子 RTC 存本地时间且 unix_to_sd2506 无时区处理,
# 故必须发"本地墙钟当 UTC"的伪 epochcalendar.timegm
# 不能用 time.mktime返回真正 UTC epoch会导致板子慢 8 小时)。
local_epoch = int(calendar.timegm(time.localtime()))
pkt = b"TIME" + struct.pack(">I", local_epoch)
with socket.create_connection((mcu_ip, port), timeout=5) as sock: