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;
}
### 关于ESP32-S3-N16R8芯片Flash存储的相关参数配置 ESP32-S3-WROOM-1-N16R8 是一款基于乐鑫 ESP32-S3 的模组,支持外部 PSRAM 和 SPI Flash 存储器。以下是关于该芯片 Flash 存储相关的参数配置说明: #### 1. **Flash 容量** - 默认情况下,ESP32-S3-WROOM-1-N16R8 模组配备了一个 16MB (128Mb) 的 SPI Flash 芯片[^1]。 #### 2. **Flash 工作模式** - 支持 Quad SPI 模式以及 Dual SPI 模式。 - 在 Quad SPI 模式下,数据传输速率更高,适合用于加载固件和运行程序。 #### 3. **Flash 地址映射** - Flash 的地址空间通常被划分为多个区域,包括引导区、分区表、应用程序固件和其他自定义数据区域。 - 具体的分区布局可以在 `partition_table` 文件中设置,常见的默认分区表文件为 `default_4mb_with_otadata.csv` 或者更大的容量版本。 #### 4. **Flash 配置命令** - 使用 IDF 提供的工具可以轻松完成 Flash 的烧录操作。例如,在编译完成后通过以下命令写入 Flash: ```bash esptool.py --chip esp32s3 write_flash 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/your_firmware.bin ``` #### 5. **PSRAM 配合使用** - 如果启用了 PSRAM,则需要在 SDKConfig 中启用相关选项以优化内存分配策略。具体来说,需开启 `CONFIG_SPIRAM_USE` 并调整堆管理方式。 #### 6. **SDKConfig 设置** - 在项目的 `sdkconfig` 文件中,可进一步定制 Flash 的工作频率(如 40MHz 或 80MHz),并指定是否启用加密功能或其他高级特性。 --- ### 示例代码:初始化 I2C 接口并与 ADXL345 进行通信 虽然问题是针对 Flash 参数配置,但考虑到引用中的相关内容涉及到了 ADXL345 加速度计的应用场景,这里提供一段简单的 Arduino 初始化 I2C 接口并与 ADXL345 设备交互的示例代码作为补充[^2]: ```cpp #include <Wire.h> #define ADXL345_ADDRESS 0x53 void setup() { Wire.begin(); // 初始化I2C总线 Serial.begin(9600); // 开始串口通讯 // 向ADXL345发送启动测量指令 Wire.beginTransmission(ADXL345_ADDRESS); Wire.write(0x2D); // Power Control Register Wire.write(0x08); // Measurement mode Wire.endTransmission(); } void loop() { int x, y, z; // 获取X轴加速度值 Wire.requestFrom(ADXL345_ADDRESS, 6); while(Wire.available() < 6); x = Wire.read() | Wire.read() << 8; y = Wire.read() | Wire.read() << 8; z = Wire.read() | Wire.read() << 8; Serial.print("X="); Serial.print(x); Serial.print(", Y="); Serial.print(y); Serial.print(", Z="); Serial.println(z); delay(100); } ``` 此代码展示了如何利用 I2C 协议读取 ADXL345 数据,并可通过类似方法扩展到其他外设应用上。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值