您的位置 首页 IOT

SST25VF080B SPI接口FLASH STM32驱动

所有的FLASHA都一样只能从1变0,要想从0变1只有擦除一个页扇,SST25VF080B最小可以擦除4KB的页速度也不错50MHz容量1MB挺够用的…

一切的FLASHA 都相同只能从1变0,要想从0变1 只要擦除一个页扇,SST25VF080B 最小能够擦除4KB的页速度也不错 50MHz 容量1MB 挺够用的 10万次的擦写寿数。最低2.7V 就可正常作业。

Flexible Erase Capability

– Uniform 4 KByte sectors
– Uniform 32 KByte overlay blocks
– Uniform 64 KByte overlay blocks
先记下 这些个7788的指令

SST25VF080B 的各种指令比较繁琐

Status Register这个设置写维护多点 我这儿只用它的判忙BUSY

相同先装备SPI与GPIO口上图~~

在这也便是CE有用片选嘛~~

#defineSST_SELECT()GPIO_ResetBits(GPIOC, GPIO_Pin_13)/* SST CS = L */
#defineSST_DESELECT()GPIO_SetBits(GPIOC, GPIO_Pin_13)/* SST CS = H */

/***********************************************
**函数名:FLASH_SPI_Config
**功用:初始化串行FLASH的SPI接口
**留意事项:串行FLASH运用了SPI1接口
***********************************************/
void FLASH_SPI_Config(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC |
RCC_APB2Periph_AFIO |
RCC_APB2Periph_SPI1,
ENABLE);

/* SCK, MISO and MOSI A5=CLK,A6=MISO,A7=MOSI*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);

/* PC.13 作片选*/
GPIO_SetBits(GPIOC, GPIO_Pin_13);//预置为高
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);

/* SPI1 configuration */
SPI_Cmd(SPI1, DISABLE); //必须先禁能,才干改动MODE
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//两线全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//主
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//8位
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;//CPOL=0 时钟悬空低
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//CPHA=0 数据捕获第1个
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//软件NSS
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;//2分频=36M SST25VF说是50M没事
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//高位在前
SPI_InitStructure.SPI_CRCPolynomial = 7;//CRC7 我不解的是假设犯错要怎么处理

SPI_Init(SPI1, &SPI_InitStructure);
//SPI_SSOutputCmd(SPI1, ENABLE); //使能NSS脚可用 我这就一个SPI 器材
SPI_Cmd(SPI1, ENABLE);

}

/***************************************
**函数名:SPIByte
**功用:读写SPI总线
**留意事项:关于SPI来说,主机的读也需求先写,
**运用此函数,读的时分主张参数设置为0xff,写的时分则写参数.这儿运用直接操作寄存器的方法完成SPI硬件层读写,是为了加速速写速度 在说LCD 的时分我用的便是库函数 比方

SPI_I2S_SendDataSPI_I2S_ReceiveData SPI_I2S_GetFlagStatus
***************************************/
static u8 SPIByte(u8 byte)
{
/*等候发送寄存器空*/
while((SPI1->SR & SPI_I2S_FLAG_TXE)==RESET);
/*发送一个字节*/
SPI1->DR = byte;
/* 等候接纳寄存器有用*/
while((SPI1->SR & SPI_I2S_FLAG_RXNE)==RESET);
return(SPI1->DR);
}

//咱用形式0

/*****************************************
**函数名:SSTCmd1/2/4
**功用:写一个SST指令/写一个指令后接一个数据/写一个指令后再写3个数据
**留意事项:这是一个完好的单指令操作,不回来
*****************************************/
void SSTCmd1(u8 cmd)
{
SST_SELECT();
SPIByte(cmd);
SST_DESELECT();
}

void SSTCmd2(u8 cmd,u8 data)
{
SST_SELECT();
SPIByte(cmd);
SPIByte(data);
SST_DESELECT();
}

void SSTCmd4(u8 cmd,u8 *addr)
{
SST_SELECT();
SPIByte(cmd);//首指令
SPIByte(*addr++);
SPIByte(*addr++);
SPIByte(*addr);
SST_DESELECT();
}

/****************************************
**函数名:SSTCmdb1b/SSTCmd4bs
**功用:写一个SST指令,回来1字节数据/写1个指令字,3个地址字,回来多个字节
**更多运用在读出上的
****************************************/
u8 SSTCmdb1b(u8 cmd)
{
u8 tmp;
SST_SELECT();
SPIByte(cmd);
tmp=SPIByte(0xff);
SST_DESELECT();
return(tmp);
}
void SSTCmd4bs(u8 cmd,u8* addr,u8* data,u32 no)
{
SST_SELECT();
SPIByte(cmd);//首指令
SPIByte(*addr++);
SPIByte(*addr++);
SPIByte(*addr);
for(;no>0;no–)
{
*data++=SPIByte(0xff);
}
SST_DESELECT();
}

//指令时序杂乱啊~~当然了我这为了求全都写出来了

常用的芯片功用

/***************************************
SST25WREN 答应写功用
***************************************/
void SST25WREN(void)
{
SSTCmd1(0x06);
}

/***********************************
SST25WRDI 屏蔽写功用
***********************************/
void SST25WRDI(void)
{
SSTCmd1(0x04);
}

/**********************************
SST25BY 检测忙
**********************************/
u8 SST25BY(void)
{
u8 sta;
sta=SSTCmdb1b(0x05);
return(sta&0x01);
}

/***********************************
SST25WPEN 答应软件写维护
留意事项:25的写入比较繁琐,主张在每次操作前都撤销掉写维护,操作完成后则从头答应写维护

***********************************/
void SST25WPEN(void)
{
u8 sta;
sta=SSTCmdb1b(0x05)|0x1c;//读出寄存器并参加维护位
SSTCmd1(0x50);//答应写Status Register
SSTCmd2(0x01,sta);
}

//先消除维护位,再答应写位
void SST25WriteEn(void)
{
u8 sta;
sta=SSTCmdb1b(0x05)&(~0x1c);//读出寄存器并消除维护位
SSTCmd1(0x50);//答应写寄存器Status Register
SSTCmd2(0x01,sta);//写寄存器
SSTCmd1(0x06);//答应写
}

/********************************寄存器Status Register**********************************/

便是这样完成写维护。

/**********************************
SST25ReadID 读取SST的ID 这个功用 呵呵不必多说~当然单纯的读写操作必定用不上
**********************************/
u16 SST25ReadID(void)
{
u8 id[3];
u8 addr[3]={0,0,0};

SSTCmd4bs(0x90,addr,id,3);
return((id[0]<<8)+id[1]);
}

/**********************************
SST25ChipErase 刷除CHIP
**********************************/
void SST25ChipErase(void)
{
SST25WriteEn();
SSTCmd1(0x60);
while(SST25BY());
SST25WPEN();
}

/***********************************
SST25SectorErase 刷扇区 用的是4kb巨细 假设地址在0~4095 之间那么这之间的地址都会刷除

当然我给 4096 的话4096到4096+4095 之间都会刷掉
***********************************/
void SST25SectorErase(u32 addr)
{
u8 ad[3];
ad[0]=(addr>>16)&0xff;
ad[1]=(addr>>8)&0xff;
ad[2]=addr&0xff;

SST25WriteEn();

SST_SELECT();
SPIByte(0x20);
SPIByte(ad[0]);
SPIByte(ad[1]);
SPIByte(ad[2]);
SST_DESELECT();

while(SST25BY());
//SST25WPEN();
}

/**********************************
SST25ByteProgram 写一个字节*留意在此前要调用撤销写维护,实践写应运用AAI,此函数在AAI中调用,用于写奇数个字节
**********************************/
void SST25ByteProgram(u32 addr,u8 byte)
{
u8 ad[3];
ad[0]=(addr>>16)&0xff;
ad[1]=(addr>>8)&0xff;
ad[2]=addr&0xff;

SST_SELECT();
SPIByte(0x02);
SPIByte(ad[0]);
SPIByte(ad[1]);
SPIByte(ad[2]);
SPIByte(byte);
SST_DESELECT();
while(SST25BY());
}

/***********************************
SST25Write 写多个字节
***********************************/
void SST25Write(u32 addr,u8* p_data,u32 no)
{
u8 ad[3];
u32 cnt;
if(no==0)
return;

SST25WriteEn();

if(no==1)//no<2则应运用一般单字节方法
{
SST25ByteProgram(addr,*p_data);
//SST25WPEN();
}
else
{
cnt=no;

ad[2]=(addr>>16)&0xff;
ad[1]=(addr>>8)&0xff;
ad[0]=addr&0xff;

SST_SELECT();
SPIByte(0xad);
SPIByte(ad[2]);
SPIByte(ad[1]);
SPIByte(ad[0]);
SPIByte(*p_data++);
SPIByte(*p_data++);
SST_DESELECT();
cnt-=2;
while(SST25BY());//判忙

//中心的双字节写
for(;cnt>1;cnt-=2)
{
SST_SELECT();
SPIByte(0xad);
SPIByte(*p_data++);
SPIByte(*p_data++);
SST_DESELECT();
while(SST25BY());//判忙
}
SST25WRDI();//WRDI用于退出AAI写形式 所谓AAI 便是地址主动加

//假设有最终一个字节(no为奇数)
if(cnt==1)
{
SST25WriteEn();
SST25ByteProgram(addr+no-1,*p_data);
}
}
SST25WPEN();//WP维护
}

//咱们用的是下边这种

/*************************************
SST25Read 高速读 关于后续带5的芯片,可调用此函数读
*************************************/
void SST25Read(u32 addr,u8* p_data,u32 no)
{
SST_SELECT();

SPIByte(0x0b);
SPIByte(addr>>16);
SPIByte(addr>>8);
SPIByte(addr);
SPIByte(0xff);

for(;no>0;no–)
*p_data++=SPIByte(0xff);
SST_DESELECT();
}

/****************************************
SST25ReadL 低速读
****************************************/
void SST25ReadL(u32 addr,u8* p_data,u32 no)
{
u8 ad[3];
ad[2]=(addr>>16)&0xff;
ad[1]=(addr>>8)&0xff;
ad[0]=addr&0xff;

SSTCmd4bs(0x03,ad,p_data,no);
}

好了 一切的底层读写都做好了~!
后边~~
SST25SectorErase(0);//擦除 0~4095 地址之间的数据
SST25Write(addr,db_sst1,64);//往addr 写入db_sst164个字节
SST25Read(addr,db_sst1,64);//从addr读64个字节到db_sst1
就这些接口常用了~~~

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/yingyong/iot/252438.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部