本文在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引脚,保持结束
}