SFDP – NOR Flash 的简历

/ 0评 / 1

JEDEC有一个针对Nor Flash的标准,当然不是所有Nor Flash都符合这个标准.比如国产GD你说兼容不兼容,我就懒得说了.
下面我说的是镁光的65nm闪存N25Q128A,支持SFDP的.此身份证总长9 DWORD.为了更准确验证,我们应该写个程序.因为不是所有Flash都支持QSPI,DSPI所以用单线的验证下.特别是有些Flash必须人工写入某寄存器才能开启QSPI的...

指令固定是0x5A,因为事先假设不知道Flash型号,然后发24bit地址,8个dummy.然后返回长度是9个DWORD,这是根据SPDF的官方手册(JEDEC)写的,9 * 4 = 36Byte,然后0x0F - 0x2F是保留不使用的,所以总长是84个字节.不排除以后出现超过9个DWORD,那么程序就得改了,因为9 DWORD后面暂时没内容,所以暂时以9 DWORD来判断.先写个获取代码.

void BSP_QSPI_Read_SPDF(uint8_t *pData)
{
    QSPI_CommandTypeDef sCommand;
    /* Initialize the read command */
    sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
    sCommand.Instruction       = 0x5A;
    sCommand.AddressMode       = QSPI_ADDRESS_1_LINE;
    sCommand.AddressSize       = QSPI_ADDRESS_24_BITS;
    sCommand.Address           = 0x00000000;
    sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
    sCommand.DataMode          = QSPI_DATA_1_LINE;
    sCommand.DummyCycles       = 8;
    sCommand.NbData            = 84;
    sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;
    sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
    sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;
    /* Configure the command */
    QSPI_Command(&sCommand);
    /* Reception of the data */
    QSPI_Receive(pData);
}

pData就是返回的数据,记得不要导致内存溢出了.明显,签名字节已经获取到了.

然后我做成个结构体,这样方便我自己访问.

typedef struct
{
    uint32_t Signature;
    uint16_t Revision;
    uint8_t Number;
    uint8_t RESERVED0;
    uint8_t Parameter_ID;
    uint8_t Parameter_Minor_Rev;
    uint8_t Parameter_Major_Rev;
    uint8_t Parameter_Length;
    uint32_t PTP;
    uint32_t dwData[9];
} BSP_QSPI_SFDP_TypeDef;

dwData就是真正简历部分,要通过PTP寻址.然后我的读取函数改成.

void BSP_QSPI_Read_SPDF(BSP_QSPI_SFDP_TypeDef *pID)
{
    QSPI_CommandTypeDef sCommand;
    uint8_t *pRxBuffPtr = (uint8_t *)pID;
    /* Initialize the read command */
    sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
    sCommand.Instruction       = 0x5A;
    sCommand.AddressMode       = QSPI_ADDRESS_1_LINE;
    sCommand.AddressSize       = QSPI_ADDRESS_24_BITS;
    sCommand.Address           = 0x00000000;
    sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
    sCommand.DataMode          = QSPI_DATA_1_LINE;
    sCommand.DummyCycles       = 8;
    sCommand.NbData            = 16;
    sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;
    sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
    sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;
    /* Configure the command */
    QSPI_Command(&sCommand);
    /* Reception of the data */
    QSPI_Receive(pRxBuffPtr);
    pID->PTP = pID->PTP & 0xFFFFFF;
    /* 此处获得对应位置指针. */
    /* Initialize the read command */
    sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
    sCommand.Instruction       = 0x5A;
    sCommand.AddressMode       = QSPI_ADDRESS_1_LINE;
    sCommand.AddressSize       = QSPI_ADDRESS_24_BITS;
    sCommand.Address           = pID->PTP;
    sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
    sCommand.DataMode          = QSPI_DATA_1_LINE;
    sCommand.DummyCycles       = 8;
    sCommand.NbData            = 36;
    sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;
    sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
    sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;
    /* Configure the command */
    QSPI_Command(&sCommand);
    /* Reception of the data */
    QSPI_Receive(pRxBuffPtr + 0x10);
}

读取得到.

参考解码手册:
JESD216
解码第一个WORD(其他差不多):

主要代码:

#include "N25Q128.h"
#include "SEGGER_RTT.h"
BSP_QSPI_ID_TypeDef pId;
BSP_QSPI_SFDP_TypeDef pSFDP;
void SPIFFS_Main(void)
{
    BSP_QSPI_Init();
    BSP_QSPI_RDID(&pId);
    BSP_QSPI_Read_SPDF(&pSFDP);
    SEGGER_RTT_printf(0, "SFDP Detect! 
");
    if((pSFDP.dwData[0] & 0x03) == 0x01)
    {
        SEGGER_RTT_printf(0, "4KB Erase Support:YES 
");
    }
    else
    {
        SEGGER_RTT_printf(0, "4KB Erase Support:NO 
");
    }
    if((pSFDP.dwData[0] & 0x04) == 0x04)
    {
        SEGGER_RTT_printf(0, "64B Write Buffer:YES 
");
    }
    else
    {
        SEGGER_RTT_printf(0, "64B Write Buffer:NO 
");
    }
    if((pSFDP.dwData[0] & 0x08) == 0x08)
    {
        SEGGER_RTT_printf(0, "WRITE ENABLE command required for writing to volatile status registers:YES 
");
    }
    else
    {
        SEGGER_RTT_printf(0, "WRITE ENABLE command required for writing to volatile status registers:NO 
");
    }
    if((pSFDP.dwData[0] & 0x10) == 0x10)
    {
        SEGGER_RTT_printf(0, "WRITE ENABLE command code select for writing to volatile status register:YES 
");
    }
    else
    {
        SEGGER_RTT_printf(0, "WRITE ENABLE command code select for writing to volatile status register:NO 
");
    }
    if(pSFDP.dwData[0] & 0xFF00)
    {
        SEGGER_RTT_printf(0, "4KB ERASE command code:0x%02X 
", (pSFDP.dwData[0] & 0xFF00) >> 8);
    }
    if((pSFDP.dwData[0] & 0x10000) == 0x10000)
    {
        SEGGER_RTT_printf(0, "Supports 1-1-2 fast read:YES 
");
    }
    else
    {
        SEGGER_RTT_printf(0, "Supports 1-1-2 fast read:NO 
");
    }
    if((pSFDP.dwData[0] & 0x60000) == 0x00000)
    {
        SEGGER_RTT_printf(0, "Address Bytes:3 Byte 
");
    }
    else if((pSFDP.dwData[0] & 0x60000) == 0x20000)
    {
        SEGGER_RTT_printf(0, "Address Bytes:3 Byte + 4Byte 
");
    }
    else if((pSFDP.dwData[0] & 0x60000) == 0x40000)
    {
        SEGGER_RTT_printf(0, "Address Bytes:4Byte 
");
    }
    if((pSFDP.dwData[0] & 0x80000) == 0x80000)
    {
        SEGGER_RTT_printf(0, "Supports Double Transfer Rate (DTR) Clocking:YES 
");
    }
    else
    {
        SEGGER_RTT_printf(0, "Supports Double Transfer Rate (DTR) Clocking:NO 
");
    }
    if((pSFDP.dwData[0] & 0x100000) == 0x100000)
    {
        SEGGER_RTT_printf(0, "Supports (1-2-2) Fast Read:YES 
");
    }
    else
    {
        SEGGER_RTT_printf(0, "Supports (1-2-2) Fast Read:NO 
");
    }
    if((pSFDP.dwData[0] & 0x200000) == 0x200000)
    {
        SEGGER_RTT_printf(0, "Supports (1-4-4) Fast Read:YES 
");
    }
    else
    {
        SEGGER_RTT_printf(0, "Supports (1-4-4) Fast Read:NO 
");
    }
    if((pSFDP.dwData[0] & 0x400000) == 0x400000)
    {
        SEGGER_RTT_printf(0, "Supports (1-1-4) Fast Read:YES 
");
    }
    else
    {
        SEGGER_RTT_printf(0, "Supports (1-1-4) Fast Read:NO 
");
    }
    for(;;)
    {
        vTaskDelay(1);
    }
}

 

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注