基于RT1052的FlexSPI读写FLASH(W25Q256JV)

本文档详细介绍了如何在RT1052平台上通过FlexSPI接口实现W25Q256JV闪存的读写操作,包括指令定义、查找表定制、初始化过程和关键函数的使用示例,如读取JedecDeviceID、写使能和扇区擦除等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于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();
......
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值