STM32之SPI驱动外部Flash

16 篇文章 2 订阅
1 篇文章 0 订阅

MCU为STM32F030C8T6,Nor Flash为IS25LQ010B。

spi.h源代码

#ifndef __spi_H
#define __spi_H

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "stm32f0xx_hal.h"

#define    SPI2_NSS     GPIO_PIN_12    /* PB12 */
#define    SPI2_SCLK    GPIO_PIN_13    /* PB13 */
#define    SPI2_MISO    GPIO_PIN_14    /* PB14 */
#define    SPI2_MOSI    GPIO_PIN_15    /* PB15 */

/* Variables */
extern SPI_HandleTypeDef hspi2;


/* Function prototype */
extern void _Error_Handler(char *, int);
void MX_SPI2_Init(void);

#ifdef __cplusplus
}
#endif

#endif /*__ spi_H */

spi.c源代码:

#include "spi.h"

SPI_HandleTypeDef hspi2;

/* SPI2 init function */
void MX_SPI2_Init(void)
{
    hspi2.Instance = SPI2;
    hspi2.Init.Mode = SPI_MODE_MASTER;
    hspi2.Init.Direction = SPI_DIRECTION_2LINES;
    hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
    hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
    hspi2.Init.NSS = SPI_NSS_SOFT;
    hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
    hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
    hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    hspi2.Init.CRCPolynomial = 7;
    hspi2.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
    hspi2.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;

    if (HAL_SPI_Init(&hspi2) != HAL_OK)
    {
        _Error_Handler(__FILE__, __LINE__);
    }
}

/* Init SPI GPIO pins */
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    if(spiHandle->Instance==SPI2)
    {
        /* SPI2 clock enable */
        __HAL_RCC_SPI2_CLK_ENABLE();
        __HAL_RCC_GPIOB_CLK_ENABLE();

        /**SPI2 GPIO Configuration
        PB12     ------> SPI2_NSS
        PB13     ------> SPI2_SCK
        PB14     ------> SPI2_MISO
        PB15     ------> SPI2_MOSI
        */
        GPIO_InitStruct.Pin = SPI2_NSS;
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        GPIO_InitStruct.Pin =  SPI2_SCLK | SPI2_MISO | SPI2_MOSI;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF0_SPI2;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        /* Configure SPI2_NSS default output level */
        HAL_GPIO_WritePin(GPIOB, SPI2_NSS, GPIO_PIN_SET);
    }
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{
    if(spiHandle->Instance==SPI2)
    {
        /* Peripheral clock disable */
        __HAL_RCC_SPI2_CLK_DISABLE();
        __HAL_RCC_GPIOB_CLK_DISABLE();

        /**SPI2 GPIO Configuration
        PB12     ------> SPI2_NSS
        PB13     ------> SPI2_SCK
        PB14     ------> SPI2_MISO
        PB15     ------> SPI2_MOSI
        */
        HAL_GPIO_DeInit(GPIOB, SPI2_NSS | SPI2_SCLK | SPI2_MISO | SPI2_MOSI);
    }
}

flash.h源代码:

#ifndef __FLASH_IS25LQ010B_H__
#define __FLASH_IS25LQ010B_H__  /* Define macro __FLASH_IS25LQ010B_H__ */

#ifdef __cplusplus
extern "C"{
#endif

#include <stdint.h>
#include <stdbool.h>

#define IS25LQ010B   /* Define NOR Flash type */
#define MAX_COMMAND_SIZE  (256+3+1)

#define    DUMMY_BYTE    (0x00)
#define    SPI2_TIMEOUT  (1000)
#define    SPI2_WAITING_FOREVER    (0xFFFFFFFF)

#define IS25LQ010B_FLASH_BASE_ADDRESS    (0x000000)
#define IS25LQ010B_FLASH_SECTOR_SIZE     (0x1000)              /* 4Kb */
#define IS25LQ010B_FLASH_BLOCK_SIZE      (IS25LQ010B_FLASH_SECTOR_SIZE*8)    /* 32Kb */
#define IS25LQ010B_FLASH_SIZE            (IS25LQ010B_FLASH_BLOCK_SIZE*4)      /* 128Kb */

/* Device Operation Instruction Set */
#define   RD       0x03    /* Read Data Bytes from Memory at Normal Read Mode, SPI mode, Maximum frequency 33MHz */
#define   FR       0x0B    /* Read Data Bytes from Memory at Fast Read Mode, SPI mode, Maximum frequency 104MHz */
#define   FRDIO    0xBB    /* Fast Read Dual I/O, SPI mode, Maximum frequency 104MHz */
#define   FRDO     0x3B    /* Fast Read Dual Output, SPI mode, Maximum frequency 104MHz */
#define   FRQIO    0xEB    /* Fast Read Quad I/O, SPI mode, Maximum frequency 104MHz */
#define   FRQO     0x6B    /* Fast Read Quad Output, SPI mode, Maximum frequency 104MHz */

/* Follow instructions must be preceded by the WREN instruction */ 
/************************** Start *********************************/ 
#define    PP    0x02       /* Page Program Data Bytes into Memory, SPI mode, Maximum frequency 104MHz */
#define    PPQ   0x32       /* Page Program Data Bytes into Memory with Quad Interface, SPI mode, Maximum frequency 104MHz */
//#define    PPQ   0x38     /* Page Program Data Bytes into Memory with Quad Interface, SPI mode, Maximum frequency 104MHz */
#define    SER   0xD7       /* Sector Erase 4KB, SPI mode, Maximum frequency 104MHz */
//#define    SER   0x20     /* Sector Erase 4KB, SPI mode, Maximum frequency 104MHz */

#if defined(IS25LQ040B) || defined(IS25LQ020B) || defined(IS25LQ010B)
    #define    BER32    0x52    /* Block Erase 32KB, SPI mode, Maximum frequency 104MHz */
    #define    BER64    0xD8    /* Block Erase 64KB, SPI mode, Maximum frequency 104MHz */
#elif defined(IS25LQ512B) || defined(IS25LQ025B)
    #define    BER32    0x52    /* Block Erase 32KB, SPI mode, Maximum frequency 104MHz */
    //#define    BER32    0xD8    /* Block Erase 32KB, SPI mode, Maximum frequency 104MHz */
    #define    BER64            /* Unsupported instruction */
#endif

#if defined(IS25LQ040B) || defined(IS25LQ020B) || defined(IS25LQ010B) || defined(IS25LQ512B)
    #define    CER      0xC7    /* Chip Erase, SPI mode, Maximum frequency 104MHz */
    //#define    CER      0x60    /* Chip Erase, SPI mode, Maximum frequency 104MHz */
#endif

#define    WRSR     0x01    /* Write Status Register, SPI mode, Maximum frequency 104MHz */
#define    WRFR     0x42    /* Write Function Register, SPI mode, Maximum frequency 104MHz */
#define    IRP      0x62    /* Program Information Row, SPI mode, Maximum frequency 104MHz */
/************************** End *********************************/

#define    WREN     0x06    /* Write Enable, SPI mode, Maximum frequency 104MHz */
#define    WRDI     0x04    /* Write Disable, SPI mode, Maximum frequency 104MHz */
#define    RDSR     0x05    /* Read Status Register, SPI mode, Maximum frequency 104MHz */
#define    RDFR     0x48    /* Read Function Register, SPI mode, Maximum frequency 104MHz */
#define    PERSUS   0x75    /* Suspend during the Program/Erase, SPI mode, Maximum frequency 104MHz */ 
//#define    PERSUS   0xB0    /* Suspend during the Program/Erase, SPI mode, Maximum frequency 104MHz */
#define    PERRSM    0x7A   /* Resume Program/Erase, SPI mode, Maximum frequency 104MHz */ 
//#define    PERRSM    0x30   /* Resume Program/Erase, SPI mode, Maximum frequency 104MHz */
#define    DP       0xB9    /* Deep Power Down Mode, SPI mode, Maximum frequency 104MHz */
#define    RDID     0xAB    /* Read Manufacturer and Product ID/Release Deep Power Down, SPI mode, Maximum frequency 104MHz */
#define    RDPD     0xAB    /* Read Manufacturer and Product ID/Release Deep Power Down, SPI mode, Maximum frequency 104MHz */
#define    RDUID    0x4B    /* Read Unique ID Number, SPI mode, Maximum frequency 104MHz */
#define    RDJDID   0x9F    /* Read Manufacturer and Product ID by JEDEC ID Command, SPI mode, Maximum frequency 104MHz */
#define    RDMDID   0x90    /* Read Manufacturer and Device ID, SPI mode, Maximum frequency 104MHz */
#define    RDSFDP   0x5A    /* SFDP Read, SPI mode, Maximum frequency 104MHz */
#define    RSTEN    0x66    /* Software Reset Enable, SPI mode, Maximum frequency 104MHz */
#define    RST      0x99    /* Reset, SPI mode, Maximum frequency 104MHz */
#define    IRRD     0x68    /* Read Information Row, SPI mode, Maximum frequency 104MHz */
#define    SECUNLOCK  0x26  /* Sector Unlock, SPI mode, Maximum frequency 104MHz */
#define    SECLOCK  0x24    /* Sector Lock, SPI mode, Maximum frequency 104MHz */

/* Function Prototype */
void IS25LQ010B_NORFlashInit(void);
void IS25LQ010B_NSSEnable(void);
void IS25LQ010B_NSSDisable(void);
bool IS25LQ010B_WriteEnable(void);
bool IS25LQ010B_WriteDisable(void);
int32_t IS25LQ010B_ReadStatusRegister(uint8_t* StatusRegister);
int32_t IS25LQ010B_WriteSatusRegister(uint8_t SatusRegister);
int32_t IS25LQ010B_ReadFunctionRegister(uint8_t* FunctionRegister);
int32_t IS25LQ010B_WriteFunctionRegister(uint8_t FunctionRegister);
bool IS25LQ010B_DeviceIsBusy(void);
int32_t IS25LQ010B_WritePage(uint32_t Address, uint8_t* Data, uint16_t Size);
int32_t IS25LQ010B_WriteNoCheck(uint32_t Address, uint8_t* Data, uint16_t Size);
int32_t IS25LQ010B_Write(uint32_t Address, uint8_t* Data, uint16_t Size);
int32_t IS25LQ010B_SectorErase(uint32_t Address);
int32_t IS25LQ010B_BlockErase32KB(uint32_t Address);
int32_t IS25LQ010B_BlockErase64KB(uint32_t Address);
int32_t IS25LQ010B_EraseChip(void);
int32_t IS25LQ010B_Read(uint32_t Address, uint8_t* Data, uint16_t Size);
int32_t IS25LQ010B_FastRead(uint32_t Address, uint8_t* Data, uint16_t Size);
int32_t IS25LQ010B_DeepPowerDown(void);
int32_t IS25LQ010B_ReleaseDeepPowerDown(void);
int32_t IS25LQ010B_ReadDeviceID(uint8_t* DeviceID);
int32_t IS25LQ010B_ReadManufacturerProductCapacity(uint8_t* ManufacturerID, uint8_t* DeviceType, uint8_t* Capacity);
int32_t IS25LQ010B_ReadManufacturerIDDeviceID(uint32_t Address, uint8_t* ManufacturerID, uint8_t* DeviceID);
int32_t IS25LQ010B_ReadUID(uint32_t Address, uint8_t* UID, uint16_t* UIDSize);
int32_t IS25LQ010B_ReadSerialFlashDiscoverableParameter(uint32_t Address, uint8_t* Data, uint16_t Size);
int32_t IS25LQ010B_SoftwareReset(void);
int32_t IS25LQ010B_WritRowPage(uint32_t Address, uint8_t* Data, uint16_t Size);
int32_t IS25LQ010B_WriteRowNoCheck(uint32_t Address, uint8_t* Data, uint16_t Size);
int32_t IS25LQ010B_WriteRow(uint32_t Address, uint8_t* Data, uint16_t Size);
int32_t IS25LQ010B_ReadRow(uint32_t Address, uint8_t* Data, uint16_t Size);
int32_t IS25LQ010B_SectorLock(void);
int32_t IS25LQ010B_SectorUnlock(uint32_t Address);

#ifdef __cplusplus
}
#endif

#endif /* End define macro __FLASH_IS25LQ010B_H__ */

flash.c源代码:

#include "flash_is25lq010b.h"
#include "spi.h"
#include <string.h>

/*
** @Brief: Init flash spi driver
** @Parameter: None
** @Return: None
**/
void IS25LQ010B_NORFlashInit(void)
{
    MX_SPI2_Init();
}

/*
** @Brief: Spi Chip Select Pin pull down and enable spi
** @Parameter: None
** @Return: None
**/
void IS25LQ010B_NSSEnable(void)
{
    HAL_GPIO_WritePin(GPIOB, SPI2_NSS, GPIO_PIN_RESET);
}

/*
** @Brief: Spi Chip Select Pin up down and disable spi
** @Parameter: None
** @Return: None
**/
void IS25LQ010B_NSSDisable(void)
{
    HAL_GPIO_WritePin(GPIOB, SPI2_NSS, GPIO_PIN_SET);
}

/*
** @Brief: Enable flash write function
** @Parameter: None
** @Return: 1) true, Enable OK
            2) false, Enable failed
**/
bool IS25LQ010B_WriteEnable(void)
{
    uint8_t Command = WREN;

    IS25LQ010B_NSSEnable();

    HAL_StatusTypeDef State = HAL_SPI_Transmit(&hspi2, &Command, 1, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return false;
    }

    IS25LQ010B_NSSDisable();

    return true;
}

/*
** @Brief: Disable flash write function
** @Parameter: None
** @Return: 1) true, Disable OK
            2) false, Disable failed
**/
bool IS25LQ010B_WriteDisable(void)
{
    uint8_t Command = WRDI;

    IS25LQ010B_NSSEnable();

    HAL_StatusTypeDef State = HAL_SPI_Transmit(&hspi2, &Command, 1, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return false;
    }

    IS25LQ010B_NSSDisable();

    return true;
}

/*
** @Brief: Read status register value
** @Parameter: StatusRegister, Status Register value
** @Return: 1) 0, get Status Register OK
            2) -1, get Status Register failed
**/
int32_t IS25LQ010B_ReadStatusRegister(uint8_t* StatusRegister)
{
    uint8_t Command = RDSR;
    HAL_StatusTypeDef State = HAL_OK;

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, &Command, 1, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        StatusRegister = NULL;
        return -1;
    }

    State = HAL_SPI_Receive(&hspi2, StatusRegister, 1, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        StatusRegister = NULL;
        return -2;
    }

    IS25LQ010B_NSSDisable();

    return 0;
}

/*
** @Brief: Write status register value
** @Parameter: SatusRegister, status register value
** @Return: 1) -1, transmit command data failed
            2) 0, set status register value successful
**/
int32_t IS25LQ010B_WriteSatusRegister(uint8_t SatusRegister)
{
    uint8_t Command[2] = {0};
    uint16_t CommandSize = 0;
    HAL_StatusTypeDef State = HAL_OK;

    Command[CommandSize++] = WRSR;
    Command[CommandSize++] = SatusRegister;

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, Command, CommandSize, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return -1;
    }

    IS25LQ010B_NSSDisable();

    return 0;
}

/*
** @Brief: Read function register value
** @Parameter: FunctionRegister, Function Register
** @Return: 1) 0, get Function Register value
            2) -1, get Function Register failed
**/
int32_t IS25LQ010B_ReadFunctionRegister(uint8_t* FunctionRegister)
{
    uint8_t Command = RDFR;
    HAL_StatusTypeDef State = HAL_OK;

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, &Command, 1, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        FunctionRegister = NULL;
        return -1;
    }

    State = HAL_SPI_Receive(&hspi2, FunctionRegister, 1, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        FunctionRegister = NULL;
        return -2;
    }

    IS25LQ010B_NSSDisable();

    return 0;
}

/*
** @Brief: Write function register value
** @Parameter: FunctionRegister, function register value
** @Return: 1) -1, transmit command failed
            2) 0, set function register value successful
**/
int32_t IS25LQ010B_WriteFunctionRegister(uint8_t FunctionRegister)
{
    uint8_t Command[2] = {0};
    uint16_t CommandSize = 0;
    HAL_StatusTypeDef State = HAL_OK;

    Command[CommandSize++] = WRFR;
    Command[CommandSize++] = FunctionRegister;

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, Command, CommandSize, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return -1;
    }

    IS25LQ010B_NSSDisable();

    return 0;
}

/*
** @Brief: Check device is busy
** @Parameter: None
** @Return: 1) true, device is busy
            2) false, device ready
**/
bool IS25LQ010B_DeviceIsBusy(void)
{
    uint8_t StatusRegister = 0;
    int32_t Result = 0;

    Result = IS25LQ010B_ReadStatusRegister(&StatusRegister);
    if(Result < 0)
    {
        /* Device busy, get status register failed */
        return true;
    }

    if(StatusRegister & 0x01)
    {
        /* Device busy */
        return true;
    }

    /* Device ready */
    return false;
}

/*
** @Brief: Write data to flash page
** @Parameter: 1) Address, flash address
               2) Data, write data
               3) Size, write data size
** @Return: 1) -1, enable write failed
            2) -2, write data to flash failed
            3) 0, write data to flash successful
**/
int32_t IS25LQ010B_WritePage(uint32_t Address, uint8_t* Data, uint16_t Size)
{
    uint8_t Command[MAX_COMMAND_SIZE] = {0};
    uint16_t CommandSize = 0;
    HAL_StatusTypeDef State = HAL_OK;

    if(!IS25LQ010B_WriteEnable())
    {
        return -1;
    }

    Command[CommandSize++] = PP;
    Command[CommandSize++] = (Address >> 16) & 0xFF;
    Command[CommandSize++] = (Address >>  8) & 0xFF;
    Command[CommandSize++] = Address & 0xFF;
    memcpy(&Command[CommandSize], Data, Size);
    CommandSize = Size + 4;

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, Command, CommandSize, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
         return -2;
    }

    IS25LQ010B_NSSDisable();

    return 0;
}

/*
** @Brief: Write data to flash
** @Parameter: 1) Address, flash address
               2) Data, write data
               3) Size, write data size
** @Return: 1) -1, write data to flash page failed
            2) 0, write data to flash successful
**/
int32_t IS25LQ010B_WriteNoCheck(uint32_t Address, uint8_t* Data, uint16_t Size)
{
    uint16_t PageRemain = 256 - Address % 256;
    int32_t Result = 0;

    if(PageRemain >= Size)
    {
        PageRemain = Size;
    }

    while(1)
    {
        Result = IS25LQ010B_WritePage(Address, Data, PageRemain);
        if(Result != 0)
        {
             return -1;
        }

        if(Size == PageRemain)
        {
            break;
        }
        else
        {
            Data    += PageRemain;
            Address += PageRemain;
            Size    -= PageRemain;

            if(Size > 256)
            {
                PageRemain = 256;
            }
            else
            {
                PageRemain = Size;
            }
        }
    }

    return 0;
}

/*
** @Brief: Write data to flash
** @Parameter: 1) Address, flash address
               2) Data, write data
               3) Size, write data size
** @Return: 1) -1, read flash data failed
            2) -2, erase sector failed
            3) -3, write date to flash failed
            4) -4, write data to flash failed
            5) 0, write data to flash successful
**/
int32_t IS25LQ010B_Write(uint32_t Address, uint8_t* Data, uint16_t Size)
{
    uint16_t SectorPosition = Address / IS25LQ010B_FLASH_SECTOR_SIZE;
    uint16_t SectorOffset = Address % IS25LQ010B_FLASH_SECTOR_SIZE;
    uint16_t SectorRemain = IS25LQ010B_FLASH_SECTOR_SIZE - SectorOffset;
    uint8_t TempBuffer[IS25LQ010B_FLASH_SECTOR_SIZE] = {0};
    int32_t Result = 0;
    int32_t Index = 0;

    if(SectorRemain >= Size)
    {
        SectorRemain = Size;
    }

    while(1)
    {
        Result = IS25LQ010B_Read(SectorPosition*IS25LQ010B_FLASH_SECTOR_SIZE, TempBuffer, IS25LQ010B_FLASH_SECTOR_SIZE);
        if(Result != 0)
        {
            return -1;
        }

        for(Index = 0; Index < SectorRemain; Index++)
        {
            if(TempBuffer[SectorOffset + Index] != 0xFF)
            {
                break;
            }
        }

        if(Index < SectorRemain)
        {
            Result = IS25LQ010B_SectorErase(SectorPosition);
            if(Result != 0)
            {
                return -2;
            }

            memcpy(&TempBuffer[SectorOffset], Data, SectorRemain);

            Result = IS25LQ010B_WriteNoCheck(SectorPosition*IS25LQ010B_FLASH_SECTOR_SIZE, TempBuffer, IS25LQ010B_FLASH_SECTOR_SIZE);
            if(Result != 0)
            {
                return -3;
            }
        }
        else
        {
            Result = IS25LQ010B_WriteNoCheck(Address, Data, SectorRemain);
            if(Result != 0)
            {
                return -4;
            }
        }

        if(SectorRemain == Size)
        {
            break;
        }
        else
        {
            SectorPosition++;
            SectorOffset = 0;
            Data    += SectorRemain;
            Address += SectorRemain;
            Size    -= SectorRemain;

            if(Size > IS25LQ010B_FLASH_SECTOR_SIZE)
            {
                SectorRemain = IS25LQ010B_FLASH_SECTOR_SIZE;
            }
            else
            {
                SectorRemain = Size;
            }
        }
    }

    return 0;
}

/*
** @Brief: Erase a sector
** @Parameter: Address, sector address
** @Return: 1) -1, sector address illegal
            2) -2, write enable failed
            3) -3, sector erase  failed
            4) 0, sector erase successfil
**/
int32_t IS25LQ010B_SectorErase(uint32_t Address)
{
    uint8_t Command[4] = {0};
    uint16_t CommandSize = 0;
    HAL_StatusTypeDef State = HAL_OK;

    /* Check whether address is legal */
    if(Address > (IS25LQ010B_FLASH_SIZE - IS25LQ010B_FLASH_SECTOR_SIZE))
    {
        return -1;
    }

    if(!IS25LQ010B_WriteEnable())
    {
        return -2;
    }

    while(IS25LQ010B_DeviceIsBusy());

    Command[CommandSize++] = SER;
    Command[CommandSize++] = (Address >> 16) & 0xFF;
    Command[CommandSize++] = (Address >>  8) & 0xFF;
    Command[CommandSize++] = Address & 0xFF;

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, Command, CommandSize, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return -3;
    }

    IS25LQ010B_NSSDisable();

    while(IS25LQ010B_DeviceIsBusy());

    return 0;
}

/*
** @Brief: Erase a block
** @Parameter: Address, block address
** @Return: 1) -1, block address illegal
            2) -2, write enable failed
            3) -3, block erase failed
            4) 0, block erase successfil
**/
int32_t IS25LQ010B_BlockErase32KB(uint32_t Address)
{
    uint8_t Command[4] = {0};
    uint16_t CommandSize = 0;

    /* Check whether address is legal */
    if(Address > (IS25LQ010B_FLASH_SIZE - IS25LQ010B_FLASH_BLOCK_SIZE))
    {
        return -1;
    }

    if(!IS25LQ010B_WriteEnable())
    {
        return -2;
    }

    while(IS25LQ010B_DeviceIsBusy());

    Command[CommandSize++] = BER32;
    Command[CommandSize++] = (Address >> 16) & 0xFF;
    Command[CommandSize++] = (Address >>  8) & 0xFF;
    Command[CommandSize++] = Address & 0xFF;

    IS25LQ010B_NSSEnable();

    /* Transmit erase sector command */
    HAL_StatusTypeDef TransmitState = HAL_SPI_Transmit(&hspi2, Command, CommandSize, SPI2_TIMEOUT);
    if(TransmitState != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return -3;
    }

    IS25LQ010B_NSSDisable();

    while(IS25LQ010B_DeviceIsBusy());

    return 0;
}

/*
** @Brief: Erase a block
** @Parameter: Address, block address
** @Return: 1) -1, block address illegal
            2) -2, write enable failed
            3) -3, erase 64 Kb failed
            4) 0, erase 64Kb successfil
**/
int32_t IS25LQ010B_BlockErase64KB(uint32_t Address)
{
    uint8_t Command[4] = {0};
    uint16_t CommandSize = 0;

    /* Check whether address is legal */
    if(Address > (IS25LQ010B_FLASH_SIZE - 2 * IS25LQ010B_FLASH_BLOCK_SIZE))
    {
        return -1;
    }

    if(!IS25LQ010B_WriteEnable())
    {
        return -2;
    }

    while(IS25LQ010B_DeviceIsBusy());

    Command[CommandSize++] = BER64;
    Command[CommandSize++] = (Address >> 16) & 0xFF;
    Command[CommandSize++] = (Address >>  8) & 0xFF;
    Command[CommandSize++] = Address & 0xFF;

    IS25LQ010B_NSSEnable();

    /* Transmit erase sector command */
    HAL_StatusTypeDef TransmitState = HAL_SPI_Transmit(&hspi2, Command, CommandSize, SPI2_TIMEOUT);
    if(TransmitState != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return -3;
    }

    IS25LQ010B_NSSDisable();

    while(IS25LQ010B_DeviceIsBusy());

    return 0;
}

/*
** @Brief: Erase flash chip
** @Parameter: None
** @Return: 1) -1, write enable failed
            2) -2, erase flash chip failed
            0) 0, erase flash chip successful
**/
int32_t IS25LQ010B_EraseChip(void)
{
    uint8_t EraseChipCommand = CER;

    if(!IS25LQ010B_WriteEnable())
    {
        return -1;
    }

    while(IS25LQ010B_DeviceIsBusy());

    IS25LQ010B_NSSEnable();

    /* Transmit erase sector command */
    HAL_StatusTypeDef TransmitState = HAL_SPI_Transmit(&hspi2, &EraseChipCommand, 1, SPI2_TIMEOUT);
    if(TransmitState != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return -2;
    }

    IS25LQ010B_NSSDisable();

    while(IS25LQ010B_DeviceIsBusy());

    return 0;
}

/*
** @Brief:  Read memory contents of the device at a maximum frequency of 33MHz
** @Parameter: 1) Address, flash address
               2) Data,    read data
               3) Size,    read data size
** @Return: 1) -1, Address illegal
            2) -2, transmit read command failed
            3) -3, receive read data failed
            4) 0, read data from flash successful
**/
int32_t IS25LQ010B_Read(uint32_t Address, uint8_t* Data, uint16_t Size)
{
    uint8_t Command[4] = {0};
    uint16_t CommandSize = 0;
    HAL_StatusTypeDef State = HAL_OK;

    /* Check whether parameters is legal */
    if((0 == Size) || (Address >= IS25LQ010B_FLASH_SIZE))
    {
        return -1;
    }

    Command[CommandSize++] = RD;
    Command[CommandSize++] = (Address >> 16) & 0xFF;
    Command[CommandSize++] = (Address >>  8) & 0xFF;
    Command[CommandSize++] = Address & 0xFF;

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, Command, CommandSize, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return -2;
    }

    State = HAL_SPI_Receive(&hspi2, Data, Size, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return -3;
    }

    IS25LQ010B_NSSDisable();

    return 0;
}

/*
** @Brief: Read memory data at up to a 104MHZ clock
** @Parameter: 1) Address, flash address
               2) Data,    read data
               3) Size,    read data size
** @Return: 1) -1, Address illegal
            2) -2, transmit read command failed
            3) -3, receive read data failed
            4) 0, read data from flash successful
**/
int32_t IS25LQ010B_FastRead(uint32_t Address, uint8_t* Data, uint16_t Size)
{
    uint8_t Command[5] = {0};
    uint16_t CommandSize = 0;
    HAL_StatusTypeDef ReceiveState = HAL_OK;

    /* Check whether parameters is legal */
    if((0 == Size) || (Address >= IS25LQ010B_FLASH_SIZE))
    {
        return -1;
    }

    Command[CommandSize++] = FR;
    Command[CommandSize++] = (Address >> 16) & 0xFF;
    Command[CommandSize++] = (Address >>  8) & 0xFF;
    Command[CommandSize++] = Address & 0xFF;
    Command[CommandSize++] = DUMMY_BYTE;

    IS25LQ010B_NSSEnable();

    /* Transmit read data instrction */
    ReceiveState = HAL_SPI_Transmit(&hspi2, Command, CommandSize, SPI2_TIMEOUT);
    if(ReceiveState != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return -2;
    }

    ReceiveState = HAL_SPI_Receive(&hspi2, Data, Size, SPI2_TIMEOUT);
    if(ReceiveState != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return -3;
    }

    IS25LQ010B_NSSDisable();

    return 0;
}

/*
** @Brief: Enter device minimizing the power comsumption
** @Parameter: None
** @Return: 1) -1, transmit command failed
            2) 0, operate execute successful
**/
int32_t IS25LQ010B_DeepPowerDown(void)
{
    uint8_t Command = DP;
    HAL_StatusTypeDef State = HAL_OK;

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, &Command, 1, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return -1;
    }

    IS25LQ010B_NSSDisable();

    return 0;
}

/*
** @Brief: Release device minimizing the power comsumption
** @Parameter: None
** @Return: 1) -1, transmit command failed
            2) 0, operate execute successful
**/
int32_t IS25LQ010B_ReleaseDeepPowerDown(void)
{
    uint8_t Command = RDPD;
    HAL_StatusTypeDef State = HAL_OK;

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, &Command, 1, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return -1;
    }

    IS25LQ010B_NSSDisable();

    return 0;
}

/*
** @Brief: Read a byte device ID
** @Parameter: DeviceID, device ID
** @Return: 1) -1, transmit command failed
            2) -2, receive device ID failed
            3) 0, get a byte device ID successful
**/
int32_t IS25LQ010B_ReadDeviceID(uint8_t* DeviceID)
{
    uint8_t Command[4] = {0};
    uint16_t CommandSize = 0;
    HAL_StatusTypeDef State = HAL_OK;

    Command[CommandSize++] = RDID;
    Command[CommandSize++] = DUMMY_BYTE;
    Command[CommandSize++] = DUMMY_BYTE;
    Command[CommandSize++] = DUMMY_BYTE;

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, Command, CommandSize, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        DeviceID = NULL;
        return -1;
    }

    State = HAL_SPI_Receive(&hspi2, DeviceID, 1, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        DeviceID = NULL;
        return -2;
    }

    IS25LQ010B_NSSDisable();

    return 0;
}

/*
** @Brief: Read Manufacturer ID, Device type and Capacity
** @Parameter: 1) ManufacturerID
               2) DeviceType
               3) Capacity
** @Return: 1) -1, command transmit failed
            2) -2, recive Manufacturer ID, Device Type and Capacity data failed
            3) 0, operate successful
**/
int32_t IS25LQ010B_ReadManufacturerProductCapacity(uint8_t* ManufacturerID, uint8_t* DeviceType, uint8_t* Capacity)
{
    HAL_StatusTypeDef State = HAL_OK;
    uint8_t Command = RDJDID;
    uint8_t TmpData[3] = {0};

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, &Command, 1, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        ManufacturerID = NULL;
        DeviceType = NULL;
        Capacity = NULL;
        return -1;
    }

    State = HAL_SPI_Receive(&hspi2, TmpData, 3, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        ManufacturerID = NULL;
        DeviceType = NULL;
        Capacity = NULL;
        return -2;
    }

    IS25LQ010B_NSSDisable();

    *ManufacturerID = TmpData[0];
    *DeviceType     = TmpData[1];
    *Capacity       = TmpData[2];

    return 0;
}

/*
** @Brief: Read Manufacturer ID and Device ID
** @Parameter: 1) Address, flash address
               2) ManufacturerID, need return Manufacturer ID
               3) DeviceID, need return Device ID
** @Return: 1) -1, Address illegal
            2) -2, command transmit failed
            3) -3, receive data failed
            0) 0, operate successful
**/
int32_t IS25LQ010B_ReadManufacturerIDDeviceID(uint32_t Address, uint8_t* ManufacturerID, uint8_t* DeviceID)
{
    uint8_t Command[4] = {0};
    uint16_t CommandSize = 0;
    HAL_StatusTypeDef State = HAL_OK;
    uint8_t TmpData[2] = {0};

    /* Check whether parameters is legal */
    if(Address >= IS25LQ010B_FLASH_SIZE)
    {
        ManufacturerID = NULL;
        DeviceID = NULL;
        return -1;
    }

    Command[CommandSize++] = RDMDID;
    Command[CommandSize++] = (Address >> 16) & 0xFF;
    Command[CommandSize++] = (Address >>  8) & 0xFF;
    Command[CommandSize++] = Address & 0xFF;

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, Command, CommandSize, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSEnable();
        ManufacturerID = NULL;
        DeviceID = NULL;
        return -2;
    }

    State = HAL_SPI_Receive(&hspi2, TmpData, 2, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSEnable();
        ManufacturerID = NULL;
        DeviceID = NULL;
        return -3;
    }

    IS25LQ010B_NSSEnable();

    *ManufacturerID = TmpData[0];
    *DeviceID       = TmpData[1];

    return 0;
}

/*
** @Brief: Get 16 bytes unique ID number
** @Parameter: 1) Address, flash address
               2) UID, need return UID
               3) UIDSize, UID size
** @Return: 1) -1, parameter illegal
            2) -2,command transmit failed
            3) -3, receive UID data failed
            4) 0, operate successful
**/
int32_t IS25LQ010B_ReadUID(uint32_t Address, uint8_t* UID, uint16_t* UIDSize)
{
    uint8_t Command[5] = {0};
    uint16_t CommandSize = 0;
    HAL_StatusTypeDef State = HAL_OK;
    uint8_t TmpUID[16] = {0};

    if(Address > IS25LQ010B_FLASH_SIZE)
    {
        return -1;
    }

    Command[CommandSize++] = RDUID;
    Command[CommandSize++] = (Address >> 16) & 0xFF;
    Command[CommandSize++] = (Address >>  8) & 0xFF;
    Command[CommandSize++] = Address & 0xFF;
    Command[CommandSize++] = DUMMY_BYTE;

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, Command, CommandSize, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return -2;
    }

    State = HAL_SPI_Receive(&hspi2, TmpUID, 16, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return -3;
    }

    IS25LQ010B_NSSDisable();

    /* return 16-byte device unique number */
    *UIDSize = 16;
    memcpy(UID, TmpUID, *UIDSize);

    return 0;
}

/*
** @Brief: Read Serial Flash Discoverable Parameter(SFDP)
** @Parameter: 1) Address, flash address
               2) Data, SFDP data
               3) Size, SFDP data size
** @Return: 1) -1, address illegal
            2) -2, command transmit failed
            3) -3, receive SFDP data failed
            4) 0, operate successful
**/
int32_t IS25LQ010B_ReadSerialFlashDiscoverableParameter(uint32_t Address, uint8_t* Data, uint16_t Size)
{
    uint8_t Command[5] = {0};
    uint16_t CommandSize = 0;
    HAL_StatusTypeDef State = HAL_OK;

    if(Address > IS25LQ010B_FLASH_SIZE)
    {
        memset(Data, 0, Size);
        return -1;
    }

    Command[CommandSize++] = RDSFDP;
    Command[CommandSize++] = (Address >> 16) & 0xFF;
    Command[CommandSize++] = (Address >>  8) & 0xFF;
    Command[CommandSize++] = Address & 0xFF;
    Command[CommandSize++] = DUMMY_BYTE;

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, Command, CommandSize, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        memset(Data, 0, Size);
        return -2;
    }

    State = HAL_SPI_Receive(&hspi2, Data, Size, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        memset(Data, 0, Size);
        return -3;
    }

    IS25LQ010B_NSSDisable();

    return 0;
}

/*
** @Brief: software reset operation
** @Parameter: None
** @Return: 1) -1, transmit reset enable command failed
            2) -2, transmit reset command failed
            0) 0, operate successful
**/
int32_t IS25LQ010B_SoftwareReset(void)
{
    uint8_t ResetEnableCommand = RSTEN;
    uint8_t ResetCommand = RST;
    HAL_StatusTypeDef State = HAL_OK;

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, &ResetEnableCommand, 1, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return -1;
    }

    IS25LQ010B_NSSDisable();

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, &ResetCommand, 1, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return -2;
    }

    IS25LQ010B_NSSDisable();

    return 0;
}

/*
** @Brief: Write data to flash page
** @Parameter: 1) Address, flash address
               2) Data, write data
               3) Size, write data size
** @Return: 1) -1, enable write failed
            2) -2, write data to flash failed
            3) 0, write data to flash successful
**/
int32_t IS25LQ010B_WritRowPage(uint32_t Address, uint8_t* Data, uint16_t Size)
{
    uint8_t Command[MAX_COMMAND_SIZE] = {0};
    uint16_t CommandSize = 0;
    HAL_StatusTypeDef State = HAL_OK;

    if(!IS25LQ010B_WriteEnable())
    {
        return -1;
    }

    Command[CommandSize++] = IRP;
    Command[CommandSize++] = (Address >> 16) & 0xFF;
    Command[CommandSize++] = (Address >>  8) & 0xFF;
    Command[CommandSize++] = Address & 0xFF;
    memcpy(&Command[CommandSize], Data, Size);
    CommandSize = Size + 4;

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, Command, CommandSize, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
         return -2;
    }

    IS25LQ010B_NSSDisable();

    return 0;
}

/*
** @Brief: Write data to flash
** @Parameter: 1) Address, flash address
               2) Data, write data
               3) Size, write data size
** @Return: 1) -1, write data to flash page failed
            2) 0, write data to flash successful
**/
int32_t IS25LQ010B_WriteRowNoCheck(uint32_t Address, uint8_t* Data, uint16_t Size)
{
    uint16_t PageRemain = 256 - Address % 256;
    int32_t Result = 0;

    if(PageRemain >= Size)
    {
        PageRemain = Size;
    }

    while(1)
    {
        Result = IS25LQ010B_WritRowPage(Address, Data, PageRemain);
        if(Result != 0)
        {
             return -1;
        }

        if(Size == PageRemain)
        {
            break;
        }
        else
        {
            Data    += PageRemain;
            Address += PageRemain;
            Size    -= PageRemain;

            if(Size > 256)
            {
                PageRemain = 256;
            }
            else
            {
                PageRemain = Size;
            }
        }
    }


    return 0;
}

/*
** @Brief: Write data to flash
** @Parameter: 1) Address, flash address
               2) Data, write data
               3) Size, write data size
** @Return: 1) 0, write data to flash successful
            2) -1, parameter illegal
            3) -2, write enable failed
            4) -3, write data to flash failed
            5) -4, write data to flash failed
**/
int32_t IS25LQ010B_WriteRow(uint32_t Address, uint8_t* Data, uint16_t Size)
{
    uint16_t SectorPosition = Address / IS25LQ010B_FLASH_SECTOR_SIZE;
    uint16_t SectorOffset = Address % IS25LQ010B_FLASH_SECTOR_SIZE;
    uint16_t SectorRemain = IS25LQ010B_FLASH_SECTOR_SIZE - SectorOffset;
    uint8_t TempBuffer[IS25LQ010B_FLASH_SECTOR_SIZE] = {0};
    int32_t Result = 0;
    int32_t Index = 0;

    if(SectorRemain >= Size)
    {
        SectorRemain = Size;
    }

    while(1)
    {
        Result = IS25LQ010B_ReadRow(SectorPosition*IS25LQ010B_FLASH_SECTOR_SIZE, TempBuffer, IS25LQ010B_FLASH_SECTOR_SIZE);
        if(Result != 0)
        {
            return -1;
        }

        for(Index = 0; Index < SectorRemain; Index++)
        {
            if(TempBuffer[SectorOffset + Index] != 0xFF)
            {
                break;
            }
        }

        if(Index < SectorRemain)
        {
            Result = IS25LQ010B_SectorErase(SectorPosition);
            if(Result != 0)
            {
                return -2;
            }

            memcpy(&TempBuffer[SectorOffset], Data, SectorRemain);

            Result = IS25LQ010B_WriteRowNoCheck(SectorPosition*IS25LQ010B_FLASH_SECTOR_SIZE, TempBuffer, IS25LQ010B_FLASH_SECTOR_SIZE);
            if(Result != 0)
            {
                return -3;
            }
        }
        else
        {
            Result = IS25LQ010B_WriteRowNoCheck(Address, Data, SectorRemain);
            if(Result != 0)
            {
                return -4;
            }
        }

        if(SectorRemain == Size)
        {
            break;
        }
        else
        {
            SectorPosition++;
            SectorOffset = 0;
            Data    += SectorRemain;
            Address += SectorRemain;
            Size    -= SectorRemain;

            if(Size > IS25LQ010B_FLASH_SECTOR_SIZE)
            {
                SectorRemain = IS25LQ010B_FLASH_SECTOR_SIZE;
            }
            else
            {
                SectorRemain = Size;
            }
        }
    }

    return 0;
}

/*
** @Brief:  Read memory data at up to a 104MHZ clock
** @Parameter: 1) Address, flash address
               2) Data, read data
               3) Size, read data size
** @Return: 1) -1, parameter illegal
            2) -2, command transmit failed
            3) -3, receive data failed
            4) 0, read data from falsh successful
**/
int32_t IS25LQ010B_ReadRow(uint32_t Address, uint8_t* Data, uint16_t Size)
{
    uint8_t Command[5] = {0};
    uint16_t CommandSize = 0;
    HAL_StatusTypeDef State = HAL_OK;

    if((0 == Size) || ((Address + Size/256 * IS25LQ010B_FLASH_SECTOR_SIZE) > IS25LQ010B_FLASH_SIZE))
    {
        return -1;
    }

    Command[CommandSize++] = IRRD;
    Command[CommandSize++] = (Address >> 16) & 0xFF;
    Command[CommandSize++] = (Address >>  8) & 0xFF;
    Command[CommandSize++] = Address & 0xFF;
    Command[CommandSize++] = DUMMY_BYTE;

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, Command, CommandSize, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        memset(Data, 0, Size);
        return -2;
    }

    State = HAL_SPI_Receive(&hspi2, Data, Size, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        memset(Data, 0, Size);
        return -3;
    }

    IS25LQ010B_NSSDisable();

    return 0;
}

/*
** @Brief: The Sector Lock command relocks a sector that was previously unlocked by the Sector Unlock command
** @Parameter: None
** @Return: 1) -1, command transmit failed
            2) 0, operate successful
**/
int32_t IS25LQ010B_SectorLock(void)
{
    uint8_t Command = SECLOCK;
    HAL_StatusTypeDef State = HAL_OK;

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, &Command, 1, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return -1;
    }

    IS25LQ010B_NSSDisable();

    return 0;
}

/*
** @Brief: Unlock sector
** @Parameter: Address, flash address
** @Return: 1) -1, parameter illegal
            2) -2, command transmit failed
            3) 0, operate successful
**/
int32_t IS25LQ010B_SectorUnlock(uint32_t Address)
{
    uint8_t Command[4] = {0};
    uint16_t CommandSize = 0;
    HAL_StatusTypeDef State = HAL_OK;

    if(Address > IS25LQ010B_FLASH_SIZE)
    {
        return -1;
    }

    Command[CommandSize++] = SECUNLOCK;
    Command[CommandSize++] = (Address >> 16) & 0xFF;
    Command[CommandSize++] = (Address >>  8) & 0xFF;
    Command[CommandSize++] = Address & 0xFF;

    IS25LQ010B_NSSEnable();

    State = HAL_SPI_Transmit(&hspi2, Command, CommandSize, SPI2_TIMEOUT);
    if(State != HAL_OK)
    {
        IS25LQ010B_NSSDisable();
        return -2;
    }

    IS25LQ010B_NSSDisable();

    return 0;
}
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32 HAL库提供了对W25Qxx系列SPI Flash驱动程序。W25Qxx是一种常见的SPI Flash存储器,在嵌入式系统中被广泛使用。以下是一个简单的示例代码来说明如何使用STM32 HAL库驱动W25Qxx SPI Flash。 首先,我们需要在STM32 CubeMX中配置SPI外设和引脚。选择正确的SPI接口,并将其配置为主模式。然后,选择适当的引脚作为SPI的时钟线、MISO线和MOSI线。在配置完成后,生成代码并导出到STM32Cube HAL库中。 生成代码后,我们需要在应用程序中包含必要的头文件,例如"stm32fxxx_hal.h"和"w25qxx.h"。接下来,我们需要初始化SPI和W25Qxx。通过调用相应的初始化函数来完成这些操作。例如,使用HAL_SPI_Init()函数来初始化SPI外设,使用W25QXX_Init()函数来初始化W25Qxx。 初始化完成后,我们可以使用W25Qxx提供的函数来完成读写操作。例如,使用W25Qxx_ReadData()函数来从Flash中读取数据,使用W25Qxx_WriteData()函数写入数据。这些函数通常需要传递参数,如读写地址和数据缓冲区。 除了读写操作外,W25Qxx还提供了其他一些有用的函数,如擦除某个扇区、块或整个芯片的函数。在使用这些函数之前,我们需要确保已正确初始化W25Qxx。 最后,在应用程序结束时,我们应该调用HAL_SPI_DeInit()和W25Qxx_DeInit()函数来释放资源并关闭SPI和W25Qxx外设。 总结一下,通过使用STM32 HAL库和W25Qxx SPI Flash驱动程序,我们可以方便地在STM32微控制器上实现SPI Flash存储器的读写操作。希望以上内容对你有帮助! ### 回答2: stm32 HAL库是针对STMicroelectronics公司的STM32系列MCU(微控制器)而提供的一套硬件抽象层,旨在简化嵌入式代码的开发过程。W25Qxx是一种串行外部存储器,通过SPI接口与STM32 MCU通信。在使用W25Qxx SPI Flash时,可以使用stm32 HAL库来轻松地编写驱动程序。 首先,需要在代码中包含stm32 HAL库的相关头文件以及SPI驱动程序的头文件。然后,要定义所需的SPI外设和引脚,并初始化SPI外设。 在初始化完成后,可以通过函数HAL_SPI_Transmit来发送命令给W25Qxx SPI Flash进行读取或写入操作。例如,可以使用“读取数据”命令来从存储器中读取数据。使用函数HAL_SPI_Transmit发送命令字节,然后使用函数HAL_SPI_Receive接收返回的数据。类似地,可以使用“写入数据”命令来向W25Qxx SPI Flash写入数据。 另外,还可以使用“擦除扇区”命令来擦除存储器的一个扇区。使用函数HAL_SPI_Transmit发送擦除命令,接着发送擦除地址以确定要擦除的扇区的位置。 需要注意的是,为了与W25Qxx SPI Flash正确通信,还需要了解W25Qxx芯片的寄存器和命令格式。可以参考W25Qxx的数据手册来获取相关信息。 总之,使用STM32 HAL库来驱动W25Qxx SPI Flash是一个简单而有效的方法。通过初始化SPI外设并使用HAL库的函数来发送命令和接收数据,可以轻松地实现对W25Qxx SPI Flash的控制和读写操作。 ### 回答3: STM32 HAL库是ST公司为STM32系列微控制器提供的一套高级应用程序编程接口(API),它提供了一系列的函数和工具,方便开发者在STM32上进行硬件驱动和应用程序的开发。 W25Qxx是一种SPI Flash存储器,广泛应用于嵌入式系统中,具有高速度、大容量和低功耗等优点。为了在STM32上使用W25Qxx SPI Flash,需要编写相应的驱动程序。 首先,需要通过HAL库提供的函数,对SPI总线进行初始化设置。可以通过配置STM32的GPIO引脚和SPI相关寄存器,设置传输速度、数据位宽等参数,实现SPI总线的初始化。 接下来,需要编写读取和写入数据的函数。在读取数据时,首先通过发送读取指令的命令字,将数据从W25Qxx中读入缓冲区,然后通过SPI总线传输数据。在写入数据时,首先发送写使能命令,然后发送写入指令的命令字,将数据写入W25Qxx中。需要注意的是,写入操作需要先擦除对应的扇区或页,再进行写入。 在编写驱动程序时,还需要考虑到错误处理和异常情况。通过判断SPI总线是否正常工作、W25Qxx是否擦除、写入是否成功等,可以对错误进行处理,并给出相应的提示和解决方案。 最后,在整个驱动程序中,可以根据实际需求,添加其他功能。例如,可以编写擦除整片Flash的函数、快速读取数据的函数等,以满足具体的应用需求。 综上所述,编写STM32 HAL库的W25Qxx SPI Flash驱动程序,需要对SPI总线进行初始化设置,编写读取和写入数据的函数,考虑错误处理和异常情况,并根据实际需求添加其他功能。这样可以方便地在STM32上使用W25Qxx SPI Flash,实现数据存储和读取等功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值