SPI实现SST25VF016B驱动(Flash)

本文在STM32F103上实现SSH25的驱动,实现数据的写入和读取:

1:此驱动未加擦除时候是否擦除成功的判断,一般写入FLASH不成功的最大原因就是擦除不成功,所以一般特选FLASH里面的一个地址存储一个特征字,比如0x12,当执行完操作擦除命令后,去判断这个特征字是否被擦除为0xff,如果擦除成功,执行写指令,当然,也可以进行CRC校验,判断写入和读取的是否一致;

2:FLASH的写入时,避免被中断打断;

main.c

#include "stdio.h"
#include "sys.h"
#include "USART_Init.h"
#include "SST25_SPI_Init.h"

u8 SSH_Buff[20];
u32 baud_menu[] = {1200,2400,3840,4800,5760,9600,19200,115200};
u16 ARR = 0;

int main()
{
	NVIC_Configuration();                    //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 
	delay_init();                            //延时函数初始化
	Usart_Init(9600);   	                   //串口初始化 
	Spi_Init();                              //SPI1/SSH25初始化

	Write_State_Register(0X00);              //写状态寄存器为0x00,取消写保护,上电默认全片保护
	Block_Clear(Clear_4_K,10);               //擦除4K扇区
	Write_Mul_Byte(0,"sunshine",8);          //将"sunshine"字符串写入扇区0       
	Read_Data(0,8,SSH_Buff);                 //将扇区0开始8个字节读进SSH_Buff
	Usart_Send_Data(SSH_Buff,8);             //发送串口打印
	delay_ms(1000);
}
SSH_SPI_Init.h
#ifndef SSH25
#define SSH25

#include 
#include "delay.h"

extern u8 ID[3];

typedef enum
{
	Clear_4_K = 0,
	Clear_32_K = 1,
	Clear_64_K = 2,
	Clear_ALL_FLASH = 3,
}Block_Cnt;

#define CS_LOW()  GPIO_ResetBits(GPIOC, GPIO_Pin_4)
#define CS_HIGH() GPIO_SetBits(GPIOC,GPIO_Pin_4)

/*未使用*/
#define HOLD_LOW() 
#define HOLD_HIGH() 

/*未使用*/
#define WP_LOW()
#define WP_HIGH()

//函数申明
void Spi_Init(void);
u8 Read_State_Register(void);
void Wait_Busy_Clear(void);
void Write_State_Register(u8 dat);
void Write_Enable(void);
void Write_Disable(void);
void Read_Data(long add,u16 cnt,u8 *buff);
void Read_High_Speed_Data(u32 add,u16 cnt,u8 *buff);
void Write_Byte(u32 add,u8 dat);
void Write_Mul_Byte(u32 add,u8 *buff,u32 cnt);
void Block_Clear(Block_Cnt flag,u32 add);
void Read_ID(void);
void Write_Protect_Func(void);
void Hold_Func(u8 flag);

#endif
SSH25_SPI_Init.c

#include "SST25_SPI_Init.h"

//SPI初始化
void Spi_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;                       //定义gpio结构体  
	SPI_InitTypeDef SPI_InitStruct;                         //SPI结构体初始化
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);    //使能GPIOB口时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,  ENABLE ); //SPI2时钟使能 	
	
	//GPIO结构体初始化
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;            //GPIO复用推挽 
	GPIO_InitStruct.GPIO_Speed =GPIO_Speed_50MHz;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;  //SPI2_NSS复用 启用软件从设备管理 NSS引脚上的电平由SI位确定
	GPIO_Init(GPIOA,&GPIO_InitStruct);     
	
	//CS片选
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
  GPIO_InitStruct.GPIO_Speed =GPIO_Speed_50MHz;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOC, &GPIO_InitStruct);
	GPIO_SetBits(GPIOC,GPIO_Pin_4);

	//SPI结构体初始化
	SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; 
	SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;
	SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;
	SPI_InitStruct.SPI_CRCPolynomial = 7;
	SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
	SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; 
	SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;	
	SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
	SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;                             //启动软件从设备管理
	SPI_Init(SPI1,&SPI_InitStruct); 
	
	SPI_Cmd(SPI1,ENABLE);                                               //spi2使能
}

/*SST25发送一个字节的数据*/
u8 SST25_Send_Byte(u8 dat)
{
	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
	SPI_I2S_SendData(SPI1,dat);
	
	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
	return SPI_I2S_ReceiveData(SPI1);
}

/*SST25读取一个字节的数据*/
u8 SST25_Receive_Byte()
{
	return SST25_Send_Byte(0xff);
}

/*读状态寄存器*/
u8 Read_State_Register()
{
	u8 flag = 0;
	CS_LOW();                //使能片选信号
	SST25_Send_Byte(0x05);   //发送读状态寄存器操作码0x05*/
	flag = SST25_Receive_Byte();
	CS_HIGH();               //禁止片选信号 
	return flag;
}

/*等待内部擦除或者编程操作结束*/
void Wait_Busy_Clear()
{
	while((Read_State_Register()&0x01) != 0x00);
}

/*写状态寄存器*/
void Write_State_Register(u8 dat)
{
	CS_LOW();                //使能片选信号
	SST25_Send_Byte(0x50);   //发送写状态寄存器使能操作码0x50 
	CS_HIGH();               //禁止片选信号 
	
	CS_LOW();                //使能片选信号
	SST25_Send_Byte(0x01);   //发送写状态寄存器操作码0x01 
	SST25_Send_Byte(dat);   //写状态寄存器为0x00
	CS_HIGH();               //禁止片选信号 
	Wait_Busy_Clear();
}

/*写使能操作*/
void Write_Enable()
{
	CS_LOW();                //使能片选信号
	SST25_Send_Byte(0x06);   //发送写使能操作码0x06
	CS_HIGH();               //禁止片选信号
}

/*写禁止操作*/
void Write_Disable()
{
	CS_LOW();                //使能片选信号
	SST25_Send_Byte(0x04);   //发送写使能操作码0x04
	CS_HIGH();               //禁止片选信号
}

/*读操作*/
void Read_Data(long add,u16 cnt,u8 *buff)
{
	CS_LOW();                //使能片选信号
	SST25_Send_Byte(0x03);   //发送写使能操作码0x03 
	SST25_Send_Byte(add>>16);//发送存储地址,24位
	SST25_Send_Byte(add>>8); //发送存储地址,24位
	SST25_Send_Byte(add);    //发送存储地址,24位
	for(;cnt>0;cnt--)
		*(buff++) = SST25_Receive_Byte();
	CS_HIGH();               //禁止片选信号
}

/*高速读*/
void Read_High_Speed_Data(u32 add,u16 cnt,u8 *buff)
{
	CS_LOW();                //使能片选信号
	SST25_Send_Byte(0x0b);   //发送写使能操作码0x0b
	SST25_Send_Byte(add>>16);//发送存储地址,24位
	SST25_Send_Byte(add>>8); //发送存储地址,24位
	SST25_Send_Byte(add);    //发送存储地址,24位 
	SST25_Send_Byte(0x00);   //发送一个空周期 
	for(;cnt>0;cnt--)
		*(buff++) = SST25_Receive_Byte();
	CS_HIGH();               //禁止片选信号
}

/*写单个字节操作,字节编程*/
void Write_Byte(u32 add,u8 dat)
{
	Write_Enable();          //写使能
	CS_LOW();                //使能片选信号
	SST25_Send_Byte(0x02);   //发送字节编程操作码0x02*/ 
	SST25_Send_Byte(add>>16);//发送存储地址,24位
	SST25_Send_Byte(add>>8); //发送存储地址,24位
	SST25_Send_Byte(add);    //发送存储地址,24位 
	SST25_Send_Byte(dat);    //发送写入的数据 
	CS_HIGH();               //禁止片选信号 
	Wait_Busy_Clear();
}

/*写多个字节操作,AAI编程*/
void Write_Mul_Byte(u32 add,u8 *buff,u32 cnt)
{
	u32 i = 0;
	Write_Enable();          //写使能
	CS_LOW();                //使能片选信号
	SST25_Send_Byte(0xad);   //发送AAI编程操作码0xad*/ 
	SST25_Send_Byte(add>>16);//发送存储地址,24位
	SST25_Send_Byte(add>>8); //发送存储地址,24位
	SST25_Send_Byte(add);    //发送存储地址,24位 
	SST25_Send_Byte(buff[0]);//发送写入的数据 
	SST25_Send_Byte(buff[1]);//发送写入的数据 
	CS_HIGH();               //禁止片选信号 
	
	i = 2;
	while(i>16);//发送存储地址,24位
		SST25_Send_Byte(add>>8); //发送存储地址,24位
		SST25_Send_Byte(add);    //发送存储地址,24位 
		CS_HIGH();               //禁止片选信号 
		Wait_Busy_Clear();       //等待写结束 
	}
	else
	if(flag == 1)              //32K块擦除
	{
		Write_Enable();          //写使能
		CS_LOW();                //使能片选信号 
		SST25_Send_Byte(0x52);   //发送32K块擦除操作码0x52
		SST25_Send_Byte(add>>16);//发送存储地址,24位
		SST25_Send_Byte(add>>8); //发送存储地址,24位
		SST25_Send_Byte(add);    //发送存储地址,24位 
		CS_HIGH();               //禁止片选信号 
		Wait_Busy_Clear();       //等待写结束 
	}
	else
	if(flag == 2)              //64K块擦除 
	{
		Write_Enable();          //写使能
		CS_LOW();                //使能片选信号 
		SST25_Send_Byte(0xd8);   //发送64K块擦除操作码0xd8
		SST25_Send_Byte(add>>16);//发送存储地址,24位
		SST25_Send_Byte(add>>8); //发送存储地址,24位
		SST25_Send_Byte(add);    //发送存储地址,24位 
		CS_HIGH();               //禁止片选信号 
		Wait_Busy_Clear();       //等待写结束 
	}
	else
	if(flag == 3)              //全部擦除 
	{
		Write_Enable();          //写使能
		CS_LOW();                //使能片选信号 
		SST25_Send_Byte(0x60);   //发送64K块擦除操作码0x60/0xc7
		SST25_Send_Byte(add>>16);//发送存储地址,24位
		SST25_Send_Byte(add>>8); //发送存储地址,24位
		SST25_Send_Byte(add);    //发送存储地址,24位 
		CS_HIGH();               //禁止片选信号 
		Wait_Busy_Clear();       //等待写结束 
	}
}

u8 ID[3];
/*读设备ID*/
void Read_ID()
{
	CS_LOW();                     //使能片选信号 
	SST25_Send_Byte(0x9f);        //读ID指令
	ID[0] = SST25_Receive_Byte(); //获取ID
	ID[1] = SST25_Receive_Byte(); 
	ID[2] = SST25_Receive_Byte();    
	CS_HIGH();                    //禁止片选信号 
}

/*写保护函数*/
void Write_Protect_Func()
{
	Write_State_Register(0x80);   //BPL位为1
	WP_LOW();                     //写保护使能位拉低,BP0-BP4默认为高,只能读内存,不能写 
}
/*保持操作*/
void Hold_Func(u8 flag)
{
	if(flag == ENABLE)
		HOLD_LOW();             //拉低HOLD引脚,开始保持
	else
	if(flag == DISABLE)
		HOLD_HIGH();            //拉高HOLD引脚,保持结束
}




你可能感兴趣的:(stm32)