#include "hal_flash.h" /********************************************************************* *DEFINITION */ typedef struct zone_s { uint8_t page_num; uint32_t zone_start_addr; }zone_t; /********************************************************************* * LOCAL VARIABLES */ static int16_t PageCount = FLASH_PAGE_NUM; //可用页数 static uint32_t zone_used_index = 0; //zone结构体下标 static zone_t zone[FLASH_PAGE_NUM]; //zone结构体 /********************************************************************* * LOCAL FUNCTIONS */ /** @brief 通过区域地址获取区域索引 @param zone_addr[in] - 分配的区域地址 @param zone_index[out] - 返回分配的区域索引 @return 错误代码 */ static uint32_t Zone_GetIndex(uint32_t zone_addr, uint32_t *zone_index) { for(int i=0; i < zone_used_index; i++) { if( zone[i].zone_start_addr <= zone_addr && (zone[i].zone_start_addr + zone[i].page_num * FLASH_PAGE_SIZE) > zone_addr ){ if(zone_index != NULL)*zone_index = i; return ZONE_OP_SUCCESS; } } return ZONE_ERROR_NO_INDEX; } /********************************************************************* * PUBLIC FUNCTIONS */ /** @brief 初始化一个区域 @param page_size[in] - 该区域使用了几个页 @param zone_start_addr[out] - 返回分配的区域首地址 @return 错误代码 */ uint32_t Zone_Alloca(uint8_t page_num, uint32_t *zone_start_addr) { if(page_num <= 0) return ZONE_ERROR_PARAM_PAGE_NUM; if(PageCount - page_num < 0)return ZONE_ERROR_NO_PAGE; zone[zone_used_index].page_num = page_num; if(zone_used_index == 0)zone[zone_used_index].zone_start_addr = FLASH_ZONE_ADDR_1; else zone[zone_used_index].zone_start_addr = zone[zone_used_index-1].zone_start_addr + FLASH_PAGE_SIZE * zone[zone_used_index-1].page_num; if(zone_start_addr != NULL)*zone_start_addr = zone[zone_used_index].zone_start_addr; PageCount -= page_num; zone_used_index++; return ZONE_OP_SUCCESS; } /** @brief 读取一个区域中指定位置的数据 @param destination_addr[in] - 读取区域的地址 @param pData[in] - 指向存储的buff @param dataLen[in] - 读取的长度,单位字节 @return 错误代码 */ uint32_t Zone_Read(uint32_t destination_addr, uint32_t *pData, uint32_t dataLen) { uint32_t err_code; //错误代码 uint32_t zone_index; //是否有相对应的区域索引 uint32_t next_zone_addr; //下个区域的首地址 //验证是否申请了对应区域 err_code = Zone_GetIndex(destination_addr, &zone_index); if(err_code != ZONE_OP_SUCCESS)return err_code; if(pData != NULL && dataLen != 0) { next_zone_addr = zone[zone_index].zone_start_addr + zone[zone_index].page_num * FLASH_PAGE_SIZE; //不能读到下一个区域 if((destination_addr + dataLen) > next_zone_addr)return ZONE_ERROR_READ_FAIL; //读取 err_code = Read_N_Byte_flash(destination_addr, pData, dataLen); if(err_code != FLASH_OP_SUCCESS)return ZONE_ERROR_READ_FAIL; } return ZONE_OP_SUCCESS; } /** @brief 往一个区域指定位置写入数据(支持跨页写) @param destination_addr[in] - 写入区域的地址 @param pData[in] - 指向存储的buff @param dataLen[in] - 写入的长度 @return 错误代码 */ uint32_t Zone_Write(uint32_t destination_addr, uint32_t *pData, uint32_t dataLen) { uint32_t err_code; //错误代码 uint32_t zone_index; //是否有相对应的区域索引 uint32_t next_zone_addr; //下个区域的首地址 //验证是否申请了对应区域 err_code = Zone_GetIndex(destination_addr, &zone_index); if(err_code != ZONE_OP_SUCCESS)return err_code; if(pData != NULL && dataLen != 0) { next_zone_addr = zone[zone_index].zone_start_addr + zone[zone_index].page_num * FLASH_PAGE_SIZE; //不能写到下一个区域 if((destination_addr + dataLen) > next_zone_addr)return ZONE_ERROR_WRITE_FAIL; //写入 err_code = Write_N_4Byte_flash(destination_addr, pData, dataLen); if(err_code != FLASH_OP_SUCCESS)return ZONE_ERROR_WRITE_FAIL; } return ZONE_OP_SUCCESS; } /** @brief 擦除一个区域 @param zone_start_addr[in] - 分配的区域首地址 @return 错误代码 */ uint32_t Zone_Erase(uint32_t zone_start_addr) { uint32_t err_code; //错误代码 uint32_t zone_index; //是否有相对应的区域索引 uint16_t PageNum; //验证是否申请了对应区域 err_code = Zone_GetIndex(zone_start_addr, &zone_index); if(err_code != ZONE_OP_SUCCESS)return err_code; //一页一页擦除 for(uint8_t i = 0; i < zone[zone_index].page_num; i++) { //获取输入地址对应的页号 err_code = GetPageNum(zone[zone_index].zone_start_addr + i * FLASH_PAGE_SIZE, &PageNum); if(err_code != FLASH_OP_SUCCESS)return ZONE_ERROR_ERASE_FAIL; //根据页号擦除一整页 err_code = Erase_OnePage(PageNum); if(err_code != FLASH_OP_SUCCESS)return ZONE_ERROR_ERASE_FAIL; } return ZONE_OP_SUCCESS; } /** @brief 获取一个区域的总字节大小 @param zone_start_addr[in] - 分配的区域首地址 @param bytes[out] - 返回区域的字节大小 @return 错误代码 */ uint32_t Zone_GetByteSize(uint32_t zone_start_addr, uint32_t *bytes) { uint32_t err_code; //错误代码 uint32_t zone_index; //是否有相对应的区域索引 //验证是否申请了对应区域 err_code = Zone_GetIndex(zone_start_addr, &zone_index); if(err_code != ZONE_OP_SUCCESS)return err_code; if(bytes != NULL)*bytes = zone[zone_index].page_num * FLASH_PAGE_SIZE; return ZONE_OP_SUCCESS; }