FLASH存儲參數

在嵌入式項目中,經常使用FLASH來存儲關鍵的參數。這些參數影響整個設備系統的運行,保證參數存儲的正確性是至關重要,常用的方法是通過校驗參數存儲以及參數備份的方式去降低出錯的風險,本文將講述具體的實現方法。
在FLASH上開放兩個扇區,用於備份數據,可有效降低丟失數據風險。

#define SPI_FLASH_PARAM_SIZE	0x1000
#define SPI_FLASH_PARAM_BASE	(0x00000000U)
#define SPI_FLASH_PARAM_BKUP	(SPI_FLASH_PARAM_BASE + SPI_FLASH_PARAM_SIZE)

#define flash_param_base_erase	bsp_spi_flash_sector_erase(SPI_FLASH_SECTOR0)
#define flash_param_bkup_erase	bsp_spi_flash_sector_erase(SPI_FLASH_SECTOR1)

定義校驗參數的結構體,以參數ID識別類型,校驗存儲的參數值。

typedef struct{
	uint32_t param_id;	//參數ID
	uint16_t crc;		//校驗值
	uint16_t len;	    //參數長度
	uint8_t  data[1];
}single_save_t;

對於需要存儲的參數,可放在一個或多個結構體中,可在設備上電時導入存儲在FLASH裏的參數。

#define  PARAM_ID 0x12345678
typedef struct {
	uint8_t param_1;
	uint8_t param_2;
	uint8_t param_3;
	uint8_t param_4;
	uint8_t param_5;
}sys_param_t;
sys_param_t SysParam;
sys_param_t *gp_sys_param = &SysParam;

16位CRC校驗,可採用尋表的方式去校驗,另外其他的校驗也可以使用。具體的實現方法可另外到網上查詢。

存儲參數

FLASH的寫操作是需要先擦除,在存儲參數時可檢查存儲的參數是否需要修改。

/*
 * @brief 檢查參數
**/
int bsp_spi_flash_check_param(uint32_t readaddr, uint8_t *pbuffer, uint32_t num)
{
	int i = 0;
	uint8_t temp;
	uint8_t *pbuf = (uint8_t *)pbuffer;

	FLASH_SPI_CS_ENABLE();
	bsp_spi_flash_sendbyte(FLASH_READ);

	bsp_spi_flash_sendbyte((readaddr >> 16) & 0xFF);
	bsp_spi_flash_sendbyte((readaddr >> 8) & 0xFF);
	bsp_spi_flash_sendbyte(readaddr & 0xFF);

	for (i = 0; i < num; i++, pbuf++) {
		temp = bsp_spi_flash_sendbyte(0xff);
		if (temp != *pbuf) break;
	}
	FLASH_SPI_CS_DISABLE();
	if (i >= num) return 1;
	return 0;
}

/*
 * @brief 保存設備參數
**/
static int save_single_param(uint32_t param_id, uint32_t flash_addr, uint8_t *ram_addr, uint32_t len)
{
	single_save_t psave;

	psave.param_id = param_id;
	psave.len = len;
	psave.crc = CRC16(ram_addr, len);
	
	if (bsp_spi_flash_check_param(flash_addr, (uint8_t*)&psave, 8)) {
		if (bsp_spi_flash_check_param(flash_addr + 8, ram_addr, len)) {
			return 0;
		}
	}
	if (SPI_FLASH_PARAM_BASE == flash_addr) {
		flash_param_base_erase();
	} else {
		flash_param_bkup_erase();
	}

	bsp_spi_flash_buffer_write((uint8_t *)&psave, flash_addr, 8);
	bsp_spi_flash_buffer_write(ram_addr, flash_addr + 8, len);
	return 0;
}

/*
 * @brief 保存設備參數以及備份參數
**/
void save_param(void)
{
	save_single_param(PARAM_ID, SPI_FLASH_PARAM_BASE, (uint8_t *)&SysParam, sizeof(sys_param_t));
	save_single_param(PARAM_ID, SPI_FLASH_PARAM_BKUP, (uint8_t *)&SysParam, sizeof(sys_param_t));
}

參數導入

定義默認參數值,可在設備第一次運行時導入或者FLASH出錯時自動導入。

/*
 * @brief 可設置設備運行的默認參數
**/
void load_default_param(void)
{
	gp_sys_param->param_1 = 0;
	gp_sys_param->param_2 = 0;
	gp_sys_param->param_3 = 0;
	gp_sys_param->param_4 = 0;
	gp_sys_param->param_5 = 0;
}

/*
 * @brief 導入分區存儲參數
**/
int load_single_param(uint32_t param_id, uint32_t flash_addr, uint8_t *ram_addr, uint32_t maxlen)
{
	single_save_t psave;
	uint16_t crc;

	bsp_spi_flash_buffer_read((uint8_t*)&psave, flash_addr, 8);
	if (param_id != psave.param_id) return 1;
	if (maxlen != psave.len) return 1;

	bsp_spi_flash_buffer_read(ram_addr, flash_addr + 8, maxlen);
	crc = CRC16(ram_addr, maxlen);
	if (crc != psave.crc) return 1;

	return 0;
}

/*
 * @brief 導入存儲參數
 * @return 0:導入存儲參數成功,1:導入默認參數
**/
int load_param(void)
{
	if (load_single_param(PARAM_ID, SPI_FLASH_PARAM_BASE, (uint8_t*)&SysParam, sizeof(sys_param_t))) {
		if (load_single_param(PARAM_ID, SPI_FLASH_PARAM_BKUP, (uint8_t*)&SysParam, sizeof(sys_param_t))) {
			load_default_param();
			save_param();
			return 1;
		}
		save_param();
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章