标题:
GPIO模拟驱动W25Q16 FLASH源程序
[打印本页]
作者:
liupdeng
时间:
2019-8-21 15:24
标题:
GPIO模拟驱动W25Q16 FLASH源程序
GPIO模拟驱动W25Q16 FLASH
程序代码应用到产品,非常稳定
源程序如下:
#include "_cpus.h"
#include "_coms.h"
/*=====================================================================================================================*/
//SPI模式:CPOL=1 CPHA=1 CS Active low
//clock is high when inactive
//Data is valid on clock trailing edge
//不活动时,时钟为高 也就是数据可改变区
//数据在时钟后沿有效 数据作用点
#define ENTER_CRITICAL()
#define EXIT_CRITICAL()
#define MOSI PC6
#define SPSCK PC7
#define ADD_EN_WP PC8
#define MISO PC9
#define SS PC10
#define SS_OUT_L b_hGpioOut(SS,0)
#define SS_OUT_H b_hGpioOut(SS,1)
#define WP_OUT_L b_hGpioOut(ADD_EN_WP,0)
#define WP_OUT_H b_hGpioOut(ADD_EN_WP,1)
#define SPI_CLK b_hGpioOut(SPSCK,0);b_dNOP();b_dNOP();b_dNOP();b_dNOP();b_dNOP();b_hGpioOut(SPSCK,1);//和EE相位相反
#define Flash_CS_0 b_hGpioOut(SPSCK,1); ENTER_CRITICAL();WP_OUT_H;SS_OUT_L;
#define Flash_CS_1 WP_OUT_L;SS_OUT_H;EXIT_CRITICAL(); b_hGpioOut(SPSCK,0);
void b_hExFlashSetChip2NomlPower(void);
extern void b_hExFlashInit(void)
{
b_hGpioInit(SS,eOUT_PUSH_PULL,1);
b_hGpioInit(SPSCK,eOUT_PUSH_PULL,0);
b_hGpioInit(MOSI,eOUT_PUSH_PULL,0);
b_hGpioInit(MISO,eOUT_PUSH_PULL,0);
b_hGpioInit(ADD_EN_WP,eOUT_PUSH_PULL,0);
b_hExFlashSetChip2NomlPower();
}
/*****************************************************************
** function name : SPISendByte
** description : SPI1 send one byte
** input parameter: byte to be sent
** return : byte received
******************************************************************/
static uint08_t ExFlash_hSendByte(uint08_t b)
{
//时钟低到高输出,高到低输入
//将b写到ee中,返回数据写到f中
uint8_t i,f;
f=0;
// b_hGpioOut(SS,0);
//SPI_SDI_DDR = IOisIN;
b_hGpioInit(MISO,eIN_PULL_UP,0);
//h_bGpioInit(SPSCK,eOUT_PUSH_PULL,0);
//h_bGpioInit(MOSI,eOUT_PUSH_PULL,0);
//SPI_SDI_UP=1; SPI_SCK_UP=1; SPI_SDO_UP=1;
for(i=8;i;i--)
{
//TicksDelayMs(1);
if(b&bit7){
// SPI_SDO_ODR=1; /*向ee写1输出1p4.3*/
b_hGpioOut(MOSI,1);
}else{
//SPI_SDO_ODR=0; /*向ee写0*/
b_hGpioOut(MOSI,0);
}
SPI_CLK;
// b_hGpioOut(SPSCK,0); //低到高跳变时钟
// TicksDelayMs(1);
// b_hGpioOut(SPSCK,1);
// TicksDelayMs(1);
b<<=1;
f<<=1;
if(b_hGpioRead(MISO))f|=bit0; /*接收数据*/
}
// SPI_SDO_UP=0; SPI_SCK_UP=0;SPI_SDI_DDR = IOisOUT;SPI_SDI_ODR= IOisLOW;SPI_SDI_UP=0;
b_hGpioInit(MISO,eOUT_PUSH_PULL,0);
//b_hGpioOut(SS,1);
return f;
}
/*****************************************************************
** function name : SPIReceiveByte
** description : SPI1 receive byte
** input parameter: none
** return : byte received
******************************************************************/
static uint08_t ExFlash_hReceiveByte(void)
{
uint8_t i,f, b=0xff;;
f=0;
// b_hGpioOut(SS,0);
// SPI_SDI_DDR = IOisIN; SPI_SDI_UP=1; SPI_SCK_UP=1; SPI_SDO_UP=1;
b_hGpioInit(MISO,eIN_PULL_UP,0);
for(i=8;i;i--)
{
if(b&bit7)
b_hGpioOut(MOSI,1);
else
b_hGpioOut(MOSI,0);
SPI_CLK;
// b_hGpioOut(SPSCK,0);
// TicksDelayMs(1);
// b_hGpioOut(SPSCK,1);
// TicksDelayMs(1);
b<<=1;
f<<=1;
if(b_hGpioRead(MISO))f|=bit0;
}
b_hGpioInit(MISO,eOUT_PUSH_PULL,0);
// b_hGpioOut(SS,1);
return f;
}
/******************************************
** 函 数 名:WriteEnable
** 功能描述:写使能
** 参 数:无
** 返 回:无
*******************************************/
static void ExFlash_hWriteEnable(void)
{
Flash_CS_0;
ExFlash_hSendByte(0x06);//写使能
Flash_CS_1;
}
static void ExFlash_hWriteDisable( void )
{
Flash_CS_0;
ExFlash_hSendByte(0x04);//写禁能
Flash_CS_1;
}
/******************************************************************************/
/* 函数名称:uint8 check_flash_busy(void) */
/* 功能描述:检查flash是否忙 */
/* 参数说明:无 */
/* 参数返回: 如果忙返回1,不忙返回0 */
/******************************************************************************/
extern uint08_t b_hExFlashCheckBusy(void)
{
uint08_t busy_flag;
Flash_CS_0;
ExFlash_hSendByte(0x05);
busy_flag=ExFlash_hReceiveByte();
Flash_CS_1;
if(busy_flag & 0x03)
busy_flag = 1;
else
busy_flag = 0;
return busy_flag;
}
extern uint16_t ExFlash_hReadStateReg1_2( void )
{
uint16_t temp_state;
Flash_CS_0;
temp_state=ExFlash_hSendByte(0x05);
temp_state=temp_state<<8;
temp_state=temp_state+ExFlash_hSendByte(0x35);
Flash_CS_1;
return temp_state;
}
extern void ExFlash_hWriteStateReg1_2( uint08_t highS,uint08_t lowS)
{
ExFlash_hWriteEnable();
Flash_CS_0;
ExFlash_hSendByte(0x01);//send write state regster cmd
ExFlash_hSendByte(lowS);
ExFlash_hSendByte(highS);
Flash_CS_1;
ExFlash_hWriteDisable();
}
/******************************************************************************
** 函 数 名:ExFlash_hPageProgram
** 功能描述: 向指定的地址写入指定数量的字节
** 参 数:数据缓冲区,字节数,FLASH起始地址
** 返 回:无
******************************************************************************/
extern void ExFlash_hFlashProgram(uint08_t *databuffer,uint32_t address,uint32_t datasize)
{
ExFlash_hWriteEnable(); //写使能
Flash_CS_0; //置cs低选中
ExFlash_hSendByte(0x02);
ExFlash_hSendByte((uint08_t)(address>>16));
ExFlash_hSendByte((uint08_t)(address>>8));
ExFlash_hSendByte((uint08_t)address);
while(datasize>0)
{
ExFlash_hSendByte(*databuffer);
databuffer++;
datasize--;
}
Flash_CS_1; //置cs高不选中
while(b_hExFlashCheckBusy()); //等待器件写完结束
}
/********************************************
**函 数 名:ReadUniqueID
**功能描述:读取芯片唯一ID号,总共8字节
**参 数:数据缓冲区
*********************************************/
extern void ExFlash_hReadUniqueID(uint08_t *databuffer)
{
uint08_t i;
// EnterNoInt();
Flash_CS_0; //置cs低选中
ExFlash_hSendByte(0x4B);
ExFlash_hSendByte(0xff); //这里发送的三个字节是任意的,不一定是0xff
ExFlash_hSendByte(0xff);
ExFlash_hSendByte(0xff);
ExFlash_hSendByte(0xff);
for(i=0;i<8;i++)
{
*databuffer=ExFlash_hReceiveByte();
databuffer++;
}
Flash_CS_1;
// ExitNoInt();
}
/********************************************************
** 函 数 名:SectorErase
** 功能描述:扇区擦除
** 参 数:扇区地址
** 返 回:无
*********************************************************/
void ExFlash_hSector4KErase(uint32_t sector4kN)
{
// b_dDI();
sector4kN*=4096;
ExFlash_hWriteEnable(); //写使能
Flash_CS_0; //置cs低选中
ExFlash_hSendByte(0x20);
ExFlash_hSendByte((uint08_t)(sector4kN>>16));
ExFlash_hSendByte((uint08_t)(sector4kN>>8));
ExFlash_hSendByte((uint08_t)sector4kN);
Flash_CS_1; //置cs高不选中
// while(b_hExFlashCheckBusy()); //等待器件写完结束
// EI;
}
extern void b_hExFlashSector4KEraseAddr(uint32_t sectorAddr)
{
//b_dDI();
ExFlash_hWriteEnable(); //写使能
Flash_CS_0; //置cs低选中
ExFlash_hSendByte(0x20);
ExFlash_hSendByte((uint08_t)(sectorAddr>>16));
ExFlash_hSendByte((uint08_t)(sectorAddr>>8));
ExFlash_hSendByte((uint08_t)sectorAddr);
Flash_CS_1; //置cs高不选中
//while(b_hExFlashCheckBusy()); //等待器件写完结束
// EI;
}
void ExFlash_hBlock32KErase(uint32_t sector32kN)
{
// b_dDI();
sector32kN*=131072;
ExFlash_hWriteEnable(); //写使能
Flash_CS_0; //置cs低选中
ExFlash_hSendByte(0x52);
ExFlash_hSendByte((uint08_t)(sector32kN>>16));
ExFlash_hSendByte((uint08_t)(sector32kN>>8));
ExFlash_hSendByte((uint08_t)sector32kN);
Flash_CS_1; //置cs高不选中
// while(b_hExFlashCheckBusy()); //等待器件写完结束
// EI;
}
void ExFlash_hBlock64KErase(uint32_t address)
{
// b_dDI();
ExFlash_hWriteEnable(); //写使能
Flash_CS_0; //置cs低选中
ExFlash_hSendByte(0xD8);
ExFlash_hSendByte((uint08_t)(address>>16));
ExFlash_hSendByte((uint08_t)(address>>8));
ExFlash_hSendByte((uint08_t)address);
Flash_CS_1; //置cs高不选中
// while(b_hExFlashCheckBusy()); //等待器件写完结束
// EI;
}
void ExFlash_hAllChipErase(void)
{
// b_dDI();
ExFlash_hWriteEnable(); //写使能
Flash_CS_0; //置cs低选中
ExFlash_hSendByte(0xC7);
Flash_CS_1; //置cs高不选中
// while(b_hExFlashCheckBusy()); //等待器件写完结束
// EI;
}
extern void b_hExFlashSetChip2LowPower(void)
{
// b_dDI();
ExFlash_hWriteEnable(); //写使能
Flash_CS_0; //置cs低选中
ExFlash_hSendByte(0xB9);
Flash_CS_1; //置cs高不选中
// while(b_hExFlashCheckBusy()); //等待器件写完结束
// EI;
}
extern void ExFlash_hSetChip2HighPower(void)
{
// b_dDI();
ExFlash_hWriteEnable(); //写使能
Flash_CS_0; //置cs低选中
ExFlash_hSendByte(0xA3);
Flash_CS_1; //置cs高不选中
// while(b_hExFlashCheckBusy()); //等待器件写完结束
// EI;
}
void b_hExFlashSetChip2NomlPower(void)
{
ExFlash_hWriteEnable(); //写使能
Flash_CS_0; //置cs低选中
ExFlash_hSendByte(0xAB);
Flash_CS_1; //置cs高不选中
ExFlash_hWriteDisable();
// while(b_hExFlashCheckBusy());//FDW去掉的
// EI;
}
/*****************************************************************
** 函 数 名:ReadRFlash
** 功能描述:从指定的地址读取指定数量的字节
** 参 数:数据缓冲区,字节数,起始地址
** 返 回:无
******************************************************************/
extern void b_hExFlashRead(uint08_t *databuffer,uint32_t address,uint16_t datasize)
{
uint16_t i;
// b_dDI();
//while( b_hExFlashCheckBusy());
Flash_CS_0;
ExFlash_hSendByte(0x03);
ExFlash_hSendByte((uint08_t)(address>>16));
ExFlash_hSendByte((uint08_t)(address>>8));
ExFlash_hSendByte((uint08_t)address);
for(i=0;i<datasize;i++)
{
databuffer[i]=ExFlash_hReceiveByte();
}
Flash_CS_1; //置cs高不选中
// EI;
}
/**************************************************************************
** 函数名:CheckData
** 功能描述:检验指定的Flash起始地址的数据和指定的缓冲区的数据是否全部相等
** 参数:数据缓冲区DataBuffer, Flash起始地址DataAddr,数据字节数
** 返回:全部相同返回1,否则返回0
***************************************************************************/
extern uint8_t ExFlash_hCheckData(uint08_t *DataBuffer, uint32_t DataAddr, uint16_t DataSize)
{
uint08_t data;
uint16_t i;
for(i=0;i<DataSize;i++)
{
b_hExFlashRead(&data,1,DataAddr+i);
if(data!=DataBuffer[i])return 0;
}
return 1;
}
//extern void ExFlash_mWDataToSector(uint08_t *pDataBuffer,uint16_t dataSize, uint08_t sector)
//{
//
// uint08_t
// for(uint16_t i=0;i<dataSize;i++)//校验数据
// {
// if(SPI_FLASH_BUF[secoff+i]!=0XFF)break;//需要擦除
// }
//}
//无检验写SPI FLASH
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
extern void ExFlash_hWriteMustErase(uint08_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
uint16_t pageremain;
pageremain=256-WriteAddr%256; //单页剩余的字节数
if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
while(1)
{
ExFlash_hFlashProgram(pBuffer,WriteAddr,pageremain);
if(NumByteToWrite==pageremain)break;//写入结束了
else //NumByteToWrite>pageremain
{
pBuffer+=pageremain;
WriteAddr+=pageremain;
NumByteToWrite-=pageremain; //减去已经写入了的字节数
if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节
else pageremain=NumByteToWrite; //不够256个字节了
}
};
}
//写SPI FLASH
//在指定地址开始写入指定长度的数据
//该函数带擦除操作!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
//屏敝注解掉此随机写SPI_FLASH函数,
//原因:资源消耗大--需要栈空间要调设到 4096+0x200 测试时用的是 0x2200的栈空间
//void ExFlash_hWrite(uint08_t *pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
//{
// static uint32_t secpos;
// uint16_t secoff;
// uint16_t secremain;
// uint16_t i;
// uint08_t SPI_FLASH_BUF[4096];
//
//
// secpos=WriteAddr/4096;//起始地址所在扇区号 地址 0~511 for w25x16
// secoff=WriteAddr%4096;//起始地址所在扇区号的偏移 在扇区内的偏移
// secremain=4096-secoff;//起始地址所在扇区剩余空间大小
//
//
// if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节 装的下
// while(1)
// {
// b_hExFlashRead(SPI_FLASH_BUF,secpos*4096,4096);//读出整个扇区的内容
// for(i=0;i<secremain;i++)//校验数据
// {
// if(SPI_FLASH_BUF[secoff+i]!=0XFF)break;//需要擦除
// }
// if(i<secremain)//需要擦除
// {
// ExFlash_hSector4KErase(secpos);//擦除这个扇区
// for(i=0;i<secremain;i++) //复制
// {
// SPI_FLASH_BUF[i+secoff]=pBuffer[i];
// }
// ExFlash_hWriteMustErase(SPI_FLASH_BUF,secpos*4096,4096);//写入整个扇区
//
// }else ExFlash_hWriteMustErase(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间.
//
// if(NumByteToWrite==secremain)break;//写入结束了
// else//写入未结束
// {
// secpos++;//扇区地址增1
// secoff=0;//偏移位置为0
//
// pBuffer+=secremain; //指针偏移
// WriteAddr+=secremain;//写地址偏移
// NumByteToWrite-=secremain; //字节数递减
// if(NumByteToWrite>4096)secremain=4096; //下一个扇区还是写不完
// else secremain=NumByteToWrite; //下一个扇区可以写完了
// }
// };
//}
extern void b_hExFlashWrite(uint08_t *databuffer,uint32_t address,uint32_t datasize)
{
ExFlash_hWriteEnable(); //写使能
Flash_CS_0; //置cs低选中
ExFlash_hSendByte(0x02);
ExFlash_hSendByte((uint08_t)(address>>16));
ExFlash_hSendByte((uint08_t)(address>>8));
ExFlash_hSendByte((uint08_t)address);
while(datasize>0)
{
ExFlash_hSendByte(*databuffer);
databuffer++;
datasize--;
}
Flash_CS_1; //置cs高不选中
//等待器件写完结束
}
复制代码
作者:
liupdeng
时间:
2019-8-21 15:26
自已顶一下,有需要的拿走
作者:
Muker
时间:
2023-3-12 23:56
感谢分享,回头试试
作者:
Ljp989A
时间:
2025-7-3 11:45
顶楼主!感谢分享!
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1