一. 初始化qspi
设置flash容量和片数
//初始化容量寄存器
val = chip_num << 3 | chip_size ; //片数 和 每片容量
qspi_write(val,QSPI_FLASH_CAPACITY);
示例:
2片flash,每片容量128MB
chip_num = 2;
chip_size = 128MB;
val = 1 << 3 | 0x5; //片数 和 每片容量
qspi_write(val,QSPI_FLASH_CAPACITY);
二. flash读
直接拷贝即可:
uboot下: cp.b 0x60000000 0x90000000 0x200000
拷贝 flash 6MB到内存0x90000000地址,大小为2MB。
vx下:
memcpy(0x90000000, 0x60000000 ,0x200000);
三. flash 擦除
a. 流程:
1. 写 CMD_PORT 寄存器,仅修改[31:24],填入对应 flash 写使能命令,并且置位 bit22。
2. 写 LD_PORT,填入 0x1,发送命令。
3. 写 CMD_PORT 寄存器,仅修改[31:24],填入对应 flash 擦除命令,并且置位 bit22 和 bit15。4. 写 ADDR_PORT 寄存器,填入需要擦除的地址。
5. 写 LD_PORT,填入 0x1,发送命令。
b. 示例
#define QSPI_SECTOR_SIZE 0x10000 //64KB
void qspiFlashSectorErase_4byte(UINT32 blockAddr)
{
UINT32 cmd_id;
semTake(Flash_Sem,WAIT_FOREVER);
int qspi_csx = qspi_cs_get(blockAddr); //根据地址片选
cmd_id = CMD_WREN; // 写使能指令
qspi_write(0x400000 | (cmd_id << 24) | (qspi_csx << 19) , (void*)QSPI_CMD_PORT);
qspi_write(0x1, (void*)QSPI_LD_PORT);
__asm__ volatile("isb;dsb");
cmd_id = CMD_ERASE_4BYTE;//4字节擦除指令
qspi_write(0x408000 | (cmd_id << 24)| (1<<12) | (qspi_csx << 19) , (void*)QSPI_CMD_PORT);
qspi_write(blockAddr, (void*)QSPI_ADDR_PORT);
qspi_write(0x1, (void*)QSPI_LD_PORT);
__asm__ volatile("isb;dsb");
semGive(Flash_Sem);
}
void qspiFlashErase_4byte(UINT32 addr, UINT32 len)
{
setcmd(CMD_ENABLE_4BYTE);
while(len) {
qspiFlashSectorErase_4byte(addr);
addr += QSPI_SECTOR_SIZE;
len -= QSPI_SECTOR_SIZE;
}
setcmd(CMD_DISABLE_4BYTE);
}
四. flash写
a.流程
1、 写 CMD_PORT 寄存器,仅修改[31:24],填入对应 flash 写使能命令,并且置位 bit22。
2、 写 LD_PORT,填入 0x1,发送命令。
3、 写 WR_CFG 寄存器,仅修改[31:24],填入对应 flash 编程命令,并且置位 bit9 及 bit3。
4、 直接写 0x0 ---- 0x1FFFFFFF 的地址空间,可以连续写入,且必须保证每次写都是四字节写。
5、 写 LD_PORT,填入 0x1,发送命令。
6、 写 WR_CFG 寄存器为 0 关闭写使能。
b.示例
//一页 256个字节
void qspiPageProgramFlush_4byte(UINT32* src_addr, UINT32* page_addr, UINT32 pp_num)
{
UINT32 i = 0;
UINT32 temp[64] = {0};
UINT32 cmd_id = 0;
semTake(Flash_Sem,WAIT_FOREVER);
for(i = 0; i < (pp_num>>2); i++) {
temp[i] = *(src_addr + i);
}
int qspi_csx = qspi_cs_get(page_addr);
cmd_id = CMD_WREN;
qspi_write(0x400000 | (cmd_id << 24) | (qspi_csx << 19) , (void*)QSPI_CMD_PORT);
qspi_write(0x1, (void*)QSPI_LD_PORT);
__asm__ volatile("isb;dsb");
cmd_id = CMD_PP_4BYTE;
qspi_write(0x000208 | (cmd_id << 24) | (1<<4), (void*)QSPI_WR_CFG);
__asm__ volatile("isb;dsb");
for(i = 0; i < (pp_num>>2); i++) {
*(page_addr +i) = temp[i];
}
qspi_write(0x1, (void*)QSPI_FLUSH_REG);
semGive(Flash_Sem);
}
void qspiPageProgram_4byte(UINT32* src_addr, UINT32* page_addr, UINT32 pp_num)
{
UINT32 i = 0;
UINT32 add = 0;
if(pp_num <= 256) {
add = 1;
} else {
if((pp_num % 256) > 0) {
add = pp_num / 256 + 1;
} else {
add = pp_num /256;
}
}
setcmd(CMD_ENABLE_4BYTE);
for(i = 0; i < add; i++) {
//src_addr为int型,一次操作4个字节。4 * 64 = 256
qspiPageProgramFlush_4byte(src_addr + i*64, page_addr + i*64, 256);
}
setcmd(CMD_DISABLE_4BYTE);
}
五.读flash_id
int read_flash_id()
{
unsigned int cmd_id = ID_CMD;//0x9f
qspi_write((cmd_id << 24) |1<<22 |1<<13 |1<<6 | (cs << 19), (void*)QSPI_CMD_PORT);
int val = qspi_read(QSPI_LD_PORT);
printf("\r\n flash CMD:%x val=0x%x\r\n",CMD,val);
}
备注:flash命令
flash常用命令:
#define CMD_WREN 0x06
#define CMD_PP 0x02
#define CMD_PP_4BYTE 0x12
#define CMD_ERASE 0xD8
#define CMD_ERASE_4BYTE 0xDC
#define CMD_ENABLE_4BYTE 0xB7
#define CMD_DISABLE_4BYTE 0xE9