Flash
Flash作为一种非易失性存储器,与RAM不同。RAM可以直接读写,直接执行代码或存储数据。而flash的写入操作只能在空的或已擦除的单元内进行。因此,在执行flash写访问之前常常需要先执行擦除访问。
备注
Flash具有最高100,000次的编程次数限制,如果频繁对某个区块擦写,将容易产生坏块。当用户需要利用flash存储数据时,Flash驱动程序的接口并不首推给APP使用,更建议使用 FTL 接口。
Flash布局
RTL87x2G集成flexible memory controller(FMC),支持外挂SPI Flash。FMC支持最大的地址映射空间为64M bytes,对应地址空间0x04000000 ~ 0x07FFFFFF。
Flash布局分两级来设置,包括High Level Flash map和OTA Bank map,具体见: 调整Flash布局。
High Level Flash Map
RTL87x2G SDK中,High Level Flash Map由11部分组成,包括Reserved,OEM Header(即config file的存储空间),Bank0 Boot Patch,Bank1 Boot Patch,OTA Bank 0,OTA Bank 1,Bank0 Secure APP(optional),Bank1 Secure APP(optional),OTA Tmp,FTL和APP Defined Section。Flash布局 说明如下。
内存段 |
起始地址 |
大小 |
作用 |
---|---|---|---|
Reserved |
0x00400000 |
0x1000 |
系统保留区域 |
OEM Header |
0x00401000 |
0x1000 |
config信息存储区域,包括蓝牙地址,AES Key,和用户可修改的Flash布局等 |
Bank0 Boot Patch |
可变 (由eFuse决定) |
可变 (由eFuse决定) |
Flash boot loader,Bank0 Boot Patch和Bank1 Boot Patch作用相同,互为备份区 |
Bank1 Boot Patch |
可变 (由eFuse决定) |
可变 (由eFuse决定) |
Flash boot loader |
OTA Bank0 |
可变 (由eFuse决定) |
可变 (由eFuse决定) |
存储数据和代码运行,进一步细分为OTA Header,System Patch,BT Stack Patch,BT Host,APP,APP Data1,APP Data2,APP Data3,APP Data4,APP Data5,APP Data6。如果选择不切换bank的OTA方案,OTA_TMP区用作OTA备份区;相反,如果选择切换bank的OTA方案,OTA bank0和OTA bank1作用相同,互为备份区 |
OTA Bank1 |
可变 (由eFuse决定) |
可变 (由eFuse决定) |
选择切换bank的OTA方案时才存在,假设OTA Bank0为运行区,则OTA Bank1为备份区 相反,如果OTA Bank1为运行区,则OTA Bank0为备份区,其大小必须和OTA Bank0一致 |
Bank0 Secure APP |
可变 (由eFuse决定) |
可变 (由eFuse决定) |
TrustZone enable下才需要,Secure APP中开启TrustZone,Bank0 Secure APP 和Bank1 Secure APP作用相同,互为备份区 |
Bank1 Secure APP |
可变 (由eFuse决定) |
可变 (由eFuse决定) |
TrustZone enable下才需要 |
OTA TMP |
可变 (由eFuse决定) |
可变 (由eFuse决定) |
不切换bank方式下,作为OTA备份区使用,大小必须不小于OTA bank0最大的image大小 |
FTL |
可变 (由eFuse决定) |
可变 (由eFuse决定) |
该区域空间支持以逻辑地址访问flash,用户可以以最小4bytes为单位读写flash |
APP Defined Section |
可变 (由eFuse决定) |
可变 (由eFuse决定) |
Flash剩余未划分区域,用户可以自由使用,但不可以进行OTA升级 |
OTA Bank Map
RTL87x2G SDK中,OTA Bank中包括12种类型的image,分别是OTA Header,System Patch,BT Stack Patch,BT Host,APP,APP Config File, APP Data1,APP Data2,APP Data3,APP Data4,APP Data5,APP Data6。OTA Bank这一级的布局是由其中的OTA header决定,通过Flashmap Generate Tool可以生成不同OTA Bank布局的OTA header。
内存段 |
起始地址 |
大小 |
作用 |
---|---|---|---|
OTAHeader |
由OEM header决定 |
4KB |
存储OTA header的版本信息、Bank中各image的起始地址和大小 |
System Patch |
由OTA header决定 |
可变 |
对non-secure rom中系统的优化和扩展代码 |
BT Stack Patch |
由OTA header决定 |
可变 |
蓝牙controller协议栈优化和扩展代码 |
BT Host |
由OTA header决定 |
可变 |
实现HCI及以上蓝牙协议栈部分代码 |
APP |
由OTA header决定 |
可变 |
开发方案的运行代码 |
App Config File |
由OTA header决定 |
可变 |
App配置信息 |
App Data1 |
由OTA header决定 |
可变 |
开发方案中需要升级的数据区 |
App Data2 |
由OTA header决定 |
可变 |
开发方案中需要升级的数据区 |
App Data3 |
由OTA header决定 |
可变 |
开发方案中需要升级的数据区 |
App Data4 |
由OTA header决定 |
可变 |
开发方案中需要升级的数据区 |
App Data5 |
由OTA header决定 |
可变 |
开发方案中需要升级的数据区 |
App Data6 |
由OTA header决定 |
可变 |
开发方案中需要升级的数据区 |
调整Flash布局
Flash布局设置分为两级,其中High Level Flash map是由config文件决定,而OTA Bank map是由OTA Header文件决定。用户可通过MPTool中 Config Set 选项加载自定义的flash布局文件并生成config文件。
为方便用户使用,Realtek提供Flashmap Generate Tool用于生成flash布局文件(flash map.ini
和 flash_map.h
)。flash map.ini
文件可以导入到MP Tool,用于生成config file和OTA header。而 flash_map.h
文件则需要拷贝到APP的工程目录下,编译出正确可运行的APP image。
但与此同时,必须遵从以下的原则来调整flash布局。
如果选择支持bank切换的OTA方案,保证OTA bank0的大小等于OTA bank1的大小,并且将OTA TMP区域的大小设置为0。
如果选择支持bank切换的OTA方案,可以使用不同的OTA bank布局来生成Bank0 OTA Header file和Bank1 OTA Header file,但是OTA bank0和bank1大小不可变,并且不小于OTA bank内各个image大小的总和。
如果选择不支持bank切换的OTA方案,将OTA bank1的大小设置为0,OTA tmp区域的大小不小于OTA bank0中最大的image的大小。
原始的APP Data bin文件需要经过RTL87x2G SDK中提供的App Data tool处理之后才可以通过MPTool烧录和MPPackTool打包。该工具路径在sdk/tools/AppData,处理之后会添加一个满足特定格式的1280Byte的image header。注意,OTA bank内的APP Data1、APP Data2、APP Data3、APP Data4、APP Data5或APP Data6区域是存储需要进行OTA的App Data。如果数据无需升级,应当放在“APP Defined Section”区域。
为了将所有的code区域都上锁,以防止非预期的flash写入和擦除操作,尽可能地将OTA bank1结束地址相对于flash起始地址的偏移对齐到实际所选用的flash所支持的某个保护级别对应的范围,如64KB、128KB、256KB、512KB等。
因为存放在OTA bank内的APP Data1、APP Data2、APP Data3、APP Data4、APP Data5或APP Data6区域的数据是有可能落在flash上锁范围内的,所以该区域内一般是存储只读的数据。如需存储要改写的数据应该放在“APP Defined Section”区域。
Flash布局示例
基于上文所述的调整flash布局的规则,本节提供不切bank方案和切bank方案下的Flash布局示例。
不切bank方案Flash布局示例
flash总大小为1MB的示例布局 |
大小(字节) |
起始地址 |
---|---|---|
Reserved |
4K |
0x04000000 |
OEM Header |
4K |
0x04001000 |
Bank0 Boot Patch |
32K |
0x04002000 |
Bank1 Boot Patch |
32K |
0x0400A000 |
OTA Bank0 |
612K |
0x04012000 |
|
4K |
0x04012000 |
|
32K |
0x04013000 |
|
60K |
0x0401B000 |
|
212K |
0x0402A000 |
|
304K |
0x0405F000 |
|
4K |
0x040AC000 |
|
0K |
0x040AD000 |
|
0K |
0x040AD000 |
|
0K |
0x040AD000 |
|
0K |
0x040AD000 |
|
0K |
0x040AD000 |
|
0K |
0x040AD000 |
OTA Bank1(等于0) |
0K |
0x040AD000 |
Bank0 Secure APP code |
0K |
0x040AD000 |
Bank0 Secure APP Data |
0K |
0x040AD000 |
Bank1 Secure APP code |
0K |
0x040AD000 |
Bank1 Secure APP Data |
0K |
0x040AD000 |
OTA Temp |
312K |
0x040AD000 |
FTL |
16K |
0x040FB000 |
APP Defined Section |
4K |
0x040FF000 |
切bank方案Flash布局示例
flash总大小为2MB的示例布局 |
大小(字节) |
起始地址 |
---|---|---|
Reserved |
4K |
0x04000000 |
OEM Header |
4K |
0x04001000 |
Bank0 Boot Patch |
32K |
0x04002000 |
Bank1 Boot Patch |
32K |
0x0400A000 |
OTA Bank0 |
596K |
0x04012000 |
|
4K |
0x04012000 |
|
32K |
0x04013000 |
|
60K |
0x0401B000 |
|
212K |
0x0402A000 |
|
284K |
0x0405F000 |
|
4K |
0x040A6000 |
|
0K |
0x040A7000 |
|
0K |
0x040A7000 |
|
0K |
0x040A7000 |
|
0K |
0x040A7000 |
|
0K |
0x040A7000 |
|
0K |
0x040A7000 |
OTA Bank1 |
596K |
0x040A7000 |
|
4K |
0x040A7000 |
|
32K |
0x040A8000 |
|
60K |
0x040B0000 |
|
212K |
0x040BF000 |
|
284K |
0x040F4000 |
|
4K |
0x0413B000 |
|
0K |
0x0413C000 |
|
0K |
0x0413C000 |
|
0K |
0x0413C000 |
|
0K |
0x0413C000 |
|
0K |
0x0413C000 |
|
0K |
0x0413C000 |
Bank0 Secure APP code |
0K |
0x0413C000 |
Bank0 Secure APP Data |
0K |
0x0413C000 |
Bank1 Secure APP code |
0K |
0x0413C000 |
Bank1 Secure APP Data |
0K |
0x0413C000 |
OTA Temp |
32K |
0x0413C000 |
FTL |
16K |
0x04148000 |
APP Defined Section |
736K |
0x040FF000 |
FTL
FTL(Flash Translation Layer)是基于flash driver实现的软件抽象层,用于用户读写flash数据。FTL物理空间的位置可以查看 flash 布局。FTL的目的是简化对flash中数据的修改过程。
如果不使用FTL,在用户需要修改flash上的数据时,需要先擦除flash。频繁修改flash时,会在擦除上浪费大量时间。而FTL用逻辑地址代替物理地址来访问flash,在用户进行数据修改时,原先的数据不会被直接修改,而是将新的数据会写入新的物理地址,并且逻辑地址会指向该物理地址。在这种方式下,可以避免频繁擦除flash,节约修改数据所需时间。
当FTL检测到没有足够的空间写入新记录时,会触发垃圾回收(GC,Garbage Collection)机制,对过期或不再被使用的记录进行擦除和回收。FTL由于循环使用flash空间、均匀分布擦写操作,可以避免某些块过早失效,达到磨损均衡的效果。
目前,FTL支持v1和v2版本。v1版本包含上述功能的完整实现。在v1的基础上,v2版本在最大存储空间和flash利用率方面进行了改进,并且支持创建“module”划分逻辑空间。
备注
FTL适用于需要频繁改写的数据,一方面API接口更为简单,另一方面有助于延长flash使用寿命(磨损均衡)。
如果数据量较大、只读(或偶尔改写)、不需要支持OTA升级,推荐使用flash API将数据存储在“APP Defined Section”区域。
如果数据量较大、只读(或偶尔改写)、需要支持OTA升级,推荐将数据存储在OTA bank内的App Data1、App Data2、App Data3、App Data4、App Data5、App Data6和secure app data区域。
FTL v1
SDK v1.2.0及以前版本默认支持FTL v1,在后续SDK版本如需使用FTL v1,请参考以下步骤:
打开SDK根目录。
拷贝
ftl_v1\ftl.h
到bsp\sdk_lib\inc\
,替换目标路径下已有 ftl.h 文件。如果使用 GCC 编译,将
ftl_v1\librtl87x2g_sdk.a
拷贝到bsp\sdk_lib\lib\rtl87x2g\gcc\
,替换目标路径下已有librtl87x2g_sdk.a
文件。如果使用 MDK 编译,将
ftl_v1\rtl87x2g_sdk.lib
拷贝到bsp\sdk_lib\lib\rtl87x2g\mdk\
,替换目标路径下已有rtl87x2g_sdk.lib
文件。重新编译APP工程。
FTL空间的功能划分
FTL空间按照其功能划分为以下两块存储空间,以默认设置的FTL物理空间大小为16K为例。
BT存储空间
逻辑地址范围 [0x0000, 0x0D00),但是这部分空间的大小可通过otp_config.h参数调整。(当前SDK暂时未支持)
用于存储BT信息,例如设备地址,link key等。
详细请参考 LE Host。
APP存储空间
逻辑地址范围 [0x0D00, 0x17F0)。
用于存储APP的信息。
可用以下API读/写APP存储的数据
uint32_t ftl_save(void *pdata, uint16_t offset, uint16_t size); uint32_t ftl_load(void *pdata, uint16_t offset, uint16_t size);
备注
ftl_save API和ftl_load API在实现上已对传入的offset参数加上APP存储空间的偏移0x0D00,因此,APP使用这两个API时offset参数从0开始规划即可。
调整FTL空间的大小
FTL的物理空间大小是可配置的,通过修改config文件的配置参数来调整(更多Flash布局调整相关内容,请参考 调整Flash布局)。操作步骤如下:
首先利用Flashmap Generate Tool(随MPTool一起发布)来生成
flash map.ini
和flash_map.h
文件。将
flash_map.h
文件拷贝到APP工程目录下,例如:sdk\samples\bluetooth\ble_peripheral
,这样APP编译的时候可以获取正确的加载地址。将第一步生成的
flash map.ini
加载到MPTool中生成config文件用于烧录,如下图示例,调整FTL的物理空间到32K。
备注
当调整FTL物理空间大小时,APP可使用的最大逻辑空间也会对应改变。假设实际FTL的物理空间大小设置的mK(m是4的整数倍),对应APP可使用的最大逻辑空间等于((511*(m-4) - 4) - 3328) bytes。
为了提升FTL读取的效率,底层做了一套物理地址和逻辑地址的映射机制,这个映射表会占用一定的RAM空间。在默认设置FTL物理空间大小为16K情况下,这个映射表占用2298byte的RAM HEAP空间。假设实际FTL的物理空间大小设置的mK(m是4的整数倍),其映射表占用的RAM空间等于((511 * (m-4) - 4) * 0.375) bytes。
用户在调整FTL空间大小需要依据具体的应用场景来合理调整,如果调至过大将会浪费一部分RAM资源。另一方面,如果对于选用的比较小的flash并且想压缩FTL的占用的空间,必须保证FTL的物理空间不比12K小。由于映射表中每个逻辑地址对应的物理地址默认使用12个bit来表示,FTL的物理空间最大可以调整到32K。
FTL v2
SDK v1.3.0及以后版本默认使用FTL v2。FTL v2延续了v1的基本功能,并且在以下方面进行优化升级:
扩大映射表单元,每个逻辑地址对应的物理地址使用16个bit来表示(v1使用12个bit),可以支持更大的存储空间。
新增通过“module”划分逻辑空间的功能。
每个FTL module在创建时都可以独立设置block_len。合理选择“module”的block_len参数,能够减少辅助信息的空间占用而获得更高的Flash利用率。
“module”之间逻辑空间相互独立,每个“module”的逻辑地址都从0地址开始,有助于上层应用组织和管理数据。
FTL空间的功能划分
FTL初始化时自动创建“系统module”,用于保证FTL基础功能和存储BT信息,用户可创建新的module以存储用户数据。
系统module
逻辑地址范围 [0x0000, 0x0C00),占用物理空间6144 bytes,但这部分空间的大小可通过otp_config.h参数调整。(当前SDK暂时未支持)
[0x0000, 0x0A20) 用于存储BT信息,例如设备地址,link key等,详细请参考 LE Host。
[0xA20, 0x0C00) 用于存储FTL module info等。
用户module
支持用户创建最多6个module,在创建新的module前,需要确保FTL物理空间充足,请参考 调整FTL空间的大小。
用于存储APP的信息。
FTL APIs
int32_t ftl_init_module(char *module_name, uint16_t malloc_size, uint8_t block_len);
int32_t ftl_save_to_module(char *module_name, void *pdata, uint16_t offset, uint16_t size);
int32_t ftl_load_from_module(char *module_name, void *pdata, uint16_t offset, uint16_t size);
备注
ftl_init_module的block_len参数决定module的最小可访问逻辑空间,需要对齐4bytes。根据实际存储数据单元的大小,尽可能选用较大的block_len能够减少RAM空间占用并获得更高的flash利用率(减少了辅助信息占用的空间)。
ftl_save_to_module/ftl_load_from_module的offset参数为存储/读取数据的逻辑地址,需要与block_len对齐。
ftl_init_module API用于创建FTL module,ftl_save_to_module/ftl_load_from_module API用于向module写入数据/从module读取数据。在创建新的FTL module之前,请确保FTL物理空间充足,详见 调整FTL空间的大小。
基础示例如下:
#define EXT_FTL_NAME "TEST_FTL"
#define EXT_FTL_LOGIC_SIZE (0x1000)
#define EXT_FTL_BLOCK_SIZE (64)
void ftl_ext_module_demo(void)
{
// Init an ext FTL module
ftl_init_module(EXT_FTL_NAME, EXT_FTL_LOGIC_SIZE, EXT_FTL_BLOCK_SIZE);
// Save data
uint8_t data_buf[EXT_FTL_BLOCK_SIZE];
memset(data_buf, 0x5A, EXT_FTL_BLOCK_SIZE);
uint16_t test_offset = 0x800;
uint32_t ret = ftl_save_to_module(EXT_FTL_NAME, data_buf, test_offset, EXT_FTL_BLOCK_SIZE);
if (ret != ESUCCESS)
{
//save data error
return;
}
//Load data
uint8_t read_buf[EXT_FTL_BLOCK_SIZE];
ret = ftl_load_from_module(EXT_FTL_NAME, read_buf, test_offset, EXT_FTL_BLOCK_SIZE);
if (ret != ESUCCESS)
{
//load data error
return;
}
}
调整FTL空间的大小
调整FTL物理空间方法与FTL v1一致,请参考 调整FTL空间的大小。
进行调整时,需要保证FTL module可用物理空间满足需求,否则module将创建失败,计算方法如下:
此外,为提升FTL读取效率,在创建module时会为其建立映射表,用于实现逻辑地址和物理地址的转换。FTL module的映射表占用RAM空间: (malloc_size / block_len * 2Bytes) 。
备注
由于FTL需要预留空间用于“系统module”和GC机制,并且FTL物理空间大小与4KB对齐,所以如果选用较小的flash并且需要压缩FTL占用的空间,必须保证FTL物理空间不小于16KB。(FTL预留空间可通过otp_config.h参数调整,当前SDK暂时未支持)
Flash API
如果FTL无法满足需求而必须使用flash driver,请调用下文中介绍的flash 读、写、擦 操作。
读操作
函数名 |
flash_nor_read_locked |
---|---|
函数原型 |
FLASH_NOR_RET_TYPE flash_nor_read_locked(uint32_t addr, uint8_t *data, uint32_t len) |
功能描述 |
读取flash数据 |
输入参数 |
addr:flash读取地址 data:读出数据的存储buffer,注意buffer的地址不能在flash上 len: 读取的数据长度 |
返回值 |
若读取成功 通过十进制查看返回值为24(对应FLASH_NOR_RET_SUCCESS) |
先决条件 |
无 |
写操作
函数名 |
flash_nor_write_locked |
---|---|
函数原型 |
FLASH_NOR_RET_TYPE flash_nor_write_locked(uint32_t addr, uint8_t *data, uint32_t len) |
功能描述 |
写数据到flash |
输入参数 |
addr:flash写入地址 data:写入数据的存储buffer,注意buffer的地址不能在flash上 len: 写入的数据长度 |
返回值 |
若写入成功 通过十进制查看返回值为24(对应FLASH_NOR_RET_SUCCESS) |
先决条件 |
无 |
擦除操作
函数名 |
flash_nor_erase_locked |
---|---|
函数原型 |
FLASH_NOR_RET_TYPE flash_nor_erase_locked(uint32_t addr, FLASH_NOR_ERASE_MODE mode) |
功能描述 |
擦除flash |
输入参数 |
addr:flash擦除地址 FLASH_NOR_ERASE_MODE:flash擦除类型 |
返回值 |
若擦除成功 通过十进制查看返回值为24(对应FLASH_NOR_RET_SUCCESS) |
先决条件 |
无 |
flash_nor_erase_locked()
支持三种擦除类型(FLASH_NOR_ERASE_MODE)
擦除Sector(4K-Byte) (FLASH_NOR_ERASE_SECTOR)
擦除Block(64K-byte) (FLASH_NOR_ERASE_BLOCK)
擦除chip(flash整片擦除) (FLASH_NOR_ERASE_CHIP)
备注
需要注意的是FLASH_NOR_ERASE_CHIP在一般应用中没有使用场景,因此整片擦除功能很少使用。
位模式
除了标准串行外围接口(SPI)之外,大多数flash模型还支持高性能的双位/四位模式I/O SPI,由以下六个引脚控制。
串行时钟 (CLK)
片选 (CS#)
串行数据IO0 (DI)
串行数据IO1 (DO)
串行数据IO2 (WP#)
串行数据IO3 (HOLD#)
三种位模式
- 单位模式
标准的SPI模式,也称为1位模式,只使用CLK,CS#,DI和DO。WP#作为写保护的输入,而HOLD#作为保持功能的输入。
- 双位模式
使用CLK,CS#,并将DI、DO分别用作IO0、IO1。WP#和HOLD#的功能和和单位模式中一致。
- 四位模式
使用CLK,CS#,并将DI、DO、WP#、HOLD#分别用作IO0、IO1、IO2、IO3。由于6根管脚全部被使用,所以四位模式下写保护和保持功能不可用。
备注
目前RTL87x2G支持SDR和DTR两种四位读取模式,用户如果需要使用相应的四位读取模式,应预先确认flash型号与特性。
位模式切换
RTL87x2G为支持更多flash型号,在启动时默认flash都是在1位模式。如果用户需要切换至高速位模式(2或4位模式),可调用SDK中提供的接口:flash_nor_try_high_speed_mode()
切换至高速位模式,并由参数“mode”配置flash尝试切换至的高位模式,如果切换失败将会切回1位模式。
SDK中提供的进行位模式切换的接口函数原型如下。
函数名 |
flash_nor_try_high_speed_mode |
---|---|
函数原型 |
FLASH_NOR_RET_TYPE flash_nor_try_high_speed_mode(FLASH_NOR_IDX_TYPE idx, FLASH_NOR_BIT_MODE mode) |
功能描述 |
切换flash到不同的位模式 |
输入参数 |
idx:默认设置为FLASH_NOR_IDX_SPIC0 mode:切换的位模式(FLASH_NOR_1_BIT_MODE, FLASH_NOR_2_BIT_MODE, FLASH_NOR_4_BIT_MODE, FLASH_NOR_DTR_4_BIT_MODE) |
返回值 |
若切换成功 通过十进制查看返回值为24(对应FLASH_NOR_RET_SUCCESS) |
先决条件 |
无 |
软件块保护
Flash支持通过硬件保护管脚(#WP)来锁定整个flash以防止写入和擦除操作,但有以下两个缺点。
如果使用管脚#WP用作保护功能,就无法使用flash的四位模式。
硬件保护只能选择保护整颗flash或者全部不保护,不能保护部分flash空间。
RTL87x2G通过一个更为灵活的机制——软件块保护(Software Block Protect,BP)来防止意外的flash的擦写操作。其原理是利用flash状态寄存器中的一些BP位来选择要保护的范围。Flash使用状态寄存器中的BP(X)位来识别要锁定的块的数量,以及TB位来决定锁定的方向。RTL87x2G只支持从flash的低地址端开始上锁。
RTL87x2G默认是利用BP功能来保护一些重要的数据(如配置的参数)和代码段,而不是整个flash空间。
备注
需要注意的是,由于不同的Flash供应商和模型有不同的规则和限制,而且Flash状态寄存器默认使用NVRAM类型来保持数据,BP函数需要改变BP位来切换不同的保护级别,但是NVRAM有100K次编程限制。虽然大多数厂商支持使用0x50命令将Flash状态寄存器切换至SRAM类型,但也不是所有的flash厂商都支持,例如MXIC。那么,频繁访问状态寄存器将会损坏flash。
RTL87x2G所使用的flash不一定支持上图所示有比例的上锁方式(即0~1/2~1/4~…)。例如 GD25WD80C软件块保护,最小的上锁范围为768KB,不到二分之一,此时driver中只会支持将其设定为全部上锁或全部解锁。
提供的进行BP设定的接口函数如下。
函数名 |
flash_nor_set_bp_lv_locked |
---|---|
函数原型 |
FLASH_NOR_RET_TYPE flash_nor_set_bp_lv_locked(FLASH_NOR_IDX_TYPE idx, uint8_t bp_lv) |
功能描述 |
设置flash bp等级 |
输入参数 |
idx:默认设置为FLASH_NOR_IDX_SPIC0 bp_lv:设定的bp等级 |
返回值 |
若设定成功 通过十进制查看返回值为24(对应FLASH_NOR_RET_SUCCESS) |
先决条件 |
无 |
函数名 |
flash_nor_get_bp_lv_locked |
---|---|
函数原型 |
FLASH_NOR_RET_TYPE flash_nor_get_bp_lv_locked(FLASH_NOR_IDX_TYPE idx, uint8_t *bp_lv) |
功能描述 |
获取flash当前的bp等级 |
输入参数 |
idx:默认设置为FLASH_NOR_IDX_SPIC0 bp_lv:读出数据的存储buffer |
返回值 |
若获取成功 通过十进制查看返回值为24(对应FLASH_NOR_RET_SUCCESS) |
先决条件 |
无 |
省电
Flash的功耗模式主要分以下三种场景。
工作模式:耗电一般在10 mA数量级
待机模式:耗电一般在几十uA左右
Power Down模式:耗电更低,甚至低于1 uA
Flash在没有访问时会自动进入待机模式,当需要再访问时会自动进入工作状态。而要进入Power Down模式,需要使用特定的命令:大多数Flash使用命令0xB9控制其进入Power Down模式,使用命令0xAB退出Power Down模式,而MXIC是通过切换#CS引脚退出Power Down模式。
需要注意的是,Flash在进入Power Down模式之后,除了退出Power Down命令(0xAB)之外,接收其他的命令都是危险的。因为Flash在进入Power Down模式之后只接受唤醒命令退出Power Down模式,其他命令都将被忽略,但Flash控制器可能会进入无限循环等待Flash的响应。
为了防止滥用Flash Power Down模式带来的风险,系统的DLPS机制中已经加入Flash Power Down模式的控制:进入DLPS时自动下指令使Flash进入Power Down模式,在退出DLPS时唤醒Flash。
XIP
当所剩的RAM空间不够时,需要将部分或者全部APP代码放在flash上执行。RTL87x2G上执行XIP的相关配置总结如下。
- 宏FEATURE_RAM_CODE(mem_config.h中配置)a. 配置为1时,默认不加任何section修饰的代码都将在RAM上执行。b. 配置为0时,默认不加任何section修饰的代码都将在flash上执行。
- Section修饰(参考app_section.h)a. APP_FLASH_TEXT_SECTION:指定代码在flash上执行。b. APP_RAM_TEXT_SECTION:指定代码在RAM上执行。
备注
如果RAM空间不足,要优先将时间敏感的代码放在RAM上执行以保证效率。
- 提高XIP执行代码的效率的方式将flash切换至双位或者四位模式:调用
flash_nor_try_high_speed_mode()
。
RTL87x2G通过SPIC的支持可以使用自动模式去读取flash并且直接在SPI Flash上执行代码。但是用户有可能通过调用提供的接口在用户模式下对flash执行读写擦操作,而用户模式访问flash的操作不是原子性的,如果被另一个自动模式访问操作打断,就会造成flash访问异常。为保证用户模式访问flash操作的原子性,XIP时需要遵循以下的使用限制和注意事项。
备注
RTL87x2G中提供的用户模式访问flash的接口都带“_locked”后缀,默认加临界区保护,会关闭0和1优先级以下的中断,也就是中断优先级数值设置为2到7的中断(中断优先级数值越大,中断优先级越低)。如果flash操作的时间过久,比如一次写大量的数据,建议将一次写的动作拆分成多次少量数据写的动作,以避免关闭中断时间过长而丢中断。
如果有时间非常关键的中断(中断优先级0和1的中断)需要处理,需要保证中断服务例程本身不能XIP,中断服务例程中也禁止访问flash。