基于RT1052的FlexSPI读写FLASH(W25Q256JV)
/*
bsp_flexspi.c
*/
#include "bsp_flexspi.h"
/* 定义指令在查找表中的编号 */
#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0
#define NOR_CMD_LUT_SEQ_IDX_READ_FAST 1
#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2
#define NOR_CMD_LUT_SEQ_IDX_READSTATUS 3
#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 4
#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE 6
#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7
#define NOR_CMD_LUT_SEQ_IDX_READID 8
#define NOR_CMD_LUT_SEQ_IDX_READJEDECID 9
#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 10
#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 11
#define NOR_CMD_LUT_SEQ_IDX_ERASECHIP 12
#define NOR_CMD_LUT_SEQ_IDX_AHB_PAGEPROGRAM_QUAD_1 13
#define NOR_CMD_LUT_SEQ_IDX_AHB_PAGEPROGRAM_QUAD_2 14
#define NOR_CMD_LUT_SEQ_IDX_READ_UUID_ISSI 15
// #define NOR_CMD_LUT_SEQ_IDX_READ_UUID_WB 16
/* 查找表的长度 */
#define CUSTOM_LUT_LENGTH 64
//Flash BUSY bit
#define FLASH_BUSY_STATUS_OFFSET 0
//读写测试使用的缓冲区
#define EXAMPLE_SIZE (4*1024)
#define EXAMPLE_SECTOR 1000 //第1000个扇区
static uint8_t s_nor_program_buffer[EXAMPLE_SIZE];
static uint8_t s_nor_read_buffer[EXAMPLE_SIZE];
/* 定义查找表LUT
* 下表以[4 * NOR_CMD_LUT_SEQ_IDX_xxxx]表示1个序列,
* 1个序列最多包含8条指令,使用宏FLEXSPI_LUT_SEQ可以一次定义2个指令。
* 一个FLEXSPI_LUT_SEQ占一个LUT寄存器,端口A和端口B各有64个LUT寄存器,
* 所以CUSTOM_LUT_LENGTH最大值为64。每个序列占 4 个数组元素
*
* FLEXSPI_LUT_SEQ格式如下(LUT指令0,使用的数据线数目,指令的参数,
LUT指令1,使用的数据线数目,指令的参数)
*
* 不满8条指令的序列应以STOP指令结束,即kFLEXSPI_Command_STOP,
* 不过因为STOP指令中的所有参数均为0,而数组的初始值也都为0,
* 所以部分序列的末尾忽略了STOP指令也能正常运行。
*/
const uint32_t customLUT[CUSTOM_LUT_LENGTH] = {
/* 1普通读指令,Normal read mode -SDR */
[4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, W25Q_ReadData_4Addr,
kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, FLASH_ADDR_LENGTH),
[4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL + 1] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04,
kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
/* 2快速读指令,Fast read mode - SDR */
[4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, W25Q_FastReadData_4Addr,
kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, FLASH_ADDR_LENGTH),
[4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST + 1] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 0x08,
kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
/* 3QUAD模式快速读指令,Fast read quad mode - SDR */
[4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, W25Q_FastReadQuad_4Addr,
kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, FLASH_ADDR_LENGTH),
[4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD + 1] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, 0x08,
kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04),
/* 4读取扩展参数,Read extend parameters */
[4 * NOR_CMD_LUT_SEQ_IDX_READSTATUS] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, W25Q_ReadStatusReg,
kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
/* 5写使能,Write Enable */
[4 * NOR_CMD_LUT_SEQ_IDX_WRITEENABLE] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, W25Q_WriteEnable,
kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
/* 6擦除扇区,Erase Sector */
[4 * NOR_CMD_LUT_SEQ_IDX_ERASESECTOR] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, W25Q_SectorErase_4Addr,
kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, FLASH_ADDR_LENGTH),
/* 7SINGLE模式页写入,Page Program - single mode */
[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, W25Q_PageProgram_4Addr,
kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, FLASH_ADDR_LENGTH),
[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE + 1] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04,
kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
/* 8QUAD模式页写入,Page Program - quad mode */
[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, W25Q_PageProgramQuad_4Addr,
kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, FLASH_ADDR_LENGTH),
[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD + 1] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, 0x04,
kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
/* 9读ID,Read ID ,ID7-ID0*/
[4 * NOR_CMD_LUT_SEQ_IDX_READID] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, W25Q_DeviceID,
kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, FLASH_ADDR_LENGTH),
[4 * NOR_CMD_LUT_SEQ_IDX_READID + 1] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04,
kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
/* 10读JedecDeviceID,MF7-MF0+ID15-ID0 */
[4 * NOR_CMD_LUT_SEQ_IDX_READJEDECID] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, W25Q_JedecDeviceID,
kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
/* 11写状态寄存器,Enable Quad mode */
[4 * NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, W25Q_WriteStatusReg,
kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04),
/* 12读状态寄存器,Read status register */
[4 * NOR_CMD_LUT_SEQ_IDX_READSTATUSREG] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, W25Q_ReadStatusReg,
kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
/* 13擦除整片FLASH,Erase Chip */
[4 * NOR_CMD_LUT_SEQ_IDX_ERASECHIP] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, W25Q_ChipErase,
kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
/* 给AHB命令访问的 QUAD模式页写入 序列,包含写使能和页写入两条序列 */
/* 14写使能,Write Enable */
[4 * NOR_CMD_LUT_SEQ_IDX_AHB_PAGEPROGRAM_QUAD_1] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, W25Q_WriteEnable,
kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
/* 15QUAD模式页写入,Page Program - quad mode */
[4 * NOR_CMD_LUT_SEQ_IDX_AHB_PAGEPROGRAM_QUAD_2] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, W25Q_PageProgramQuad_4Addr,
kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, FLASH_ADDR_LENGTH),
[4 * NOR_CMD_LUT_SEQ_IDX_AHB_PAGEPROGRAM_QUAD_2 + 1] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, 0x04,
kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
// 16读唯一ID ISSI芯片,命令0X4B/
[4 * NOR_CMD_LUT_SEQ_IDX_READ_UUID_ISSI] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR,kFLEXSPI_1PAD,0x4B,
kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, FLASH_ADDR_LENGTH),
[4 * NOR_CMD_LUT_SEQ_IDX_READ_UUID_ISSI + 1] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR,kFLEXSPI_1PAD,0x04,
kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
// // 17读唯一ID 华邦芯片,命令0X4B/
// [4 * NOR_CMD_LUT_SEQ_IDX_READ_UUID_WB] =
// FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x4B,
// kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 0x18),
// [4 * NOR_CMD_LUT_SEQ_IDX_READ_UUID_WB + 1] =
// FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04,
// kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
};
extern flexspi_device_config_t deviceconfig;
flexspi_device_config_t deviceconfig = {
.flexspiRootClk = 120000000,
.flashSize = FLASH_SIZE,
.CSIntervalUnit = kFLEXSPI_CsIntervalUnit1SckCycle,
.CSInterval = 2,
.CSHoldTime = 1,
.CSSetupTime = 1,
.dataValidTime = 2,
.columnspace = 0,
.enableWordAddress = false,
.AWRSeqIndex = NOR_CMD_LUT_SEQ_IDX_AHB_PAGEPROGRAM_QUAD_1,
.AWRSeqNumber = 2,
.ARDSeqIndex = NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD,
.ARDSeqNumber = 1,
/* W25Q256 typical time=0.7ms,max time=3ms
* fAHB = 528MHz,T AHB = 1/528us
* unit = 32768/528 = 62.06us
* 取延时时间为1ms,
* AHBWriteWaitInterval = 1*1000/62.06 = 17
*/
.AHBWriteWaitUnit = kFLEXSPI_AhbWriteWaitUnit32768AhbCycle,
.AHBWriteWaitInterval = 17,
};
static void FlexSPI_NorFlash_IOMUXC_Config(void)
{
IOMUXC_SetPinMux(NONEFLASH_SS_IOMUXC,1);//不使用SION应该也可以,需要测试
IOMUXC_SetPinMux(NONEFLASH_SCLK_IOMUXC,1);
IOMUXC_SetPinMux(NONEFLASH_DATA00_IOMUXC,1);
IOMUXC_SetPinMux(NONEFLASH_DATA01_IOMUXC,1);
IOMUXC_SetPinMux(NONEFLASH_DATA02_IOMUXC,1);
IOMUXC_SetPinMux(NONEFLASH_DATA03_IOMUXC,1);
}
static void FlexSPI_NorFlash_IOMUXC_PAD_Config(void)
{
IOMUXC_SetPinConfig(NONEFLASH_SS_IOMUXC,FLEXSPI_PAD_CONFIG_DATA);
IOMUXC_SetPinConfig(NONEFLASH_SCLK_IOMUXC,FLEXSPI_PAD_CONFIG_DATA);
IOMUXC_SetPinConfig(NONEFLASH_DATA00_IOMUXC,FLEXSPI_PAD_CONFIG_DATA);
IOMUXC_SetPinConfig(NONEFLASH_DATA01_IOMUXC,FLEXSPI_PAD_CONFIG_DATA);
IOMUXC_SetPinConfig(NONEFLASH_DATA02_IOMUXC,FLEXSPI_PAD_CONFIG_DATA);
IOMUXC_SetPinConfig(NONEFLASH_DATA03_IOMUXC,FLEXSPI_PAD_CONFIG_DATA);
}
static void FlexSPI_NorFlash_ModeInit(void)
{
flexspi_config_t config;
//初始化USB1PLL PLL3 loopDivider=0 USB1PLL=PLL3 = 24*20 = 480
const clock_usb_pll_config_t g_ccmConfigUsbPll = {.loopDivider = 0U};
CLOCK_InitUsb1Pll(&g_ccmConfigUsbPll);
/* 设置 PLL3 PFD0 频率为: PLL3*18/24 = 360MHZ. */
CLOCK_InitUsb1Pfd(kCLOCK_Pfd0, 24);
/* 选择 PLL3 PFD0 作为 flexspi 时钟源
00b derive clock from semc_clk_root_pre
01b derive clock from pll3_sw_clk
10b derive clock from PLL2 PFD2
11b derive clock from PLL3 PFD0 */
CLOCK_SetMux(kCLOCK_FlexspiMux, 0x3);
/* 设置 flexspiDiv 分频因子,
得到 FLEXSPI_CLK_ROOT = PLL3 PFD0/(flexspiDiv+1) = 120M. */
CLOCK_SetDiv(kCLOCK_FlexspiDiv, 2);
/* 关闭 DCache 功能 */
SCB_DisableDCache();
//获取FlexSPI常用默认配置
FLEXSPI_GetDefaultConfig(&config);
//允许AHB预读取功能
config.ahbConfig.enableAHBPrefetch = true;
//写入配置
FLEXSPI_Init(FLEXSPI,&config);
//根据串行闪存功能配置闪存设
FLEXSPI_SetFlashConfig(FLEXSPI,&deviceconfig,kFLEXSPI_PortA1);
//更新查找表
FLEXSPI_UpdateLUT(FLEXSPI,0,customLUT,CUSTOM_LUT_LENGTH);
}
void FlexSPI_NorFlash_Init(void)
{
FlexSPI_NorFlash_IOMUXC_Config();
FlexSPI_NorFlash_IOMUXC_PAD_Config();
FlexSPI_NorFlash_ModeInit();
}
//读取FLASH芯片的JedecDevice ID
status_t FlexSPI_NorFlash_Get_JedecDevice_ID(FLEXSPI_Type *base,uint32_t *vendorID)
{
uint32_t temp;
status_t status=kStatus_Fail;
// typedef struct _flexspi_transfer
// {
// //要操作的设备地址 设置 IP 指令要访问的 FLASH 设备的内部地址 例如读命令中要读取地址 0x1000 的内容,那么控制时这个 deviceAddress 的值就应赋值为 0x1000
// uint32_t deviceAddress; /*!< Operation device address. */
// //要操作的端口A1 A2 B1 B2
// flexspi_port_t port; /*!< Operation port. */
// //要执行的命令类型 命令操作、配置设备模式操作、读操作以及写操作
// flexspi_command_type_t cmdType; /*!< Execution command type. */
// //命令序列ID 即要执行的指令序列在 LUT中的编号, FlexSPI 外设通过该配置在 LUT 中找到对应的指令序列执行
// uint8_t seqIndex; /*!< Sequence ID for command. */
// //命令序列数量 要执行 LUT 指令序列的数量
// uint8_t SeqNumber; /*!< Sequence number for command. */
// //数据缓冲区
// uint32_t *data; /*!< Data buffer. */
// //传输数据的字节数 一次传输最多不能超过 65535 个字节
// size_t dataSize; /*!< Data size in bytes. */
// } flexspi_transfer_t;
flexspi_transfer_t flashXfer;
flashXfer.deviceAddress = 0;
flashXfer.port = kFLEXSPI_PortA1;
flashXfer.cmdType = kFLEXSPI_Read;
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_READJEDECID;
flashXfer.SeqNumber = 1;
flashXfer.data = &temp;
flashXfer.dataSize = 3;
status = FLEXSPI_TransferBlocking(base,&flashXfer);
*vendorID = ((temp&0xFF)<<16) | (temp&0xFF00) | ((temp&0xFF0000)>>16);
return status;
}
//写使能
status_t FlexSPI_NorFlash_Write_Enable(FLEXSPI_Type *base)
{
status_t status=kStatus_Fail;
flexspi_transfer_t flashXfer;
flashXfer.deviceAddress = 0;
flashXfer.port = kFLEXSPI_PortA1;
flashXfer.cmdType = kFLEXSPI_Command;
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_WRITEENABLE;
flashXfer.SeqNumber = 1;
status = FLEXSPI_TransferBlocking(base,&flashXfer);
return status;
}
//等待Flash空闲状态
status_t FlexSPI_NorFlash_Wait_BusIdle(FLEXSPI_Type *base)
{
status_t status=kStatus_Fail;
flexspi_transfer_t flashXfer;
uint32_t readValue;
bool isBusy = false;
flashXfer.deviceAddress = 0;
flashXfer.port = kFLEXSPI_PortA1;
flashXfer.cmdType = kFLEXSPI_Read;
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_READSTATUSREG;
flashXfer.SeqNumber = 1;
flashXfer.data = &readValue;
flashXfer.dataSize = 1;
do{
status = FLEXSPI_TransferBlocking(base,&flashXfer);
if(status!=kStatus_Success){
return status;
}
if(readValue & (1U<<FLASH_BUSY_STATUS_OFFSET)){
isBusy = true;
}else{
isBusy = false;
}
}while(isBusy);
return status;
}
//Flash扇区擦除 FLASH 中对存储单元擦除的基本操作单位都是多个字节进行
/*
FLASH 芯片支持“扇区擦除”、“块擦除”以及“整片擦除”
扇区擦除 4KB
块擦除 64KB
整片擦除 整个芯片完全擦除
W25Q_SectorErase_4Addr 0x21
1、扇区擦除命令的第一个字节为命令编码,紧接着发送的 3 个字节用于表示要擦除的存储矩阵地址
2、要注意的是在扇区擦除命令前,还需要先发送前面的写使能命令“Write Enable(编码 0x06)”
3、发送扇区擦除指令后,要通过读取寄存器状态等待扇区擦除操作完毕
4、调用扇区擦除命令时注意输入的地址要对齐到 4KB
*/
status_t FlexSPI_NorFlash_Erase_Sector(FLEXSPI_Type *base,uint32_t destAddr)
{
status_t status=kStatus_Fail;
flexspi_transfer_t flashXfer;
status = FlexSPI_NorFlash_Write_Enable(base);//写使能
if(status != kStatus_Success){
return status;
}
//擦除指令
flashXfer.deviceAddress = destAddr;
flashXfer.port = kFLEXSPI_PortA1;
flashXfer.cmdType = kFLEXSPI_Command;
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_ERASESECTOR;
flashXfer.SeqNumber = 1;
status = FLEXSPI_TransferBlocking(base,&flashXfer);
if(status != kStatus_Success){
return status;
}
//等待擦除结束
status=FlexSPI_NorFlash_Wait_BusIdle(base);
if(status != kStatus_Success){
return status;
}
return status;
}
//Flash的Quad模式页写入
/*
1、使用页写入命令最多可以一次向 FLASH 传输 256 个字节的数据
2、第 1 个字节为“Quad 模式页写入指令”命令的编码 0x34
3、紧接着是 32 位的“地址 A”,它表示要写入的 FLASH 内部存储单元的起始地址
4、随后是要写入的内容,最多个可以发送 256 字节数据,这些数据将会从“地址 A”开始,按顺序写入到 FLASH 的存储单元中。若发送的数据超出 256 个,则会覆盖前面发送的数据
5、页写入指令的地址并不要求按 256 字节对齐但是要确认目标存储单元是擦除状态
6、实际应用中由于基本擦除单元是 4KB,一般都以扇区为单位进行读写
dataSize 不能大于256
*/
status_t FlexSPI_NorFlash_Page_Program(FLEXSPI_Type *base,const uint32_t destAddr,const uint8_t *src,const uint16_t dataSize)
{
status_t status=kStatus_Fail;
flexspi_transfer_t flashXfer;
status = FlexSPI_NorFlash_Write_Enable(base);//写使能
if(status != kStatus_Success){
return status;
}
//设置传输结构体
flashXfer.deviceAddress = destAddr;
flashXfer.port = kFLEXSPI_PortA1;
flashXfer.cmdType = kFLEXSPI_Write;
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD;
flashXfer.SeqNumber = 1;
flashXfer.data = (uint32_t *)src;
flashXfer.dataSize = dataSize;
status = FLEXSPI_TransferBlocking(base,&flashXfer);
if(status != kStatus_Success){
return status;
}
//等待写入完成
status=FlexSPI_NorFlash_Wait_BusIdle(base);
if(status != kStatus_Success){
return status;
}
return status;
}
//不定量写入数据
status_t FlexSPI_NorFlash_Buffer_Program(FLEXSPI_Type *base,uint32_t destAddr,uint8_t *src,uint16_t dataSize)
{
status_t status=kStatus_Fail;
uint16_t NumOfPage = 0;//总共几页
uint16_t NumOfSingle = 0;//剩余数据数
uint16_t Addr = 0;//写入数据是否对齐
uint16_t count = 0;//当前页还剩余可写入个数
uint16_t NumByteToWriteRest = dataSize;//最后需要处理的字节数
//判断写入地址是否对齐,判断当前页是否已写满
Addr = destAddr % FLASH_PAGE_SIZE;
count = FLASH_PAGE_SIZE - Addr;
//判断待写入数据是否小于当前页可写入数据量
NumByteToWriteRest = (dataSize>count) ? (dataSize-count) :(dataSize);
//总共需要写入的页数
NumOfPage = NumByteToWriteRest / FLASH_PAGE_SIZE;
//整数页写完后还剩余个数
NumOfSingle = NumByteToWriteRest % FLASH_PAGE_SIZE;
//如果数据量大于当前页剩余可写入个数
if(0 != count && dataSize > count){
status = FlexSPI_NorFlash_Page_Program(base,destAddr,src,count);
if(status != kStatus_Success){
return status;
}
destAddr +=count;
src += count;
}
//处理剩余数据
if(NumOfPage == 0){//如果剩余数据不足一页,则写入剩余个数
status = FlexSPI_NorFlash_Page_Program(base,destAddr,src,NumOfSingle);
if(status != kStatus_Success){
return status;
}
}else{
while(NumOfPage--){//写入整页
status = FlexSPI_NorFlash_Page_Program(base,destAddr,src,FLASH_PAGE_SIZE);
if(status != kStatus_Success){
return status;
}
destAddr +=FLASH_PAGE_SIZE;
src += FLASH_PAGE_SIZE;
}
if(NumOfSingle){//写入最后剩余个数
status = FlexSPI_NorFlash_Page_Program(base,destAddr,src,NumOfSingle);
if(status != kStatus_Success){
return status;
}
}
}
return status;
}
status_t FlexSPI_NorFlash_Buffer_Read(FLEXSPI_Type *base,uint32_t address,uint8_t *dst,uint16_t dataSize)
{
status_t status=kStatus_Fail;
flexspi_transfer_t flashXfer;
//设置传输结构体
flashXfer.deviceAddress = address;
flashXfer.port = kFLEXSPI_PortA1;
flashXfer.cmdType = kFLEXSPI_Read;
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD;
flashXfer.SeqNumber = 1;
flashXfer.data = (uint32_t *)dst;
flashXfer.dataSize = dataSize;
status = FLEXSPI_TransferBlocking(base,&flashXfer);
if(status != kStatus_Success){
return status;
}
return status;
}
status_t NorFlash_IPCommand_Test(void)
{
uint32_t JedecDeviceID=0;
status_t status=kStatus_Fail;
uint16_t i;
uint16_t errcount=0;
PRINTF("\r\n NorFlash_IPCommand_Test...\r\n");
FlexSPI_NorFlash_Get_JedecDevice_ID(FLEXSPI,&JedecDeviceID);
PRINTF("\r\n JedecDeviceID = %x\r\n",JedecDeviceID);
PRINTF("\r\nerase test...\r\n");
status = FlexSPI_NorFlash_Erase_Sector(FLEXSPI,EXAMPLE_SECTOR*SECTOR_SIZE);//通过“EXAMPLE_SECTOR * SECTOR_SIZE”操作来计算出该扇区的地址 1000 的扇区,其地址为 1000*4096
if(status != kStatus_Success){
return status;
}
status=FlexSPI_NorFlash_Buffer_Read(FLEXSPI,EXAMPLE_SECTOR*SECTOR_SIZE,s_nor_read_buffer,EXAMPLE_SIZE);
if(status != kStatus_Success){
return status;
}
for(i=0;i<EXAMPLE_SIZE;i++){
if(0xFF!=s_nor_read_buffer[i]){
errcount++;
}
}
if(0==errcount){
PRINTF("\r\nerase success...\r\n");
}else{
PRINTF("\r\nerase faile...\r\n");
}
PRINTF("\r\nwrite test...\r\n");
for(i=0;i<100;i++){
s_nor_program_buffer[i] = (uint8_t)i;
}
status=FlexSPI_NorFlash_Buffer_Program(FLEXSPI,EXAMPLE_SECTOR*SECTOR_SIZE,s_nor_program_buffer,100);
if(status != kStatus_Success){
return status;
}
status=FlexSPI_NorFlash_Buffer_Read(FLEXSPI,EXAMPLE_SECTOR*SECTOR_SIZE,s_nor_read_buffer,100);
if(status != kStatus_Success){
return status;
}
errcount=0;
for(i=0;i<100;i++){
if(s_nor_program_buffer[i]!=s_nor_read_buffer[i]){
PRINTF("\r\ns_nor_program_buffer[%d]=%d s_nor_read_buffer[%d]=%d\r\n",i,s_nor_program_buffer[i],i,s_nor_read_buffer[i]);
errcount++;
}
}
if(0==errcount){
PRINTF("\r\nwrite success...\r\n");
}else{
PRINTF("\r\nwrite faile...\r\n");
}
return status;
}
/*
bsp_flexspi.h
*/
#ifndef __BSP_FLEXSPI_H__
#define __BSP_FLEXSPI_H__
#include "fsl_debug_console.h"
#include "fsl_common.h"
#include "fsl_iomuxc.h"
#include "fsl_gpio.h"
#include "fsl_flexspi.h"
#include "pad_config.h"
#define FLASH_SIZE (32*1024)
#define FLASH_PAGE_SIZE 256 //页大小
#define SECTOR_SIZE (4*1024) /* 扇区大小4K */
//FLASH IO口宏定义
#define NONEFLASH_SS_IOMUXC IOMUXC_GPIO_SD_B1_06_FLEXSPIA_SS0_B
#define NONEFLASH_SCLK_IOMUXC IOMUXC_GPIO_SD_B1_07_FLEXSPIA_SCLK
#define NONEFLASH_DATA00_IOMUXC IOMUXC_GPIO_SD_B1_08_FLEXSPIA_DATA00
#define NONEFLASH_DATA01_IOMUXC IOMUXC_GPIO_SD_B1_09_FLEXSPIA_DATA01
#define NONEFLASH_DATA02_IOMUXC IOMUXC_GPIO_SD_B1_10_FLEXSPIA_DATA02
#define NONEFLASH_DATA03_IOMUXC IOMUXC_GPIO_SD_B1_11_FLEXSPIA_DATA03
//使用FLASH地址宽度,单位bit
#define FLASH_ADDR_LENGTH (32U)
//W25Q256JV 常用命令
#define W25Q_WriteEnable 0x06
#define W25Q_WriteDisable 0x04
#define W25Q_ReadStatusReg 0x05
#define W25Q_WriteStatusReg 0x01
#define W25Q_ReadData 0x03
#define W25Q_ReadData_4Addr 0x13
#define W25Q_FastReadData 0x0B
#define W25Q_FastReadData_4Addr 0x0C
#define W25Q_FastReadDataQual 0x3B
#define W25Q_FastReadDataQual_4Addr 0x3C
#define W25Q_FastReadQuad 0x6B
#define W25Q_FastReadQuad_4Addr 0x6C
#define W25Q_PageProgram 0x02
#define W25Q_PageProgram_4Addr 0x12
#define W25Q_PageProgramQuad 0x32
#define W25Q_PageProgramQuad_4Addr 0x34
#define W25Q_BlockErase 0xD8
#define W25Q_BlockErase_4Addr 0xDC
#define W25Q_SectorErase 0x20
#define W25Q_SectorErase_4Addr 0x21
#define W25Q_ChipErase 0xC7
#define W25Q_PowerDown 0xB9
#define W25Q_ReleasePowerDown 0xAB
#define W25Q_DeviceID 0xAB
#define W25Q_ManufactDeciceID 0X90
#define W25Q_JedecDeviceID 0x9F
#define FLASH_ID 0x18
#define FLASH_JEDECDEVICE_ID 0xEF4019
#define FLEXSPI_PAD_CONFIG_DATA (SRE_1_FAST_SLEW_RATE | \
DSE_6_R0_6 | \
SPEED_3_MAX_200MHz | \
ODE_0_OPEN_DRAIN_DISABLED | \
PKE_1_PULL_KEEPER_ENABLED | \
PUE_0_KEEPER_SELECTED | \
PUS_0_100K_OHM_PULL_DOWN | \
HYS_0_HYSTERESIS_DISABLED)
void FlexSPI_NorFlash_Init(void);
status_t FlexSPI_NorFlash_Get_JedecDevice_ID(FLEXSPI_Type *base,uint32_t *vendorID);
status_t FlexSPI_NorFlash_Write_Enable(FLEXSPI_Type *base);
status_t FlexSPI_NorFlash_Wait_BusIdle(FLEXSPI_Type *base);
status_t FlexSPI_NorFlash_Erase_Sector(FLEXSPI_Type *base,uint32_t destAddr);
status_t FlexSPI_NorFlash_Page_Program(FLEXSPI_Type *base,const uint32_t destAddr,const uint8_t *src,const uint16_t dataSize);
status_t FlexSPI_NorFlash_Buffer_Program(FLEXSPI_Type *base,uint32_t destAddr,uint8_t *src,uint16_t dataSize);
status_t FlexSPI_NorFlash_Buffer_Read(FLEXSPI_Type *base,uint32_t address,uint8_t *dst,uint16_t dataSize);
status_t NorFlash_IPCommand_Test(void);
#endif // __BSP_FLEXSPI_H__
/*
main.c
*/
......
FlexSPI_NorFlash_Init();
NorFlash_IPCommand_Test();
......