gateway_mcu/CH32V303-FreeRTOS/App/hardwareDriver/Src/HD_Flash.c

457 lines
15 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.

/*
* Flash.c
*
* Created on: 2024年5月16日
* Author: 34509
*/
#include "HD_Flash.h"
#include "pDebug.h"
/* Global Variable */
uint8_t SPI_FLASH_BUF[4096];
void delay_us(uint32_t us) {
volatile uint32_t cycles = us * SystemCoreClock / 4000000; // 根据实测调整
while (cycles--) {
__asm__ volatile ("nop"); // 防止循环被优化
}
}
/*******************************************************************************
* Function Name : SPI_Flash_Init
* Description : Configuring the SPI for operation flash.
* Input : None
* Return : None
*******************************************************************************/
void SPI_Flash_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOX, ENABLE );
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPIX, ENABLE );
GPIO_InitStructure.GPIO_Pin = CS_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(CS_GPIO, &GPIO_InitStructure);
GPIO_SetBits(CS_GPIO, CS_PIN); //CS引脚PA15置高电平
GPIO_InitStructure.GPIO_Pin = CLK_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(CLK_GPIO, &GPIO_InitStructure );
GPIO_InitStructure.GPIO_Pin = DO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(DO_GPIO, &GPIO_InitStructure );
GPIO_InitStructure.GPIO_Pin = DI_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DI_GPIO, &GPIO_InitStructure );
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI通讯方向为双线全双工方式
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI为主机端模式
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI通讯的数据帧大小为8位
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //设置SPI的时钟极性为高电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //设置SPI的时钟相位为在SCK的偶数边沿采集数据
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //设置NSS引脚即片选引脚的使用模式为软件模式
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; //设置波特率分频因子为4分频
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //设置数据传输为高位数据在前
SPI_InitStructure.SPI_CRCPolynomial = 7; //SPI的CRC校验中多项式的值
SPI_Init(SPIX, &SPI_InitStructure); //初始化SPI
SPI_Cmd(SPIX, ENABLE); //使能SPI3外设
}
/*******************************************************************************
* Function Name : SPIX_ReadWriteByte
* Description : SPIX read or write one byte.
* Input : TxData: write one byte data.
* Return : Read one byte data.
*******************************************************************************/
u8 SPI_ReadWriteByte(u8 TxData)
{
u8 i=0;
while (SPI_I2S_GetFlagStatus(SPIX, SPI_I2S_FLAG_TXE) == RESET) //等待发送缓冲区为空TXE事件
{
i++;
if(i>200)return 0;
}
SPI_I2S_SendData(SPIX, TxData); //写入数据寄存器把要写入的数据写入发送缓冲区即通过外设SPI1发送一个数据
i=0;
while (SPI_I2S_GetFlagStatus(SPIX, SPI_I2S_FLAG_RXNE) == RESET) //等待接收缓冲区非空RXNE事件
{
i++;
if(i>200)return 0;
}
return SPI_I2S_ReceiveData(SPIX); //读取数据寄存器获取接收缓冲区数据即返回SPI1最近接收到的数据
}
/*******************************************************************************
* Function Name : SPI_Flash_ReadSR
* Description : Read W25Qxx status register.
* ——BIT7 6 5 4 3 2 1 0
* ——SPR RV TB BP2 BP1 BP0 WEL BUSY
* Input : None
* Return : byte: status register value.
*******************************************************************************/
u8 SPI_Flash_ReadSR(void)
{
u8 byte=0;
GPIO_WriteBit(CS_GPIO, CS_PIN, 0); //PA2=0,使能片选信号
SPI_ReadWriteByte(W25X_ReadStatusReg); //发送读状态寄存器命令
byte=SPI_ReadWriteByte(0Xff); //读取一个字节
GPIO_WriteBit(CS_GPIO, CS_PIN, 1); //取消片选信号
return byte;
}
/*******************************************************************************
* Function Name : SPI_FLASH_Write_SR
* Description : Write W25Qxx status register.
* Input : sr:status register value.
* Return : None
*******************************************************************************/
void SPI_FLASH_Write_SR(u8 sr)
{
GPIO_WriteBit(CS_GPIO, CS_PIN, 0);
SPI_ReadWriteByte(W25X_WriteStatusReg); //发送写状态寄存器命令
SPI_ReadWriteByte(sr); //写入一个字节
GPIO_WriteBit(CS_GPIO, CS_PIN, 1);
}
/*******************************************************************************
* Function Name : SPI_Flash_Wait_Busy
* Description : Wait flash free.
* Input : None
* Return : None
*******************************************************************************/
void SPI_Flash_Wait_Busy(void)
{
while((SPI_Flash_ReadSR()&0x01)==0x01); //等待FLASH空闲
}
/*******************************************************************************
* Function Name : SPI_FLASH_Write_Enable
* Description : Enable flash write.
* Input : None
* Return : None
*******************************************************************************/
void SPI_FLASH_Write_Enable(void)
{
GPIO_WriteBit(CS_GPIO, CS_PIN, 0);
SPI_ReadWriteByte(W25X_WriteEnable); //发送写使能
GPIO_WriteBit(CS_GPIO, CS_PIN, 1);
}
/*******************************************************************************
* Function Name : SPI_FLASH_Write_Disable
* Description : Disable flash write.
* Input : None
* Return : None
*******************************************************************************/
void SPI_FLASH_Write_Disable(void)
{
GPIO_WriteBit(CS_GPIO, CS_PIN, 0);
SPI_ReadWriteByte(W25X_WriteDisable); //发送写禁止指令
GPIO_WriteBit(CS_GPIO, CS_PIN, 1);
}
/*******************************************************************************
* Function Name : SPI_Flash_ReadID
* Description : Read flash ID.
* Input : None
* Return : Temp: FLASH ID.
*******************************************************************************/
u16 SPI_Flash_ReadID(void)
{
u16 Temp = 0;
GPIO_WriteBit(CS_GPIO, CS_PIN, 0);
SPI_ReadWriteByte(W25X_ManufactDeviceID); //发送读取ID命令
SPI_ReadWriteByte(0x00);
SPI_ReadWriteByte(0x00);
SPI_ReadWriteByte(0x00);
Temp|=SPI_ReadWriteByte(0xFF)<<8;
Temp|=SPI_ReadWriteByte(0xFF);
GPIO_WriteBit(CS_GPIO, CS_PIN, 1);
return Temp;
}
/*******************************************************************************
* Function Name : SPI_Flash_Erase_Sector
* Description : Erase one sector(4Kbyte).
* Input : Dst_Addr: 0 —— 2047
* Return : None
*******************************************************************************/
void SPI_Flash_Erase_Sector(u32 Dst_Addr)
{
Dst_Addr*=4096;
SPI_FLASH_Write_Enable();
SPI_Flash_Wait_Busy();
GPIO_WriteBit(CS_GPIO, CS_PIN, 0);
SPI_ReadWriteByte(W25X_SectorErase); //发送扇区擦除指令
SPI_ReadWriteByte((u8)((Dst_Addr)>>16)); //发送24bit地址
SPI_ReadWriteByte((u8)((Dst_Addr)>>8));
SPI_ReadWriteByte((u8)Dst_Addr);
GPIO_WriteBit(CS_GPIO, CS_PIN, 1);
SPI_Flash_Wait_Busy(); //等待擦除完成
}
/*******************************************************************************
* Function Name : SPI_Flash_Read
* Description : Read data from flash.
* Input : pBuffer:
* ReadAddr:Initial address(24bit).
* size: Data length.
* Return : None
*******************************************************************************/
void SPI_Flash_Read(u8* pBuffer,u32 ReadAddr,u16 size)
{
u16 i;
GPIO_WriteBit(CS_GPIO, CS_PIN, 0);
SPI_ReadWriteByte(W25X_ReadData); //发送读取命令
SPI_ReadWriteByte((u8)((ReadAddr)>>16)); //发送24bit地址
SPI_ReadWriteByte((u8)((ReadAddr)>>8));
SPI_ReadWriteByte((u8)ReadAddr);
for(i=0;i<size;i++)
{
pBuffer[i] = SPI_ReadWriteByte(0XFF); //循环读数
}
GPIO_WriteBit(CS_GPIO, CS_PIN, 1);
}
/*******************************************************************************
* Function Name : SPI_Flash_Write_Page
* Description : Write data by one page.
* Input : pBuffer:
* WriteAddr:Initial address(24bit).
* size:Data length.
* Return : None
*******************************************************************************/
void SPI_Flash_Write_Page(u8* pBuffer,u32 WriteAddr,u16 size)
{
u16 i;
SPI_FLASH_Write_Enable();
GPIO_WriteBit(CS_GPIO, CS_PIN, 0);
SPI_ReadWriteByte(W25X_PageProgram); //发送写页命令
SPI_ReadWriteByte((u8)((WriteAddr)>>16)); //发送24bit地址
SPI_ReadWriteByte((u8)((WriteAddr)>>8));
SPI_ReadWriteByte((u8)WriteAddr);
for(i=0;i<size;i++)
{
SPI_ReadWriteByte(pBuffer[i]); //循环写数
}
GPIO_WriteBit(CS_GPIO, CS_PIN, 1);
SPI_Flash_Wait_Busy(); //等待写入结束
}
/*******************************************************************************
* Function Name : SPI_Flash_Write_NoCheck
* Description : Write data to flash.(need Erase)
* All data in address rang is 0xFF.
* Input : pBuffer:
* WriteAddr: Initial address(24bit).
* size: Data length.
* Return : None
*******************************************************************************/
void SPI_Flash_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 size)
{
u16 pageremain;
pageremain=256-WriteAddr%256; //单页剩余的字节数
if(size<=pageremain)pageremain=size; //不大于256个字节
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; //一次可以写入256个字节
else pageremain=size; //不够256个字节了
}
}
}
/*******************************************************************************
* Function Name : SPI_Flash_Write
* Description : Write data to flash.(no need Erase)
* Input : pBuffer:
* WriteAddr: Initial address(24bit).
* size: Data length.
* Return : None
*******************************************************************************/
void SPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 size)
{
u32 secpos;
u16 secoff;
u16 secremain;
u16 i;
secpos=WriteAddr/4096; //扇区地址
secoff=WriteAddr%4096; //在扇区内的便宜
secremain=4096-secoff; //扇区剩余空间大小
if(size<=secremain)secremain=size; //不大于4096个字节
while(1)
{
SPI_Flash_Read(SPI_FLASH_BUF,secpos*4096,4096); //读出整个扇区的内容
for(i=0;i<secremain;i++) //校验数据
{
if(SPI_FLASH_BUF[secoff+i]!=0XFF)break; //需要擦除
}
if(i<secremain) //需要擦除
{
SPI_Flash_Erase_Sector(secpos); //擦除这个扇区
for(i=0;i<secremain;i++) //复制
{
SPI_FLASH_BUF[i+secoff]=pBuffer[i];
}
SPI_Flash_Write_NoCheck(SPI_FLASH_BUF,secpos*4096,4096); //写入整个扇区
}
else
{
SPI_Flash_Write_NoCheck(pBuffer,WriteAddr,secremain); //写已经擦除了的,直接写入扇区剩余空间
}
if(size==secremain)
{
break; //写入结束
}
else
{
secpos++; //扇区地址增1
secoff=0; //偏移位置为0
pBuffer+=secremain; //指针偏移
WriteAddr+=secremain; //写地址偏移
size-=secremain; //字节数递减
if(size>4096)
{
secremain=4096; //下一个扇区还是写不完
}
else
{
secremain=size; //下一个扇区可以写完了
}
}
}
}
/*******************************************************************************
* Function Name : SPI_Flash_Erase_Chip
* Description : Erase all FLASH pages.
* Input : None
* Return : None
*******************************************************************************/
void SPI_Flash_Erase_Chip(void)
{
SPI_FLASH_Write_Enable();
SPI_Flash_Wait_Busy();
GPIO_WriteBit(CS_GPIO, CS_PIN, 0);
SPI_ReadWriteByte(W25X_ChipErase); //发送片擦除指令
GPIO_WriteBit(CS_GPIO, CS_PIN, 1);
SPI_Flash_Wait_Busy();
}
/*******************************************************************************
* Function Name : SPI_Flash_PowerDown
* Description : Enter power down mode.
* Input : None
* Return : None
*******************************************************************************/
void SPI_Flash_PowerDown(void)
{
GPIO_WriteBit(CS_GPIO, CS_PIN, 0);
SPI_ReadWriteByte(W25X_PowerDown); //发送进入断电模式之灵
GPIO_WriteBit(CS_GPIO, CS_PIN, 1);
delay_us(3);
}
/*******************************************************************************
* Function Name : SPI_Flash_WAKEUP
* Description : Power down wake up.
* Input : None
* Return : None
*******************************************************************************/
void SPI_Flash_WAKEUP(void)
{
GPIO_WriteBit(CS_GPIO, CS_PIN, 0);
SPI_ReadWriteByte(W25X_ReleasePowerDown); //发送断电唤醒指令
GPIO_WriteBit(CS_GPIO, CS_PIN, 1);
delay_us(3);
}
void SPI_Flash_TEST(void)
{
const int SIZE = 100;
u8 TEXT_Buf[100] = "hello world \n";
u8 datap[SIZE];
u16 Flash_Model;
SPI_Flash_Init();
Flash_Model = SPI_Flash_ReadID();
log_info("SPI_Flash_ReadID = %x \n", Flash_Model);
switch(Flash_Model)
{
case W25Q80:
log_info("W25Q80 OK!\r\n");
break;
case W25Q16:
log_info("W25Q16 OK!\r\n");
break;
case W25Q32:
log_info("W25Q32 OK!\r\n");
break;
case W25Q64:
log_info("W25Q64 OK!\r\n");
break;
case W25Q128:
log_info("W25Q128 OK!\r\n");
break;
default:
log_info("Fail!\r\n");
break;
}
log_info("Start Erase W25Qxx....\r\n");
SPI_Flash_Erase_Sector(0);
log_info("W25Qxx Erase Finished!\r\n");
delay_us(500);
log_info("Start Write W25Qxx....\r\n");
SPI_Flash_Write((u8*)TEXT_Buf,0,SIZE);
log_info("W25Qxx Write Finished!\r\n");
delay_us(500);
log_info("Start Read W25Qxx....\r\n");
SPI_Flash_Read(datap,0x0,SIZE);
log_info("READ:%s\r\n", datap );
}