├── README.md ├── tinyFlash.c ├── tinyFlash.h ├── tinyFlash_port.c └── tinyFlash_port.h /README.md: -------------------------------------------------------------------------------- 1 | # tinyFlash 2 | 3 | 一种轻量级的flash数据存储方案 4 | 5 | ## 设计原理 6 | 7 | 本方案采用两个扇区轮流使用的方法存储数据,每个扇区4096字节,扇区状态如下表: 8 | 9 | |扇区编号|使用状态|数据分布| 10 | |--------|----|---| 11 | |扇区一 |使用中|0xAA ·······················································| 12 | |扇区二 |未使用|0xFF ·······················································| 13 | 14 | 使用中的扇区数据分布如下表: 15 | 16 | |扇区头部|K1|V1|K2|V2|.....|Kn|Vn| 17 | |--------|----|---|----|----|----|-----|-----| 18 | |32字节 |3字节|n字节|3字节|n字节|.....|3字节|n字节| 19 | 20 | 每个K-V数据存储形式如下表: 21 | 22 | |第一字节|第二字节|第三字节|n个字节| 23 | |--------|----|---|----| 24 | |Key |~Key|Len|Len个字节数据内容| 25 | 26 | 第一个字节存放的是数据的Key,取值范围是 0x01 - 0xFE 27 | 28 | 第二个字节的数据为Key取反,如果第二个字节的数据为0x00,表示该处存储的数据已被废弃 29 | 30 | 第三个自己表示数据长度,取值范围是0x01 - 0xFF 31 | 32 | 之后的字节是数据的内容,最长不得超过0xFF 33 | 34 | ## 使用示例 35 | 36 | #define My_DATA_INDEX = 1 37 | 38 | tinyFlash_Init(); 39 | char * _data = "Hello World"; 40 | 41 | tinyFlash_Write(My_DATA_INDEX, _data, sizeof(_data)); 42 | 43 | char _buf[128] = { 0 } 44 | unsigned char _len = 128; 45 | 46 | tinyFlash_Read(My_DATA_INDEX, _buf, &_len); 47 | 48 | printf(_buf); 49 | 50 | 51 | 52 | ## API介绍 53 | 54 | ------------------------------------------------------------------------------- 55 | bool tinyFlash_Init(); 56 | 57 | 函数功能:初始化tinyFlash 58 | 59 | 返回值:true 成功 60 | 61 | ------------------------------------------------------------------------------- 62 | int tinyFlash_Read(unsigned char KEY, unsigned char * buf, unsigned char * len); 63 | 64 | 函数功能:从tinyFlash中读取Key中存储的数据内容,数据长度,或者删除数据 65 | 66 | 参数 KEY:要读取的Key 67 | 68 | 参数 buf:Key中存储的数据内容的传出指针,如果该指针为NULL,则只传输数据长度 69 | 70 | 参数 len: 传入的是最大能接受的数据长度,传输的是读取到的实际数据长度,如果为NULL则为删除该KEY 71 | 72 | 返回值: 0 操作成功,其他值 操作失败 73 | 74 | ------------------------------------------------------------------------------ 75 | int tinyFlash_Write(unsigned char KEY, unsigned char * buf, unsigned char len); 76 | 77 | 函数功能: 向tinyFlash中存储一个数据 78 | 79 | 参数 KEY: 要存储的数据的Key值 80 | 81 | 参数 buf: 要存储的数据内容 82 | 83 | 参数 len: 要存储的数据长度 84 | 85 | 返回值:0 操作成功,其他值 操作失败 86 | 87 | ------------------------------------------------------------------------------ 88 | void tinyFlash_Format(void); 89 | 90 | 函数功能:格式化tinyFlash数据区域,擦除全部tinyFlash扇区 91 | 92 | -------------------------------------------------------------------------------- 93 | 94 | ## 移植及配置 95 | 移植只需要在```tinyFlash_port.c```中实现如下三个函数: 96 | 97 | int _flash_write(unsigned long addr, unsigned long len, unsigned char *buf); 98 | int _flash_read(unsigned long addr, unsigned long len, unsigned char *buf); 99 | int _flash_sector_erase(unsigned long addr); 100 | 101 | 源码中已根据TLSR825X平台实现了相关函数。 102 | 103 | ### 配置说明 104 | 所有的配置项都在```tinyFlash_port.h```中,配置示例如下: 105 | 106 | #define TINY_START_ADDR 0x7A000 //tinyFlash起始地址 107 | #define TINY_SECTOR_SIZE 4096 //flash扇区大小 108 | #define TINY_BUFFER_SIZE 256 //tiny缓冲区大小 109 | 110 | #define TINY_SECHAD_SIZE 32 //记录扇区使用情况的扇区头大小 111 | 112 | ## 接下来的工作 113 | - 多扇区支持 114 | - 数据加密 115 | - 优化查找及存储速度 116 | - 意外掉电防护 -------------------------------------------------------------------------------- /tinyFlash.c: -------------------------------------------------------------------------------- 1 | #include "tinyFlash.h" 2 | 3 | static unsigned char _buf[TINY_BUFFER_SIZE] = { 0 }; 4 | 5 | static unsigned long tinyFlash_Used_Addr = 0; //当前使用的扇区地址 6 | static unsigned long tinyFlash_Swap_Addr = 0; //当前未使用的扇区地址 7 | 8 | bool tinyFlash_Init() 9 | { 10 | memset(_buf, 0 , TINY_BUFFER_SIZE); 11 | 12 | _flash_read(TINY_START_ADDR, TINY_BUFFER_SIZE, _buf); 13 | 14 | if(_buf[0] != 0XFF) //第一个扇区在使用 15 | { 16 | tinyFlash_Used_Addr = TINY_START_ADDR; 17 | tinyFlash_Swap_Addr = TINY_START_ADDR + TINY_SECTOR_SIZE; 18 | } 19 | else //第二个扇区在使用 20 | { 21 | tinyFlash_Used_Addr = TINY_START_ADDR + TINY_SECTOR_SIZE; 22 | tinyFlash_Swap_Addr = TINY_START_ADDR; 23 | } 24 | 25 | return true; 26 | } 27 | 28 | int tinyFlash_Read(unsigned char KEY, unsigned char * outbuf, unsigned char * len) 29 | { 30 | unsigned long _addr_start = tinyFlash_Used_Addr + TINY_SECHAD_SIZE;; 31 | unsigned long _addr_end = tinyFlash_Used_Addr + TINY_SECTOR_SIZE; 32 | 33 | while(1) 34 | { 35 | if(_addr_start > _addr_end -3) //该扇区查找完毕 36 | { 37 | break; 38 | } 39 | 40 | _flash_read(_addr_start, TINY_BUFFER_SIZE, _buf); 41 | 42 | if(_buf[0] == KEY) //目标KEY 43 | { 44 | if(_buf[1] == (KEY ^ 0xFF)) //该KEY正在使用中 45 | { 46 | if(len == NULL) //删除操作 47 | { 48 | _buf[0] = 0; 49 | _flash_write(_addr_start + 1 , 1 , _buf); 50 | } 51 | else if(outbuf == NULL) //读取长度 52 | { 53 | *len = _buf[2]; 54 | } 55 | else //读取数据 56 | { 57 | memcpy(outbuf, _buf + 3, _buf[2]); 58 | *len = _buf[2]; 59 | } 60 | 61 | return 0; 62 | } 63 | else //该KEY已被删除 64 | { 65 | _addr_start += (_buf[2] + 3); 66 | continue; 67 | } 68 | } 69 | else if((_buf[0] != 0) && (_buf[0] != 0xff)) //其他KEY 70 | { 71 | _addr_start += (_buf[2] + 3); 72 | continue; 73 | } 74 | else //读取到扇区尾部未使用的区域 75 | { 76 | break; 77 | } 78 | } 79 | 80 | return -1; 81 | } 82 | 83 | int tinyFlash_Write(unsigned char KEY, unsigned char * buf, unsigned char len) 84 | { 85 | tinyFlash_Read(KEY, NULL, NULL); 86 | 87 | unsigned long _addr_start = tinyFlash_Used_Addr + TINY_SECHAD_SIZE;; 88 | unsigned long _addr_end = tinyFlash_Used_Addr + TINY_SECTOR_SIZE; 89 | 90 | unsigned long dirty_data_len = 0; 91 | 92 | while(1) 93 | { 94 | if(_addr_start > _addr_end -3 - len) //该扇区已查找完毕,无可用空间 95 | { 96 | if(dirty_data_len > 0) //当前扇区中存在脏数据 97 | { 98 | tinyFlash_Swap(); //交换新旧扇区,清理脏数据 99 | 100 | _addr_start = tinyFlash_Used_Addr + TINY_SECHAD_SIZE;; 101 | _addr_end = tinyFlash_Used_Addr + TINY_SECTOR_SIZE; 102 | } 103 | else //无可用空间 104 | { 105 | return -1; 106 | } 107 | } 108 | 109 | _flash_read(_addr_start, TINY_BUFFER_SIZE, _buf); 110 | 111 | if(_buf[0] == 0xFF) //该区域可使用 112 | { 113 | //at_print_hexstr(&_addr_start, 2); 114 | 115 | _buf[0] = KEY; 116 | _buf[1] = (KEY ^ 0xFF); 117 | _buf[2] = len; 118 | memcpy(_buf +3, buf, len); 119 | 120 | _flash_write(_addr_start, len + 3, _buf);//写入数据 121 | 122 | return 0; 123 | } 124 | else if(_buf[0] != 0) //已存储其他KEY 125 | { 126 | if(_buf[1] == 0) //脏数据 127 | { 128 | dirty_data_len += (_buf[2] + 3); 129 | } 130 | else if (_buf[1] == (KEY ^ 0xFF)) //当前要写入的Key 131 | { 132 | _buf[0] = 0; 133 | _flash_write(_addr_start + 1 , 1 , _buf);//删除数据 134 | } 135 | 136 | _addr_start += (_buf[2] + 3); 137 | 138 | continue; 139 | } 140 | else //读取到错误的数据 141 | { 142 | break; 143 | } 144 | } 145 | 146 | return 1; 147 | } 148 | 149 | void tinyFlash_Swap() //扇区使用完了,需要清理数据,才能存储别的数据 150 | { 151 | unsigned long _addr_start = tinyFlash_Used_Addr + TINY_SECHAD_SIZE; //当前使用的扇区的起始地址 152 | unsigned long _addr_end = tinyFlash_Used_Addr + TINY_SECTOR_SIZE; //当前使用的扇区的结束地址 153 | 154 | unsigned long _new_addr_start = tinyFlash_Swap_Addr + TINY_SECHAD_SIZE; //将要使用的扇区的起始地址 155 | 156 | unsigned long tmp = 0; 157 | 158 | while(1) 159 | { 160 | if(_addr_start > _addr_end -3) //该扇区已查找完毕,无可用空间 161 | { 162 | break; 163 | } 164 | 165 | _flash_read(_addr_start, TINY_BUFFER_SIZE, _buf); 166 | 167 | if(_buf[0] == 0xFF) //数据转移完毕 168 | { 169 | break; 170 | } 171 | else if(_buf[0] == 0) //读取到了错误的数据 172 | { 173 | break; 174 | } 175 | else //读取到正确的Key数据 176 | { 177 | _addr_start += (_buf[2] + 3); 178 | 179 | if(_buf[1] == (_buf[0] ^ 0xFF)) //数据仍有效(未删除) 180 | { 181 | tmp = _new_addr_start & 0xff; 182 | 183 | _flash_write(_new_addr_start, _buf[2] + 3, _buf); 184 | _new_addr_start += (_buf[2] + 3); 185 | } 186 | continue; 187 | } 188 | } 189 | 190 | _buf[0] = 0xaa; 191 | _flash_write(tinyFlash_Swap_Addr, 1, _buf); //将新扇区标记为在使用 192 | _flash_sector_erase(tinyFlash_Used_Addr); //擦除旧扇区 193 | 194 | _new_addr_start = tinyFlash_Swap_Addr; 195 | 196 | tinyFlash_Swap_Addr = tinyFlash_Used_Addr; 197 | tinyFlash_Used_Addr = _new_addr_start; 198 | } 199 | 200 | /*擦除所有扇区*/ 201 | void tinyFlash_Format(void) 202 | { 203 | _flash_sector_erase(tinyFlash_Used_Addr);//擦除旧扇区 204 | _flash_sector_erase(tinyFlash_Swap_Addr);//擦除旧扇区 205 | } -------------------------------------------------------------------------------- /tinyFlash.h: -------------------------------------------------------------------------------- 1 | #ifndef __tiny_Flash__ 2 | #define __tiny_Flash__ 3 | 4 | #include "tinyFlash_port.h" 5 | 6 | //tinyFlash提供了如下API供应用程序使用 7 | bool tinyFlash_Init(); 8 | int tinyFlash_Read(unsigned char KEY, unsigned char * buf, unsigned char * len); 9 | int tinyFlash_Write(unsigned char KEY, unsigned char * buf, unsigned char len); 10 | 11 | #endif -------------------------------------------------------------------------------- /tinyFlash_port.c: -------------------------------------------------------------------------------- 1 | #include "tinyFlash_port.h" 2 | 3 | //Flash写入函数 4 | int _flash_write(unsigned long addr, unsigned long len, unsigned char *buf) 5 | { 6 | unsigned long tmp = addr & 0xff; 7 | 8 | if(tmp + len > 0x100) //跨扇区写入 9 | { 10 | flash_write_page(addr, 0x100 - tmp, buf); 11 | 12 | tmp = (0x100 - tmp); 13 | 14 | len -= tmp; 15 | 16 | buf += tmp; 17 | 18 | addr &= 0xffffff00; 19 | 20 | addr += 0x100; 21 | } 22 | 23 | flash_write_page(addr, len, buf); 24 | 25 | return 0; 26 | } 27 | 28 | int _flash_read(unsigned long addr, unsigned long len, unsigned char *buf) 29 | { 30 | flash_read_page(addr, len, buf); 31 | return 0; 32 | } 33 | 34 | int _flash_sector_erase(unsigned long addr) 35 | { 36 | flash_erase_sector(addr); 37 | return 0; 38 | } -------------------------------------------------------------------------------- /tinyFlash_port.h: -------------------------------------------------------------------------------- 1 | /**************包含平台相关系统驱动头文件*********/ 2 | #include "tl_common.h" 3 | #include "drivers.h" 4 | 5 | /*********如下配置项需根据所在平台参数自行配置****/ 6 | 7 | #define TINY_START_ADDR 0x7A000 //tinyFlash起始地址 8 | #define TINY_SECTOR_SIZE 4096 //flash扇区大小 9 | #define TINY_BUFFER_SIZE 256 //tiny缓冲区大小 10 | 11 | #define TINY_SECHAD_SIZE 32 //记录扇区使用情况的扇区头大小 12 | 13 | /*********移植tinyFlash需提供如下函数************/ 14 | int _flash_write(unsigned long addr, unsigned long len, unsigned char *buf); 15 | int _flash_read(unsigned long addr, unsigned long len, unsigned char *buf); 16 | int _flash_sector_erase(unsigned long addr); --------------------------------------------------------------------------------