📄 spi_flash.c
字号:
/**********************************************************************
* 文件名 : spi_flash.c
* 功能描述 : SPI串行外设接口与M25P64T通信管理程序和功能函数
**********************************************************************/
/*头文件 */
#include "spi_flash.h"
#define SPI_FLASH_PageSize 256
#define WRITE 0x02 /* 写指令 */
#define WRSR 0x01 /* 写读状态寄存器指令 */
#define WREN 0x06 /* 写使能指令 */
#define READ 0x03 /* 读指令 */
#define RDSR 0x05 /* 读状态寄存器指令 */
#define RDID 0x9F /* 读签名 */
#define SE 0xD8 /* 扇区擦除指令 */
#define BE 0xC7 /* 批量擦除指令 */
#define WIP_Flag 0x01 /* 写标志 */
#define Dummy_Byte 0xA5
/*******************************************************************************
* 函数名 : SPI_FLASH_Init
* 描述 : SPI外设接口初始化
* 输入 : 无
* 输出 : 无
* 返回 : 无
*******************************************************************************/
void SPI_FLASH_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* 使能SPI1及GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_GPIOA, ENABLE);
/* 配置SPI1引脚: NSS, SCK, MISO and 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);
/* 配置PA4上位输出作为M25P64片选信号 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 片选引脚高电平信号 */
SPI_FLASH_CS_HIGH();
/* SPI1接口配置 */
/*必须先禁能,才能改变MODE,两线全双工*/
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
/*SPI主模式*/
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
/*8位*/
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
/*CPOL=1 */
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
/*CPHA=0 数据捕获第2个*/
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
/*软件NSS*/
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
/*4分频=18M*/
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
/*高位在前*/
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
/*CRC7*/
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
/* 使能 SPI1接口 */
SPI_Cmd(SPI1, ENABLE);
}
/*******************************************************************************
* 函数名 : SPI_FLASH_SectorErase
* 描述 : 擦除扇区
* 输入 : 扇区地址
* 输出 : 无
* 返回 : 无
*******************************************************************************/
void SPI_FLASH_SectorErase(u32 SectorAddr)
{
/* 发送写使能指令 */
SPI_FLASH_WriteEnable();
/* 片选信号低,选中FLASH */
SPI_FLASH_CS_LOW();
/* 发送擦除扇区指令 */
SPI_FLASH_SendByte(SE);
/* 发送扇区高四位地址 */
SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);
/* 发送扇区中四位地址 */
SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8);
/* 发送扇区低四位地址 */
SPI_FLASH_SendByte(SectorAddr & 0xFF);
/* 片选禁止,拉高电平 */
SPI_FLASH_CS_HIGH();
/* 等待写完成 */
SPI_FLASH_WaitForWriteEnd();
}
/*******************************************************************************
* 函数名 : SPI_FLASH_BulkErase
* 描述 : 批量擦除
* 输入 : 无
* 输出 : 无
* 返回 : 无
*******************************************************************************/
void SPI_FLASH_BulkErase(void)
{
/* 写使能指令 */
SPI_FLASH_WriteEnable();
/* 批量擦除 */
/* 片选信号低有效 */
SPI_FLASH_CS_LOW();
/* 批量擦除指令 */
SPI_FLASH_SendByte(BE);
/* 禁止片选,上拉高电平 */
SPI_FLASH_CS_HIGH();
/* 等待写完成 */
SPI_FLASH_WaitForWriteEnd();
}
/*******************************************************************************
* 函数名 : SPI_FLASH_PageWrite
* 描述 : 单个写周期内写入多字节,字节数不可超出页面容量
* 输入 : - pBuffer:缓冲区数据
- WriteAddr : 写入地址
- NumByteToWrite:需写入字节数,小于或等于页面大小
* 输出 : 无
* 返回 : 无
*******************************************************************************/
void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
/* 写使能 */
SPI_FLASH_WriteEnable();
/* 片选有效 */
SPI_FLASH_CS_LOW();
/* 写指令 */
SPI_FLASH_SendByte(WRITE);
/* 写入地址高四位 */
SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16);
/* 写入地址中四位 */
SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8);
/* 写入地址低四位 */
SPI_FLASH_SendByte(WriteAddr & 0xFF);
/* 当写入FLASH时,计数-- */
while(NumByteToWrite--)
{
/* 发送数据 */
SPI_FLASH_SendByte(*pBuffer);
/* 指向另外一字节数据 */
pBuffer++;
}
/* 片选信号拉高 */
SPI_FLASH_CS_HIGH();
/* 等待写操作完成 */
SPI_FLASH_WaitForWriteEnd();
}
/*******************************************************************************
* 函数名 : SPI_FLASH_BufferWrite
* 描述 : 块数据写入。
* 输入 : - pBuffer:缓冲区数据
- WriteAddr : 写入地址
- NumByteToWrite:需写入字节数
* 输出 : 无
* 返回 : 无
*******************************************************************************/
void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
Addr = WriteAddr % SPI_FLASH_PageSize;
count = SPI_FLASH_PageSize - Addr;
NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
if(Addr == 0) /* 写地址对齐 */
{
if(NumOfPage == 0) /* 写数据字节 < SPI_FLASH页面大小 */
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
}
else /* 写数据字节 > SPI_FLASH_页面大小 */
{
while(NumOfPage--)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
WriteAddr += SPI_FLASH_PageSize;
pBuffer += SPI_FLASH_PageSize;
}
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
}
}
else /* 写地址未对齐 */
{
if(NumOfPage== 0) /* 写数据字节 < SPI_FLASH_页面大小 */
{
if(NumOfSingle > count)
{
temp = NumOfSingle - count;
SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
WriteAddr += count;
pBuffer += count;
SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);
}
else
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
}
}
else /* 写数据字节 > SPI_FLASH_页面大小 */
{
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
WriteAddr += count;
pBuffer += count;
while(NumOfPage--)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
WriteAddr += SPI_FLASH_PageSize;
pBuffer += SPI_FLASH_PageSize;
}
if(NumOfSingle != 0)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
}
}
}
}
/*******************************************************************************
* 函数名 : SPI_FLASH_BufferRead
* 功能描述 :从FLASH读一个数据块.
* 输入: - pBuffer : 读数据缓冲区指针.
* - ReadAddr : 读操作地址.
* - NumByteToRead : 读操作的字节数.
* 输出:无
* 返回: 无
*******************************************************************************/
void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)
{
/* FLASH片选: CS为低电平 */
SPI_FLASH_CS_LOW();
/* 发送 "Read from Memory " 指令 */
SPI_FLASH_SendByte(READ);
/* 发送读操作高四位地址*/
SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
/* 发送读操作中间四位地址*/
SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
/* 发送读操作低四位地址*/
SPI_FLASH_SendByte(ReadAddr & 0xFF);
while(NumByteToRead--) /* 等待读操作就绪 */
{
/* 一个空读字节 */
*pBuffer = SPI_FLASH_SendByte(Dummy_Byte);
pBuffer++;
}
/* 片选未选中*/
SPI_FLASH_CS_HIGH();
}
/*******************************************************************************
* 函数名: SPI_FLASH_ReadID
* 功能描述 Reads FLASH identification.
* 输入: 无
* 输出:无
* 返回: FLASH identification
*******************************************************************************/
u32 SPI_FLASH_ReadID(void)
{
u32 Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
/* 片选信号选中 */
SPI_FLASH_CS_LOW();
/* 发送"RDID " 指令*/
SPI_FLASH_SendByte(0x9F);
/* 从FLASH读数据*/
Temp0 = SPI_FLASH_SendByte(Dummy_Byte); /*一个空读字节*/
/* 二个空读字节 */
Temp1 = SPI_FLASH_SendByte(Dummy_Byte);
/* 三个空读字节 */
Temp2 = SPI_FLASH_SendByte(Dummy_Byte);
/* 片选未选中 */
SPI_FLASH_CS_HIGH();
Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
return Temp;
}
/*******************************************************************************
* 函数名: SPI_FLASH_StartReadSequence
* 功能描述:初始化读数据指令序列
* 输入: - ReadAddr : 读操作地址.
* 输出: 无
* 返回: 无
*******************************************************************************/
void SPI_FLASH_StartReadSequence(u32 ReadAddr)
{
/* 片选选中 */
SPI_FLASH_CS_LOW();
/* 发送"READ"指令 */
SPI_FLASH_SendByte(READ);
/* 发送A23~A0 3字节地址*/
/* 发送高四位地址 */
SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
/* 发送中四位地址 */
SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
/* 发送低四位地址 */
SPI_FLASH_SendByte(ReadAddr & 0xFF);
}
/*******************************************************************************
* 函数名: SPI_FLASH_ReadByte
* 功能描述:从FLASH读一个字节的数据,仅用于开始读操作序列发送空读字节
* 输入: 无
* 输出: 无
* 返回: 空读字节.
*******************************************************************************/
u8 SPI_FLASH_ReadByte(void)
{
return (SPI_FLASH_SendByte(Dummy_Byte));
}
/*******************************************************************************
* 函数名: SPI_FLASH_SendByte
* 功能描述:发送数据及返回接收的SPI总线数据
* 输入: byte :发送数据字节.
* 输出:无
* 返回: 接收的数据.
*******************************************************************************/
u8 SPI_FLASH_SendByte(u8 byte)
{
/* 循环直到DR寄存器不空*/
while(SPI_GetFlagStatus(SPI1, SPI_FLAG_TXE) == RESET);
/* 向SPI1发送数据字节 */
SPI_SendData(SPI1, byte);
/* 等待写数据*/
while(SPI_GetFlagStatus(SPI1, SPI_FLAG_RXNE) == RESET);
/* 返回SPI总线接收到的数据 */
return SPI_ReceiveData(SPI1);
}
/*******************************************************************************
* 函数名: SPI_FLASH_SendHalfWord
* 功能描述:发送半字数据和返回SPI总线接收到的半字数据 .
* 输入: Half Word : 半字发送.
* 输出: 无
* 返回: 半字接收数据返回.
*******************************************************************************/
u16 SPI_FLASH_SendHalfWord(u16 HalfWord)
{
/* 循环直到DR寄存器不为空*/
while(SPI_GetFlagStatus(SPI1, SPI_FLAG_TXE) == RESET);
/* SPI1半字发送*/
SPI_SendData(SPI1, HalfWord);
/* 等待半字接收*/
while(SPI_GetFlagStatus(SPI1, SPI_FLAG_RXNE) == RESET);
/* SPI总线半字接收数据返回*/
return SPI_ReceiveData(SPI1);
}
/*******************************************************************************
* 函数名: SPI_FLASH_WriteEnable
* 功能描述: 写使能指令.
* 输入: 无
* 输出: 无
* 返回: 无
*******************************************************************************/
void SPI_FLASH_WriteEnable(void)
{
/* 片选选中 */
SPI_FLASH_CS_LOW();
/* 发送"WREN"指令*/
SPI_FLASH_SendByte(WREN);
/* 片选信号拉高=未选中 */
SPI_FLASH_CS_HIGH();
}
/*******************************************************************************
* 函数名: SPI_FLASH_WaitForWriteEnd
* 功能描述: 轮询WIP标志位直至写操作完成
* 输入: 无
* 输出: 无
* 返回: 无
*******************************************************************************/
void SPI_FLASH_WaitForWriteEnd(void)
{
u8 FLASH_Status = 0;
/*片选选中*/
SPI_FLASH_CS_LOW();
/* 发送"RDSR"指令*/
SPI_FLASH_SendByte(RDSR);
do
{
/* 发送空读字节 */
FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte);
} while((FLASH_Status & WIP_Flag) == SET); /* 写入 */
/* 片选拉高=未选中 */
SPI_FLASH_CS_HIGH();
}
/******************* (C) COPYRIGHT 2007 STMicroelectronics *****END OF FILE****/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -