- /*!
- * [url=/u/file]@file[/url] main.c
- * [url=/u/brief]@brief[/url] APM32F407 Backup SRAM VBAT断电测试(精简版)
- * [url=/u/version]@version[/url] V1.0.6
- * [url=/u/date]@date[/url] 2025-02-15
- * [url=/u/Attention]@Attention[/url] Copyright (C) 2021-2025 Geehy Semiconductor
- */
- /* Includes ****************************************************************/
- #include "main.h"
- #include <stdio.h>
- #include <string.h>
- /* Private Macro ***********************************************************/
- #define DEBUG_USART USART1
- #define BACKUP_SRAM_SIZE 4096 // 4KB容量
- #define BKPSRAM_TEST_OFFSET 0x0000 // 测试数据偏移
- #define BKPSRAM_FLAG_OFFSET 0x0100 // 标志位偏移
- #define BKPSRAM_FIRST_FLAG 0x55AA55AAUL // 首次运行标志
- // 修复:改用“数据保持状态”判断VBAT(通过参数传递,避免全局变量)
- #define VBAT_OK(fr, do) ((fr) == 0 && (do) == 1) // VBAT有效(断电后数据完整)
- #define VBAT_ERR(fr, do) (!(VBAT_OK(fr, do))) // VBAT无效(首次运行或数据丢失)
- /* Private Variables *******************************************************/
- uint8_t g_test_buf[] = {0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA};
- uint8_t g_read_buf[sizeof(g_test_buf)] = {0};
- /* Private Function Prototypes *********************************************/
- uint8_t BackupSRAM_Init(void);
- uint16_t BackupSRAM_Write(uint16_t off, uint8_t *buf, uint16_t len);
- uint16_t BackupSRAM_Read(uint16_t off, uint8_t *buf, uint16_t len);
- uint8_t IsFirstRun(void);
- void SetFirstRunFlag(void);
- // 修复:添加参数传递first_run和data_ok
- void VBAT_Check(uint8_t first_run, uint8_t data_ok);
- void Delay(uint32_t cnt);
- /* Function Definitions ****************************************************/
- /**
- * @brief 备份SRAM初始化
- * @retval 0:成功 1:失败
- */
- uint8_t BackupSRAM_Init(void)
- {
- RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_PMU);
- PMU_EnableBackupAccess();
- RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_BKPSRAM);
- PMU_EnableBackupRegulator();
- // 修复:等待调压器就绪(用正确的PMU_FLAG_BKPR,而非VOSR)
- uint32_t timeout = 0xFFFF;
- while((PMU_ReadStatusFlag(PMU_FLAG_BKPR) == RESET) && timeout--);
- return timeout ? 0 : 1;
- }
- /**
- * @brief 备份SRAM写入
- * @param off: 地址偏移 len: 数据长度
- * @retval 实际写入长度
- */
- uint16_t BackupSRAM_Write(uint16_t off, uint8_t *buf, uint16_t len)
- {
- if(!buf || !len || off >= BACKUP_SRAM_SIZE) return 0;
- uint16_t real_len = (off + len) > BACKUP_SRAM_SIZE ? (BACKUP_SRAM_SIZE - off) : len;
- memcpy((uint8_t *)BKPSRAM_BASE + off, buf, real_len);
- return real_len;
- }
- /**
- * @brief 备份SRAM读取
- * @param off: 地址偏移 len: 读取长度
- * @retval 实际读取长度
- */
- uint16_t BackupSRAM_Read(uint16_t off, uint8_t *buf, uint16_t len)
- {
- if(!buf || !len || off >= BACKUP_SRAM_SIZE) return 0;
- uint16_t real_len = (off + len) > BACKUP_SRAM_SIZE ? (BACKUP_SRAM_SIZE - off) : len;
- memcpy(buf, (uint8_t *)BKPSRAM_BASE + off, real_len);
- return real_len;
- }
- /**
- * @brief 检查是否首次运行
- * @retval 1:首次 0:非首次
- */
- uint8_t IsFirstRun(void)
- {
- return *(uint32_t *)(BKPSRAM_BASE + BKPSRAM_FLAG_OFFSET) != BKPSRAM_FIRST_FLAG;
- }
- /**
- * @brief 设置首次运行标志
- */
- void SetFirstRunFlag(void)
- {
- uint32_t flag = BKPSRAM_FIRST_FLAG;
- BackupSRAM_Write(BKPSRAM_FLAG_OFFSET, (uint8_t *)&flag, sizeof(flag));
- }
- /**
- * @brief VBAT状态检测提示(修复参数传递和判断逻辑)
- * @param first_run: 是否首次运行(1:是 0:否)
- * @param data_ok: 数据是否完整(1:完整 0:丢失)
- */
- void VBAT_Check(uint8_t first_run, uint8_t data_ok)
- {
- // 首次运行时无法判断,仅提示;断电后根据数据状态判断
- if(first_run == 1)
- {
- printf("\r\nVBAT状态:暂无法判断(首次运行)\r\n");
- printf("提示:未接VBAT时断电数据将丢失(正常特性)\r\n");
- }
- else
- {
- printf("\r\nVBAT状态:%s\r\n", VBAT_OK(first_run, data_ok) ? "供电正常" : "未检测到供电");
- }
- }
- /**
- * @brief 简单延时
- */
- void Delay(uint32_t cnt)
- {
- volatile uint32_t delay = cnt;
- while(delay--);
- }
- /**
- * @brief 主函数
- */
- int main(void)
- {
- uint8_t init_ok, first_run, data_ok = 1;
-
- USART_Config_T usartConfigStruct;
-
- /* 串口配置:115200 8N1 仅发送(测试无需接收) */
- usartConfigStruct.baudRate = 115200;
- usartConfigStruct.hardwareFlow = USART_HARDWARE_FLOW_NONE;
- usartConfigStruct.mode = USART_MODE_TX;
- usartConfigStruct.parity = USART_PARITY_NONE;
- usartConfigStruct.stopBits = USART_STOP_BIT_1;
- usartConfigStruct.wordLength = USART_WORD_LEN_8B;
- BOARD_COMInit(COM1, &usartConfigStruct);
- // 标题打印
- printf("================================\r\n");
- printf("APM32F407 备份SRAM VBAT测试\r\n");
- printf("================================\r\n");
- // 备份SRAM初始化
- init_ok = BackupSRAM_Init();
- printf("备份SRAM初始化:%s\r\n", init_ok ? "失败" : "成功");
- // 首次运行判断(移到VBAT_Check前,供判断使用)
- first_run = IsFirstRun();
- // 修复:传递参数first_run和data_ok
- VBAT_Check(first_run, data_ok);
- if(first_run)
- {
- // 首次运行:写入测试数据
- printf("\r\n【首次运行】写入测试数据...\r\n");
- uint16_t wlen = BackupSRAM_Write(BKPSRAM_TEST_OFFSET, g_test_buf, sizeof(g_test_buf));
- for(uint8_t i=0; i<wlen; i++) printf("0x%02X ", g_test_buf[i]);
- printf("\r\n写入长度:%d Bytes\r\n", wlen);
- SetFirstRunFlag();
- printf("写入完成!按断电键测试数据保持性\r\n");
- }
- else
- {
- // 断电后:读取验证
- printf("\r\n【断电后】读取备份数据...\r\n");
- uint16_t rlen = BackupSRAM_Read(BKPSRAM_TEST_OFFSET, g_read_buf, sizeof(g_read_buf));
- for(uint8_t i=0; i<rlen; i++) printf("0x%02X ", g_read_buf[i]);
- printf("\r\n读取长度:%d Bytes\r\n", rlen);
- // 数据校验
- if(rlen != sizeof(g_test_buf)) data_ok = 0;
- else for(uint8_t i=0; i<rlen; i++) if(g_read_buf[i] != g_test_buf[i]) data_ok = 0;
- // 结果提示
- if(data_ok)
- {
- printf("\r\n测试成功!数据保持完整\r\n");
- }
- else
- {
- printf("\r\n数据丢失!\r\n");
- if(VBAT_ERR(first_run, data_ok))
- {
- printf("原因:未接VBAT电池\r\n");
- }
- else
- {
- printf("原因:VBAT供电但数据丢失(配置/硬件异常)\r\n");
- }
- }
- }
- while(1)
- {
-
- }
- }
- /* printf重定向 ************************************************************/
- #if defined (__CC_ARM) || defined (__ICCARM__) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
- int fputc(int ch, FILE* f)
- {
- USART_TxData(DEBUG_USART, (uint8_t)ch);
- while(USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);
- return ch;
- }
- #elif defined (__GNUC__)
- int __io_putchar(int ch)
- {
- USART_TxData(DEBUG_USART, ch);
- while(USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);
- return ch;
- }
- int _write(int file, char* ptr, int len)
- {
- UNUSED(file);
- for(int i=0; i<len; i++) __io_putchar(*ptr++);
- return len;
- }
- #else
- #warning Not supported compiler type
- #endif