V2.4
This commit is contained in:
@@ -0,0 +1,465 @@
|
||||
/*********************************************************************
|
||||
* File Name : flash.c
|
||||
* Author : WCH
|
||||
* Version : V1.0.0
|
||||
* Date : 2023/8/15
|
||||
* Description : file for spi flash.
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2023 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
#include "flash.h"
|
||||
#include "spi.h"
|
||||
|
||||
static uint8_t FLASH_readWrite(uint8_t TxData)
|
||||
{
|
||||
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET)
|
||||
;
|
||||
SPI_I2S_SendData(SPI1, TxData);
|
||||
|
||||
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)
|
||||
;
|
||||
|
||||
return SPI_I2S_ReceiveData(SPI1);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn cs_pin_init
|
||||
*
|
||||
* @brief gpio cs pin init
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void cs_pin_init()
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
RCC_APB2PeriphClockCmd(FLASH_CS_RCC, ENABLE);
|
||||
GPIO_InitStructure.GPIO_Pin = FLASH_CS_PIN;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_Init(FLASH_CS_PORT, &GPIO_InitStructure);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SPI_FLASH_Init
|
||||
*
|
||||
* @brief SPI FLASH Init
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SPI_FLASH_Init(void)
|
||||
{
|
||||
SPI1_Init();
|
||||
SPI1_Read_DMA_Init();
|
||||
cs_pin_init();
|
||||
FLASH_CS_SET;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SPI_Flash_ReadSR
|
||||
*
|
||||
* @brief Read W25Qxx status register.
|
||||
* !!BIT7 6 5 4 3 2 1 0
|
||||
* !!SPR RV TB BP2 BP1 BP0 WEL BUSY
|
||||
*
|
||||
* @return byte - status register value.
|
||||
*/
|
||||
uint8_t SPI_Flash_ReadSR(void)
|
||||
{
|
||||
uint8_t byte = 0;
|
||||
|
||||
FLASH_CS_CLR;
|
||||
FLASH_readWrite(W25X_ReadStatusReg);
|
||||
byte = FLASH_readWrite(0Xff);
|
||||
FLASH_CS_SET;
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SPI_FLASH_Write_SR
|
||||
*
|
||||
* @brief Write W25Qxx status register.
|
||||
*
|
||||
* @param sr - status register value.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SPI_FLASH_Write_SR(uint8_t sr)
|
||||
{
|
||||
FLASH_CS_CLR;
|
||||
FLASH_readWrite(W25X_WriteStatusReg);
|
||||
FLASH_readWrite(sr);
|
||||
FLASH_CS_SET;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SPI_Flash_Wait_Busy
|
||||
*
|
||||
* @brief Wait flash free.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SPI_Flash_Wait_Busy(void)
|
||||
{
|
||||
while ((SPI_Flash_ReadSR() & 0x01) == 0x01)
|
||||
;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SPI_FLASH_Write_Enable
|
||||
*
|
||||
* @brief Enable flash write.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SPI_FLASH_Write_Enable(void)
|
||||
{
|
||||
FLASH_CS_CLR;
|
||||
FLASH_readWrite(W25X_WriteEnable);
|
||||
FLASH_CS_SET;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SPI_FLASH_Write_Disable
|
||||
*
|
||||
* @brief Disable flash write.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SPI_FLASH_Write_Disable(void)
|
||||
{
|
||||
FLASH_CS_CLR;
|
||||
FLASH_readWrite(W25X_WriteDisable);
|
||||
FLASH_CS_SET;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SPI_Flash_ReadID
|
||||
*
|
||||
* @brief Read flash ID.
|
||||
*
|
||||
* @return Temp - FLASH ID.
|
||||
*/
|
||||
uint16_t SPI_Flash_ReadID(void)
|
||||
{
|
||||
uint16_t Temp = 0;
|
||||
|
||||
FLASH_CS_CLR;
|
||||
FLASH_readWrite(W25X_ManufactDeviceID);
|
||||
FLASH_readWrite(0x00);
|
||||
FLASH_readWrite(0x00);
|
||||
FLASH_readWrite(0x00);
|
||||
Temp |= FLASH_readWrite(0xFF) << 8;
|
||||
Temp |= FLASH_readWrite(0xFF);
|
||||
FLASH_CS_SET;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SPI_Flash_ReadJedecDeviceID
|
||||
*
|
||||
* @brief Read JedecDevice ID.
|
||||
*
|
||||
* @return JedecDevice ID.
|
||||
*/
|
||||
uint32_t SPI_Flash_ReadJedecDeviceID(void)
|
||||
{
|
||||
uint32_t Temp = 0;
|
||||
FLASH_CS_CLR;
|
||||
FLASH_readWrite(W25X_JedecDeviceID);
|
||||
Temp |= FLASH_readWrite(0xFF) << 16;
|
||||
Temp |= FLASH_readWrite(0xFF) << 8;
|
||||
Temp |= FLASH_readWrite(0xFF);
|
||||
FLASH_CS_SET;
|
||||
return Temp;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SPI_Flash_Erase_Sector
|
||||
*
|
||||
* @brief Erase one sector(4Kbyte).
|
||||
*
|
||||
* @param Dst_Addr - 0 !! 2047
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SPI_Flash_Erase_Sector(uint32_t Dst_Addr)
|
||||
{
|
||||
Dst_Addr *= 4096;
|
||||
SPI_FLASH_Write_Enable();
|
||||
SPI_Flash_Wait_Busy();
|
||||
FLASH_CS_CLR;
|
||||
FLASH_readWrite(W25X_SectorErase);
|
||||
FLASH_readWrite((uint8_t)((Dst_Addr) >> 16));
|
||||
FLASH_readWrite((uint8_t)((Dst_Addr) >> 8));
|
||||
FLASH_readWrite((uint8_t)Dst_Addr);
|
||||
FLASH_CS_SET;
|
||||
SPI_Flash_Wait_Busy();
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SPI_Flash_Read
|
||||
*
|
||||
* @brief Read data from flash.
|
||||
*
|
||||
* @param pBuffer -
|
||||
* ReadAddr -Initial address(24bit).
|
||||
* size - Data length.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SPI_Flash_Read(uint8_t *pBuffer, uint32_t ReadAddr, uint16_t size)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
FLASH_CS_CLR;
|
||||
FLASH_readWrite(W25X_ReadData);
|
||||
FLASH_readWrite((uint8_t)((ReadAddr) >> 16));
|
||||
FLASH_readWrite((uint8_t)((ReadAddr) >> 8));
|
||||
FLASH_readWrite((uint8_t)ReadAddr);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
pBuffer[i] = FLASH_readWrite(0XFF);
|
||||
}
|
||||
|
||||
FLASH_CS_SET;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SPI_Flash_Write_Page
|
||||
*
|
||||
* @brief Write data by one page.
|
||||
*
|
||||
* @param pBuffer -
|
||||
* WriteAddr - Initial address(24bit).
|
||||
* size - Data length.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SPI_Flash_Write_Page(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t size)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
SPI_FLASH_Write_Enable();
|
||||
FLASH_CS_CLR;
|
||||
FLASH_readWrite(W25X_PageProgram);
|
||||
FLASH_readWrite((uint8_t)((WriteAddr) >> 16));
|
||||
FLASH_readWrite((uint8_t)((WriteAddr) >> 8));
|
||||
FLASH_readWrite((uint8_t)WriteAddr);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
FLASH_readWrite(pBuffer[i]);
|
||||
}
|
||||
|
||||
FLASH_CS_SET;
|
||||
SPI_Flash_Wait_Busy();
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SPI_Flash_Write_NoCheck
|
||||
*
|
||||
* @brief Write data to flash.(need Erase)
|
||||
* All data in address rang is 0xFF.
|
||||
*
|
||||
* @param pBuffer -
|
||||
* WriteAddr - Initial address(24bit).
|
||||
* size - Data length.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SPI_Flash_Write_NoCheck(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t size)
|
||||
{
|
||||
uint16_t pageremain;
|
||||
|
||||
pageremain = 256 - WriteAddr % 256;
|
||||
|
||||
if (size <= pageremain)
|
||||
pageremain = size;
|
||||
|
||||
while (1)
|
||||
{
|
||||
SPI_Flash_Write_Page(pBuffer, WriteAddr, pageremain);
|
||||
|
||||
if (size == pageremain)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
pBuffer += pageremain;
|
||||
WriteAddr += pageremain;
|
||||
size -= pageremain;
|
||||
|
||||
if (size > 256)
|
||||
pageremain = 256;
|
||||
else
|
||||
pageremain = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t W25QXX_BUFFER[4096];
|
||||
/*********************************************************************
|
||||
* @fn SPI_Flash_Write
|
||||
*
|
||||
* @brief Write data to flash.(no need Erase)
|
||||
*
|
||||
* @param pBuffer -
|
||||
* WriteAddr - Initial address(24bit).
|
||||
* size - Data length.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SPI_Flash_Write(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t size)
|
||||
{
|
||||
uint32_t secpos;
|
||||
uint16_t secoff;
|
||||
uint16_t secremain;
|
||||
uint16_t i;
|
||||
|
||||
secpos = WriteAddr / 4096;
|
||||
secoff = WriteAddr % 4096;
|
||||
secremain = 4096 - secoff;
|
||||
|
||||
if (size <= secremain)
|
||||
secremain = size;
|
||||
|
||||
while (1)
|
||||
{
|
||||
SPI_Flash_Read(W25QXX_BUFFER, secpos * 4096, 4096);
|
||||
|
||||
for (i = 0; i < secremain; i++)
|
||||
{
|
||||
if (W25QXX_BUFFER[secoff + i] != 0XFF)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < secremain)
|
||||
{
|
||||
SPI_Flash_Erase_Sector(secpos);
|
||||
|
||||
for (i = 0; i < secremain; i++)
|
||||
{
|
||||
W25QXX_BUFFER[i + secoff] = pBuffer[i];
|
||||
}
|
||||
|
||||
SPI_Flash_Write_NoCheck(W25QXX_BUFFER, secpos * 4096, 4096);
|
||||
}
|
||||
else
|
||||
{
|
||||
SPI_Flash_Write_NoCheck(pBuffer, WriteAddr, secremain);
|
||||
}
|
||||
|
||||
if (size == secremain)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
secpos++;
|
||||
secoff = 0;
|
||||
|
||||
pBuffer += secremain;
|
||||
WriteAddr += secremain;
|
||||
size -= secremain;
|
||||
|
||||
if (size > 4096)
|
||||
{
|
||||
secremain = 4096;
|
||||
}
|
||||
else
|
||||
{
|
||||
secremain = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SPI_Flash_Erase_Block
|
||||
*
|
||||
* @brief Erase all FLASH pages.
|
||||
*
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SPI_Flash_Erase_Block(uint32_t Dst_Addr)
|
||||
{
|
||||
SPI_FLASH_Write_Enable();
|
||||
SPI_Flash_Wait_Busy();
|
||||
FLASH_CS_CLR;
|
||||
FLASH_readWrite(W25X_BlockErase);
|
||||
FLASH_readWrite((uint8_t)((Dst_Addr) >> 16));
|
||||
FLASH_readWrite((uint8_t)((Dst_Addr) >> 8));
|
||||
FLASH_readWrite((uint8_t)Dst_Addr);
|
||||
FLASH_CS_SET;
|
||||
SPI_Flash_Wait_Busy();
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SPI_Flash_PowerDown
|
||||
*
|
||||
* @brief Enter power down mode.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SPI_Flash_PowerDown(void)
|
||||
{
|
||||
FLASH_CS_CLR;
|
||||
FLASH_readWrite(W25X_PowerDown);
|
||||
FLASH_CS_SET;
|
||||
Delay_Us(3);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SPI_Flash_WAKEUP
|
||||
*
|
||||
* @brief Power down wake up.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SPI_Flash_WAKEUP(void)
|
||||
{
|
||||
FLASH_CS_CLR;
|
||||
FLASH_readWrite(W25X_ReleasePowerDown);
|
||||
FLASH_CS_SET;
|
||||
Delay_Us(3);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SPI_Flash_Read_dma_start
|
||||
*
|
||||
* @brief enable spi dma and set read address
|
||||
*
|
||||
* @param ReadAddr - the address in spi flash
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SPI_Flash_Read_dma_start(uint32_t ReadAddr)
|
||||
{
|
||||
FLASH_CS_CLR;
|
||||
FLASH_readWrite(W25X_FastReadData);
|
||||
FLASH_readWrite((uint8_t)((ReadAddr) >> 16));
|
||||
FLASH_readWrite((uint8_t)((ReadAddr) >> 8));
|
||||
FLASH_readWrite((uint8_t)ReadAddr);
|
||||
FLASH_readWrite(0xFF);
|
||||
SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SPI_Flash_Read_dma_end
|
||||
*
|
||||
* @brief disable spi dma
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SPI_Flash_Read_dma_end(void)
|
||||
{
|
||||
FLASH_CS_SET;
|
||||
SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, DISABLE);
|
||||
}
|
||||
Reference in New Issue
Block a user