408 lines
10 KiB
C
408 lines
10 KiB
C
#include <string.h>
|
|
#include "type.h"
|
|
|
|
//#include "stm32f4xx_spi.h"
|
|
//#include "stm32f4xx_gpio.h"
|
|
//#include "stm32f4xx_hal.h"
|
|
|
|
#include "stm32f4xx_spi.h"
|
|
#include "stm32f4xx_gpio.h"
|
|
|
|
|
|
#include "config.h"
|
|
#include "os_task.h"
|
|
#include "delay.h"
|
|
#include "flash.h"
|
|
#include "sys_config.h"
|
|
|
|
#if USE_SPI_FLASH
|
|
|
|
#define SST25_SECTOR_PER_SIZE (4096) //一个扇区为4kB
|
|
#define SST25_TOTAL_SIZE (4*1024*1024*2/8) //总大小为4Mb 512*2KB 128个扇区
|
|
|
|
#define SST25_TOTAL_SECTOR_NUM (SST25_TOTAL_SIZE/SST25_SECTOR_PER_SIZE)
|
|
|
|
#define FLASH_SPI SPI1
|
|
|
|
#define SST25_SELECT() do{GPIO_ResetBits(GPIOA,GPIO_Pin_4);}while(0)
|
|
#define SST25_DESELECT() do{GPIO_SetBits(GPIOA,GPIO_Pin_4);}while(0)
|
|
|
|
|
|
#define SST25_READDATA 0x03
|
|
#define SST25_FASTREADDATA 0x0B
|
|
#define SST25_4KBYTE_BLOCKERASE 0x20
|
|
#define SST25_32KBYTE_BLOCKERASE 0x52
|
|
#define SST25_64KBYTE_BLOCKERASE 0xD8
|
|
#define SST25_CHIPERASE 0xC7
|
|
#define SST25_BYTEPORGRAM 0x02
|
|
#define SST25_AAI_WORDPROGRAM 0xAD
|
|
#define SST25_READSTATUSREG 0x05
|
|
#define SST25_ENABLEWRITESTATUSREG 0x50
|
|
#define SST25_WRITESTATUSREG 0x01
|
|
#define SST25_WRITEENABLE 0x06
|
|
#define SST25_WRITEDISABLE 0x04
|
|
#define SST25_DEVICEID 0x90
|
|
#define SST25_JEDECDEVICEID 0x9F
|
|
#define SST25_EBSY 0x70
|
|
#define SST25_DBSY 0x80
|
|
|
|
//extern SPI_HandleTypeDef hspi1;
|
|
|
|
static uint8 spi1_read_byte(void)
|
|
{
|
|
while (SPI_I2S_GetFlagStatus(FLASH_SPI, SPI_I2S_FLAG_TXE) == RESET);
|
|
SPI_I2S_SendData(FLASH_SPI,0xff);
|
|
while (SPI_I2S_GetFlagStatus(FLASH_SPI, SPI_I2S_FLAG_RXNE) == RESET);
|
|
return (SPI_I2S_ReceiveData(FLASH_SPI));
|
|
}
|
|
static void spi1_write_byte(uint8 byte)
|
|
{
|
|
while (SPI_I2S_GetFlagStatus(FLASH_SPI, SPI_I2S_FLAG_TXE) == RESET);
|
|
SPI_I2S_SendData(FLASH_SPI, byte);
|
|
while (SPI_I2S_GetFlagStatus(FLASH_SPI, SPI_I2S_FLAG_RXNE) == RESET);
|
|
(void)SPI_I2S_ReceiveData(FLASH_SPI);
|
|
}
|
|
/******************************************
|
|
写一个命令
|
|
******************************************/
|
|
void sst25_write_cmd(uint8 cmd)
|
|
{
|
|
SST25_SELECT();
|
|
spi1_write_byte(cmd);
|
|
SST25_DESELECT();
|
|
}
|
|
|
|
/******************************************
|
|
写一个命令一个数据
|
|
******************************************/
|
|
void sst25_write_cmd_data(uint8 cmd,uint8 data)
|
|
{
|
|
SST25_SELECT();
|
|
spi1_write_byte(cmd);
|
|
spi1_write_byte(data);
|
|
SST25_DESELECT();
|
|
}
|
|
/******************************************
|
|
写一个命令三个数据
|
|
******************************************/
|
|
void sst25_write_cmd_data3(uint8 cmd, uint8* data)
|
|
{
|
|
SST25_SELECT();
|
|
spi1_write_byte(cmd);
|
|
spi1_write_byte(*data++);
|
|
spi1_write_byte(*data++);
|
|
spi1_write_byte(*data);
|
|
SST25_DESELECT();
|
|
}
|
|
/******************************************
|
|
写一个命令返回一个数据
|
|
******************************************/
|
|
uint8 sst25_read_data(uint8 cmd)
|
|
{
|
|
uint8 temp;
|
|
|
|
SST25_SELECT();
|
|
spi1_write_byte(cmd);
|
|
temp = spi1_read_byte();
|
|
SST25_DESELECT();
|
|
return temp;
|
|
}
|
|
|
|
/******************************************
|
|
写一个命令,三个地址 返回多个数据
|
|
******************************************/
|
|
void sst25_read_datas(uint8 cmd,uint8 *addr,uint8 *data,uint32 no)
|
|
{
|
|
uint16 i;
|
|
|
|
SST25_SELECT();
|
|
spi1_write_byte(cmd);
|
|
spi1_write_byte(*addr++);
|
|
spi1_write_byte(*addr++);
|
|
spi1_write_byte(*addr);
|
|
for(i=0;i<no;i++)
|
|
{
|
|
data[i] = spi1_read_byte();
|
|
}
|
|
SST25_DESELECT();
|
|
}
|
|
/******************************************
|
|
SST25读取状态寄存器
|
|
******************************************/
|
|
uint8 sst25_readsr(void)
|
|
{
|
|
uint8 sr;
|
|
|
|
sr = sst25_read_data(SST25_READSTATUSREG);
|
|
return sr;
|
|
}
|
|
/******************************************
|
|
SST25写状态寄存器
|
|
******************************************/
|
|
void sst25_writesr(uint8 cmd)
|
|
{
|
|
sst25_write_cmd(SST25_ENABLEWRITESTATUSREG);
|
|
sst25_write_cmd_data(SST25_WRITESTATUSREG,cmd);
|
|
}
|
|
/******************************************
|
|
SST25写使能
|
|
******************************************/
|
|
void sst25_wren(void)
|
|
{
|
|
sst25_write_cmd(SST25_WRITEENABLE);
|
|
}
|
|
/******************************************
|
|
SST25写失能
|
|
******************************************/
|
|
void sst25_wrdi(void)
|
|
{
|
|
sst25_write_cmd(SST25_WRITEDISABLE);
|
|
}
|
|
/******************************************
|
|
SST25忙检测
|
|
1 忙
|
|
******************************************/
|
|
void sst25_wait_busy(void)
|
|
{
|
|
while(sst25_readsr()&0x01);
|
|
}
|
|
/******************************************
|
|
SST25允许软件写保护
|
|
******************************************/
|
|
void sst25_wpen(void)
|
|
{
|
|
uint8 sta;
|
|
|
|
sta = sst25_read_data(SST25_READSTATUSREG)|0x1c;
|
|
sst25_write_cmd(SST25_ENABLEWRITESTATUSREG);
|
|
sst25_write_cmd_data(0x01,sta);
|
|
}
|
|
/******************************************
|
|
SST25先取消保护位,再允许写
|
|
******************************************/
|
|
void sst25_writeen(void)
|
|
{
|
|
uint8 sta;
|
|
|
|
sta = sst25_read_data(SST25_READSTATUSREG)&(~0x0c);
|
|
sst25_write_cmd(SST25_ENABLEWRITESTATUSREG);
|
|
sst25_write_cmd(0xff);
|
|
sst25_write_cmd_data(SST25_WRITESTATUSREG,sta);
|
|
sst25_write_cmd(SST25_WRITEENABLE);
|
|
}
|
|
/******************************************
|
|
SST25 读芯片ID
|
|
******************************************/
|
|
uint16 sst25_readid(void)
|
|
{
|
|
uint8 id[3]= {0,};
|
|
uint8 addr[3] = {0,0,0};
|
|
|
|
sst25_read_datas(SST25_DEVICEID,addr,id,2);
|
|
return ((id[0]<<8)+id[1]);
|
|
}
|
|
/******************************************
|
|
SST25 擦除整块flash
|
|
******************************************/
|
|
void sst25_chip_erase(void)
|
|
{
|
|
sst25_writesr(0x02);
|
|
sst25_wren();
|
|
sst25_write_cmd(SST25_CHIPERASE);
|
|
sst25_wait_busy();
|
|
}
|
|
/******************************************
|
|
SST25 擦除扇区
|
|
******************************************/
|
|
void sst25_sector_erase(uint32 addr)
|
|
{
|
|
uint8 ad[3]={0,};
|
|
|
|
ad[0] = ((addr>>16)&0xff);
|
|
ad[1] = ((addr>>8)&0xff);
|
|
ad[2] = (addr&0xff);
|
|
|
|
sst25_writesr(0x02);
|
|
sst25_wren();
|
|
SST25_SELECT();
|
|
spi1_write_byte(SST25_4KBYTE_BLOCKERASE);
|
|
spi1_write_byte(ad[0]);
|
|
spi1_write_byte(ad[1]);
|
|
spi1_write_byte(ad[2]);
|
|
SST25_DESELECT();
|
|
|
|
sst25_wait_busy();
|
|
}
|
|
/******************************************
|
|
SST25 写入一个字节
|
|
|
|
******************************************/
|
|
void sst25_byte_write(uint32 addr,uint8 byte)
|
|
{
|
|
sst25_writesr(0x02);
|
|
sst25_wren();
|
|
SST25_SELECT();
|
|
spi1_write_byte(SST25_BYTEPORGRAM);
|
|
spi1_write_byte((addr>>16)&0xff);
|
|
spi1_write_byte((addr>>8)&0xff);
|
|
spi1_write_byte(addr&0xff);
|
|
spi1_write_byte(byte);
|
|
SST25_DESELECT();
|
|
sst25_wait_busy();
|
|
}
|
|
/******************************************
|
|
SST25 写入多个字节
|
|
|
|
******************************************/
|
|
void sst25_datas_write(uint32 addr,uint8 *buf,uint32 no)
|
|
{
|
|
uint32 cnt;
|
|
|
|
if(no == 0)
|
|
return;
|
|
|
|
sst25_writesr(0x02);
|
|
sst25_wren();
|
|
if(no == 1)
|
|
{
|
|
sst25_byte_write(addr,*buf);
|
|
}
|
|
|
|
else
|
|
{
|
|
cnt = no;
|
|
SST25_SELECT();
|
|
spi1_write_byte(SST25_AAI_WORDPROGRAM);
|
|
spi1_write_byte((addr>>16)&0xff);
|
|
spi1_write_byte((addr>>8)&0xff);
|
|
spi1_write_byte(addr&0xff);
|
|
spi1_write_byte(*buf++);
|
|
spi1_write_byte(*buf++);
|
|
SST25_DESELECT();
|
|
cnt-=2;
|
|
sst25_wait_busy();
|
|
|
|
for(;cnt>1;cnt-=2)
|
|
{
|
|
SST25_SELECT();
|
|
spi1_write_byte(SST25_AAI_WORDPROGRAM);
|
|
spi1_write_byte(*buf++);
|
|
spi1_write_byte(*buf++);
|
|
SST25_DESELECT();
|
|
sst25_wait_busy();
|
|
}
|
|
sst25_wrdi();
|
|
|
|
if(cnt == 1)
|
|
{
|
|
sst25_wren();
|
|
sst25_byte_write(addr+no-1,*buf);
|
|
}
|
|
}
|
|
sst25_wpen();
|
|
}
|
|
/******************************************
|
|
SST25 高速读
|
|
|
|
******************************************/
|
|
void sst25_readh(uint32 addr,uint8 *buf,uint32 no)
|
|
{
|
|
uint16 i;
|
|
|
|
SST25_SELECT();
|
|
spi1_write_byte(SST25_FASTREADDATA);
|
|
spi1_write_byte((uint8)(addr>>16)&0xff);
|
|
spi1_write_byte((uint8)(addr>>8)&0xff);
|
|
spi1_write_byte((uint8)addr&0xff);
|
|
spi1_write_byte(0xff);
|
|
|
|
for(i=0;i<no;i++)
|
|
{
|
|
buf[i] = spi1_read_byte();
|
|
}
|
|
SST25_DESELECT();
|
|
}
|
|
/******************************************
|
|
SST25 低速读
|
|
|
|
******************************************/
|
|
void sst25_readl(uint32 addr,uint8 *buf,uint32 no)
|
|
{
|
|
uint8 ad[3];
|
|
|
|
ad[0] = (addr>>16)&0xff;
|
|
ad[1] = (addr>>8)&0xff;
|
|
ad[2] = addr&0xff;
|
|
|
|
sst25_read_datas(SST25_READDATA,ad,buf,no);
|
|
}
|
|
void flash_write_byte(uint8 byte,uint32 addr)
|
|
{
|
|
uint32 secpos;
|
|
|
|
secpos = addr/SST25_SECTOR_PER_SIZE;
|
|
if(secpos>=SST25_TOTAL_SECTOR_NUM)
|
|
return;
|
|
|
|
sst25_sector_erase(secpos);
|
|
sst25_byte_write(addr,byte);
|
|
}
|
|
void flash_write_buf(uint8 *buf,uint32 num,uint32 addr)
|
|
{
|
|
uint32 secpos;
|
|
|
|
secpos = addr/SST25_SECTOR_PER_SIZE;
|
|
if(secpos >= SST25_TOTAL_SECTOR_NUM)
|
|
return;
|
|
|
|
if(addr+num>SST25_TOTAL_SIZE)
|
|
num = SST25_TOTAL_SIZE - addr;
|
|
|
|
sst25_datas_write(addr, buf, num);
|
|
}
|
|
|
|
void flash_erase_sector(uint32 start_address,uint32 num)
|
|
{
|
|
uint32 secpos,secoff,secremain;
|
|
uint16 secnum=0;
|
|
int32 i = 0;
|
|
|
|
secpos = start_address/SST25_SECTOR_PER_SIZE;
|
|
if(secpos >= SST25_TOTAL_SECTOR_NUM)
|
|
return;
|
|
|
|
if(start_address+num>SST25_TOTAL_SIZE)
|
|
num = SST25_TOTAL_SIZE - start_address;
|
|
|
|
secoff = start_address%SST25_SECTOR_PER_SIZE;
|
|
secremain = SST25_SECTOR_PER_SIZE-secoff;
|
|
|
|
if(num < secremain)
|
|
{
|
|
secnum = 1;
|
|
}
|
|
else
|
|
{
|
|
secnum = 1;
|
|
i = num -secremain;
|
|
do
|
|
{
|
|
secnum++;
|
|
i = i - SST25_SECTOR_PER_SIZE;
|
|
}while(i>0);
|
|
}
|
|
|
|
for(i=0;i<secnum;i++)
|
|
{
|
|
sst25_sector_erase((secpos+i)*SST25_SECTOR_PER_SIZE);
|
|
}
|
|
}
|
|
void flash_read_buf(uint8 *buf,uint32 len,uint32 addr)
|
|
{
|
|
if(addr >= SST25_TOTAL_SIZE)
|
|
return;
|
|
sst25_readl(addr,buf,len);
|
|
}
|
|
|
|
#endif
|
|
|