/******************** (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: | |
* 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 and GPIOA clocks */ | |
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_GPIOA, ENABLE); | |
/* Configure SPI1 pins: 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); | |
/* Configure PA.4 as Output push-pull, used as Flash Chip select */ | |
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); | |
/* Deselect the FLASH: Chip Select high */ | |
SPI_FLASH_ChipSelect(High); | |
/* SPI1 configuration */ | |
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_4; | |
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; | |
SPI_InitStructure.SPI_CRCPolynomial = 7; | |
SPI_Init(SPI1, &SPI_InitStructure); | |
/* Enable SPI1 */ | |
SPI_Cmd(SPI1, 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_ChipSelect(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_ChipSelect(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_ChipSelect(Low); | |
/* Send Bulk Erase instruction */ | |
SPI_FLASH_SendByte(BE); | |
/* Deselect the FLASH: Chip Select high */ | |
SPI_FLASH_ChipSelect(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(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite) | |
{ | |
/* Enable the write access to the FLASH */ | |
SPI_FLASH_WriteEnable(); | |
/* Select the FLASH: Chip Select low */ | |
SPI_FLASH_ChipSelect(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_ChipSelect(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(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_ChipSelect(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_ChipSelect(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_ChipSelect(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_ChipSelect(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_ChipSelect(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_ChipSelect | |
* Description : Selects or deselects the FLASH. | |
* Input : State : level to be applied on the FLASH's ChipSelect pin. | |
* Output : None | |
* Return : None | |
*******************************************************************************/ | |
void SPI_FLASH_ChipSelect(u8 State) | |
{ | |
/* Set High or low the chip select line on PA.4 pin */ | |
GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)State); | |
} | |
/******************************************************************************* | |
* 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_GetFlagStatus(SPI1, SPI_FLAG_TXE) == RESET); | |
/* Send byte through the SPI1 peripheral */ | |
SPI_SendData(SPI1, byte); | |
/* Wait to receive a byte */ | |
while(SPI_GetFlagStatus(SPI1, SPI_FLAG_RXNE) == RESET); | |
/* Return the byte read from the SPI bus */ | |
return SPI_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_GetFlagStatus(SPI1, SPI_FLAG_TXE) == RESET); | |
/* Send Half Word through the SPI1 peripheral */ | |
SPI_SendData(SPI1, HalfWord); | |
/* Wait to receive a Half Word */ | |
while(SPI_GetFlagStatus(SPI1, SPI_FLAG_RXNE) == RESET); | |
/* Return the Half Word read from the SPI bus */ | |
return SPI_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_ChipSelect(Low); | |
/* Send "Write Enable" instruction */ | |
SPI_FLASH_SendByte(WREN); | |
/* Deselect the FLASH: Chip Select high */ | |
SPI_FLASH_ChipSelect(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_ChipSelect(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_ChipSelect(High); | |
} | |
/******************* (C) COPYRIGHT 2007 STMicroelectronics *****END OF FILE****/ |