Flash使用指南
1. FLASH介绍
SiFLi FLASH 控制器支持最多同时挂载多个FLASH颗粒(55X系列支持4个, 58X系列支持5个, 56X系列支持4个),可以是NOR-FLASH, 也可以是NAND-FLASH。
相比55X, 58X和56X的控制器增加了对8线和16线PSRAM的支持,控制器名字由QSPI改为MPI,意为专门为Memory提供的控制器。
针对55X系列,一般控制器一默认控制片内NOR-FLASH , 二和三由不同方案的板子决定, 四接NOR FLASH, 可以由LCPU访问(HCPU也可以访问)。
针对58X系列,一般控制器一和二默认控制片内NOR-FLASH 或PSRAM,具体由芯片封装决定, 三和四由不同方案的板子决定, 五为片内NOR FLASH, 可以由LCPU访问(HCPU也可以访问)。
针对56X系列,一般控制器一和二默认控制片内NOR-FLASH 或PSRAM,具体由芯片封装决定, 三由不同方案的板子决定, 五为片内NOR FLASH, 可以由LCPU访问(HCPU也可以访问)(没有四)。
FLASH驱动分为HAL层和DRV层,其中HAL层提供硬件寄存器访问和简单逻辑接口,DRV层提供了FLASH读/写/擦等基本操作接口,初始化及控制接口,针对设备和文件系统操作的接口。
控制器可以提供单线FLASH操作及4线FLASH操作
内部有DMA进行加速
支持PAGE写,支持PAGE读(NOR-FLASH支持通过AHB总线直接以内存方式进行读)
支持SECTOR/BLOCK 不同大小擦除,基本操作单位大小与颗粒有关
2. FLASH 配置
FLASH控制器对应的FLASH颗粒属性及使用方式可以通过menuconfig(rtconfig.h)进行配置,包括是否使能,是否使用DMA, 是否连接MTD设备及文件系统信息等。
下面是55X EVB开发板上部分功能示例:
命令行输入 “menuconfig” 开启配置:
Choose “RTOS —>”
Choose “On-chip Peripheral Driver —> “
Choose “Enable QSPI —> “
Choose “Enable QSPI Driver “
Choose “QSPI Controller 1 Enable —>”
Choose “QSPI1 Mode: 0 NOR, 1 NAND, 2 PSRAM, 3 OTHERS “
Choose “QSPI1 Use File System —”
Choose “QSPI1 Mem Size()MB”
Choose “QSPI1 Manul & Device ID”
下面是对各个FLASH控制器的配置对应定义宏的示例和意义。
FLASH1:(FLASH1默认为NOR-FLASH, 模式不可修改)
#define BSP_USING_QSPI 1 /*使能QSPI 模块*/
#define BSP_USING_SPI_FLASH 1 /*使能QSPI 控制FLASH功能(为了兼容以前版本)*/
#define BSP_ENABLE_QSPI1 1 /*使能QSPI控制器1*/
#define BSP_QSPI1_USING_DMA 1 /*QSPI1 使用FIFO DMA */
#define BSP_QSPI1_MODE 0 /*QSPI1 连接控制Nor FLASH*/
#define BSP_QSPI1_MEM_SIZE 4 /*配置FLASH1的总大小为4MB*/
#define BSP_QSPI1_CHIP_ID 0 /*FLASH1 DEV ID 由系统获取,不需要手动输入(这个配置是为了当有些FLASH获取ID的命令时序与默认设置不同时,手动添加ID以便查找正确的命令表)*/
FLASH2:
#define BSP_ENABLE_QSPI2 1 /*使能QSPI2 模块*/
#define BSP_QSPI2_USING_DMA 1 /*使能QSPI2 FIFO DMA <*/
#define BSP_QSPI2_MODE 0 /*设置FLASH2 为NOR-FLASH*/
#define BSP_QSPI2_MTD_EN 1 /*FLASH2 注册MTD 设备 */
#define BSP_QSPI2_FS_START 2048 /*FLASH2 MTD 设备可访问地址的起始位置为8MB(2048*4K)*/
#define BSP_QSPI2_FS_SIZE 2048 /*长度为8MB(2048*4KB)*/
#define BSP_QSPI2_MEM_SIZE 32 /*配置FLASH2的总大小为32MB*/
#define BSP_QSPI2_CHIP_ID 0 /*FLASH2 DEV ID 由系统获取,不需要手动输入*/
FLASH3:
#define BSP_ENABLE_QSPI3 1 /*使能QSPI3 模块*/
#define BSP_QSPI3_USING_DMA 1 /*使能QSPI3 FIFO DMA <*/
#define BSP_QSPI3_MODE 1 /*设置FLASH2 为NAND-FLASH*/
#define BSP_QSPI3_MEM_SIZE 128 /*配置FLASH3的总大小为128MB*/
#define BSP_QSPI3_CHIP_ID 0 /*FLASH3 DEV ID 由系统获取,不需要手动输入*/
下面是58X EVB开发板上部分功能示例:
命令行输入 “menuconfig” 开启配置:
Choose “RTOS —>”
Choose “On-chip Peripheral Driver —> “
Choose “Enable MPI —> “
Choose “Enable QSPI Driver “
Choose “MPI Controller 1 Enable —>”
Choose “MPI Mode: 0 NOR, 1 NAND, 2 PSRAM, 3 OPSRAM, 4 HPSRAM, 5 LEGACY_PSRAM “
Choose “MPI1 Mem Size()MB”
下面是对各个FLASH控制器的配置对应定义宏的示例和意义。
MPI:(MPI 默认设置,部分设置为了兼容之前版本)
#define BSP_USING_MPI 1 /*使能MPI 模块*/
#define BSP_USING_SPI_FLASH 1 /*使能MPI 控制FLASH功能(为了兼容以前版本)*/
MPI1:(FLASH1默认为NOR-FLASH, 模式不可修改)
#define BSP_ENABLE_MPI1 1 /*使能MPI 1 模块*/
#define BSP_ENABLE_QSPI1 1 /*使能MPI 1(为了兼容以前版本)*/
#define BSP_MPI1_MODE_4 1 /*MPI1 设置为功能4---16线PSRAM*/
#define BSP_QSPI1_MODE 4
#define BSP_USING_PSRAM1 1
#define BSP_QSPI1_MEM_SIZE 32 /*配置MPI1的总大小为16MB*/
MPI2:
#define BSP_ENABLE_MPI2 1 /*使能MPI 2 模块*/
#define BSP_ENABLE_QSPI2 1 /*使能MPI 2(为了兼容以前版本)*/
#define BSP_MPI2_MODE_4 1 /*MPI2 设置为功能4---16线PSRAM*/
#define BSP_QSPI2_MODE 4
#define BSP_USING_PSRAM2 1
#define BSP_QSPI2_MEM_SIZE 32 /*配置MPI2的总大小为32MB*/
MPI3:
#define BSP_ENABLE_MPI3 1 /*使能MPI 3 模块*/
#define BSP_ENABLE_QSPI3 1 /*使能MPI 3(为了兼容以前版本)*/
#define BSP_MPI3_MODE_0 1 /*MPI3 设置为功能0---NOR FLASH*/
#define BSP_QSPI3_MODE 0
#define BSP_USING_NOR_FLASH3 1
#define BSP_QSPI3_USING_DMA 1 /*MPI3 使用DMA*/
#define BSP_QSPI3_MEM_SIZE 32 /*配置MPI2的总大小为32MB*/
MPI4:
#define BSP_ENABLE_MPI4 1 /*使能MPI 4 模块*/
#define BSP_ENABLE_QSPI4 1 /*使能MPI 4(为了兼容以前版本)*/
#define BSP_MPI4_MODE_1 1 /*MPI4 设置为功能1---NAND FLASH*/
#define BSP_QSPI4_MODE 1
#define BSP_USING_NAND_FLASH4 1
#define BSP_QSPI4_USING_DMA 1 /*MPI5 使用DMA*/
#define BSP_QSPI4_MEM_SIZE 128 /*配置MPI2的总大小为128MB*/
MPI5:
#define BSP_ENABLE_MPI5 1 /*使能MPI 5 模块*/
#define BSP_ENABLE_QSPI5 1 /*使能MPI 5(为了兼容以前版本)*/
#define BSP_MPI5_MODE_0 1 /*MPI5 设置为功能0---NOR FLASH*/
#define BSP_QSPI5_MODE 0
#define BSP_USING_NOR_FLASH5 1
#define BSP_QSPI5_USING_DMA 1 /*MPI5 使用DMA*/
#define BSP_QSPI5_MEM_SIZE 4 /*配置MPI5的总大小为4MB*/
56X的配置除了不存在MPI4,其他与58X基本一致,这里不再单独列举示例。
3.FLASH 地址空间
55X 系列地址
默认EVB上FLASH大小配置,其中大小为可使用空间,描述为实际情况下开发板进行配置:
名称 |
起始地址 |
结束地址 |
最大大小(字节) |
描述 |
---|---|---|---|---|
FLASH1 |
0x10000000 |
0x11FFFFFF |
32 * 1024 * 1024 |
EVB的容量为4MByte |
FLASH2 |
0x64000000 |
0x67FFFFFF |
64 * 1024 * 1024 |
EVB的容量为32MByte |
FLASH3 |
0x68000000 |
0x6FFFFFFF |
128 * 1024 * 1024 |
EVB未使能 |
FLASH4 |
0x12000000 |
0x13FFFFFF |
32 * 1024 * 1024 |
EVB未使能 |
4个FLASH控制器基地址定义可在 mem_map.h 中找到, 对应的最大内存空间如表中描述,而实际使用的大小由menuconfig通过实际连接的颗粒决定:
#define QSPI1_MEM_BASE (0x10000000)
#define QSPI2_MEM_BASE (0x64000000)
#define QSPI3_MEM_BASE (0x68000000)
#define QSPI4_MEM_BASE (0x12000000)
58X 系列地址
默认EVB上FLASH大小配置,其中大小为可使用空间,描述为实际情况下开发板进行配置:
C-BUS 地址:
名称 |
起始地址 |
结束地址 |
最大大小(字节) |
描述 |
---|---|---|---|---|
MPI1 |
0x10000000 |
0x11FFFFFF |
32 * 1024 * 1024 |
EVB的容量为16MByte |
MPI2 |
0x12000000 |
0x13FFFFFF |
32 * 1024 * 1024 |
EVB的容量为16MByte |
MPI3 |
0x14000000 |
0x17FFFFFF |
64 * 1024 * 1024 |
EVB的容量为32MByte |
MPI4 |
0x18000000 |
0x1BFFFFFF |
64 * 1024 * 1024 |
EVB的容量为64MByte |
MPI5 |
0x1C000000 |
0x1FFFFFFF |
64 * 1024 * 1024 |
EVB的容量为4MByte |
S-BUS 地址:
名称 |
起始地址 |
结束地址 |
最大大小(字节) |
描述 |
---|---|---|---|---|
MPI1 |
0x60000000 |
0x61FFFFFF |
32 * 1024 * 1024 |
EVB的容量为16MByte |
MPI2 |
0x62000000 |
0x63FFFFFF |
32 * 1024 * 1024 |
EVB的容量为16MByte |
MPI3 |
0x64000000 |
0x67FFFFFF |
64 * 1024 * 1024 |
EVB的容量为32MByte |
MPI4 |
0x68000000 |
0x9FFFFFFF |
896 * 1024 * 1024 |
EVB的容量为64MByte |
为了NAND FLASH 能使用超过64MB的空间,在MPI挂载NAND的时候,建议挂载在MPI4,同时使用0x68000000开始的地址。
5个MPI控制器基地址定义可在 mem_map.h 中找到, 对应的最大内存空间如表中描述,而实际使用的大小由menuconfig通过实际连接的颗粒决定:
#define QSPI1_MEM_BASE (0x10000000)
#define QSPI2_MEM_BASE (0x12000000)
#define QSPI3_MEM_BASE (0x14000000)
#define QSPI4_MEM_BASE (0x18000000)
#define QSPI5_MEM_BASE (0x1C000000)
56X 系列地址
默认EVB上FLASH大小配置,其中大小为可使用空间,描述为实际情况下开发板进行配置:
C-BUS 地址:
名称 |
起始地址 |
结束地址 |
最大大小(字节) |
描述 |
---|---|---|---|---|
MPI1 |
0x10000000 |
0x107FFFFF |
8 * 1024 * 1024 |
EVB的容量为4MByte |
MPI2 |
0x10800000 |
0x13FFFFFF |
56 * 1024 * 1024 |
EVB的容量为16MByte |
MPI3 |
0x14000000 |
0x17FFFFFF |
128 * 1024 * 1024 |
EVB的容量为128MByte |
MPI5 |
0x1C000000 |
0x1FFFFFFF |
64 * 1024 * 1024 |
EVB的容量为1MByte |
S-BUS 地址:
名称 |
起始地址 |
结束地址 |
最大大小(字节) |
描述 |
---|---|---|---|---|
MPI1 |
0x60000000 |
0x607FFFFF |
8 * 1024 * 1024 |
|
MPI2 |
0x60800000 |
0x63FFFFFF |
56 * 1024 * 1024 |
|
MPI3 |
0x64000000 |
0x9FFFFFFF |
960 * 1024 * 1024 |
4个MPI控制器基地址定义可在_mem_map.h_ 中找到, 对应的最大内存空间如表中描述,而实际使用的大小由menuconfig通过实际连接的颗粒决定:
#define QSPI1_MEM_BASE (0x10000000)
#define QSPI2_MEM_BASE (0x10800000)
#define QSPI3_MEM_BASE (0x14000000)
#define QSPI5_MEM_BASE (0x1C000000)
4.FLASH RT-Thread驱动访问
基于RT-THREAD ,FLASH提供了一套访问接口,可以通过地址进行操作(绝对地址来决定使用哪一个控制器)。
/**
* @brief Flash controller hardware initial.
* @retval 0 if success.
int rt_hw_flash_init(void);
/**
* @brief Read nor-flash memory
* @param[in] addr: start address for flash memory.
* @param[out] buf: output data buffer, should not be null.
* @param[in] size: read memory size, in bytes.
* @return read size, 0 if fail.
*/
int rt_flash_read(rt_uint32_t addr, rt_uint8_t *buf, size_t size);
/**
* @brief Write nor-flash memory
* @param[in] addr: start address for flash memory.
* @param[in] buf: input data buffer, should not be null.
* @param[in] size: write memory size, in bytes.
* @return write size, 0 if fail.
*/
int rt_flash_write(rt_uint32_t addr, const rt_uint8_t *buf, size_t size);
/**
* @brief erase flash.
* @param[in] addr: start address for flash memory.
* @param[in] size: erase memory size, in bytes.
* @return RT_EOK if success.
*/
rt_err_t rt_flash_erase(rt_uint32_t addr, size_t size);
通过接口rt_hw_flash_init
进行初始化,在此之前,各个FLASH是否使能,以及对应的配置都已经由 rtconfig.h 决定,这里不再通过输入参数来修改。
通过rt_flash_read
进行读数据操作,对NOR-FLASH可以直接通过内存方式读,对NAND-FLASH只能通过此接口,调用者需要自行维护数据缓冲区的管理。
通过rt_flash_write
进行数据写操作,无论NAND/NOR, 写操作都需要通过该接口来完成,同样调用者需要维护数据缓冲区。
通过rt_flash_erase
进行擦除,对NOR-FLASH而言,最小的擦除单位为SECTOR(一般为4KB),需要地址和长度都按照SECTOR对齐,否则会出现误擦除的现象,调用者需要自行维护不对齐部分地址数据的恢复。
对NAND-FLASH而言, 最小擦除单位为BLOCK(一般为128KB),需要地址和长度都按照BLOCK对齐,调用者需要自行维护不对齐部分的数据备份和恢复。
备注
需要注意,FLASH不支持XIP时擦写同一片Flash,因此需要将Flash驱动相关代码放在SRAM中执行,以下为Keil的链接脚本片段, 地址0x200E1000开始64KB空间用于存放需要在SRAM执行的Flash驱动代码,可以对照修改链接脚本
LR_IROM1 0x10020000 0x100000 { ; load region size_region
...
ER_IROM1_EX 0x200E1000 0x10000 { ; Flash code and RO need to put in SRAM
drv_flash_z0.o (.text.*)
drv_flash_z0.o (.rodata.*)
bf0_hal_flash.o (.text.*)
bf0_hal_flash_ext_z0.o (.text.*)
...
}
...
}
下面是对FLASH1 1MB地址进行4KB数据写操作的示例:
unsigned long address = FLASH_BASE_ADDR + 0x100000;
char * buf = NULL;
char * buf2 = NULL;
// Erase flash
int res = rt_flash_erase(address, 4096);
if(res != 0)
goto err;
// Write flash
// malloc buf and initial data before write
buf = malloc(4096);
if(buf == NULL)
return ERROR;
int size = rt_flash_write(address, buf, 4096);
if(size != 4096)
goto err;
// read flash
buf2 = malloc(4096);
if(buf2 == NULL)
goto err;
size = rt_flash_read(address, buf2, 4096);
if(size != 4096)
goto err;
// check data
for(int i=0; i<4096; i++)
if(buf[i] != buf2[i])
goto err;
....
err:
if(buf)
free(buf);
if(buf2)
free(buf);
return ERROR;
...
5.FLASH RT-Thread MTD 设备使用
RT-THREAD 中的MTD包含MTD-NOR 和MTD-NAND两种设备驱动,如果在配置文件中对FLASH进行了MTD进行了正确的配置并使能,在系统启动过程中会对这些设备自动注册, 注册成功与否可以通过接口查询。
比如FLASH1的查询,可以通过rt_device_find(“flash1”) 的方式进行查询,每个控制器对应的设备名分别为“flash1” , “flash2”, “flash3” , 若查询返回非空,即已经注册成功。
目前MTD设备已经用在了文件系统和USB STORAGE上,在使用上主要是查找设备,之后绑定设备即可,MTD的读写已经在mtd_nor中进行了封装,不需要用户处理。
下面是注册时候对应的数据类型,若用户自己注册,则需要填写对应数据并实现操作接口,如果已经注册完成,则只需要查找设备,之后的操作由系统后台完成。
MTD-NOR:
struct rt_mtd_nor_device
{
struct rt_device parent;
rt_uint32_t block_size; /* The Block size in the flash */
rt_uint32_t block_start; /* The start of available block*/
rt_uint32_t block_end; /* The end of available block */
/* operations interface */
const struct rt_mtd_nor_driver_ops* ops;
};
struct rt_mtd_nor_driver_ops
{
rt_uint32_t (*read_id) (struct rt_mtd_nor_device* device);
rt_size_t (*read) (struct rt_mtd_nor_device* device, rt_off_t offset, rt_uint8_t* data, rt_uint32_t length);
rt_size_t (*write) (struct rt_mtd_nor_device* device, rt_off_t offset, const rt_uint8_t* data, rt_uint32_t length);
rt_err_t (*erase_block)(struct rt_mtd_nor_device* device, rt_off_t offset, rt_uint32_t length);
};
rt_err_t rt_mtd_nor_register_device(const char* name, struct rt_mtd_nor_device* device);
MTD-NAND:
struct rt_mtd_nand_device
{
struct rt_device parent;
rt_uint16_t page_size; /* The Page size in the flash */
rt_uint16_t oob_size; /* Out of bank size */
rt_uint16_t oob_free; /* the free area in oob that flash driver not use */
rt_uint16_t plane_num; /* the number of plane in the NAND Flash */
rt_uint32_t pages_per_block; /* The number of page a block */
rt_uint16_t block_total;
rt_uint32_t block_start; /* The start of available block*/
rt_uint32_t block_end; /* The end of available block */
/* operations interface */
const struct rt_mtd_nand_driver_ops* ops;
};
struct rt_mtd_nand_driver_ops
{
rt_uint32_t (*read_id) (struct rt_mtd_nand_device* device);
rt_err_t (*read_page)(struct rt_mtd_nand_device* device,
rt_off_t page,
rt_uint8_t* data, rt_uint32_t data_len,
rt_uint8_t * spare, rt_uint32_t spare_len);
rt_err_t (*write_page)(struct rt_mtd_nand_device * device,
rt_off_t page,
const rt_uint8_t * data, rt_uint32_t data_len,
const rt_uint8_t * spare, rt_uint32_t spare_len);
rt_err_t (*move_page) (struct rt_mtd_nand_device *device, rt_off_t src_page, rt_off_t dst_page);
rt_err_t (*erase_block)(struct rt_mtd_nand_device* device, rt_uint32_t block);
rt_err_t (*check_block)(struct rt_mtd_nand_device* device, rt_uint32_t block);
rt_err_t (*mark_badblock)(struct rt_mtd_nand_device* device, rt_uint32_t block);
};
rt_err_t rt_mtd_nand_register_device(const char* name, struct rt_mtd_nand_device* device);
下面是MTD-NOR 在用在文件系统时的实例:
// 注册MTD DEVICE
struct rt_mtd_nor_device *nod = malloc(sizeof(struct rt_mtd_nor_device));
nod->block_start = BSP_FLASH1_FS_START;
nod->block_size = FLASH_SECT_SIZE;
nod->block_end = nod->block_start + BSP_FLASH1_FS_SIZE;
nod->ops = &flash_ops;
nod->parent.user_data = &lflash_handle[0];
lflash_handle[0].nod = nod;
rt_mtd_nor_register_device("flash1", (struct rt_mtd_nor_device *)(lflash_handle[0].nod));
// 查找MTD DEVICE:
rt_device_t dev = rt_device_find("flash1");
if (dev) // device find, it has beed registered to mtd
{
// MTD设备的使用,直接使用设备名,mkfs, mount都会去查找设备并调用设备的读写接口
if (dfs_mkfs("elm", "flash1") == 0)
{
dfs_mount("flash1", "/", "elm", 0, 0);
....
}
}
6.当前FLASH空间已分配使用情况
从 mem_map.h 中已列出的空间看, 从FLASH1的起始位置(0x10000000 )的64KB用来存放flash_table, 之后的64KB(0x10010000)用来存方boot patch, 从 0x10020000开始用来存放bin。
FLASH2 如果为NOR-FLASH, 则watch 的资源文件从其起始位置开始存放(0x64000000).
#define FLASH_TABLE_SIZE (20*1024)
#define FLASH_CAL_TABLE_SIZE (8*1024)
#define FLASH_BOOT_PATCH_SIZE (64*1024)
#define FLASH_BASE_ADDR (0x10000000)
#define FLASH_TABLE_START_ADDR (FLASH_BASE_ADDR)
#define FLASH_TABLE_END_ADDR (END_ADDR(FLASH_TABLE_START_ADDR, FLASH_TABLE_SIZE))
#define FLASH_CAL_TABLE_START_ADDR (FLASH_TABLE_END_ADDR+1)
#define FLASH_BOOT_PATCH_START_ADDR (0x10010000)
#define FLASH_BOOT_PATCH_END_ADDR (END_ADDR(FLASH_BOOT_PATCH_START_ADDR, FLASH_BOOT_PATCH_SIZE)) /* 0x1001FFFF */
#define FLASH_USER_CODE_START_ADDR (FLASH_BOOT_PATCH_END_ADDR + 1) /* 0x10020000 */
FLASH 还用在了存储变量和日志上,目前使用FLASHDB(或者EasyFlash), flash1/flash2 都有部分空间暂时用来使用, 这部分需要按系统需求重新规划。
7. NOR-FLASH 移植
根据不同客户的开发板,在设计时会使用不同的NOR-FLASH 颗粒,而在使用这些颗粒时,主要从硬件规格和操作命令配置上进行匹配。
硬件规格
电压配置 : 3.3V 或 1.8V
SPI 模式 : 除单线外,是否支持双线,4线SPI.
最高频率 : 在单线/双线/4线模式下分别支持的最高频率
其他如工作温度,擦写速度等,这些与软件移植无关,可以先不用考虑
操作命令
操作命令主要时指读/写/擦等相关的颗粒命令,这个与厂商和具体颗粒有关,需要从规格书中查找对比。
A0 上增加了添加命令表的方式,用来增加对新FLASH颗粒的支持(flash_table.c),主要涉及的命令都在 bf0_hal_qspi.h中SPI_FLASH_CMD_E 定义,其中包含了NAND/NOR的命令。
/**
* @brief SPI_FLASH command index
*/
typedef enum
{
SPI_FLASH_CMD_WREN = 0, /*!< write enable, nor+nand */
SPI_FLASH_CMD_WRDI, /*!< write disable, nor+nand */
SPI_FLASH_CMD_RDSR, /*!< read status register, nor+nand */
SPI_FLASH_CMD_WRSR, /*!< write status register, nor+nand */
SPI_FLASH_CMD_PREAD, /*!< page read, nand */
SPI_FLASH_CMD_READ, /*!< single line read, nor+nand */
SPI_FLASH_CMD_FREAD, /*!< fast read , nor + nand */
SPI_FLASH_CMD_DREAD, /*!< fast read dual output, nor+nand */
SPI_FLASH_CMD_QREAD, /*!< fast read quad output, nor+nand */
SPI_FLASH_CMD_2READ, /*!< 2 line read, nor+nand */
SPI_FLASH_CMD_4READ, /*!< 4 line read, nor+nand . ==== 10 */
SPI_FLASH_CMD_RDID, /*!< read id, nor+nand */
SPI_FLASH_CMD_PLD, /*!< load program data, nand */
SPI_FLASH_CMD_QPLD, /*!< qual program load, nand */
SPI_FLASH_CMD_PLDR, /*!< randome program load, nand */
SPI_FLASH_CMD_QPLDR, /*!< qual random program load, nand */
SPI_FLASH_CMD_PEXE, /*!< program execute, nand */
SPI_FLASH_CMD_BE, /*!< block erase, nand */
SPI_FLASH_CMD_RST, /*!< reset, nor+nand */
SPI_FLASH_CMD_RST_EN, /*!< reset en, nor */
SPI_FLASH_CMD_RDSR2, /*!< read status register 2, nor ==== 20 */
SPI_FLASH_CMD_WVSR, /*!< write volatile status register, nor */
SPI_FLASH_CMD_PP, /*!< PAGE PROGRAM, nor */
SPI_FLASH_CMD_QPP, /*!< QUAL PAGE PROGRAM, nor */
SPI_FLASH_CMD_RDEAR, /*!< read extended address register, nor */
SPI_FLASH_CMD_WREAR, /*!< write extended address register, nor */
SPI_FLASH_CMD_PE, /*!< page erase, nor */
SPI_FLASH_CMD_SE, /*!< SECTOR erase, nor */
SPI_FLASH_CMD_BE32, /*!< BLOCK erase 32KB, nor */
SPI_FLASH_CMD_BE64, /*!< BLOCK erase 64KB, nor */
SPI_FLASH_CMD_CE, /*!< CHIP ERASE, nor ===== 30 */
SPI_FLASH_CMD_RDSR3, /*!< read status register 3, nor */
SPI_FLASH_CMD_WRSR3, /*!< WRITE status register 3, nor */
SPI_FLASH_CMD_EN4BM, /*!< enter 4-byte address mode, nor */
SPI_FLASH_CMD_ET4BM, /*!< exit 4-byte address mode, nor */
SPI_FLASH_CMD_RD4BA, /*!< read with 4-byte address, nor */
SPI_FLASH_CMD_FR4BA, /*!< fast read with 4-byte address, nor */
SPI_FLASH_CMD_FQR4BA, /*!< fast read quad output with 4-byte address, nor */
SPI_FLASH_CMD_4RD4BA, /*!< 4 IO read with 4-byte address, nor */
SPI_FLASH_CMD_PP4BA, /*!< page program with 4-byte address, nor */
SPI_FLASH_CMD_QPP4BA, /*!< quad page program with 4-byte address, nor ==== 40 */
SPI_FLASH_CMD_SE4BA, /*!< sector erase with 4-byte address, nor */
SPI_FLASH_CMD_BE4BA, /*!< 64KB block erase with 4-byte address, nor */
SPI_FLASH_CMD_WRSR2, /*!< write status register command 2, nor */
SPI_FLASH_CMD_LEFPA, /*!< Last ECC Failue Page Address, NAND */
SPI_FLASH_CMD_BBM, /*!< Bad Block Management, NAND */
SPI_FLASH_CMD_RBLUT, /*!< Read BBM Look Up Table, NAND */
SPI_FLASH_CMD_COUNT /*!< current support flash command */
} SPI_FLASH_CMD_E;
系统中已经包含了部分颗粒的命令表(flash_cmd_table_list),可以先查看需要移植的颗粒对应功能与此命令码是否一致,如果完全一致,则颗粒可以直接使用,否则需要添加新的命令表。
命令表类型定义:
/**
* @brief SPI_FLASH manual command
*/
typedef struct
{
uint8_t cmd;
uint8_t func_mode; /*!< manual read 0 / write 1 */
uint8_t data_mode; /*!< 0 no data / 1 single line / 2 dual line / 3 qual line */
uint8_t dummy_cycle; /*!< dummy cycle between command and address/data */
uint8_t ab_size; /*!< alternate byte size, */
uint8_t ab_mode; /*!< alternate byte mode, 0 no, 1, single line, 2, dual line, 3 fouline */
uint8_t addr_size; /*!< address byte count - 1 */
uint8_t addr_mode; /*!< 0 no, 1 single line / 2 dual lin / 3 four line */
uint8_t cmd_mode; /*!< 0 no, 1 single lien / 2 dual line / 3 four line */
} FLASH_CMD_CFG_T;
其中 “cmd” 是指命令ID,比如 write enable 命令为0x06, read status register 命令为0x05 等
func_mode 是功能类型, 0表是读操作, 1表是写操作。
data_mode 是数据线宽度, 0表是没有数据,1表是数据单线操作,2表示数据双线操作,3表示数据4线操作。
dummy_cycle 是指在命令和数据之间可能存在的填充时钟数量。
ab_size 和 ab_mode 针对的是在地址之后的有些命令M7~M0的设置,比如针对PUYA 的4线读命令0XEB,在时序图中ADDR之后有8比特的MBYTE设置(这里用作了continue 模式的判断),表中设置这两个参数为0/3 , 其中0表是size 为1字节(n-1),3表是4线模式。
addr_size 和addr_mode 是指命令需要跟的地址参数, addr_size 为地址长度(n-1字节), addr_mode 表是无地址(0), 单线(1),双线(2), 4线(3), 当mode = 0时, 没有地址需求,size必须为0。
cmd_mode 是否flash命令,有效命令总为1
8. NAND-FLASH 移植
NAND 颗粒的移植基本上和NOR 一致,只是需要用到的命令会由差别,这个要根据具体颗粒来导出时序。
备注
有些颗粒的获取ID的时序不同,如果用默认的时序无法获取正确的ID,则不能查找到正确的命令表,这时要么需要修改代码中的获取ID时序,要么在配置时配置上正确的ID以便查找到新注册的命令表
9.PSRAM 移植
目前PSRAM只是对APM的PSRAM进行过移植,包括4线,8线和16线。大小从4MB到32MB都有型号可以支持。
其中55X只对4线PSRAM进行了支持。
58X 对4线,8线和16线都可以支持,
56X 对4线和8线进行支持。