Files
player/Project/Src/Drive/Source/spi_flash.c
2025-07-05 19:47:28 +08:00

558 lines
16 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/***
************************************************************************************
* @file spi_flash.c
* @version V1.0.0
* @brief SPI Flash相关函数
************************************************************************************
* @description
*
* 移植于官方标准固件库的例程
*
************************************************************************************
***/
#include "spi_flash.h"
void sFLASH_LowLevel_DeInit(void);
void sFLASH_LowLevel_Init(void);
//定义一个所有权保证FLASH只有一个线程使用
//static int g_used=0;
//定义在外部的延时函数
//extern void my_delay_ms(u32 ms);
//定义进入不可重入区的宏
//#define sFLASH_ENTER_USED() {while (g_used) {my_delay_ms(1);} g_used=1;}
//#define sFLASH_EXIT_USED() {g_used=0;}
#define sFLASH_ENTER_USED() { }
#define sFLASH_EXIT_USED() { }
/* Private functions ---------------------------------------------------------*/
/**
* @brief DeInitializes the peripherals used by the SPI FLASH driver.
* @param None
* @retval None
*/
void sFLASH_DeInit(void)
{
sFLASH_LowLevel_DeInit();
}
/**
* @brief Initializes the peripherals used by the SPI FLASH driver.
* @param None
* @retval None
*/
void sFLASH_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
sFLASH_LowLevel_Init();
/*!< Deselect the FLASH: Chip Select high */
sFLASH_CS_HIGH();
/*!< SPI 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_2;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(sFLASH_SPI, &SPI_InitStructure);
/*!< Enable the sFLASH_SPI */
SPI_Cmd(sFLASH_SPI, ENABLE);
}
/**
* @brief Erases the specified FLASH sector.
* @param SectorAddr: address of the sector to erase.
* @retval None
*/
void sFLASH_EraseSector(uint32_t SectorAddr)
{
sFLASH_ENTER_USED();
/*!< Send write enable instruction */
sFLASH_WriteEnable();
/*!< Sector Erase */
/*!< Select the FLASH: Chip Select low */
sFLASH_CS_LOW();
/*!< Send Sector Erase instruction */
sFLASH_SendByte(sFLASH_CMD_SE);
/*!< Send SectorAddr high nibble address byte */
sFLASH_SendByte((SectorAddr & 0xFF0000) >> 16);
/*!< Send SectorAddr medium nibble address byte */
sFLASH_SendByte((SectorAddr & 0xFF00) >> 8);
/*!< Send SectorAddr low nibble address byte */
sFLASH_SendByte(SectorAddr & 0xFF);
/*!< Deselect the FLASH: Chip Select high */
sFLASH_CS_HIGH();
/*!< Wait the end of Flash writing */
sFLASH_WaitForWriteEnd();
sFLASH_EXIT_USED()
}
/**
* @brief Erases the entire FLASH.
* @param None
* @retval None
*/
void sFLASH_EraseBulk(void)
{
/*!< Send write enable instruction */
sFLASH_WriteEnable();
/*!< Bulk Erase */
/*!< Select the FLASH: Chip Select low */
sFLASH_CS_LOW();
/*!< Send Bulk Erase instruction */
//sFLASH_SendByte(sFLASH_CMD_BE);
sFLASH_SendByte(0xc7);//改为全片擦除
/*!< Deselect the FLASH: Chip Select high */
sFLASH_CS_HIGH();
/*!< Wait the end of Flash writing */
sFLASH_WaitForWriteEnd();
}
/**
* @brief Writes more than one byte to the FLASH with a single WRITE cycle
* (Page WRITE sequence).
* @note The number of byte can't exceed the FLASH page size.
* @param pBuffer: pointer to the buffer containing the data to be written
* to the FLASH.
* @param WriteAddr: FLASH's internal address to write to.
* @param NumByteToWrite: number of bytes to write to the FLASH, must be equal
* or less than "sFLASH_PAGESIZE" value.
* @retval None
*/
void sFLASH_WritePage(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
/*!< Enable the write access to the FLASH */
sFLASH_WriteEnable();
/*!< Select the FLASH: Chip Select low */
sFLASH_CS_LOW();
/*!< Send "Write to Memory " instruction */
sFLASH_SendByte(sFLASH_CMD_WRITE);
/*!< Send WriteAddr high nibble address byte to write to */
sFLASH_SendByte((WriteAddr & 0xFF0000) >> 16);
/*!< Send WriteAddr medium nibble address byte to write to */
sFLASH_SendByte((WriteAddr & 0xFF00) >> 8);
/*!< Send WriteAddr low nibble address byte to write to */
sFLASH_SendByte(WriteAddr & 0xFF);
/*!< while there is data to be written on the FLASH */
while (NumByteToWrite--)
{
/*!< Send the current byte */
sFLASH_SendByte(*pBuffer);
/*!< Point on the next byte to be written */
pBuffer++;
}
/*!< Deselect the FLASH: Chip Select high */
sFLASH_CS_HIGH();
/*!< Wait the end of Flash writing */
sFLASH_WaitForWriteEnd();
}
/**
* @brief Writes block of data to the FLASH. In this function, the number of
* WRITE cycles are reduced, using Page WRITE sequence.
* @param pBuffer: pointer to the buffer containing the data to be written
* to the FLASH.
* @param WriteAddr: FLASH's internal address to write to.
* @param NumByteToWrite: number of bytes to write to the FLASH.
* @retval None
*/
void sFLASH_WriteBuffer(uint8_t* pBuffer, uint32_t WriteAddr, uint32_t NumByteToWrite)
{
sFLASH_ENTER_USED();
uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
Addr = WriteAddr % sFLASH_SPI_PAGESIZE;
count = sFLASH_SPI_PAGESIZE - Addr;
NumOfPage = NumByteToWrite / sFLASH_SPI_PAGESIZE;
NumOfSingle = NumByteToWrite % sFLASH_SPI_PAGESIZE;
if (Addr == 0) /*!< WriteAddr is sFLASH_PAGESIZE aligned */
{
if (NumOfPage == 0) /*!< NumByteToWrite < sFLASH_PAGESIZE */
{
sFLASH_WritePage(pBuffer, WriteAddr, NumByteToWrite);
}
else /*!< NumByteToWrite > sFLASH_PAGESIZE */
{
while (NumOfPage--)
{
sFLASH_WritePage(pBuffer, WriteAddr, sFLASH_SPI_PAGESIZE);
WriteAddr += sFLASH_SPI_PAGESIZE;
pBuffer += sFLASH_SPI_PAGESIZE;
}
sFLASH_WritePage(pBuffer, WriteAddr, NumOfSingle);
}
}
else /*!< WriteAddr is not sFLASH_PAGESIZE aligned */
{
if (NumOfPage == 0) /*!< NumByteToWrite < sFLASH_PAGESIZE */
{
if (NumOfSingle > count) /*!< (NumByteToWrite + WriteAddr) > sFLASH_PAGESIZE */
{
temp = NumOfSingle - count;
sFLASH_WritePage(pBuffer, WriteAddr, count);
WriteAddr += count;
pBuffer += count;
sFLASH_WritePage(pBuffer, WriteAddr, temp);
}
else
{
sFLASH_WritePage(pBuffer, WriteAddr, NumByteToWrite);
}
}
else /*!< NumByteToWrite > sFLASH_PAGESIZE */
{
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / sFLASH_SPI_PAGESIZE;
NumOfSingle = NumByteToWrite % sFLASH_SPI_PAGESIZE;
sFLASH_WritePage(pBuffer, WriteAddr, count);
WriteAddr += count;
pBuffer += count;
while (NumOfPage--)
{
sFLASH_WritePage(pBuffer, WriteAddr, sFLASH_SPI_PAGESIZE);
WriteAddr += sFLASH_SPI_PAGESIZE;
pBuffer += sFLASH_SPI_PAGESIZE;
}
if (NumOfSingle != 0)
{
sFLASH_WritePage(pBuffer, WriteAddr, NumOfSingle);
}
}
}
//使用这个变量来防止重入
sFLASH_EXIT_USED();
}
/**
* @brief Reads a block of data from the FLASH.
* @param pBuffer: pointer to the buffer that receives the data read from the FLASH.
* @param ReadAddr: FLASH's internal address to read from.
* @param NumByteToRead: number of bytes to read from the FLASH.
* @retval None
*/
void sFLASH_ReadBuffer(uint8_t* pBuffer, uint32_t ReadAddr, uint32_t NumByteToRead)
{
//使用这个变量防止重入
sFLASH_ENTER_USED();
/*!< Select the FLASH: Chip Select low */
sFLASH_CS_LOW();
/*!< Send "Read from Memory " instruction */
sFLASH_SendByte(sFLASH_CMD_READ);
/*!< Send ReadAddr high nibble address byte to read from */
sFLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
/*!< Send ReadAddr medium nibble address byte to read from */
sFLASH_SendByte((ReadAddr& 0xFF00) >> 8);
/*!< Send ReadAddr low nibble address byte to read from */
sFLASH_SendByte(ReadAddr & 0xFF);
while (NumByteToRead--) /*!< while there is data to be read */
{
/*!< Read a byte from the FLASH */
*pBuffer = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
/*!< Point to the next location where the byte read will be saved */
pBuffer++;
}
/*!< Deselect the FLASH: Chip Select high */
sFLASH_CS_HIGH();
//使用这个变量来防止重入
sFLASH_EXIT_USED();
}
/**
* @brief Reads FLASH identification.
* @param None
* @retval FLASH identification
*/
uint32_t sFLASH_ReadID(void)
{
uint32_t Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
/*!< Select the FLASH: Chip Select low */
sFLASH_CS_LOW();
/*!< Send "RDID " instruction */
sFLASH_SendByte(0x9F);
/*!< Read a byte from the FLASH */
Temp0 = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
/*!< Read a byte from the FLASH */
Temp1 = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
/*!< Read a byte from the FLASH */
Temp2 = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
/*!< Deselect the FLASH: Chip Select high */
sFLASH_CS_HIGH();
Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
return Temp;
}
/**
* @brief 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.
* @param ReadAddr: FLASH's internal address to read from.
* @retval None
*/
void sFLASH_StartReadSequence(uint32_t ReadAddr)
{
/*!< Select the FLASH: Chip Select low */
sFLASH_CS_LOW();
/*!< Send "Read from Memory " instruction */
sFLASH_SendByte(sFLASH_CMD_READ);
/*!< Send the 24-bit address of the address to read from -------------------*/
/*!< Send ReadAddr high nibble address byte */
sFLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
/*!< Send ReadAddr medium nibble address byte */
sFLASH_SendByte((ReadAddr& 0xFF00) >> 8);
/*!< Send ReadAddr low nibble address byte */
sFLASH_SendByte(ReadAddr & 0xFF);
}
/**
* @brief Reads a byte from the SPI Flash.
* @note This function must be used only if the Start_Read_Sequence function
* has been previously called.
* @param None
* @retval Byte Read from the SPI Flash.
*/
uint8_t sFLASH_ReadByte(void)
{
return (sFLASH_SendByte(sFLASH_DUMMY_BYTE));
}
/**
* @brief Sends a byte through the SPI interface and return the byte received
* from the SPI bus.
* @param byte: byte to send.
* @retval The value of the received byte.
*/
uint8_t sFLASH_SendByte(uint8_t byte)
{
/*!< Loop while DR register in not empty */
while (SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_TXE) == RESET);
/*!< Send byte through the SPI1 peripheral */
SPI_I2S_SendData(sFLASH_SPI, byte);
/*!< Wait to receive a byte */
while (SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_RXNE) == RESET);
/*!< Return the byte read from the SPI bus */
return SPI_I2S_ReceiveData(sFLASH_SPI);
}
/**
* @brief Sends a Half Word through the SPI interface and return the Half Word
* received from the SPI bus.
* @param HalfWord: Half Word to send.
* @retval The value of the received Half Word.
*/
uint16_t sFLASH_SendHalfWord(uint16_t HalfWord)
{
/*!< Loop while DR register in not empty */
while (SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_TXE) == RESET);
/*!< Send Half Word through the sFLASH peripheral */
SPI_I2S_SendData(sFLASH_SPI, HalfWord);
/*!< Wait to receive a Half Word */
while (SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_RXNE) == RESET);
/*!< Return the Half Word read from the SPI bus */
return SPI_I2S_ReceiveData(sFLASH_SPI);
}
/**
* @brief Enables the write access to the FLASH.
* @param None
* @retval None
*/
void sFLASH_WriteEnable(void)
{
/*!< Select the FLASH: Chip Select low */
sFLASH_CS_LOW();
/*!< Send "Write Enable" instruction */
sFLASH_SendByte(sFLASH_CMD_WREN);
/*!< Deselect the FLASH: Chip Select high */
sFLASH_CS_HIGH();
}
/**
* @brief Polls the status of the Write In Progress (WIP) flag in the FLASH's
* status register and loop until write operation has completed.
* @param None
* @retval None
*/
void sFLASH_WaitForWriteEnd(void)
{
uint8_t flashstatus = 0;
/*!< Select the FLASH: Chip Select low */
sFLASH_CS_LOW();
/*!< Send "Read Status Register" instruction */
sFLASH_SendByte(sFLASH_CMD_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 */
flashstatus = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
}
while ((flashstatus & sFLASH_WIP_FLAG) == SET); /* Write in progress */
/*!< Deselect the FLASH: Chip Select high */
sFLASH_CS_HIGH();
}
/**
* @brief Initializes the peripherals used by the SPI FLASH driver.
* @param None
* @retval None
*/
void sFLASH_LowLevel_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*!< Enable the SPI clock */
sFLASH_SPI_CLK_INIT(sFLASH_SPI_CLK, ENABLE);
/*!< Enable GPIO clocks */
RCC_AHB1PeriphClockCmd(sFLASH_SPI_SCK_GPIO_CLK | sFLASH_SPI_MISO_GPIO_CLK |
sFLASH_SPI_MOSI_GPIO_CLK | sFLASH_CS_GPIO_CLK, ENABLE);
/*!< SPI pins configuration *************************************************/
/*!< Connect SPI pins to AF5 */
GPIO_PinAFConfig(sFLASH_SPI_SCK_GPIO_PORT, sFLASH_SPI_SCK_SOURCE, sFLASH_SPI_SCK_AF);
GPIO_PinAFConfig(sFLASH_SPI_MISO_GPIO_PORT, sFLASH_SPI_MISO_SOURCE, sFLASH_SPI_MISO_AF);
GPIO_PinAFConfig(sFLASH_SPI_MOSI_GPIO_PORT, sFLASH_SPI_MOSI_SOURCE, sFLASH_SPI_MOSI_AF);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
/*!< SPI SCK pin configuration */
GPIO_InitStructure.GPIO_Pin = sFLASH_SPI_SCK_PIN;
GPIO_Init(sFLASH_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);
/*!< SPI MOSI pin configuration */
GPIO_InitStructure.GPIO_Pin = sFLASH_SPI_MOSI_PIN;
GPIO_Init(sFLASH_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
/*!< SPI MISO pin configuration */
GPIO_InitStructure.GPIO_Pin = sFLASH_SPI_MISO_PIN;
GPIO_Init(sFLASH_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
/*!< Configure sFLASH Card CS pin in output pushpull mode ********************/
GPIO_InitStructure.GPIO_Pin = sFLASH_CS_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(sFLASH_CS_GPIO_PORT, &GPIO_InitStructure);
}
/**
* @brief DeInitializes the peripherals used by the SPI FLASH driver.
* @param None
* @retval None
*/
void sFLASH_LowLevel_DeInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*!< Disable the sFLASH_SPI ************************************************/
SPI_Cmd(sFLASH_SPI, DISABLE);
/*!< DeInitializes the sFLASH_SPI *******************************************/
SPI_I2S_DeInit(sFLASH_SPI);
/*!< sFLASH_SPI Periph clock disable ****************************************/
sFLASH_SPI_CLK_INIT(sFLASH_SPI_CLK, DISABLE);
/*!< Configure all pins used by the SPI as input floating *******************/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Pin = sFLASH_SPI_SCK_PIN;
GPIO_Init(sFLASH_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = sFLASH_SPI_MISO_PIN;
GPIO_Init(sFLASH_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = sFLASH_SPI_MOSI_PIN;
GPIO_Init(sFLASH_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = sFLASH_CS_PIN;
GPIO_Init(sFLASH_CS_GPIO_PORT, &GPIO_InitStructure);
}
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/