华大FLASH之w25Q系列

W25Q64JV的标准/双/四SPl指令集由48条基本指令组成,这些指令通过SPI总线完全控制(见指令集表1-2)。
指令从芯片选择(/CS)的下降沿开始。时钟输入DI输入的第一字节数据提供指令代码。DI输入上的数据在时钟的上升沿上采样,
最高有效位(MSB)优先。指令的长度从单个字节到几个字节不等,后面可能是地址字节、数据字节、虚拟字节(无需在意),
在某些情况下还可能是组合。指令以edge/CS的上升沿完成。每条指令的时钟相对时序图如图5至57所示。所有读取指令都可以在
任何时钟位之后完成。但是,所有写、编程或擦除指令都必须在字节边界上完成(/CS驱动高电平,在时钟位满8位之后),
否则该指令将被忽略。此功能进一步保护设备免受无意写入。此外,当存储器被编程或擦除时,或者当状态寄存器被写入时,
除了读取状态寄存器之外的所有指令都将被忽略,直到编程或擦除周期完成。

 读写接口都是先发送cmd,即是表中的byte1,而后发送或者接收信息,SPI访问接口这里暂不延升。

#define LOAD_CMD(a, cmd, addr)  do  {                                       \
                                        (a)[0U] = (cmd);                    \
                                        (a)[1U] = (uint8_t)((addr) >> 16U); \
                                        (a)[2U] = (uint8_t)((addr) >> 8U);  \
                                        (a)[3U] = (uint8_t)(addr);          \
                                    } while (0U)


static void W25QXX_Wt(uint8_t u8Cmd, uint32_t u32Address, const uint8_t *pu8Data, uint32_t u32DataLength)
{
    uint8_t au8Cmd[4U];

    LOAD_CMD(au8Cmd, u8Cmd, u32Address);

    W25Q_CS_ACTIVE();
    (void)BSP_W25Q_SPI_Transmit(au8Cmd, 4U);
    (void)BSP_W25Q_SPI_Transmit(pu8Data, u32DataLength);
    W25Q_CS_INACTIVE();
}

static void W25QXX_Rd(uint8_t u8Cmd, uint32_t u32Address, uint8_t *pu8Data, uint32_t u32DataLength)
{
    uint8_t au8Cmd[4U];

    LOAD_CMD(au8Cmd, u8Cmd, u32Address);

    W25Q_CS_ACTIVE();
    (void)BSP_W25Q_SPI_Transmit(au8Cmd, 4U);
    (void)BSP_W25Q_SPI_Receive(pu8Data, u32DataLength);
    W25Q_CS_INACTIVE();
}


static void W25QXX_WriteCmd(uint8_t u8Cmd, const uint8_t *pu8CmdData, uint32_t u32CmdDataLength)
{
    W25Q_CS_ACTIVE();
    (void)BSP_W25Q_SPI_Transmit(&u8Cmd, 1U);
    (void)BSP_W25Q_SPI_Transmit(pu8CmdData, u32CmdDataLength);
    W25Q_CS_INACTIVE();
}

static void W25QXX_ReadCmd(uint8_t u8Cmd, uint8_t *pu8CmdData, uint32_t u32CmdDataLength,
                         uint8_t *pu8Info, uint8_t u8InfoLength)
{
    W25Q_CS_ACTIVE();
    (void)BSP_W25Q_SPI_Transmit(&u8Cmd, 1U);
    (void)BSP_W25Q_SPI_Transmit(pu8CmdData, u32CmdDataLength);
    (void)BSP_W25Q_SPI_Receive(pu8Info, (uint32_t)u8InfoLength);
    W25Q_CS_INACTIVE();
}

define W25Q_WRITE_ENABLE                   ((uint8_t)0x06U)
#define W25Q_VOLATILE_SR_WRITE_ENABLE       ((uint8_t)0x50U)
#define W25Q_WRITE_DISABLE                  ((uint8_t)0x04U)
#define W25Q_READ_STATUS_REG_1              ((uint8_t)0x05U)
#define W25Q_READ_STATUS_REG_2              ((uint8_t)0x35U)
#define W25Q_WRITE_STATUS_REG               ((uint8_t)0x01U)
#define W25Q_PAGE_PROGRAM                   ((uint8_t)0x02U)
#define W25Q_SECTOR_ERASE                   ((uint8_t)0x20U)
#define W25Q_BLOCK_ERASE_32K                ((uint8_t)0x52U)
#define W25Q_BLOCK_ERASE_64K                ((uint8_t)0xD8U)
#define W25Q_CHIP_ERASE                     ((uint8_t)0xC7U)
#define W25Q_ERASE_PROGRAM_SUSPEND          ((uint8_t)0x75U)
#define W25Q_ERASE_PROGRAM_RESUME           ((uint8_t)0x7AU)
#define W25Q_POWER_DOWN                     ((uint8_t)0xB9U)
#define W25Q_READ_DATA                      ((uint8_t)0x03U)
#define W25Q_FAST_READ                      ((uint8_t)0x0BU)
#define W25Q_DEVICE_ID                      ((uint8_t)0xABU)
#define W25Q_RELEASE_POWER_DOWN             (W25Q_DEVICE_ID)
#define W25Q_MANUFACTURER_DEVICE_ID         ((uint8_t)0x90U)
#define W25Q_JEDEC_ID                       ((uint8_t)0x9FU)
#define W25Q_READ_UNIQUE_ID                 ((uint8_t)0x4BU)
#define W25Q_READ_SFDP_REG                  ((uint8_t)0x5AU)
#define W25Q_REASE_SECURITY_REG             ((uint8_t)0x44U)
#define W25Q_PROGRAM_SECURITY_REG           ((uint8_t)0x42U)
#define W25Q_READ_SECURITY_REG              ((uint8_t)0x48U)
#define W25Q_ENABLE_QPI                     ((uint8_t)0x38U)
#define W25Q_ENABLE_RESET                   ((uint8_t)0x66U)
#define W25Q_RESET                          ((uint8_t)0x99U) 

#define W25Q_ST_BUSY                ((uint16_t)W25Q_BIT_0)
#define W25Q_ST_WEL                 ((uint16_t)W25Q_BIT_1) 

1,使能去使能flash 

static void W25QXX_WriteEnable(void)
{
    W25QXX_WriteCmd(W25Q_WRITE_ENABLE, NULL, 0U);
}

static void W25QXX_WriteDisable(void)
{
    W25QXX_WriteCmd(W25Q_WRITE_DISABLE, NULL, 0U);
}

2,检测flash busy忙状态:

uint16_t W25QXX_ReadStatus(void)
{
    uint8_t  u8TempStatus;
    uint16_t u16RetStatus;

    W25QXX_ReadCmd(W25Q_READ_STATUS_REG_2, NULL, 0U, &u8TempStatus, 1U);

    u16RetStatus = u8TempStatus;

    W25QXX_ReadCmd(W25Q_READ_STATUS_REG_1, NULL, 0U, &u8TempStatus, 1U);

    u16RetStatus <<= 8U;
    u16RetStatus |= u8TempStatus;

    return u16RetStatus;
}

static void W25QXX_WaitBusy(void)
{
    while ((W25QXX_ReadStatus() & W25Q_ST_BUSY) == W25Q_ST_BUSY)
    {
        ;
    }
}

 3,flash的读写

static void W25QXX_WritePage(uint32_t u32Address, const uint8_t *pu8Data, uint32_t u32DataLength)
{
    W25QXX_WriteEnable();
    W25QXX_Wt(W25Q_PAGE_PROGRAM, u32Address, pu8Data, u32DataLength);
    W25QXX_WaitBusy();
}

void W25QXX_ReadData(uint32_t u32Address, uint8_t *pu8ReadBuf, uint32_t u32NumByteToRead)
{
    W25QXX_Rd(W25Q_READ_DATA, u32Address, pu8ReadBuf, u32NumByteToRead);
}

void W25QXX_WriteData(uint32_t u32Address, const uint8_t *pu8WriteBuf, uint32_t u32NumByteToWrite)
{
    uint32_t secpos;
    uint16_t secoff;
    uint16_t secremain;
    uint16_t i;
    uint8_t  *pW25QXX_BUF;
    pW25QXX_BUF = W25QXX_BUFFER;
    uint32_t u32WriteBufAddr = (uint32_t)&pu8WriteBuf;

    secpos     = u32Address / 4096U;
    secoff     = (uint16_t)(u32Address % 4096U);
    secremain  = 4096U - secoff;

    if (u32NumByteToWrite <= secremain)
    {
        secremain = (uint16_t)u32NumByteToWrite;
    }

    for(;;)
    {
        W25QXX_ReadData(secpos * 4096U, pW25QXX_BUF, 4096U); // read one sector content
        for (i = 0U; i < secremain; i++) // check if blank sector
        {
            if (pW25QXX_BUF[secoff + i] != (uint8_t)0xFFU)
            {
                break;
            }
        }

        if (i < secremain)
        {
            W25QXX_EraseSector(secpos);          // not blank, need erase
            for (i = 0U; i < secremain; i++)     // backup first
            {
                pW25QXX_BUF[i + secoff] = pu8WriteBuf[i];
            }
            W25QXX_Write_NoCheck(pW25QXX_BUF, secpos * 4096U, 4096U); // write back after erase

        }
        else
        {
            W25QXX_Write_NoCheck((const uint8_t *)u32WriteBufAddr, u32Address,secremain);
        }

        if (u32NumByteToWrite == secremain)
        {
            break;
        }
        else
        {
            secpos++;          // next sector
            secoff          = 0U;

            u32WriteBufAddr    += secremain;
            u32Address         += secremain;
            u32NumByteToWrite  -= secremain;
            if (u32NumByteToWrite > 4096U)
            {
                secremain = 4096U;
            }
            else
            {
                secremain = (uint16_t)u32NumByteToWrite;
            }
        }
    }
}

4,earse擦除flash

void W25QXX_EraseChip(void)
{
    W25QXX_WriteEnable();
    W25QXX_WaitBusy();
    W25QXX_WriteCmd(W25Q_CHIP_ERASE, NULL, 0U);
    W25QXX_WaitBusy();
}


void W25QXX_EraseSector(uint32_t u32SectorAddress)
{
    u32SectorAddress *= W25Q_SIZE_SECTOR;

    W25QXX_WriteEnable();
    W25QXX_WaitBusy();

    W25QXX_Wt(W25Q_SECTOR_ERASE, u32SectorAddress, NULL, 0U);

    W25QXX_WaitBusy();
    W25QXX_WriteDisable();
}


void W25QXX_EraseBlock(uint32_t u32BlockAddress)
{
    W25QXX_Wt(W25Q_BLOCK_ERASE_64K, u32BlockAddress, NULL, 0U);
}

  • 18
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陌上花开缓缓归以

你的鼓励将是我创作的最大动力,

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值