/******************** (C) COPYRIGHT 2007 STMicroelectronics ********************
* File Name : spi_flash.c
* Author : MCD Application Team
* Version : V1.1
* Date : 11/26/2007
* Description : This file provides a set of functions needed to manage the
* communication between SPI peripheral and SPI M25P64 FLASH.
********************************************************************************
* 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 WRDI 0x04
#define READ 0x03 /* 25Mhz Read from Memory instruction */
#define HREAD 0x0B /* 80Mhz 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 EWSR 0x50
#define EBSY 0x70
#define DBSY 0x80
#define AII 0xAD
#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 SPI2, GPIOA and GPIOBclocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
/* Configure SPI2 pins: SCK and MOSI */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Configure SPI2 pin: MISO */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Configure PB.2 as Output push-pull, used as Flash Chip select */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Deselect the FLASH: Chip Select high */
SPI_FLASH_CS_HIGH;
/* SPI2 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_Low;
SPI_InitStructure.SPI_CPHA=SPI_CPHA_1Edge;
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);
/* Enable SPI2 */
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
*******************************************************************************/
u8 SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
u8 * pBufferStart;
pBufferStart = pBuffer;
SPI_FLASH_SendCMD(EWSR); //0x50
SPI_FLASH_WriteReg(WRSR, 0x00); //0x01 0x00 write status CMD - disable write protection
SPI_FLASH_SendCMD(EBSY); //0x70
SPI_FLASH_SendCMD(WREN); //0x06 write enable
/* Select the FLASH: Chip Select low */
SPI_FLASH_CS_LOW;
SPI_FLASH_SendByte(0xAD);
/* 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);
SPI_FLASH_SendByte(*pBuffer++);
SPI_FLASH_SendByte(*pBuffer++);
/* while there is data to be written on the FLASH */
while(pBuffer < pBufferStart + NumByteToWrite)
{
SPI_FLASH_CS_HIGH;
SPI_FLASH_CS_LOW;
while (SPI_FLASH_SendByte(0xFF) != 0xFF){};
SPI_FLASH_CS_HIGH;
SPI_FLASH_CS_LOW;
SPI_FLASH_SendByte(0xAD);
SPI_FLASH_SendByte(*pBuffer++);
SPI_FLASH_SendByte(*pBuffer++);
}
/* Deselect the FLASH: Chip Select high */
SPI_FLASH_CS_HIGH;
SPI_FLASH_CS_LOW;
while (SPI_FLASH_SendByte(0xFF) != 0xFF){};
SPI_FLASH_CS_HIGH;
SPI_FLASH_SendCMD(WRDI);
SPI_FLASH_SendCMD(DBSY);
return SPI_FLASH_WriteReg(RDSR, 0);
}
/*******************************************************************************
* 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)
{
SPI_FLASH_StartReadSequence(ReadAddr);
while(NumByteToRead--)
*pBuffer++ = SPI_FLASH_SendByte(Dummy_Byte);
/* 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(HREAD);
/* 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);
SPI_FLASH_SendByte(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(SPI2, SPI_I2S_FLAG_TXE) == RESET){};
//while (!(SPI2->SR & 2));
/* Send byte through the SPI1 peripheral */
//SPI_I2S_SendData(SPIx, byte);
SPI2->DR=byte;
/* Wait to receive a byte */
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET){};
//while (!(SPI2->SR & 1));
/* Return the byte read from the SPI bus */
//return SPI_I2S_ReceiveData(SPIx);
return SPI2->DR;
}
/*******************************************************************************
* 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(SPI2, SPI_I2S_FLAG_TXE) == RESET);
/* Send Half Word through the SPI2 peripheral */
SPI_I2S_SendData(SPI2, HalfWord);
/* Wait to receive a Half Word */
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
/* Return the Half Word read from the SPI bus */
return SPI_I2S_ReceiveData(SPI2);
}
/*******************************************************************************
* 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;
}
void SPI_FLASH_SendCMD(u8 CMD)
{
/* Select the FLASH: Chip Select low */
SPI_FLASH_CS_LOW;
/* Send command instruction */
SPI_FLASH_SendByte(CMD);
/* Deselect the FLASH: Chip Select high */
SPI_FLASH_CS_HIGH;
}
u8 SPI_FLASH_WriteReg(u8 Reg, u8 Value)
{
u8 res;
/* Select the FLASH: Chip Select low */
SPI_FLASH_CS_LOW;
SPI_FLASH_SendByte(Reg);
res = SPI_FLASH_SendByte(Value);
/* Deselect the FLASH: Chip Select high */
SPI_FLASH_CS_HIGH;
return res;
}
/*******************************************************************************
* 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****/
mySPI
banksel SSP1STAT ;bank select
bsf SSP1STAT, SMP
bsf SSP1STAT, CKE
bcf SSP1CON1, CKP
banksel SSP1CON1
bsf SSP1CON1, 0 ;SCK : Fosc/16
;spi master Fosc/16 , fastest possible, where Fosc = 32MHz
;SCK period: 2*( 4/Fosc +20ns) = 290ns or 3.448 MHz
;We need SCK at option Fosc/16 = 2MHz < 3.448 MHz
banksel SSP1CON1
bsf SSP1CON1, SSPEN
;...............................................
;send enable write enable command
call write_enable
;...............................................
;Disable protection levels:
;send write-status-register command
banksel LATD
bcf LATD, LATD1 ;CE# low
banksel byte_data
movlw 0x01 ;WRSR command
movwf byte_data
call SPI_Tx_Rx
banksel byte_data
movlw b'0000000'
movwf byte_data
call SPI_Tx_Rx
banksel LATD
bsf LATD, LATD1 ;CE# high // here WREL goes to zero
;................................................
;send enable write enable command
call write_enable
;...............................................
call poll_status_flash
;................................................
;send command for Byte write. WREN has already been enabled
banksel byte_data
movlw 0x02 ;Byte-programming command
movwf byte_data
call SPI_Tx_Rx
;send 3 byte of initial address
banksel init_addr
movf init_addr+2, W ;high add. byte
movwf byte_data
call SPI_Tx_Rx
banksel init_addr
movf init_addr+1, W ;mid add. byte
movwf byte_data
call SPI_Tx_Rx
banksel init_addr
movf init_addr, W ;low add. byte
movwf byte_data
call SPI_Tx_Rx
;send byte
banksel audio_data
movf audio_data, W
movwf byte_data
call SPI_Tx_Rx
banksel LATD
bsf LATD, LATD1 ;CE# high
;.....................................................
call poll_status_flash
;.....................................................
;read saved data
banksel LATD
bcf LATD, LATD1 ;CE# low
;send command for Read Byte.
banksel byte_data
movlw 0x03 ;READ command
movwf byte_data
call SPI_Tx_Rx
;send 3 byte of initial address
movf init_addr+2, W ;high ADD. byte
movwf byte_data
call SPI_Tx_Rx
movf init_addr+1, W ;mid ADD. byte
movwf byte_data
call SPI_Tx_Rx
movf init_addr, W ;low ADD. byte
movwf byte_data
call SPI_Tx_Rx
;read data
movlw 0x00 ;dummy byte
movwf byte_data
call SPI_Tx_Rx
movwf audio_data+1 ;save data
banksel LATD
bsf LATD, LATD1 ;CE# high
return
;.....................................................
write_enable
;send enable write enable command
banksel LATD
bcf LATD, LATD1 ;CE# low
banksel byte_data
movlw 0x06 ;WREN command
movwf byte_data
call SPI_Tx_Rx
banksel LATD
bsf LATD, LATD1 ;CE# high
nop
return
;.......................................
SPI_Tx_Rx
;sends and receives 8-bits, command or data
banksel SSP1BUF ;PIC internal spi buffer
movf SSP1BUF ,W ;clear buffer
banksel byte_data
movf byte_data, W
banksel SSP1BUF
movwf SSP1BUF ;copy and send
loop_BF
; banksel SSP1STAT
; btfss SSP1STAT, BF
banksel PIR1
btfss PIR1 , SSP1IF
goto loop_BF ;wait
bcf PIR1 , SSP1IF ;clear buffer full interrupt flag
banksel SSP1BUF
movf SSP1BUF ,W
banksel byte_data
movwf byte_data ;read and save
return
;...........................................
poll_status_flash
;for writing a byte, it takes ~10us
loop_flash_status
banksel LATD
bcf LATD, LATD1 ;CE# low
banksel byte_data
movlw 0x05 ;RDSR command (status)
movwf byte_data
call SPI_Tx_Rx
movlw 0x00 ;dummy cycle
movwf byte_data
call SPI_Tx_Rx
banksel LATD
bsf LATD, LATD1 ;CE# high
banksel byte_data
btfsc byte_data, 0x00
goto loop_flash_status
return
;send command for Byte write. WREN has already been enabled
banksel byte_data
movlw 0x02 ;Byte-programming command
movwf byte_data
call SPI_Tx_Rx
;send command for Byte write. WREN has already been enabled
banksel LATD
bcf LATD, LATD1 ;CE# low
banksel byte_data
movlw 0x02 ;Byte-programming command
movwf byte_data
call SPI_Tx_Rx
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?