/* * @Author: mbw * @Date: 2024-08-22 16:15:08 * @LastEditors: mbw && 1600520629@qq.com * @LastEditTime: 2024-09-20 10:39:08 * @FilePath: \USART1_Interrupt - RT-Thread\bsp\src\bsp_flash.c * @Description: * * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. */ #include "bsp_flash.h" #include "bsp_rtc.h" #include "rthw.h" #include "stdlib.h" #include "user_rtt.h" #define LOG_TAG "bsp_flash" // 该模块对应的标签。不定义时,默认:NO_TAG #define LOG_LVL LOG_LVL_DBG // 该模块对应的日志输出级别。不定义时,默认:调试级别 #include // 必须在 LOG_TAG 与 LOG_LVL 下面 #define FSTPG_WORD_COUNT (0x40U) // #define TEST 512 #define MAX(a, b) ((a) > (b)) ? (a) : (b) ErrorStatus Flash_Write_Record(TeRecord record); const uint32_t hr_start_addr[7] = {FLASH_HR_ALARM_START_ADDR, FLASH_HR_ALARM_RCY_START_ADDR, FLASH_HR_FAULT_START_ADDR, FLASH_HR_FAULT_RCY_START_ADDR, FLASH_HR_power_down_START_ADDR, FLASH_HR_POWER_ON_START_ADDR, FLASH_HR_SENSOR_FAILURE_START_ADDR}; /*各历史数据的条数*/ const uint16_t hr_record_max_num[7] = {HR_ALARM_MAX_NUM, HR_ALARM_RCY_MAX_NUM, HR_FAULT_MAX_NUM, HR_FAULT_RCY_MAX_NUM, HR_power_down_MAX_NUM, HR_POWER_ON_MAX_NUM, HR_SENSOR_FAILURE_MAX_NUM}; const uint8_t hr_record_pages[7] = {HR_ALARM_PAGES, HR_ALARM_RCY_PAGES, HR_FAULT_PAGES, HR_FAULT_RCY_PAGES, HR_power_down_PAGES, HR_POWER_ON_PAGES, HR_SENSOR_FAILURE_PAGES}; /*定义历史数据所在的真实起始页*/ const uint8_t hr_record_start_page_num[7] = {FLASH_HR_ALARM_PAGE, FLASH_HR_ALARM_RCY_PAGE, FLASH_HR_FAULT_PAGE, FLASH_HR_FAULT_RCY_PAGE, FLASH_HR_power_down_PAGE, FLASH_HR_POWER_ON_PAGE, FLASH_HR_SENSOR_FAILIRE_START_PAGE}; /*定义信息页的数据地址*/ const uint32_t hr_record_info_start_addr[9] = { FLASH_CONFIG_INFO_INIT_FLAG_ADDR, FLASH_FACTORY_TIME_ADDR, FLASH_EXPIRATION_TIME_ADDR, FLASH_LOW_ALARM_VALUE_ADDR, FLASH_HIGH_ALARM_VALUE_ADDR, FLASH_SOFTWARE_VERSION_ADDR, FLASH_HARDWARE_VERSION_ADDR, FLASH_COMPANY_NAME_ADDR, FLASH_UPDATE_TIME_ADDR, }; rt_ubase_t level = 0; static void BSP_Flash_UnLock(void) { std_flash_unlock(); } static void BSP_Flash_Lock(void) { std_flash_lock(); // rt_hw_interrupt_enable(interrupt_value); } static void Flash_Interrupt_Disable(void) { level = rt_hw_interrupt_disable(); } static void Flash_Interrupt_Enable(void) { rt_hw_interrupt_enable(level); } // 计算校验和的函数 uint8_t Sum_Check(TuFlashHrRecordFrame frame) { return (frame.time.year + frame.time.month + frame.time.day + frame.time.hour + frame.time.minute) & CHECKSUM_MASK; } #if 0 static size_t Flash_Read(uint32_t addr, uint8_t *buf, size_t len) { size_t read_len = 0; for (size_t i = 0; i < len; i++, buf++, addr++, read_len++) { *buf = *(uint8_t *)addr; } return read_len; } #endif static size_t Flash_ReadWord(uint32_t addr, uint32_t *buf, size_t len) { size_t read_len = 0; if ((addr & 0x03) != 0) // 地址4字节对齐 { RTT_LOG_E("addr %#X is not aligned\r\n", addr); return ERROR; } for (size_t i = 0; i < len; i++, read_len++) { buf[i] = ((uint32_t *)addr)[i]; // if (buf[i] != ((uint32_t *)addr)[i]) { RTT_LOG_E("Flash_Read Data Mismatch at addr %#X, expected %d got %d", addr, *(uint32_t *)buf, *(uint32_t *)addr); return ERROR; } } return read_len; } /** * @description: 向Flash中写入数据 * @param {uint32_t} addr * @param {uint8_t} *buf * @param {size_t} len * @return {*} */ static std_status_t Flash_WriteWord(uint32_t addr, uint32_t write_data) { if ((addr & 0x03) != 0) // 地址4字节对齐 { LOG_E("addr %#X is not aligned\r\n", addr); return ERROR; } /* 清除错误标志 */ std_flash_clear_flag(FLASH_FLAG_ALL_ERR); BSP_Flash_UnLock(); if (std_flash_get_lock_status() == false) { /* 进入编程模式 */ // std_flash_program_enable(); Flash_Interrupt_Disable(); if (std_flash_word_program(addr, write_data) != SUCCESS) // 写入操作 字节写入 { Flash_Interrupt_Enable(); LOG_D("addr = %#X, read %d", addr, *(uint32_t *)addr); // std_flash_program_disable(); BSP_Flash_Lock(); return ERROR; } Flash_Interrupt_Enable(); // std_flash_program_disable(); BSP_Flash_Lock(); if (*(uint32_t *)addr != write_data) { LOG_D("Flash_Write Data Mismatch at addr %#X, expected %d got %d", addr, write_data, *(uint32_t *)addr); /* 退出编程模式 */ return ERROR; } rt_thread_mdelay(2); } return SUCCESS; } #if 0 #if defined(__CC_ARM) #pragma arm section code = "FAST_PROGRAM" #elif defined(__ICCARM__) __ramfunc #elif defined(__GNUC__) __attribute__ ((section (".RamFunc"))) #endif /** * @brief Flash快速编程,往目标地址快速编程半页数据 * @param address 编程地址 * @param data_buf 编程数据 * @retval std_status_t 本函数执行结果 */ std_status_t BSP_Flash_Fast_Write(uint32_t address, uint32_t *data_buf) { std_status_t status = STD_OK; uint32_t prog_count = 0; /* 启动快速编程模式 */ std_flash_fast_program_enable(); /* 向目标地址写入数据 */ for (prog_count=0; prog_count < FSTPG_WORD_COUNT; prog_count++) { ((uint32_t *)address)[prog_count] = data_buf[prog_count]; /* 查询等待BSY标志被清除 */ while ((FLASH->SR & FLASH_FLAG_BSY) == FLASH_FLAG_BSY); /* 若出现错误,则退出编程循环 */ if (FLASH->SR & FLASH_FLAG_ALL_ERR) { RTT_LOG_E("FLASH_SR = %#X", FLASH->SR); RTT_LOG_E("Flash_Write Error at addr %#X, expected %X got %X", address, data_buf[prog_count], ((uint32_t *)address)[prog_count]); status = STD_ERR; break; } } /* 查询等待FSTPG_MODE状态被自动清零 */ while ((FLASH->CR & FLASH_CR_FSTPG_MODE) == FLASH_CR_FSTPG_MODE); /* 清除Flash标志 */ FLASH->SR = (FLASH_FLAG_ALL_ERR | FLASH_SR_EOP); return (status); } #if defined(__CC_ARM) #pragma arm section #endif /** * @brief Flash快速编程流程 * @param address 编程地址 * @param data_buf 编程数据 * @retval std_status_t 本函数执行结果 */ ErrorStatus BSP_Flash_Fast_Program(uint32_t address, uint32_t *data_buf) { std_status_t status = STD_OK; uint32_t prog_count; /* 检查Flash上一次操作忙状态、错误状态 */ // status = std_flash_wait_for_last_operation(FLASH_WAIT_PROGRAM); // if(status == STD_OK) // { /* 进入编程模式 */ std_flash_program_enable(); /* 短时间屏蔽中断 */ Flash_Interrupt_Disable(); /* 执行快速编程 */ if(BSP_Flash_Fast_Write(address, data_buf) != STD_OK) { status = STD_ERR; RTT_LOG_E("Flash_Fast_Write status ERROR %d", status); } /* 恢复中断 */ Flash_Interrupt_Enable(); /* 退出编程模式 */ std_flash_program_disable(); rt_thread_mdelay(2); /* 快速编程中无法对Flash执行读操作,需在编程结束后统一校验数据 */ if (status == STD_OK) { for (prog_count = 0; prog_count < FSTPG_WORD_COUNT; prog_count++) { if (((__IO uint32_t *)address)[prog_count] != data_buf[prog_count]) { RTT_LOG_E("Flash_Fast_Write Data Mismatch at addr %#X, expected %d got %d", address + prog_count * 4, data_buf[prog_count], ((__IO uint32_t *)address)[prog_count]); status = STD_ERR; break; } else { RTT_LOG_D("Flash_Fast_Write Data Match at addr %#X, expected %d got %d", address + prog_count * 4, data_buf[prog_count], ((__IO uint32_t *)address)[prog_count]); } } } // } return (status); } ErrorStatus BSP_Flash_Program_Page(uint32_t address, uint32_t *data_buf) { std_status_t status; /* 清除错误标志 */ std_flash_clear_flag(FLASH_FLAG_ALL_ERR); /* Flash控制寄存器解锁 */ BSP_Flash_UnLock(); if (std_flash_get_lock_status() == false) { /* 页擦第48页 */ status = std_flash_page_erase(FLASH_HR_INFO_PAGE); /* 擦除异常,加入自定义处理代码 */ while(status != STD_OK) { RTT_LOG_E("Flash_Erase Page %d", FLASH_HR_INFO_PAGE); return STD_ERR; } /* 快速编程64个字:前半页 */ status = BSP_Flash_Fast_Program(address, data_buf); /* 快速编程异常,加入自定义处理代码 */ while(status != STD_OK) { RTT_LOG_E("Flash_Fast_Write Page %d", FLASH_HR_INFO_PAGE); return STD_ERR; } /* 快速编程64个字:后半页 */ status = BSP_Flash_Fast_Program((address + (FSTPG_WORD_COUNT << 2)), data_buf); /* 快速编程异常,加入自定义处理代码 */ while(status != STD_OK) { RTT_LOG_E("Flash_Fast_Write Page %d", FLASH_HR_INFO_PAGE); return STD_ERR; } /* Flash控制寄存器加锁 */ BSP_Flash_Lock(); } return STD_OK; } #endif #if 0 static std_status_t Flash_WritePage(uint32_t addr, uint32_t *buf, size_t len) { std_status_t status = SUCCESS; if ((addr & 0x03) != 0) // 地址4字节对齐 { LOG_E("addr %#X is not aligned\r\n", addr); return ERROR; } for (int i = 0; i < len; i++) // 页写入的WORD数 { status = Flash_WriteWord((addr + i * sizeof(uint32_t)), *(buf + i * sizeof(uint32_t))); // 注意:地址增加应按uint32_t大小增加 if (status != SUCCESS) { return status; // 返回错误状态 } } return status; // 如果所有写入成功,返回SUCCESS } #endif std_status_t Flash_ErasePage(uint32_t index) { std_flash_unlock(); RTT_LOG_D("ErasePage %d", index); Flash_Interrupt_Disable(); std_status_t status = std_flash_erase(FLASH_ERASE_PAGE, index); Flash_Interrupt_Enable(); std_flash_lock(); return status; } /** * @description: 擦除产品信息页 * @return {*} */ void Flash_ErasePage_ConfigInfo(void) { if (Flash_ErasePage(FLASH_HR_INFO_PAGE) != SUCCESS) { RTT_LOG_E("error_page = %#x\r\n"); } } ErrorStatus BSP_Flash_Program_InfoPage(uint32_t address, uint32_t *data_buf) { ErrorStatus ret = ERROR; for (uint32_t i = 0; i < FLASH_PAGE_RECORD_WORD_NUM; i++) { ret = Flash_WriteWord(address + i * 4, data_buf[i]); if (ret != SUCCESS) { LOG_E("BSP_Flash_Program_InfoPage failed"); return ERROR; } } return ret; } /** * @description: 写产品信息页(最后一页) * @param {uint8_t*} frame * @return {*} */ ErrorStatus Flash_Write_ConfigInfo(uint32_t *buf) { return BSP_Flash_Program_InfoPage(FLASH_CONFIG_INFO_START_ADDR, buf); } /*获取当前页号*/ uint32_t Flash_Get_Current_Page(uint32_t addr) { return (addr - FLASH_START_ADDR) / FLASH_PAGE_BYTE_SIZE; } /** * @description: 擦除历史记录区的页 * @param {TeRecord} addr 需要擦除的页相对于其项目起始页的偏移量 * @return {*} */ ErrorStatus Flash_ErasePage_Records(TeRecord record, uint8_t page_offset) { ErrorStatus flag = SUCCESS; uint8_t erase_page = Flash_Get_Current_Page(hr_start_addr[record] + page_offset * FLASH_PAGE_BYTE_SIZE); if (erase_page != hr_record_start_page_num[record] + page_offset) { RTT_LOG_E("Flash_ErasePage_Records failed erase_page: %#X != %#X", erase_page, hr_record_start_page_num[record] + page_offset); return ERROR; } if (Flash_ErasePage(erase_page) != SUCCESS) { RTT_LOG_E("Flash_ErasePage failed\r\n"); return ERROR; } for (uint16_t i = 0; i < FLASH_PAGE_BYTE_SIZE; i++) // 检查擦除是否完整 { if (*(uint32_t *)((hr_start_addr[record] + FLASH_PAGE_BYTE_SIZE * erase_page) + i) != FLASH_DEFAULT_VALUE) { RTT_LOG_E("Flash_ErasePage failed\r\n"); return ERROR; } } return flag; } /** * @description: 擦除数据记录区 * @return {*} */ ErrorStatus BSP_Flash_EraseRecodrs(void) { /*擦除所有的历史记录区*/ for (TeRecord record = kRecordAlarm; record < kRecordSensorFailure; record++) { for (uint8_t i = 0; i < hr_record_pages[record]; i++) { if (Flash_ErasePage(hr_record_start_page_num[record] + i) != SUCCESS) { RTT_LOG_E("Flash_ErasePage_Records failed\r\n"); return ERROR; } } } return SUCCESS; } /** * @description: 先读再擦,以确保原有数据不会被擦除 * @param {uint8_t} *page_buf * @return {*} */ void Flash_ErasePage_ReadConfigInfo(uint32_t *page_buf) { Flash_ReadWord(FLASH_CONFIG_INFO_START_ADDR, page_buf, FLASH_PAGE_RECORD_WORD_NUM); Flash_ErasePage_ConfigInfo(); } #if 1 /** * @description: 获取产品的出厂或到期时间 * @return {*} */ ErrorStatus Flash_GetProductTimeLimit(TuFlashHrRecordFrame *pLimitTime, TeFlashProductTimeLimitId id) { if (id == kFactoryTimeId) { pLimitTime->hr_data = *(uint32_t *)FLASH_FACTORY_TIME_ADDR; if (pLimitTime->hr_data == FLASH_DEFAULT_VALUE) { RTT_LOG_E("FactoryTime is not set\r\n"); return ERROR; } if (pLimitTime->time.check_sum != Sum_Check(*pLimitTime)) { RTT_LOG_E("FactoryTime check_sum error\r\n"); return ERROR; } RTT_LOG_D("Flash_Read_FactoryTime:%04d-%02d-%02d,%02d:%02d", BASE_YEAR + pLimitTime->time.year, pLimitTime->time.month, pLimitTime->time.day, pLimitTime->time.hour, pLimitTime->time.minute); return SUCCESS; } else if (id == kExpirationTimeId) { pLimitTime->hr_data = *(uint32_t *)FLASH_EXPIRATION_TIME_ADDR; if (pLimitTime->hr_data == FLASH_DEFAULT_VALUE) { RTT_LOG_E("ExpirationTime is not set\r\n"); return ERROR; } if (pLimitTime->time.check_sum != Sum_Check(*pLimitTime)) { RTT_LOG_E("ExpirationTime check_sum error\r\n"); return ERROR; } RTT_LOG_D("Flash_Read_ExpirationTime:%04d-%02d-%02d,%02d:%02d", BASE_YEAR + pLimitTime->time.year, pLimitTime->time.month, pLimitTime->time.day, pLimitTime->time.hour, pLimitTime->time.minute); return SUCCESS; } return ERROR; } /** * @description: 设置产品的出厂或到期时间 * @param {uint16_t} year * @param {uint8_t} mon * @param {uint8_t} day * @param {uint8_t} hour * @param {uint8_t} min * @param {TeFlashProductTimeLimitId} id * @return {*} */ void Flash_SetProductTimeLimit(uint16_t year, uint8_t mon, uint8_t day, uint8_t hour, uint8_t min, TeFlashProductTimeLimitId id) { TuFlashHrRecordFrame LimitTime; TuFlashHrRecordFrame ReadLimitTime; uint32_t page_buf[FLASH_PAGE_RECORD_WORD_NUM] = {0}; // 暂存最后一页的值 Flash_ErasePage_ReadConfigInfo(page_buf); // page_buf[kFlashInitFlag] = FLASH_FIRST_INIT_VALUE; LimitTime.time.year = year - BASE_YEAR; LimitTime.time.month = mon; LimitTime.time.day = day; LimitTime.time.hour = hour; LimitTime.time.minute = min; LimitTime.time.check_sum = Sum_Check(LimitTime); if (id == kFactoryTimeId) { page_buf[kFlashFactoryTime] = LimitTime.hr_data; } else if (id == kExpirationTimeId) { page_buf[kFlashExpirationTime] = LimitTime.hr_data; } // RTT_LOG_D("Flash_SetProductTimeLimit((%d)):%04d-%02d-%02d,%02d:%02d ", id, year, mon, day, hour, min); Flash_Write_ConfigInfo(&page_buf[0]); Flash_GetProductTimeLimit(&ReadLimitTime, id); } #endif uint32_t ProductTimeLimit(uint16_t year, uint8_t mon, uint8_t day, uint8_t hour, uint8_t min) { TuFlashHrRecordFrame LimitTime; LimitTime.time.year = year - BASE_YEAR; LimitTime.time.month = mon; LimitTime.time.day = day; LimitTime.time.hour = hour; LimitTime.time.minute = min; LimitTime.time.check_sum = Sum_Check(LimitTime); return (uint32_t)LimitTime.hr_data; } /** * @description: 产品信息初始化, * @return {*} */ int BSP_Flash_Init(void) { if (*(uint32_t *)FLASH_CONFIG_INFO_START_ADDR != FLASH_FIRST_INIT_VALUE) { uint32_t info_page_buf[FLASH_PAGE_RECORD_WORD_NUM] = {0}; // TODO: 此处需要完善,比如写入初始化标志位,写入产品信息,写入出厂时间,写入到期时间 info_page_buf[kFlashInitFlag] = FLASH_FIRST_INIT_VALUE; info_page_buf[kFlashFactoryTime] = ProductTimeLimit(2024, 1, 2, 3, 4); info_page_buf[kFlashExpirationTime] = ProductTimeLimit(2024 + 10, 1, 2, 3, 4); info_page_buf[kFlashLowAlarmValue] = 0x0A; // 10%LEL info_page_buf[kFlashHighAlarmValue] = 0x32; // 50%LEL // info_page_buf[kFlashSoftwareVersion] = XXX; // info_page_buf[kFlashHardwareVersion] = XXX; // info_page_buf[kFlashCompanyName] = XXX; // info_page_buf[kFlashUpdateTime] = XXX; BSP_Flash_EraseRecodrs(); // 擦除历史数据区 Flash_ErasePage_ConfigInfo(); // 擦除配置信息 if (Flash_Write_ConfigInfo(info_page_buf) != STD_OK) { RTT_LOG_E("Flash_Write_ConfigInfo failed"); return RT_ERROR; } } return RT_EOK; } INIT_ENV_EXPORT(BSP_Flash_Init); #if 1 /** * @description: 获取索引信息 * @param {TeRecord} record * @return {*} */ TsRecordIndex Flash_GetIndex_Pos(TeRecord record) { uint32_t index_addr = RT_NULL; TsRecordIndex Index_Frame = {0}; uint32_t start_addr_default = hr_start_addr[record]; uint32_t hr_record_pages_default = hr_record_pages[record]; for (uint8_t page = 1; page <= hr_record_pages_default; page++) // 遍历对应项的历史数据扇区 { for (uint8_t i = 0; i < FLASH_HR_PAGE_RECORD_NUM; i++) // 获取扇区偏移量 { index_addr = (start_addr_default + FLASH_PAGE_BYTE_SIZE * (page - 1) + HR_RECORD_FRAME_LEN * i); if (*(uint32_t *)index_addr == FLASH_DEFAULT_VALUE) { /*获取最新的数据所在位置,如果值为0xFFFFFFFF,则表示该页有空位,是最新的页*/ if (page < hr_record_pages_default) // 当前页不是最后一页 { if (*(uint32_t *)(index_addr + FLASH_PAGE_BYTE_SIZE) == FLASH_DEFAULT_VALUE) { /* 没进行循环写入*/ Index_Frame.hr_start_addr = start_addr_default; Index_Frame.hr_index_addr = index_addr; Index_Frame.hr_num = (index_addr - start_addr_default) / HR_RECORD_FRAME_LEN; Index_Frame.hr_page = page; return Index_Frame; } else // 已经开始循环了 { Index_Frame.hr_start_addr = (index_addr + FLASH_PAGE_BYTE_SIZE); Index_Frame.hr_index_addr = index_addr; Index_Frame.hr_num = hr_record_max_num[record]; Index_Frame.hr_page = page; return Index_Frame; } } else // 当前页是最后一页,那么首地址应该在第一页,其偏移量是最后一页的偏移量 { Index_Frame.hr_start_addr = (start_addr_default + HR_RECORD_FRAME_LEN * i); Index_Frame.hr_index_addr = index_addr; Index_Frame.hr_num = hr_record_max_num[record]; Index_Frame.hr_page = page; if (page == 1) // 只有一条数据,则索引地址应该在第一页 { Index_Frame.hr_start_addr = start_addr_default; Index_Frame.hr_index_addr = Index_Frame.hr_start_addr; if (*(uint32_t *)(start_addr_default) == FLASH_DEFAULT_VALUE) { Index_Frame.hr_num = 0; } } return Index_Frame; } } } } RTT_LOG_E("Flash_GetIndex_Pos Error!"); return Index_Frame; } #endif /** * @description: * @param {TuFlashHrRecordFrame} *pHrRecord * @param {TeRecord} record * @param {uint8_t} index * @return {*} */ ErrorStatus Flash_Read_Record(TuFlashHrRecordFrame *pHrRecord, TeRecord record, size_t index) { uint32_t index_addr = 0; TuFlashHrRecordFrame RecoderFrame = {0}; TsRecordIndex Index_Frame = Flash_GetIndex_Pos(record); // 已存储的数量 uint32_t start_addr_default = hr_start_addr[record]; uint32_t hr_record_pages_default = hr_record_pages[record]; uint8_t sum_check = 0; if ((index <= hr_record_max_num[record]) && (index > 0)) { if (index <= Index_Frame.hr_num) { { if (Index_Frame.hr_start_addr == start_addr_default) // 是默认的起始地址,则读取数据就是对应的偏移量 { index_addr = start_addr_default + (index - 1) * HR_RECORD_FRAME_LEN; } else { if ((Index_Frame.hr_start_addr + index * HR_RECORD_FRAME_LEN) <= hr_record_pages_default * FLASH_PAGE_BYTE_SIZE + start_addr_default) // 没超过所在项目的页最大地址,正常读取,此时应该在缓存页 { RTT_LOG_D("read :hr_start_addr1 = %#x", Index_Frame.hr_start_addr); index_addr = Index_Frame.hr_start_addr + (index - 1) * HR_RECORD_FRAME_LEN; } else // 超过了所在项目的最大地址,此时应该循环了 { RTT_LOG_D("read :hr_start_addr2 = %#x", Index_Frame.hr_start_addr); index_addr = (Index_Frame.hr_start_addr + (index - 1) * HR_RECORD_FRAME_LEN - hr_record_pages[record] * FLASH_PAGE_BYTE_SIZE); } } } { RecoderFrame.hr_data = (*(uint32_t *)index_addr); sum_check = Sum_Check(RecoderFrame); if (RecoderFrame.time.check_sum == sum_check) { pHrRecord->hr_data = RecoderFrame.hr_data; // 赋值后读出,看对不对 RTT_LOG_D("Flash_Read_(%d)Record(%d):%04d-%02d-%02d,%02d:%02d", record, index, BASE_YEAR + pHrRecord->time.year, pHrRecord->time.month, pHrRecord->time.day, pHrRecord->time.hour, pHrRecord->time.minute); RTT_LOG_D("read :hr_start_addr = %#x, index_addr: %#x, hr_num: %d, hr_page:%d, read_data : %#X\r\n", Index_Frame.hr_start_addr, index_addr, Index_Frame.hr_num, Index_Frame.hr_page, pHrRecord->hr_data); return SUCCESS; } else { RTT_LOG_E("read :hr_start_addr = %#x, index_addr: %#x, hr_num: %d, hr_page:%d, read_data : %#X", Index_Frame.hr_start_addr, index_addr, Index_Frame.hr_num, Index_Frame.hr_page, RecoderFrame.hr_data); RTT_LOG_E("Flash_GetMaxNum((%d)_Records(%d) Sum_Check(%#X) != check_sum(%#X),index_addr :%#X\r\n", Index_Frame.hr_num, record, sum_check, RecoderFrame.time.check_sum, index_addr); pHrRecord->hr_data = 0; return ERROR; } } } else { RTT_LOG_E("index num (%d) > Actual storage num %d", index, Index_Frame.hr_num); pHrRecord->hr_data = 0; return ERROR; } } else { RTT_LOG_E("index num (%d) > hr record max num %d && index > 0", index, hr_record_max_num[record]); pHrRecord->hr_data = 0; return ERROR; } } /** * @description: 向对应的历史数据存储区写入一次数据 * @param {TeRecord} record * @return {*} */ ErrorStatus Flash_Write_Record(TeRecord record) { TsRecordIndex Index_Frame; TuFlashHrRecordFrame RecoderFrame = {0}; // uint8_t rtctime[3] = {0}, rtcdate[3] = {0}; if (record == kRecordSensorFailure && *(uint32_t *)hr_start_addr[record] != FLASH_DEFAULT_VALUE) // 传感器故障记录,且已经写入过数据,则不再写入 { RecoderFrame.hr_data = *(uint32_t *)hr_start_addr[record]; RTT_LOG_E("Flash_Write_(%d)Record(%d) num >= recorded Max num(%d)", record, Index_Frame.hr_num, hr_record_max_num[record]); Flash_Read_Record(&RecoderFrame, record, Index_Frame.hr_num); // 读取刚才写入数据 return ERROR; } // __cycleof__("my algorithm") // { // BSP_Rtc_Get_Calendar(rtcdate, rtctime); // } Index_Frame = Flash_GetIndex_Pos(record); /*这里可以使用RTC闹钟,每分钟更新一次数据,这样只需要从缓存读取数据就行,降低了访问的时间*/ RecoderFrame.time.hour = std_rtc_convert_bcd2bin(rtctime[0]); // h RecoderFrame.time.minute = std_rtc_convert_bcd2bin(rtctime[1]); // m RecoderFrame.time.year = (std_rtc_convert_bcd2bin(rtcdate[0]) - 24); // y RecoderFrame.time.month = std_rtc_convert_bcd2bin(rtcdate[1]); // m RecoderFrame.time.day = std_rtc_convert_bcd2bin(rtcdate[2]); // d RecoderFrame.time.check_sum = Sum_Check(RecoderFrame); // RTT_LOG_D("sizof TuFlashHrRecordFrame(%d)", sizeof(TuFlashHrRecordFrame)); RTT_LOG_D("write:hr_start_addr = %#x, index_addr: %#x, hr_num: %d, hr_page:%d, write_data : %#X", Index_Frame.hr_start_addr, Index_Frame.hr_index_addr, Index_Frame.hr_num, Index_Frame.hr_page, RecoderFrame.hr_data); RTT_LOG_D("Flash_Write_(%d)Record:%04d-%02d-%02d %02d:%02d, check_sum : %#X", record, RecoderFrame.time.year + BASE_YEAR, RecoderFrame.time.month, RecoderFrame.time.day, RecoderFrame.time.hour, RecoderFrame.time.minute, RecoderFrame.time.check_sum); { /*写入数据*/ if (Flash_WriteWord(Index_Frame.hr_index_addr, RecoderFrame.hr_data) != SUCCESS) { RTT_LOG_E("hr_write_data_error"); RTT_LOG_E("hr_start_addr = %#x, index_addr: %#x, hr_num: %d, hr_page:%d, write_data : %#X", Index_Frame.hr_start_addr, Index_Frame.hr_index_addr, Index_Frame.hr_num, Index_Frame.hr_page, RecoderFrame.hr_data); return ERROR; } } { /*如果把当前页写完了,要把下一页擦了,这样索引才不会出错,否则会导致索引出错*/ if (Index_Frame.hr_index_addr == hr_start_addr[record] + (Index_Frame.hr_page) * FLASH_PAGE_BYTE_SIZE - HR_RECORD_FRAME_LEN) { RTT_LOG_I("Index_Frame.hr_index_addr = hr_start_addr[record] + i * FLASH_PAGE_BYTE_SIZE - HR_RECORD_FRAME_LEN = %#X", Index_Frame.hr_index_addr); if (hr_record_pages[record] - Index_Frame.hr_page > 0) // 当前页不是最后一页,还不需要返回擦 { if (Flash_ErasePage(Index_Frame.hr_page + hr_record_start_page_num[record]) != SUCCESS) { RTT_LOG_I("Erase Page %d", Index_Frame.hr_page + hr_record_start_page_num[record]); return ERROR; } } else // 当前页是最后一页 此时需要将第一页擦除掉 { if (Flash_ErasePage(hr_record_start_page_num[record]) != SUCCESS) // 擦除第一页 { RTT_LOG_I("Erase Page %d", hr_record_start_page_num[record]); return ERROR; } } } } { if (Index_Frame.hr_num < hr_record_max_num[record]) { Flash_Read_Record(&RecoderFrame, record, Index_Frame.hr_num + 1); // 读取刚才写入数据,此时这个hr_num实际上是会+1的,当到达最大计数之前,hr_num会+1,到了以后,就默认是最大数量条数据,所以不用加 } else // 超了最大数后,每次读出来的数据都是最大数 { Flash_Read_Record(&RecoderFrame, record, Index_Frame.hr_num); // 读取刚才写入数据 } } return SUCCESS; } // static void TEST_Flash_Write_Record(int argc, char **argv) // { // if (argc == 3) // { // TeRecord record = (TeRecord)atoi(argv[1]); // int num = atoi(argv[2]); // for (int i = 1; i <= num; i++) // { // RTT_LOG_I("Flash_Write_(%d)Record:%d", record, i); // Flash_Write_Record(record); // rt_thread_mdelay(200); // 1min // } // } // else // { // LOG_E("TEST_Flash_Write_Record --use _cmd_ [record(0~6)] [num]"); // } // } // MSH_CMD_EXPORT(TEST_Flash_Write_Record, "TEST_Flash_Write_Record"); // static void TEST_Flash_Read_Record(int argc, char **argv) // { // TuFlashHrRecordFrame RecoderFrame = {0}; // if (argc == 3) // { // TeRecord record = (TeRecord)atoi(argv[1]); // int num = atoi(argv[2]); // Flash_Read_Record(&RecoderFrame, record, num); // } // else // { // LOG_E("TEST_Flash_Read_Record --use _cmd_ [record(0~6)] [num]"); // } // } // MSH_CMD_EXPORT(TEST_Flash_Read_Record, "TEST_Flash_Read_Record"); /*获取当前项目记录数*/ uint16_t Flash_GetNum_Records(TeRecord record) { TsRecordIndex Index_Frame = Flash_GetIndex_Pos(record); return Index_Frame.hr_num; } /** * @description: 获取总记录数 * @param {TsTotalRecords} *pTotalRecords * @return {*} * @note: */ ErrorStatus Flash_GetTotalRecord(TsTotalRecords *pTotalRecords) { ErrorStatus flag = ERROR; pTotalRecords->alarm = Flash_GetNum_Records(kRecordAlarm) >= 256 ? 255 : Flash_GetNum_Records(kRecordAlarm); pTotalRecords->alarm_rcy = Flash_GetNum_Records(kRecordAlarmRcy) >= 256 ? 255 : Flash_GetNum_Records(kRecordAlarmRcy); pTotalRecords->fault = Flash_GetNum_Records(kRecordFault); pTotalRecords->fault_rcy = Flash_GetNum_Records(kRecordFaultRcy); pTotalRecords->power_down = Flash_GetNum_Records(kRecordPowerDown); pTotalRecords->power_on = Flash_GetNum_Records(kRecordPowerOn); pTotalRecords->sensor_failure = Flash_GetNum_Records(kRecordSensorFailure); LOG_I("alarm:%d, alarm_rcy:%d, fault:%d, fault_rcy:%d, power_down:%d, power_on:%d, sensor_failure:%d", pTotalRecords->alarm, pTotalRecords->alarm_rcy, pTotalRecords->fault, pTotalRecords->fault_rcy, pTotalRecords->power_down, pTotalRecords->power_on, pTotalRecords->sensor_failure); flag = SUCCESS; return flag; } /** * @brief 获取记录时间 * @param record_type * @param index * @param pRecordsTime * @return ErrorStatus */ ErrorStatus Flash_GetRecord(TeFrameC2 record_type, uint16_t index, TsRecordsTime *pRecordsTime) { ErrorStatus flag = ERROR; uint16_t years = 0; if (kNumOfRecords < record_type && record_type < kGetCurrentTime) { TuFlashHrRecordFrame pHrReadRecord; /*这里存在多种情况,其中最常见的就是没有记录,,所有情况的结果就是此基数年不存在*/ if (Flash_Read_Record(&pHrReadRecord, (TeRecord)(record_type - 1), index) != SUCCESS) { years = pHrReadRecord.time.year; } else { years = BASE_YEAR + pHrReadRecord.time.year; } LOG_D("(%d)Flash_GetRecord[%d]:%04d-%02d-%02d,%02d:%02d", record_type - 1, index, years, pHrReadRecord.time.month, pHrReadRecord.time.day, pHrReadRecord.time.hour, pHrReadRecord.time.minute); pRecordsTime->year_h = years / 256; pRecordsTime->year_l = years % 256; pRecordsTime->month = pHrReadRecord.time.month; pRecordsTime->day = pHrReadRecord.time.day; pRecordsTime->hour = pHrReadRecord.time.hour; pRecordsTime->minute = pHrReadRecord.time.minute; flag = SUCCESS; } return flag; }