数据存储的负载均衡实现
需求分析
我们需要将一个重要的数据存储在片内flash中,并且会长期的对这个数据进行读写,由此一来时间一长这一个地址就会被写坏了。为了解决这一问题,我们可以划分一片内存用来做负载均衡,将原来只写一个地址的数据均衡到一片内存中,以此来增加硬件使用寿命。
详细解决方案如图所示:
每次存储时,会将8个字节的数据段存储到片内flash中(前四个字节用于校验,后四个字节才是真实数据)。因为我使用的芯片,一个扇区大小为512字节,同时有扇区擦除库函数。为了方便我就划分了两片512字节的内存分别用作主区和备份区。每一次存储数据都会向后偏移8个字节,直到写满(即存储64次),然后擦除。
代码实现
计算偏移量函数
/**
* @brief Get the offset object
* @param flash_buff 存储数组
* @return unsigned int 偏移量
*/
static unsigned int get_offset(uint8_t *flash_buff)
{
unsigned int count = 0;
for (int i = 0; i < GATE_FLASH_SIZE; i += 8) {
if (flash_buff[i] == 0x55) {
count += 8;
}
}
if (count >= GATE_FLASH_SIZE) { // 检查是否写满了一页
count = 0;
}
return count;
}
和校验
/**
* @brief 和校验函数
* @param data 校验数据
* @param length 数据长度
* @return unsigned char 返回的和校验值
*/
static unsigned char checksum(unsigned char* data, int length) {
unsigned char checksum = 0;
for (int i = 0; i < length; i++) {
checksum += data[i];
}
return checksum;
}
写入函数
/**
* @brief 开度写入函数
* @param page_offset 偏移量
* @param gate 当前开度
*/
void gate_data_write(int gate)
{
uint8_t write_buff[8];
uint8_t current_open[4];
uint8_t flash_buff[GATE_FLASH_SIZE] = {0};
uint32_t offset1 = 0;
uint32_t offset2 = 0;
write_buff[0] = 0x55;
write_buff[1] = 0xFF;
write_buff[3] = 0xAA;
hal_flash_read(GATE_SAVE_BASE1_DATA, flash_buff, GATE_FLASH_SIZE);
offset1 = get_offset(flash_buff);
memset(flash_buff, 0, sizeof(flash_buff));
hal_flash_read(GATE_SAVE_BASE2_DATA, flash_buff, GATE_FLASH_SIZE);
offset2 = get_offset(flash_buff);
memset(flash_buff, 0, sizeof(flash_buff));
if (offset1 == 0) { // 判断是否写满了
hal_flash_erase(GATE_SAVE_BASE1_DATA, GATE_FLASH_SIZE); // 擦除主区
int_to_byte4(gate, current_open);
for (int i = 0; i < 4; i++) {
write_buff[i + 4] = current_open[i];
}
write_buff[2] = checksum(current_open, 4);
memset(current_open, 0, sizeof(current_open));
hal_flash_write_nocheck(GATE_SAVE_BASE1_DATA, write_buff, sizeof(write_buff)); // 写入主区
hal_flash_erase(GATE_SAVE_BASE2_DATA, GATE_FLASH_SIZE); // 擦除备份区
hal_flash_write_nocheck(GATE_SAVE_BASE2_DATA, write_buff, sizeof(write_buff)); // 写入备份区
memset(write_buff, 0, sizeof(write_buff));
} else {
int_to_byte4(gate, current_open);
for (int i = 0; i < 4; i++) {
write_buff[i + 4] = current_open[i];
}
write_buff[2] = checksum(current_open, 4);
memset(current_open, 0, sizeof(current_open));
uint32_t curr_addr1 = GATE_SAVE_BASE1_DATA + offset1; // 计算主区当前写入的起始地址
hal_flash_write_nocheck(curr_addr1, write_buff, sizeof(write_buff)); // 写入主区
uint32_t curr_addr2 = GATE_SAVE_BASE2_DATA + offset2; // 计算备份区当前写入的起始地址
hal_flash_write_nocheck(curr_addr2, write_buff, sizeof(write_buff)); // 写入备份区
memset(write_buff, 0, sizeof(write_buff));
}
}
读取函数
/**
* @brief 闸门开度读取函数
* @param page_offset 偏移量
* @return int 闸门开度
*/
int gate_data_read(void)
{
int gate;
uint8_t read_buff[8];
uint8_t read_data[4];
uint32_t offset1 = 0;
uint32_t offset2 = 0;
uint8_t flash_buff[GATE_FLASH_SIZE] = {0};
hal_flash_read(GATE_SAVE_BASE1_DATA, flash_buff, GATE_FLASH_SIZE);
offset1 = get_offset(flash_buff);
memset(flash_buff, 0, sizeof(flash_buff));
if(offset1 == 0) {
hal_flash_read(GATE_SAVE_BASE1_DATA + 0x1F8, read_buff, sizeof(read_buff));
} else {
hal_flash_read(GATE_SAVE_BASE1_DATA + offset1, read_buff, sizeof(read_buff)); // 读取主区最新数据
}
memcpy(read_data, read_buff + 4, sizeof(read_data));
if(read_buff[2] != checksum(read_data, 4)) {
memset(read_buff, 0, sizeof(read_buff));
memset(read_data, 0, sizeof(read_data));
hal_flash_read(GATE_SAVE_BASE2_DATA, flash_buff, GATE_FLASH_SIZE);
offset2 = get_offset(flash_buff);
memset(flash_buff, 0, sizeof(flash_buff));
if(offset2 == 0) {
hal_flash_read(GATE_SAVE_BASE2_DATA + 0x1F8, read_buff, sizeof(read_buff));
} else {
hal_flash_read(GATE_SAVE_BASE2_DATA + offset1, read_buff, sizeof(read_buff));
}
memcpy(read_data, read_buff + 4, sizeof(read_data));
if(read_buff[2] != checksum(read_data, 4)) {
if(offset1 == 0) {
memset(read_data, 0, sizeof(read_data));
} else {
memset(read_buff, 0, sizeof(read_buff));
memset(read_data, 0, sizeof(read_data));
if(offset2 == 0) {
hal_flash_read(GATE_SAVE_BASE1_DATA + 0x1F8 - 8, read_buff, sizeof(read_buff)); // 读取主区上一个数据
} else {
hal_flash_read(GATE_SAVE_BASE1_DATA + offset1 - 8, read_buff, sizeof(read_buff)); // 读取备份区上一个数据
}
memcpy(read_data, read_buff + 4, sizeof(read_data));
}
}
}
gate = byte4_to_int(read_data);
memset(read_buff, 0, sizeof(read_buff));
memset(read_data, 0, sizeof(read_data));
return gate;
}