www.pudn.com > huoniu-for_128M(NAND)-FLASH).zip > spi_flash.c, change:2012-09-19,size:18328b


/******************** (C) COPYRIGHT 2007 STMicroelectronics ******************** 
* File Name          : spi_flash.c 
* Author             : MCD Application Team 
* Date First Issued  : 02/05/2007 
* Description        : This file provides a set of functions needed to manage the 
*                      communication between SPI peripheral and SPI M25P64 FLASH. 
******************************************************************************** 
* History: 
* 05/21/2007: V0.3 
* 04/02/2007: V0.2 
* 02/05/2007: V0.1 
******************************************************************************** 
* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. 
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, 
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE 
* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING 
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 
*******************************************************************************/ 
 
/* Includes ------------------------------------------------------------------*/ 
#include "spi_flash.h" 
 
/* Private typedef -----------------------------------------------------------*/ 
#define SPI_FLASH_PageSize 256 
 
#define WRITE      0x02  /* Write to Memory instruction */ 
#define WRSR       0x01  /* Write Status Register instruction */  
#define WREN       0x06  /* Write enable instruction */ 
 
#define READ       0x03  /* Read from Memory instruction */ 
#define RDSR       0x05  /* Read Status Register instruction  */ 
#define RDID       0x9F  /* Read identification */ 
#define SE         0xD8  /* Sector Erase instruction */ 
#define BE         0xC7  /* Bulk Erase instruction */ 
 
#define WIP_Flag   0x01  /* Write In Progress (WIP) flag */ 
 
#define Dummy_Byte 0xA5 
 
/* Private define ------------------------------------------------------------*/ 
/* Private macro -------------------------------------------------------------*/ 
/* Private variables ---------------------------------------------------------*/ 
/* Private function prototypes -----------------------------------------------*/ 
/* Private functions ---------------------------------------------------------*/ 
 
/******************************************************************************* 
* Function Name  : SPI_FLASH_Init 
* Description    : Initializes the peripherals used by the SPI FLASH driver. 
* Input          : None 
* Output         : None 
* Return         : None 
*******************************************************************************/ 
void SPI_FLASH_Init(void) 
{ 
  SPI_InitTypeDef  SPI_InitStructure; 
  GPIO_InitTypeDef GPIO_InitStructure; 
    
  /* Enable SPI1 GPIOA and GPIOB clocks */ 
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
  GPIO_Init(GPIOB, &GPIO_InitStructure); 
								   
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
  GPIO_Init(GPIOC, &GPIO_InitStructure); 
 
  SPI_FLASH_CS_HIGH(); 
								   
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; 
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master; 
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; 
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; 
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; 
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; 
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; 
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; 
  SPI_InitStructure.SPI_CRCPolynomial = 7; 
  SPI_Init(SPI2, &SPI_InitStructure); 
 
  SPI_Cmd(SPI2, ENABLE);     
} 
 
/******************************************************************************* 
* Function Name  : SPI_FLASH_SectorErase 
* Description    : Erases the specified FLASH sector. 
* Input          : SectorAddr: address of the sector to erase. 
* Output         : None 
* Return         : None 
*******************************************************************************/ 
void SPI_FLASH_SectorErase(u32 SectorAddr) 
{ 
  /* Send write enable instruction */ 
  SPI_FLASH_WriteEnable(); 
 
  /* Sector Erase */  
  /* Select the FLASH: Chip Select low */ 
  SPI_FLASH_CS_LOW(); 
  /* Send Sector Erase instruction */ 
  SPI_FLASH_SendByte(SE); 
  /* Send SectorAddr high nibble address byte */ 
  SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16); 
  /* Send SectorAddr medium nibble address byte */ 
  SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8); 
  /* Send SectorAddr low nibble address byte */ 
  SPI_FLASH_SendByte(SectorAddr & 0xFF); 
  /* Deselect the FLASH: Chip Select high */ 
  SPI_FLASH_CS_HIGH(); 
 
  /* Wait the end of Flash writing */ 
  SPI_FLASH_WaitForWriteEnd(); 
} 
 
/******************************************************************************* 
* Function Name  : SPI_FLASH_BulkErase 
* Description    : Erases the entire FLASH. 
* Input          : None 
* Output         : None 
* Return         : None 
*******************************************************************************/ 
void SPI_FLASH_BulkErase(void) 
{ 
  /* Send write enable instruction */ 
  SPI_FLASH_WriteEnable(); 
 
  /* Bulk Erase */  
  /* Select the FLASH: Chip Select low */ 
  SPI_FLASH_CS_LOW(); 
  /* Send Bulk Erase instruction  */ 
  SPI_FLASH_SendByte(BE); 
  /* Deselect the FLASH: Chip Select high */ 
  SPI_FLASH_CS_HIGH(); 
 
  /* Wait the end of Flash writing */ 
  SPI_FLASH_WaitForWriteEnd(); 
} 
 
/******************************************************************************* 
* Function Name  : SPI_FLASH_PageWrite 
* Description    : Writes more than one byte to the FLASH with a single WRITE 
*                  cycle(Page WRITE sequence). The number of byte can't exceed 
*                  the FLASH page size. 
* Input          : - pBuffer : pointer to the buffer  containing the data to be  
*                    written to the FLASH. 
*                  - WriteAddr : FLASH's internal address to write to. 
*                  - NumByteToWrite : number of bytes to write to the FLASH, 
*                    must be equal or less than "SPI_FLASH_PageSize" value.  
* Output         : None 
* Return         : None 
*******************************************************************************/ 
void SPI_FLASH_PageWrite(const u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite) 
{ 
  /* Enable the write access to the FLASH */ 
  SPI_FLASH_WriteEnable(); 
   
  /* Select the FLASH: Chip Select low */ 
  SPI_FLASH_CS_LOW(); 
  /* Send "Write to Memory " instruction */ 
  SPI_FLASH_SendByte(WRITE); 
  /* Send WriteAddr high nibble address byte to write to */ 
  SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16); 
  /* Send WriteAddr medium nibble address byte to write to */ 
  SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8);   
  /* Send WriteAddr low nibble address byte to write to */ 
  SPI_FLASH_SendByte(WriteAddr & 0xFF); 
   
  /* while there is data to be written on the FLASH */ 
  while(NumByteToWrite--)  
  { 
    /* Send the current byte */ 
    SPI_FLASH_SendByte(*pBuffer); 
    /* Point on the next byte to be written */ 
    pBuffer++;  
  } 
   
  /* Deselect the FLASH: Chip Select high */ 
  SPI_FLASH_CS_HIGH(); 
   
  /* Wait the end of Flash writing */ 
  SPI_FLASH_WaitForWriteEnd(); 
} 
 
/******************************************************************************* 
* Function Name  : SPI_FLASH_BufferWrite 
* Description    : Writes block of data to the FLASH. In this function, the 
*                  number of WRITE cycles are reduced, using Page WRITE sequence. 
* Input          : - pBuffer : pointer to the buffer  containing the data to be  
*                    written to the FLASH. 
*                  - WriteAddr : FLASH's internal address to write to. 
*                  - NumByteToWrite : number of bytes to write to the FLASH. 
* Output         : None 
* Return         : None 
*******************************************************************************/ 
void SPI_FLASH_BufferWrite(const 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) /* WriteAddr is SPI_FLASH_PageSize aligned  */ 
  { 
    if(NumOfPage == 0) /* NumByteToWrite < SPI_FLASH_PageSize */ 
    { 
      SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite); 
    } 
    else /* NumByteToWrite > SPI_FLASH_PageSize */  
    { 
      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 /* WriteAddr is not SPI_FLASH_PageSize aligned  */ 
  { 
    if(NumOfPage== 0) /* NumByteToWrite < SPI_FLASH_PageSize */ 
    { 
      if(NumOfSingle > count) /* (NumByteToWrite + WriteAddr) > SPI_FLASH_PageSize */ 
      { 
        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 /* NumByteToWrite > SPI_FLASH_PageSize */ 
    { 
      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); 
      } 
    } 
  } 
} 
 
/******************************************************************************* 
* Function Name  : SPI_FLASH_BufferRead 
* Description    : Reads a block of data from the FLASH. 
* Input          : - pBuffer : pointer to the buffer that receives the data read  
*                    from the FLASH. 
*                  - ReadAddr : FLASH's internal address to read from. 
*                  - NumByteToRead : number of bytes to read from the FLASH. 
* Output         : None 
* Return         : None 
*******************************************************************************/ 
void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead) 
{ 
  /* Select the FLASH: Chip Select low */ 
  SPI_FLASH_CS_LOW(); 
   
  /* Send "Read from Memory " instruction */ 
  SPI_FLASH_SendByte(READ); 
   
  /* Send ReadAddr high nibble address byte to read from */ 
  SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16); 
  /* Send ReadAddr medium nibble address byte to read from */ 
  SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8); 
  /* Send ReadAddr low nibble address byte to read from */ 
  SPI_FLASH_SendByte(ReadAddr & 0xFF); 
 
  while(NumByteToRead--) /* while there is data to be read */ 
  { 
    /* Read a byte from the FLASH */ 
    *pBuffer = SPI_FLASH_SendByte(Dummy_Byte); 
    /* Point to the next location where the byte read will be saved */ 
    pBuffer++; 
  } 
   
  /* Deselect the FLASH: Chip Select high */ 
  SPI_FLASH_CS_HIGH(); 
} 
 
/******************************************************************************* 
* Function Name  : SPI_FLASH_ReadID 
* Description    : Reads FLASH identification. 
* Input          : None 
* Output         : None 
* Return         : FLASH identification 
*******************************************************************************/ 
u32 SPI_FLASH_ReadID(void) 
{ 
  u32 Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0; 
 
  /* Select the FLASH: Chip Select low */ 
  SPI_FLASH_CS_LOW(); 
   
  /* Send "RDID " instruction */ 
  SPI_FLASH_SendByte(0x9F); 
 
  /* Read a byte from the FLASH */ 
  Temp0 = SPI_FLASH_SendByte(Dummy_Byte); 
 
  /* Read a byte from the FLASH */ 
  Temp1 = SPI_FLASH_SendByte(Dummy_Byte); 
 
  /* Read a byte from the FLASH */ 
  Temp2 = SPI_FLASH_SendByte(Dummy_Byte); 
 
  /* Deselect the FLASH: Chip Select high */ 
  SPI_FLASH_CS_HIGH(); 
          
  Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2; 
 
  return Temp; 
} 
 
/******************************************************************************* 
* Function Name  : SPI_FLASH_StartReadSequence 
* Description    : Initiates a read data byte (READ) sequence from the Flash. 
*                  This is done by driving the /CS line low to select the device, 
*                  then the READ instruction is transmitted followed by 3 bytes 
*                  address. This function exit and keep the /CS line low, so the 
*                  Flash still being selected. With this technique the whole 
*                  content of the Flash is read with a single READ instruction. 
* Input          : - ReadAddr : FLASH's internal address to read from. 
* Output         : None 
* Return         : None 
*******************************************************************************/ 
void SPI_FLASH_StartReadSequence(u32 ReadAddr) 
{ 
  /* Select the FLASH: Chip Select low */ 
  SPI_FLASH_CS_LOW(); 
   
  /* Send "Read from Memory " instruction */ 
  SPI_FLASH_SendByte(READ); 
 
/* Send the 24-bit address of the address to read from -----------------------*/   
  /* Send ReadAddr high nibble address byte */ 
  SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16); 
  /* Send ReadAddr medium nibble address byte */ 
  SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8); 
  /* Send ReadAddr low nibble address byte */ 
  SPI_FLASH_SendByte(ReadAddr & 0xFF); 
} 
 
/******************************************************************************* 
* Function Name  : SPI_FLASH_ReadByte 
* Description    : Reads a byte from the SPI Flash. 
*                  This function must be used only if the Start_Read_Sequence 
*                  function has been previously called. 
* Input          : None 
* Output         : None 
* Return         : Byte Read from the SPI Flash. 
*******************************************************************************/ 
u8 SPI_FLASH_ReadByte(void) 
{ 
  return (SPI_FLASH_SendByte(Dummy_Byte)); 
} 
 
/******************************************************************************* 
* Function Name  : SPI_FLASH_SendByte 
* Description    : Sends a byte through the SPI interface and return the byte  
*                  received from the SPI bus. 
* Input          : byte : byte to send. 
* Output         : None 
* Return         : The value of the received byte. 
*******************************************************************************/ 
u8 SPI_FLASH_SendByte(u8 byte) 
{ 
  /* Loop while DR register in not emplty */ 
  while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); 
 
  /* Send byte through the SPI1 peripheral */ 
  SPI_I2S_SendData(SPI1, byte); 
 
  /* Wait to receive a byte */ 
  while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); 
 
  /* Return the byte read from the SPI bus */ 
  return SPI_I2S_ReceiveData(SPI1); 
} 
 
/******************************************************************************* 
* Function Name  : SPI_FLASH_SendHalfWord 
* Description    : Sends a Half Word through the SPI interface and return the   
*                  Half Word received from the SPI bus. 
* Input          : Half Word : Half Word to send. 
* Output         : None 
* Return         : The value of the received Half Word. 
*******************************************************************************/ 
u16 SPI_FLASH_SendHalfWord(u16 HalfWord) 
{ 
  /* Loop while DR register in not emplty */ 
  while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); 
 
  /* Send Half Word through the SPI1 peripheral */ 
  SPI_I2S_SendData(SPI1, HalfWord); 
 
  /* Wait to receive a Half Word */ 
  while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); 
 
  /* Return the Half Word read from the SPI bus */ 
  return SPI_I2S_ReceiveData(SPI1); 
} 
 
/******************************************************************************* 
* Function Name  : SPI_FLASH_WriteEnable 
* Description    : Enables the write access to the FLASH. 
* Input          : None 
* Output         : None 
* Return         : None 
*******************************************************************************/ 
void SPI_FLASH_WriteEnable(void) 
{ 
  /* Select the FLASH: Chip Select low */ 
  SPI_FLASH_CS_LOW(); 
   
  /* Send "Write Enable" instruction */ 
  SPI_FLASH_SendByte(WREN); 
   
  /* Deselect the FLASH: Chip Select high */ 
  SPI_FLASH_CS_HIGH(); 
} 
 
/******************************************************************************* 
* Function Name  : SPI_FLASH_WaitForWriteEnd 
* Description    : Polls the status of the Write In Progress (WIP) flag in the   
*                  FLASH's status  register  and  loop  until write  opertaion 
*                  has completed.   
* Input          : None 
* Output         : None 
* Return         : None 
*******************************************************************************/ 
void SPI_FLASH_WaitForWriteEnd(void) 
{ 
  u8 FLASH_Status = 0; 
   
  /* Select the FLASH: Chip Select low */ 
  SPI_FLASH_CS_LOW(); 
   
  /* Send "Read Status Register" instruction */ 
  SPI_FLASH_SendByte(RDSR); 
   
  /* Loop as long as the memory is busy with a write cycle */ 
  do 
  { 
    /* Send a dummy byte to generate the clock needed by the FLASH  
    and put the value of the status register in FLASH_Status variable */ 
    FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte); 
 
  } while((FLASH_Status & WIP_Flag) == SET); /* Write in progress */ 
 
  /* Deselect the FLASH: Chip Select high */ 
  SPI_FLASH_CS_HIGH(); 
} 
 
/******************* (C) COPYRIGHT 2007 STMicroelectronics *****END OF FILE****/