⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spi_flash.c

📁 ARM_CORTEX-M3应用实例开发详解光盘
💻 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 + -