GPIO口模拟SPI - 驱动W25Qxx

本文详细介绍了数据闪存接口及操作命令,包括初始化IO、写使能、写禁用、判BUSY等关键功能,以及数据读取、芯片ID读取等应用实例。

废话少说,直接上代码:
DataFlash_reg.h:

/*
Using SPIO simulator
PB8  -- spi cs
PA9  -- spi clock
PA10 -- spi MOSI
PB7  -- spi MISO
PA8  -- hold
PC4  -- Write protect
*/
#define SPI_CS_Port         gpioPortB 
#define SPI_CS_Pin          8
#define SPI_CS              (*((uint32_t *)(BITBAND_PER_BASE + (((uint32_t)&(GPIO->P[SPI_CS_Port].DOUT) - PER_MEM_BASE) * 32) + (SPI_CS_Pin * 4))))

#define SPI_CLK_Port        gpioPortA 
#define SPI_CLK_Pin         9
#define SPI_CLK             (*((uint32_t *)(BITBAND_PER_BASE + (((uint32_t)&(GPIO->P[SPI_CLK_Port].DOUT) - PER_MEM_BASE) * 32) + (SPI_CLK_Pin * 4))))

#define SPI_MOSI_Port        gpioPortA 
#define SPI_MOSI_Pin         10
#define SPI_MOSI             (*((uint32_t *)(BITBAND_PER_BASE + (((uint32_t)&(GPIO->P[SPI_MOSI_Port].DOUT) - PER_MEM_BASE) * 32) + (SPI_MOSI_Pin * 4))))

#define SPI_MISO_Port        gpioPortB 
#define SPI_MISO_Pin         7
#define SPI_MISO             (*((uint32_t *)(BITBAND_PER_BASE + (((uint32_t)&(GPIO->P[SPI_MISO_Port].DIN) - PER_MEM_BASE) * 32) + (SPI_MISO_Pin * 4))))


unsigned char DataFlash_Write_Byte(unsigned char Data);

DataFlash_cmd.h:

#ifndef __DATAFLASH_CMD_H__
#define __DATAFLASH_CMD_H__

#define W25X_BUSY       0
#define W25X_NotBUSY    1    
#define Dummy_Byte1     0xA5


/*********************************************
 - W25X16的操作指令表,MCU通过向W25X16
  发送以下指令就可以对W25X16进行以下的操作
*********************************************/
#define W25X_WriteEnable            0x06    //Write Enable
#define W25X_WriteEnableVSR         0x50    //Write Enable for Volatile Status Register
#define W25X_WriteDisable           0x04    //Write Disable
#define W25X_ReadStatusReg1         0x05    //读状态寄存器1:S7~S0
#define W25X_ReadStatusReg2         0x35    //读状态寄存器2:S15~S8
#define W25X_WriteStatusReg         0x01    //写读状态寄存器:BYTE1:S7~S0  BYTE2:S15~S8
#define W25X_PageProgram            0x02    //单页编程:BYTE1:A23~A16  BYTE2:A15~A8  BYTE3:A7~A0  BYTE4:D7~D0
#define W25X_SectorErase            0x20    //扇区擦除:4K  BYTE1:A23~A16  BYTE2:A15~A8  BYTE3:A7~A0
#define W25X_BlockErase32K          0x52    //块擦除:32K  BYTE1:A23~A16  BYTE2:A15~A8  BYTE3:A7~A0
#define W25X_BlockErase64K          0xD8    //块擦除:64K  BYTE1:A23~A16  BYTE2:A15~A8  BYTE3:A7~A0
#define W25X_ChipErase              0xC7    //芯片擦除
#define W25X_EraseSuspend           0x75    //暂停擦除
#define W25X_EraseResume            0x7A    //恢复擦除
#define W25X_PowerDown              0xB9    //掉电
#define W25X_ContinuousReadMode     0xFF    //连续读模式

#define W25X_ReadData               0x03    //读数据:BYTE1:A23~A16  BYTE2:A15~A8  BYTE3:A7~A0  BYTE4:D7~D0
#define W25X_FastReadData           0x0B    //快速读取:BYTE1:A23~A16  BYTE2:A15~A8  BYTE3:A7~A0  BYTE4:dummy  BYTE5:D7~D0
#define W25X_FastReadDual           0x3B    //快速双读取:BYTE1:A23~A16  BYTE2:A15~A8  BYTE3:A7~A0  BYTE4:dummy  BYTE5:D7~D0

#define W25X_ReleasePowerDown       0xAB   
#define W25X_DeviceID               0xAB 
#define W25X_ManufactDeviceID       0x90 
#define W25X_JedecDeviceID          0x9F 

#endif

DataFlash_reg.c:

#include <stdint.h>
#include <stdbool.h>
#include "em_device.h"
#include "em_chip.h"
#include "em_cmu.h"
#include "em_gpio.h"
#include "DataFlash_reg.h"
#include "DataFlash_cmd.h"

/*
Using SPIO simulator
PB8  -- spi cs
PA9  -- spi clock
PA10 -- spi MOSI
PB7  -- spi MISO
PA8  -- hold
PC4  -- Write protect
*/
void DataFlash_Initial_IO(void)
{
    GPIO_PinModeSet(gpioPortB,8,gpioModePushPull,1);
    GPIO_PinModeSet(gpioPortA,9,gpioModePushPull,1);
    GPIO_PinModeSet(gpioPortA,10,gpioModePushPull,1);
    GPIO_PinModeSet(gpioPortB,7,gpioModeInputPull,1);
    GPIO_PinModeSet(gpioPortA,8,gpioModePushPull,1);
    GPIO_PinModeSet(gpioPortC,4,gpioModePushPull,1);
}

//*************** Write enable ****************************  OK
void DataFlash_WriteEnable  (void)
{
    SPI_CS = 0;
    __NOP();
    __NOP();
    DataFlash_Write_Byte(W25X_WriteEnable);
    __NOP();
    __NOP();
    SPI_CS = 1;
}

//*************** Write disable ****************************    OK
void DataFlash_WriteDisable (void)
{
    SPI_CS = 0;
    __NOP();
    __NOP();
    DataFlash_Write_Byte(W25X_WriteDisable);
    __NOP();
    __NOP();
    SPI_CS = 1;
}

//***************判BUSY********************************
unsigned char DataFlash_SPI_BUSY_OrNot (void) //在读和写之前得先判断FLASH是否BUSY
{                        //BUSY的原因是擦除,或是连续读写
    unsigned char k;          //如果没有以上方式,不必判定可以写读  
    SPI_CS = 0;
    __NOP();
    __NOP();
    DataFlash_Write_Byte(W25X_ReadStatusReg1);
    k = DataFlash_Write_Byte(Dummy_Byte1);
    __NOP();
    __NOP();
    SPI_CS = 1;
    if(k&0x01)return (W25X_BUSY);
    else return (W25X_NotBUSY);
}

void SPI_Flash_Read(uint32_t ReadAddr, uint32_t numBytes,void *data)
{
    uint8_t *rxBuffer = (uint8_t *) data;

    /* Enable chip select */
    SPI_CS = 0;
    __NOP();
    __NOP();

    DataFlash_Write_Byte(W25X_ReadData);
    DataFlash_Write_Byte(ReadAddr >> 16);
    DataFlash_Write_Byte(ReadAddr >> 8);
    DataFlash_Write_Byte(ReadAddr);
    while (numBytes--)
    { 
        *rxBuffer = DataFlash_Write_Byte(Dummy_Byte1); //Read one byte
        rxBuffer++;
    }

    /* Disable chip select */
    __NOP();
    __NOP();
    SPI_CS = 1;
}

/*******************************************************************************
* Function Name  : SPI_FLASH_ReadID
* Description    : Reads FLASH identification.
* Input          : None
* Output         : None
* Return         : FLASH identification
*******************************************************************************/

unsigned long SPI_Flash_ReadID(void)
{
    unsigned int Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;

   /* Enable chip select */
    SPI_CS = 0;
    __NOP();
    __NOP();

    /* Send "RDID " instruction */
    DataFlash_Write_Byte(0x9F);
    /* Read a byte from the FLASH */
    Temp0 = DataFlash_Write_Byte(Dummy_Byte1);
    /* Read a byte from the FLASH */
    Temp1 = DataFlash_Write_Byte(Dummy_Byte1);
    /* Read a byte from the FLASH */
    Temp2 = DataFlash_Write_Byte(Dummy_Byte1);

    /* Disable chip select */
    __NOP();
    __NOP();
    SPI_CS = 1;

    Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;

    return Temp;
}


////每次写一页面 地址低8位应为0
//void SPI_Flash_Page_Write(uint32_t pageNum, unsigned char* data)
//{
//    uint8_t *rxBuffer = data;
//    while(1)
//    {
//        if(SPI_BUSY_OrNot() == W25X_NotBUSY) break;
//    }
//    
//    WriteEnable();   //写允许
//    
//    /* Enable chip select */
//    GPIO_PinOutClear(Flash_SPI_CS_PORT, Flash_SPI_CS_BIT);
//    
//    SPI_FlashWrite(W25X_PageProgram);
//    
//    unsigned int WriteAddr = pageNum<<8;
//    
//    SPI_FlashWrite((WriteAddr >> 16));
//    SPI_FlashWrite((uint32_t)(WriteAddr >> 8));
//    SPI_FlashWrite((uint32_t) WriteAddr);
//    
//    for(int i=0;i<SPI_FLASH_PAGE_SIZE;i++)
//    { 
//        SPI_FlashWrite(*rxBuffer); 
//        rxBuffer++;
//    }
//    /* Disable chip select */
//    GPIO_PinOutSet(Flash_SPI_CS_PORT, Flash_SPI_CS_BIT);
//    
//    WriteDisable();//写禁止
//}
//
////**************片擦除****************** OK
//void SPI_EraseDevice(void)
//{
//    while(1)
//    {
//        if(SPI_BUSY_OrNot() == W25X_NotBUSY) break;
//    }
//    WriteEnable();   //写允许
//    GPIO_PinOutClear(Flash_SPI_CS_PORT, Flash_SPI_CS_BIT);
//    SPI_FlashWrite(W25X_ChipErase);
//    GPIO_PinOutSet(Flash_SPI_CS_PORT, Flash_SPI_CS_BIT);
//}




unsigned char DataFlash_Write_Byte(unsigned char Data)
{
    unsigned char Out = 0;
    unsigned char i = 0;

    SPI_CLK = 0;
    for(i = 0; i < 8; i++)
    {
        if(Data & 0x80)SPI_MOSI = 1;
        else SPI_MOSI = 0;
        Data = Data << 1;
        __NOP();
        __NOP();
        __NOP();
        SPI_CLK = 1;
        if(SPI_MISO)Out |= 0x80 >> i;
        __NOP();
        __NOP();
        __NOP();
        SPI_CLK = 0;
    }
    SPI_CLK = 0;

    return Out;
}
#if _USE_WRITE == 1 DRESULT USER_write ( BYTE pdrv, /* Physical drive nmuber to identify the drive / const BYTE buff, / Data to be written / DWORD sector, / Sector address in LBA / UINT count / Number of sectors to write / ) { / USER CODE BEGIN WRITE / / USER CODE HERE / uint32_t ReadAddr = sector << 12; uint32_t NumByteToRead = count << 12; uint8_t secCount = (NumByteToRead / 4096); if ((NumByteToRead%4096) > 0) secCount++; uint32_t SectorAddr = ReadAddr; for(uint8_t k = 0; k < secCount; k++){ W25qxx_EraseSector(secCount); SectorAddr += 4096; } W25qxx_WriteSector((uint8_t)buff,ReadAddr,0,NumByteToRead); return RES_OK; / USER CODE END WRITE */ }#include “w25qxx.h” #include “w25qxxConf.h” #if (_W25QXX_DEBUG==1) #include <stdio.h> #endif #define W25QXX_DUMMY_BYTE 0xA5 w25qxx_t w25qxx; #if (_W25QXX_USE_FREERTOS1) #define W25qxx_Delay(delay) osDelay(delay) #include “cmsis_os.h” #else #define W25qxx_Delay(delay) HAL_Delay(delay) #endif //################################################################################################################### uint8_t W25qxx_Spi(uint8_t Data) { uint8_t ret; HAL_SPI_TransmitReceive(&_W25QXX_SPI,&Data,&ret,1,100); return ret; } //################################################################################################################### uint32_t W25qxx_ReadID(void) { uint32_t Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0; HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); W25qxx_Spi(0x9F); Temp0 = W25qxx_Spi(W25QXX_DUMMY_BYTE); Temp1 = W25qxx_Spi(W25QXX_DUMMY_BYTE); Temp2 = W25qxx_Spi(W25QXX_DUMMY_BYTE); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2; return Temp; } //################################################################################################################### void W25qxx_ReadUniqID(void) { HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); W25qxx_Spi(0x4B); for(uint8_t i=0;i<4;i++) W25qxx_Spi(W25QXX_DUMMY_BYTE); for(uint8_t i=0;i<8;i++) w25qxx.UniqID[i] = W25qxx_Spi(W25QXX_DUMMY_BYTE); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); } //################################################################################################################### void W25qxx_WriteEnable(void) { HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); W25qxx_Spi(0x06); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); W25qxx_Delay(1); } //################################################################################################################### void W25qxx_WriteDisable(void) { HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); W25qxx_Spi(0x04); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); W25qxx_Delay(1); } //################################################################################################################### uint8_t W25qxx_ReadStatusRegister(uint8_t SelectStatusRegister_1_2_3) { uint8_t status=0; HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); if(SelectStatusRegister_1_2_31) { W25qxx_Spi(0x05); status=W25qxx_Spi(W25QXX_DUMMY_BYTE); w25qxx.StatusRegister1 = status; } else if(SelectStatusRegister_1_2_32) { W25qxx_Spi(0x35); status=W25qxx_Spi(W25QXX_DUMMY_BYTE); w25qxx.StatusRegister2 = status; } else { W25qxx_Spi(0x15); status=W25qxx_Spi(W25QXX_DUMMY_BYTE); w25qxx.StatusRegister3 = status; } HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); return status; } //################################################################################################################### void W25qxx_WriteStatusRegister(uint8_t SelectStatusRegister_1_2_3,uint8_t Data) { HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); if(SelectStatusRegister_1_2_31) { W25qxx_Spi(0x01); w25qxx.StatusRegister1 = Data; } else if(SelectStatusRegister_1_2_32) { W25qxx_Spi(0x31); w25qxx.StatusRegister2 = Data; } else { W25qxx_Spi(0x11); w25qxx.StatusRegister3 = Data; } W25qxx_Spi(Data); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); } //################################################################################################################### void W25qxx_WaitForWriteEnd(void) { W25qxx_Delay(1); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); W25qxx_Spi(0x05); do { w25qxx.StatusRegister1 = W25qxx_Spi(W25QXX_DUMMY_BYTE); W25qxx_Delay(1); } while ((w25qxx.StatusRegister1 & 0x01) == 0x01); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); } //################################################################################################################### bool W25qxx_Init(void) { w25qxx.Lock=1; while(HAL_GetTick()<100) W25qxx_Delay(1); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); W25qxx_Delay(100); uint32_t id; #if (_W25QXX_DEBUG1) printf(“w25qxx Init Begin…\r\n”); #endif id=W25qxx_ReadID(); #if (_W25QXX_DEBUG==1) printf("w25qxx ID:0x%X\r\n",id); #endif switch(id&0x0000FFFF) { case 0x401A: // w25q512 w25qxx.ID=W25Q512; w25qxx.BlockCount=1024; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q512\r\n"); #endif break; case 0x4019: // w25q256 w25qxx.ID=W25Q256; w25qxx.BlockCount=512; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q256\r\n"); #endif break; case 0x4018: // w25q128 w25qxx.ID=W25Q128; w25qxx.BlockCount=256; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q128\r\n"); #endif break; case 0x4017: // w25q64 w25qxx.ID=W25Q64; w25qxx.BlockCount=128; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q64\r\n"); #endif break; case 0x4016: // w25q32 w25qxx.ID=W25Q32; w25qxx.BlockCount=64; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q32\r\n"); #endif break; case 0x4015: // w25q16 w25qxx.ID=W25Q16; w25qxx.BlockCount=32; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q16\r\n"); #endif break; case 0x4014: // w25q80 w25qxx.ID=W25Q80; w25qxx.BlockCount=16; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q80\r\n"); #endif break; case 0x4013: // w25q40 w25qxx.ID=W25Q40; w25qxx.BlockCount=8; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q40\r\n"); #endif break; case 0x4012: // w25q20 w25qxx.ID=W25Q20; w25qxx.BlockCount=4; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q20\r\n"); #endif break; case 0x4011: // w25q10 w25qxx.ID=W25Q10; w25qxx.BlockCount=2; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q10\r\n"); #endif break; default: #if (_W25QXX_DEBUG==1) printf("w25qxx Unknown ID\r\n"); #endif w25qxx.Lock=0; return false; } w25qxx.PageSize=256; w25qxx.SectorSize=0x1000; w25qxx.SectorCount=w25qxx.BlockCount*16; w25qxx.PageCount=(w25qxx.SectorCount*w25qxx.SectorSize)/w25qxx.PageSize; w25qxx.BlockSize=w25qxx.SectorSize*16; w25qxx.CapacityInKiloByte=(w25qxx.SectorCount*w25qxx.SectorSize)/1024; W25qxx_ReadUniqID(); W25qxx_ReadStatusRegister(1); W25qxx_ReadStatusRegister(2); W25qxx_ReadStatusRegister(3); #if (_W25QXX_DEBUG==1) printf("w25qxx Page Size: %d Bytes\r\n",w25qxx.PageSize); printf("w25qxx Page Count: %d\r\n",w25qxx.PageCount); printf("w25qxx Sector Size: %d Bytes\r\n",w25qxx.SectorSize); printf("w25qxx Sector Count: %d\r\n",w25qxx.SectorCount); printf("w25qxx Block Size: %d Bytes\r\n",w25qxx.BlockSize); printf("w25qxx Block Count: %d\r\n",w25qxx.BlockCount); printf("w25qxx Capacity: %d KiloBytes\r\n",w25qxx.CapacityInKiloByte); printf("w25qxx Init Done\r\n"); #endif w25qxx.Lock=0; return true; } //################################################################################################################### void W25qxx_EraseChip(void) { while(w25qxx.Lock1) W25qxx_Delay(1); w25qxx.Lock=1; #if (_W25QXX_DEBUG1) uint32_t StartTime=HAL_GetTick(); printf(“w25qxx EraseChip Begin…\r\n”); #endif W25qxx_WriteEnable(); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); W25qxx_Spi(0xC7); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); W25qxx_WaitForWriteEnd(); #if (_W25QXX_DEBUG1) printf(“w25qxx EraseBlock done after %d ms!\r\n”,HAL_GetTick()-StartTime); #endif W25qxx_Delay(10); w25qxx.Lock=0; } //################################################################################################################### void W25qxx_EraseSector(uint32_t SectorAddr) { while(w25qxx.Lock1) W25qxx_Delay(1); w25qxx.Lock=1; #if (_W25QXX_DEBUG1) uint32_t StartTime=HAL_GetTick(); printf(“w25qxx EraseSector %d Begin…\r\n”,SectorAddr); #endif W25qxx_WaitForWriteEnd(); SectorAddr = SectorAddr * w25qxx.SectorSize; W25qxx_WriteEnable(); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); W25qxx_Spi(0x20); if(w25qxx.ID>=W25Q256) W25qxx_Spi((SectorAddr & 0xFF000000) >> 24); W25qxx_Spi((SectorAddr & 0xFF0000) >> 16); W25qxx_Spi((SectorAddr & 0xFF00) >> 8); W25qxx_Spi(SectorAddr & 0xFF); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); W25qxx_WaitForWriteEnd(); #if (_W25QXX_DEBUG1) printf(“w25qxx EraseSector done after %d ms\r\n”,HAL_GetTick()-StartTime); #endif W25qxx_Delay(1); w25qxx.Lock=0; } //################################################################################################################### void W25qxx_EraseBlock(uint32_t BlockAddr) { while(w25qxx.Lock1) W25qxx_Delay(1); w25qxx.Lock=1; #if (_W25QXX_DEBUG1) printf(“w25qxx EraseBlock %d Begin…\r\n”,BlockAddr); W25qxx_Delay(100); uint32_t StartTime=HAL_GetTick(); #endif W25qxx_WaitForWriteEnd(); BlockAddr = BlockAddr * w25qxx.SectorSize16; W25qxx_WriteEnable(); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); W25qxx_Spi(0xD8); if(w25qxx.ID>=W25Q256) W25qxx_Spi((BlockAddr & 0xFF000000) >> 24); W25qxx_Spi((BlockAddr & 0xFF0000) >> 16); W25qxx_Spi((BlockAddr & 0xFF00) >> 8); W25qxx_Spi(BlockAddr & 0xFF); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); W25qxx_WaitForWriteEnd(); #if (_W25QXX_DEBUG==1) printf(“w25qxx EraseBlock done after %d ms\r\n”,HAL_GetTick()-StartTime); W25qxx_Delay(100); #endif W25qxx_Delay(1); w25qxx.Lock=0; } //################################################################################################################### uint32_t W25qxx_PageToSector(uint32_t PageAddress) { return ((PageAddressw25qxx.PageSize)/w25qxx.SectorSize); } //################################################################################################################### uint32_t W25qxx_PageToBlock(uint32_t PageAddress) { return ((PageAddressw25qxx.PageSize)/w25qxx.BlockSize); } //################################################################################################################### uint32_t W25qxx_SectorToBlock(uint32_t SectorAddress) { return ((SectorAddressw25qxx.SectorSize)/w25qxx.BlockSize); } //################################################################################################################### uint32_t W25qxx_SectorToPage(uint32_t SectorAddress) { return (SectorAddressw25qxx.SectorSize)/w25qxx.PageSize; } //################################################################################################################### uint32_t W25qxx_BlockToPage(uint32_t BlockAddress) { return (BlockAddressw25qxx.BlockSize)/w25qxx.PageSize; } //################################################################################################################### bool W25qxx_IsEmptyPage(uint32_t Page_Address,uint32_t OffsetInByte,uint32_t NumByteToCheck_up_to_PageSize) { while(w25qxx.Lock1) W25qxx_Delay(1); w25qxx.Lock=1; if(((NumByteToCheck_up_to_PageSize+OffsetInByte)>w25qxx.PageSize)||(NumByteToCheck_up_to_PageSize0)) NumByteToCheck_up_to_PageSize=w25qxx.PageSize-OffsetInByte; #if (_W25QXX_DEBUG1) printf(“w25qxx CheckPage:%d, Offset:%d, Bytes:%d begin…\r\n”,Page_Address,OffsetInByte,NumByteToCheck_up_to_PageSize); W25qxx_Delay(100); uint32_t StartTime=HAL_GetTick(); #endif uint8_t pBuffer[32]; uint32_t WorkAddress; uint32_t i; for(i=OffsetInByte; i<w25qxx.PageSize; i+=sizeof(pBuffer)) { HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); WorkAddress=(i+Page_Addressw25qxx.PageSize); W25qxx_Spi(0x0B); if(w25qxx.ID>=W25Q256) W25qxx_Spi((WorkAddress & 0xFF000000) >> 24); W25qxx_Spi((WorkAddress & 0xFF0000) >> 16); W25qxx_Spi((WorkAddress & 0xFF00) >> 8); W25qxx_Spi(WorkAddress & 0xFF); W25qxx_Spi(0); HAL_SPI_Receive(&_W25QXX_SPI,pBuffer,sizeof(pBuffer),100); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); for(uint8_t x=0;x<sizeof(pBuffer);x++) { if(pBuffer[x]!=0xFF) goto NOT_EMPTY; } } if((w25qxx.PageSize+OffsetInByte)%sizeof(pBuffer)!=0) { i-=sizeof(pBuffer); for( ; i<w25qxx.PageSize; i++) { HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); WorkAddress=(i+Page_Addressw25qxx.PageSize); W25qxx_Spi(0x0B); if(w25qxx.ID>=W25Q256) W25qxx_Spi((WorkAddress & 0xFF000000) >> 24); W25qxx_Spi((WorkAddress & 0xFF0000) >> 16); W25qxx_Spi((WorkAddress & 0xFF00) >> 8); W25qxx_Spi(WorkAddress & 0xFF); W25qxx_Spi(0); HAL_SPI_Receive(&_W25QXX_SPI,pBuffer,1,100); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); if(pBuffer[0]!=0xFF) goto NOT_EMPTY; } } #if (_W25QXX_DEBUG1) printf(“w25qxx CheckPage is Empty in %d ms\r\n”,HAL_GetTick()-StartTime); W25qxx_Delay(100); #endif w25qxx.Lock=0; return true; NOT_EMPTY: #if (_W25QXX_DEBUG1) printf(“w25qxx CheckPage is Not Empty in %d ms\r\n”,HAL_GetTick()-StartTime); W25qxx_Delay(100); #endif w25qxx.Lock=0; return false; } //################################################################################################################### bool W25qxx_IsEmptySector(uint32_t Sector_Address,uint32_t OffsetInByte,uint32_t NumByteToCheck_up_to_SectorSize) { while(w25qxx.Lock1) W25qxx_Delay(1); w25qxx.Lock=1; if((NumByteToCheck_up_to_SectorSize>w25qxx.SectorSize)||(NumByteToCheck_up_to_SectorSize0)) NumByteToCheck_up_to_SectorSize=w25qxx.SectorSize; #if (_W25QXX_DEBUG1) printf(“w25qxx CheckSector:%d, Offset:%d, Bytes:%d begin…\r\n”,Sector_Address,OffsetInByte,NumByteToCheck_up_to_SectorSize); W25qxx_Delay(100); uint32_t StartTime=HAL_GetTick(); #endif uint8_t pBuffer[32]; uint32_t WorkAddress; uint32_t i; for(i=OffsetInByte; i<w25qxx.SectorSize; i+=sizeof(pBuffer)) { HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); WorkAddress=(i+Sector_Addressw25qxx.SectorSize); W25qxx_Spi(0x0B); if(w25qxx.ID>=W25Q256) W25qxx_Spi((WorkAddress & 0xFF000000) >> 24); W25qxx_Spi((WorkAddress & 0xFF0000) >> 16); W25qxx_Spi((WorkAddress & 0xFF00) >> 8); W25qxx_Spi(WorkAddress & 0xFF); W25qxx_Spi(0); HAL_SPI_Receive(&_W25QXX_SPI,pBuffer,sizeof(pBuffer),100); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); for(uint8_t x=0;x<sizeof(pBuffer);x++) { if(pBuffer[x]!=0xFF) goto NOT_EMPTY; } } if((w25qxx.SectorSize+OffsetInByte)%sizeof(pBuffer)!=0) { i-=sizeof(pBuffer); for( ; i<w25qxx.SectorSize; i++) { HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); WorkAddress=(i+Sector_Addressw25qxx.SectorSize); W25qxx_Spi(0x0B); if(w25qxx.ID>=W25Q256) W25qxx_Spi((WorkAddress & 0xFF000000) >> 24); W25qxx_Spi((WorkAddress & 0xFF0000) >> 16); W25qxx_Spi((WorkAddress & 0xFF00) >> 8); W25qxx_Spi(WorkAddress & 0xFF); W25qxx_Spi(0); HAL_SPI_Receive(&_W25QXX_SPI,pBuffer,1,100); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); if(pBuffer[0]!=0xFF) goto NOT_EMPTY; } } #if (_W25QXX_DEBUG1) printf(“w25qxx CheckSector is Empty in %d ms\r\n”,HAL_GetTick()-StartTime); W25qxx_Delay(100); #endif w25qxx.Lock=0; return true; NOT_EMPTY: #if (_W25QXX_DEBUG1) printf(“w25qxx CheckSector is Not Empty in %d ms\r\n”,HAL_GetTick()-StartTime); W25qxx_Delay(100); #endif w25qxx.Lock=0; return false; } //################################################################################################################### bool W25qxx_IsEmptyBlock(uint32_t Block_Address,uint32_t OffsetInByte,uint32_t NumByteToCheck_up_to_BlockSize) { while(w25qxx.Lock1) W25qxx_Delay(1); w25qxx.Lock=1; if((NumByteToCheck_up_to_BlockSize>w25qxx.BlockSize)||(NumByteToCheck_up_to_BlockSize0)) NumByteToCheck_up_to_BlockSize=w25qxx.BlockSize; #if (_W25QXX_DEBUG1) printf(“w25qxx CheckBlock:%d, Offset:%d, Bytes:%d begin…\r\n”,Block_Address,OffsetInByte,NumByteToCheck_up_to_BlockSize); W25qxx_Delay(100); uint32_t StartTime=HAL_GetTick(); #endif uint8_t pBuffer[32]; uint32_t WorkAddress; uint32_t i; for(i=OffsetInByte; i<w25qxx.BlockSize; i+=sizeof(pBuffer)) { HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); WorkAddress=(i+Block_Addressw25qxx.BlockSize); W25qxx_Spi(0x0B); if(w25qxx.ID>=W25Q256) W25qxx_Spi((WorkAddress & 0xFF000000) >> 24); W25qxx_Spi((WorkAddress & 0xFF0000) >> 16); W25qxx_Spi((WorkAddress & 0xFF00) >> 8); W25qxx_Spi(WorkAddress & 0xFF); W25qxx_Spi(0); HAL_SPI_Receive(&_W25QXX_SPI,pBuffer,sizeof(pBuffer),100); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); for(uint8_t x=0;x<sizeof(pBuffer);x++) { if(pBuffer[x]!=0xFF) goto NOT_EMPTY; } } if((w25qxx.BlockSize+OffsetInByte)%sizeof(pBuffer)!=0) { i-=sizeof(pBuffer); for( ; i<w25qxx.BlockSize; i++) { HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); WorkAddress=(i+Block_Addressw25qxx.BlockSize); W25qxx_Spi(0x0B); if(w25qxx.ID>=W25Q256) W25qxx_Spi((WorkAddress & 0xFF000000) >> 24); W25qxx_Spi((WorkAddress & 0xFF0000) >> 16); W25qxx_Spi((WorkAddress & 0xFF00) >> 8); W25qxx_Spi(WorkAddress & 0xFF); W25qxx_Spi(0); HAL_SPI_Receive(&_W25QXX_SPI,pBuffer,1,100); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); if(pBuffer[0]!=0xFF) goto NOT_EMPTY; } } #if (_W25QXX_DEBUG1) printf(“w25qxx CheckBlock is Empty in %d ms\r\n”,HAL_GetTick()-StartTime); W25qxx_Delay(100); #endif w25qxx.Lock=0; return true; NOT_EMPTY: #if (_W25QXX_DEBUG1) printf(“w25qxx CheckBlock is Not Empty in %d ms\r\n”,HAL_GetTick()-StartTime); W25qxx_Delay(100); #endif w25qxx.Lock=0; return false; } //################################################################################################################### void W25qxx_WriteByte(uint8_t pBuffer, uint32_t WriteAddr_inBytes) { while(w25qxx.Lock1) W25qxx_Delay(1); w25qxx.Lock=1; #if (_W25QXX_DEBUG1) uint32_t StartTime=HAL_GetTick(); printf(“w25qxx WriteByte 0x%02X at address %d begin…”,pBuffer,WriteAddr_inBytes); #endif W25qxx_WaitForWriteEnd(); W25qxx_WriteEnable(); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); W25qxx_Spi(0x02); if(w25qxx.ID>=W25Q256) W25qxx_Spi((WriteAddr_inBytes & 0xFF000000) >> 24); W25qxx_Spi((WriteAddr_inBytes & 0xFF0000) >> 16); W25qxx_Spi((WriteAddr_inBytes & 0xFF00) >> 8); W25qxx_Spi(WriteAddr_inBytes & 0xFF); W25qxx_Spi(pBuffer); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); W25qxx_WaitForWriteEnd(); #if (_W25QXX_DEBUG1) printf(“w25qxx WriteByte done after %d ms\r\n”,HAL_GetTick()-StartTime); #endif w25qxx.Lock=0; } //################################################################################################################### void W25qxx_WritePage(uint8_t pBuffer ,uint32_t Page_Address,uint32_t OffsetInByte,uint32_t NumByteToWrite_up_to_PageSize) { while(w25qxx.Lock1) W25qxx_Delay(1); w25qxx.Lock=1; if(((NumByteToWrite_up_to_PageSize+OffsetInByte)>w25qxx.PageSize)||(NumByteToWrite_up_to_PageSize0)) NumByteToWrite_up_to_PageSize=w25qxx.PageSize-OffsetInByte; if((OffsetInByte+NumByteToWrite_up_to_PageSize) > w25qxx.PageSize) NumByteToWrite_up_to_PageSize = w25qxx.PageSize-OffsetInByte; #if (_W25QXX_DEBUG==1) printf(“w25qxx WritePage:%d, Offset:%d ,Writes %d Bytes, begin…\r\n”,Page_Address,OffsetInByte,NumByteToWrite_up_to_PageSize); W25qxx_Delay(100); uint32_t StartTime=HAL_GetTick(); #endif W25qxx_WaitForWriteEnd(); W25qxx_WriteEnable(); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); W25qxx_Spi(0x02); Page_Address = (Page_Addressw25qxx.PageSize)+OffsetInByte; if(w25qxx.ID>=W25Q256) W25qxx_Spi((Page_Address & 0xFF000000) >> 24); W25qxx_Spi((Page_Address & 0xFF0000) >> 16); W25qxx_Spi((Page_Address & 0xFF00) >> 8); W25qxx_Spi(Page_Address&0xFF); HAL_SPI_Transmit(&_W25QXX_SPI,pBuffer,NumByteToWrite_up_to_PageSize,100); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); W25qxx_WaitForWriteEnd(); #if (_W25QXX_DEBUG1) StartTime = HAL_GetTick()-StartTime; for(uint32_t i=0;i<NumByteToWrite_up_to_PageSize ; i++) { if((i%80)&&(i>2)) { printf(“\r\n”); W25qxx_Delay(10); } printf(“0x%02X,”,pBuffer[i]); } printf(“\r\n”); printf(“w25qxx WritePage done after %d ms\r\n”,StartTime); W25qxx_Delay(100); #endif W25qxx_Delay(1); w25qxx.Lock=0; } //################################################################################################################### void W25qxx_WriteSector(uint8_t pBuffer ,uint32_t Sector_Address,uint32_t OffsetInByte ,uint32_t NumByteToWrite_up_to_SectorSize) { if((NumByteToWrite_up_to_SectorSize>w25qxx.SectorSize)||(NumByteToWrite_up_to_SectorSize0)) NumByteToWrite_up_to_SectorSize=w25qxx.SectorSize; #if (_W25QXX_DEBUG1) printf(“+w25qxx WriteSector:%d, Offset:%d ,Write %d Bytes, begin…\r\n",Sector_Address,OffsetInByte,NumByteToWrite_up_to_SectorSize); W25qxx_Delay(100); #endif if(OffsetInByte>=w25qxx.SectorSize) { #if (_W25QXX_DEBUG==1) printf(“—w25qxx WriteSector Faild!\r\n”); W25qxx_Delay(100); #endif return; } uint32_t StartPage; int32_t BytesToWrite; uint32_t LocalOffset; if((OffsetInByte+NumByteToWrite_up_to_SectorSize) > w25qxx.SectorSize) BytesToWrite = w25qxx.SectorSize-OffsetInByte; else BytesToWrite = NumByteToWrite_up_to_SectorSize; StartPage = W25qxx_SectorToPage(Sector_Address)+(OffsetInByte/w25qxx.PageSize); LocalOffset = OffsetInByte%w25qxx.PageSize; do { W25qxx_WritePage(pBuffer,StartPage,LocalOffset,BytesToWrite); StartPage; BytesToWrite-=w25qxx.PageSize-LocalOffset; pBuffer += w25qxx.PageSize - LocalOffset; LocalOffset=0; }while(BytesToWrite>0); #if (_W25QXX_DEBUG==1) printf(”—w25qxx WriteSector Done\r\n"); W25qxx_Delay(100); #endif } //################################################################################################################### void W25qxx_WriteBlock (uint8_t pBuffer ,uint32_t Block_Address ,uint32_t OffsetInByte ,uint32_t NumByteToWrite_up_to_BlockSize) { if((NumByteToWrite_up_to_BlockSize>w25qxx.BlockSize)||(NumByteToWrite_up_to_BlockSize0)) NumByteToWrite_up_to_BlockSize=w25qxx.BlockSize; #if (_W25QXX_DEBUG1) printf(“+w25qxx WriteBlock:%d, Offset:%d ,Write %d Bytes, begin…\r\n",Block_Address,OffsetInByte,NumByteToWrite_up_to_BlockSize); W25qxx_Delay(100); #endif if(OffsetInByte>=w25qxx.BlockSize) { #if (_W25QXX_DEBUG==1) printf(“—w25qxx WriteBlock Faild!\r\n”); W25qxx_Delay(100); #endif return; } uint32_t StartPage; int32_t BytesToWrite; uint32_t LocalOffset; if((OffsetInByte+NumByteToWrite_up_to_BlockSize) > w25qxx.BlockSize) BytesToWrite = w25qxx.BlockSize-OffsetInByte; else BytesToWrite = NumByteToWrite_up_to_BlockSize; StartPage = W25qxx_BlockToPage(Block_Address)+(OffsetInByte/w25qxx.PageSize); LocalOffset = OffsetInByte%w25qxx.PageSize; do { W25qxx_WritePage(pBuffer,StartPage,LocalOffset,BytesToWrite); StartPage; BytesToWrite-=w25qxx.PageSize-LocalOffset; pBuffer += w25qxx.PageSize - LocalOffset; LocalOffset=0; }while(BytesToWrite>0); #if (_W25QXX_DEBUG1) printf(“—w25qxx WriteBlock Done\r\n”); W25qxx_Delay(100); #endif } //################################################################################################################### void W25qxx_ReadByte(uint8_t *pBuffer,uint32_t Bytes_Address) { while(w25qxx.Lock1) W25qxx_Delay(1); w25qxx.Lock=1; #if (_W25QXX_DEBUG1) uint32_t StartTime=HAL_GetTick(); printf(“w25qxx ReadByte at address %d begin…\r\n”,Bytes_Address); #endif HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); W25qxx_Spi(0x0B); if(w25qxx.ID>=W25Q256) W25qxx_Spi((Bytes_Address & 0xFF000000) >> 24); W25qxx_Spi((Bytes_Address & 0xFF0000) >> 16); W25qxx_Spi((Bytes_Address& 0xFF00) >> 8); W25qxx_Spi(Bytes_Address & 0xFF); W25qxx_Spi(0); *pBuffer = W25qxx_Spi(W25QXX_DUMMY_BYTE); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); #if (_W25QXX_DEBUG1) printf(“w25qxx ReadByte 0x%02X done after %d ms\r\n”,pBuffer,HAL_GetTick()-StartTime); #endif w25qxx.Lock=0; } //################################################################################################################### void W25qxx_ReadBytes(uint8_t pBuffer, uint32_t ReadAddr, uint32_t NumByteToRead) { while(w25qxx.Lock1) W25qxx_Delay(1); w25qxx.Lock=1; #if (_W25QXX_DEBUG1) uint32_t StartTime=HAL_GetTick(); printf(“w25qxx ReadBytes at Address:%d, %d Bytes begin…\r\n”,ReadAddr,NumByteToRead); #endif HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); W25qxx_Spi(0x0B); if(w25qxx.ID>=W25Q256) W25qxx_Spi((ReadAddr & 0xFF000000) >> 24); W25qxx_Spi((ReadAddr & 0xFF0000) >> 16); W25qxx_Spi((ReadAddr& 0xFF00) >> 8); W25qxx_Spi(ReadAddr & 0xFF); W25qxx_Spi(0); HAL_SPI_Receive(&_W25QXX_SPI,pBuffer,NumByteToRead,2000); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); #if (_W25QXX_DEBUG1) StartTime = HAL_GetTick()-StartTime; for(uint32_t i=0;i<NumByteToRead ; i++) { if((i%80)&&(i>2)) { printf(”\r\n"); W25qxx_Delay(10); } printf(“0x%02X,”,pBuffer[i]); } printf(“\r\n”); printf(“w25qxx ReadBytes done after %d ms\r\n”,StartTime); W25qxx_Delay(100); #endif W25qxx_Delay(1); w25qxx.Lock=0; } //################################################################################################################### void W25qxx_ReadPage(uint8_t pBuffer,uint32_t Page_Address,uint32_t OffsetInByte,uint32_t NumByteToRead_up_to_PageSize) { while(w25qxx.Lock1) W25qxx_Delay(1); w25qxx.Lock=1; if((NumByteToRead_up_to_PageSize>w25qxx.PageSize)||(NumByteToRead_up_to_PageSize0)) NumByteToRead_up_to_PageSize=w25qxx.PageSize; if((OffsetInByte+NumByteToRead_up_to_PageSize) > w25qxx.PageSize) NumByteToRead_up_to_PageSize = w25qxx.PageSize-OffsetInByte; #if (_W25QXX_DEBUG==1) printf(“w25qxx ReadPage:%d, Offset:%d ,Read %d Bytes, begin…\r\n”,Page_Address,OffsetInByte,NumByteToRead_up_to_PageSize); W25qxx_Delay(100); uint32_t StartTime=HAL_GetTick(); #endif Page_Address = Page_Addressw25qxx.PageSize+OffsetInByte; HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET); W25qxx_Spi(0x0B); if(w25qxx.ID>=W25Q256) W25qxx_Spi((Page_Address & 0xFF000000) >> 24); W25qxx_Spi((Page_Address & 0xFF0000) >> 16); W25qxx_Spi((Page_Address& 0xFF00) >> 8); W25qxx_Spi(Page_Address & 0xFF); W25qxx_Spi(0); HAL_SPI_Receive(&_W25QXX_SPI,pBuffer,NumByteToRead_up_to_PageSize,100); HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET); #if (_W25QXX_DEBUG1) StartTime = HAL_GetTick()-StartTime; for(uint32_t i=0;i<NumByteToRead_up_to_PageSize ; i++) { if((i%80)&&(i>2)) { printf(“\r\n”); W25qxx_Delay(10); } printf(“0x%02X,”,pBuffer[i]); } printf(“\r\n”); printf(“w25qxx ReadPage done after %d ms\r\n”,StartTime); W25qxx_Delay(100); #endif W25qxx_Delay(1); w25qxx.Lock=0; } //################################################################################################################### void W25qxx_ReadSector(uint8_t pBuffer,uint32_t Sector_Address,uint32_t OffsetInByte,uint32_t NumByteToRead_up_to_SectorSize) { if((NumByteToRead_up_to_SectorSize>w25qxx.SectorSize)||(NumByteToRead_up_to_SectorSize0)) NumByteToRead_up_to_SectorSize=w25qxx.SectorSize; #if (_W25QXX_DEBUG1) printf(“+w25qxx ReadSector:%d, Offset:%d ,Read %d Bytes, begin…\r\n",Sector_Address,OffsetInByte,NumByteToRead_up_to_SectorSize); W25qxx_Delay(100); #endif if(OffsetInByte>=w25qxx.SectorSize) { #if (_W25QXX_DEBUG==1) printf(“—w25qxx ReadSector Faild!\r\n”); W25qxx_Delay(100); #endif return; } uint32_t StartPage; int32_t BytesToRead; uint32_t LocalOffset; if((OffsetInByte+NumByteToRead_up_to_SectorSize) > w25qxx.SectorSize) BytesToRead = w25qxx.SectorSize-OffsetInByte; else BytesToRead = NumByteToRead_up_to_SectorSize; StartPage = W25qxx_SectorToPage(Sector_Address)+(OffsetInByte/w25qxx.PageSize); LocalOffset = OffsetInByte%w25qxx.PageSize; do { W25qxx_ReadPage(pBuffer,StartPage,LocalOffset,BytesToRead); StartPage; BytesToRead-=w25qxx.PageSize-LocalOffset; pBuffer += w25qxx.PageSize - LocalOffset; LocalOffset=0; }while(BytesToRead>0); #if (_W25QXX_DEBUG==1) printf(”—w25qxx ReadSector Done\r\n"); W25qxx_Delay(100); #endif } //################################################################################################################### void W25qxx_ReadBlock(uint8_t pBuffer,uint32_t Block_Address,uint32_t OffsetInByte,uint32_t NumByteToRead_up_to_BlockSize) { if((NumByteToRead_up_to_BlockSize>w25qxx.BlockSize)||(NumByteToRead_up_to_BlockSize0)) NumByteToRead_up_to_BlockSize=w25qxx.BlockSize; #if (_W25QXX_DEBUG1) printf(“+w25qxx ReadBlock:%d, Offset:%d ,Read %d Bytes, begin…\r\n",Block_Address,OffsetInByte,NumByteToRead_up_to_BlockSize); W25qxx_Delay(100); #endif if(OffsetInByte>=w25qxx.BlockSize) { #if (_W25QXX_DEBUG==1) printf(“w25qxx ReadBlock Faild!\r\n”); W25qxx_Delay(100); #endif return; } uint32_t StartPage; int32_t BytesToRead; uint32_t LocalOffset; if((OffsetInByte+NumByteToRead_up_to_BlockSize) > w25qxx.BlockSize) BytesToRead = w25qxx.BlockSize-OffsetInByte; else BytesToRead = NumByteToRead_up_to_BlockSize; StartPage = W25qxx_BlockToPage(Block_Address)+(OffsetInByte/w25qxx.PageSize); LocalOffset = OffsetInByte%w25qxx.PageSize; do { W25qxx_ReadPage(pBuffer,StartPage,LocalOffset,BytesToRead); StartPage; BytesToRead-=w25qxx.PageSize-LocalOffset; pBuffer += w25qxx.PageSize - LocalOffset; LocalOffset=0; }while(BytesToRead>0); #if (_W25QXX_DEBUG==1) printf(”—w25qxx ReadBlock Done\r\n"); W25qxx_Delay(100); #endif } //###################################################################################################################
07-20
代码概述 该代码是一个用于嵌入式系统中 W25Qxx 系列 SPI NOR Flash 的完整驱动程序,包含了读写、擦除、初始化、地址转换等功能。此外,它还提供了与 FAT 文件系统兼容的底层接函数(如 `USER_write`),用于在 Flash 上实现文件系统操作。 --- 代码解析 ### 1. `USER_write` 函数 ```c DRESULT USER_write ( BYTE pdrv, const BYTE *buff, DWORD sector, UINT count ) ``` - `pdrv`:物理驱动器编号。 - `buff`:指向写入数据的指针。 - `sector`:起始扇区号。 - `count`:要写入的扇区数。 - `ReadAddr = sector << 12`:将扇区号转换为字节地址(1 扇区 = 4096 字节)。 - `NumByteToRead = count << 12`:将扇区数转换为总字节数。 - `secCount`:计算实际要操作的扇区数量。 - 使用 `for` 循环依次擦除每个扇区,防止写入前未擦除导致数据错误。 - 调用 `W25qxx_WriteSector` 函数执行写入操作。 - 返回 `RES_OK` 表示写入成功。 ### 2. W25Qxx Flash 驱动函数 - **SPI 通信**: - `W25qxx_Spi`:通过 SPI 总线发送/接收单字节数据。 - **芯片识别与初始化**: - `W25qxx_ReadID`:读取 Flash 芯片 ID。 - `W25qxx_ReadUniqID`:读取唯一识别码。 - `W25qxx_Init`:根据 ID 初始化 Flash,设置页、扇区、块大小等参数。 - **写使能与状态控制**: - `W25qxx_WriteEnable` / `W25qxx_WriteDisable`:控制写使能位。 - `W25qxx_ReadStatusRegister` / `W25qxx_WriteStatusRegister`:读写状态寄存器。 - `W25qxx_WaitForWriteEnd`:等待写操作完成。 - **擦除操作**: - `W25qxx_EraseSector`:擦除指定扇区。 - `W25qxx_EraseBlock`:擦除指定块。 - `W25qxx_EraseChip`:擦除整个芯片。 - **地址转换**: - `W25qxx_PageToSector` / `W25qxx_PageToBlock` / `W25qxx_SectorToBlock`:实现页、扇区、块之间的地址转换。 - **数据校验**: - `W25qxx_IsEmptyPage` / `W25qxx_IsEmptySector` / `W25qxx_IsEmptyBlock`:检查页/扇区/块是否为空(全 0xFF)。 - **读写操作**: - `W25qxx_WriteByte` / `W25qxx_WritePage` / `W25qxx_WriteSector` / `W25qxx_WriteBlock`:实现字节、页、扇区、块级别的写入。 - `W25qxx_ReadByte` / `W25qxx_ReadPage` / `W25qxx_ReadSector` / `W25qxx_ReadBlock`:实现字节、页、扇区、块级别的读取。 --- 知识点 1. **SPI 通信协议**:用于微控制器与 Flash 等外设之间进行高速串行通信。 2. **Flash 存储器操作机制**:包括页写入、扇区/块擦除、状态寄存器轮询、读写前必须擦除等特性。 3. **嵌入式文件系统接**:提供 FAT 文件系统所需的底层操作函数(如 `USER_write`),实现对 Flash 存储设备的文件管理。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值