Files
BLV_C1F_Module/BasicCode/Drive/FLASH/flash.c
caocong 95916b9995 fix:修改UDP通讯中,取电变化上报机制
1、问题点:当RCU网络状态异常的情况下,网络还处于协商状态下,还未进入正常通讯环节时,取电变化不会进行判断。这会导致取电变化上报与实际产生取电状态时间点对不上。
2、将BLV_C1F_Module代码上传至Gitea,之前代码修改记录请查看 .\BasicCode\Readme.txt
2026-01-23 09:23:12 +08:00

597 lines
18 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.
/*******************************************************************************
* Function Name : P25Q40H FLASH -- 4M bit == 512K*8bit
* Description : Flash驱动程序
*******************************************************************************/
#include "includes.h"
/*******************************************************************************
* Function Name : Flash_Init
* Description : P25Q40H Flash初始化
* Input : None
* Return : None
*******************************************************************************/
void Flash_Init(void)
{
#if (USE_CORE_TYPE == 1) //使用C1F核心板
//设置SPI0 GPIO
//GPIOA_ModeCfg(GPIO_Pin_3, GPIO_ModeOut_PP_5mA); //WP
//GPIOA_ModeCfg(GPIO_Pin_12, GPIO_ModeOut_PP_20mA); //CS
GPIOA_ModeCfg(GPIO_Pin_13|GPIO_Pin_14, GPIO_ModeOut_PP_5mA); //SCK,MOSI
GPIOA_ModeCfg(GPIO_Pin_15, GPIO_ModeIN_PU); //MISO
//SPI 主机模式
//SPI0_MasterDefInit( );
//Flash_WP_H; //硬件写保护引脚拉高
Flash_CS_H;
#elif (USE_CORE_TYPE == 2) //使用C1核心板
//设置SPI0 GPIO
GPIOA_ModeCfg(GPIO_Pin_3, GPIO_ModeOut_PP_5mA); //WP
GPIOB_ModeCfg(GPIO_Pin_22, GPIO_ModeOut_PP_20mA); //CS
GPIOA_ModeCfg(GPIO_Pin_13|GPIO_Pin_14, GPIO_ModeOut_PP_5mA); //SCK,MOSI
GPIOA_ModeCfg(GPIO_Pin_15, GPIO_ModeIN_PU); //MISO
//SPI 主机模式
//SPI0_MasterDefInit( );
Flash_WP_H; //硬件写保护引脚拉高
Flash_CS_H;
#endif //USE_CORE_TYPE == CORE_TYPE_C1F
}
/*******************************************************************************
* Function Name : Flash_ReadSR
* Description : P25Q40H Flash读取状态寄存器
* Input : None
* Return : P25Q40H Flash状态寄存器值
BIT7 6 5 4 3 2 1 0
SPR0 BP4 BP3 BP2 BP1 BP0 WEL WIP
SPR:默认0,状态寄存器保护位,配合WP使用
BP4,BP3,BP2,BP1,BP0:FLASH区域写保护设置
WEL:写使能锁定
BUSY:忙标记位(1,忙;0,空闲)
默认:0x00
*******************************************************************************/
uint8_t Flash_ReadSR(void)
{
uint8_t byte = 0;
Flash_CS_L;
SPI0_MasterSendByte(P24Q40H_ReadStatusReg); //发送读取状态寄存器命令
byte = SPI0_MasterRecvByte();
Flash_CS_H;
return byte;
}
/*******************************************************************************
* Function Name : Flash_WriteSR
* Description : P25Q40H Flash写状态寄存器
* Input :
sr_val:写入状态寄存器的值
BIT7 6 5 4 3 2 1 0
SPR0 BP4 BP3 BP2 BP1 BP0 WEL WIP
只有SPR0,BP3,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!!
* Return : None
*******************************************************************************/
void Flash_WriteSR(uint8_t sr_val)
{
Flash_CS_L;
SPI0_MasterSendByte(P24Q40H_WriteStatusReg);
SPI0_MasterSendByte(sr_val);
Flash_CS_H;
}
/*******************************************************************************
* Function Name : Flash_Write_Enable
* Description : P25Q40H 写使能 -- 将WEL置位
* Input : None
* Return : None
*******************************************************************************/
void Flash_Write_Enable(void)
{
Flash_CS_L;
SPI0_MasterSendByte(P24Q40H_WriteEnable);
Flash_CS_H;
}
/*******************************************************************************
* Function Name : Flash_Write_Disable
* Description : P25Q40H 写禁止 -- 将WEL清零
* Input : None
* Return : None
*******************************************************************************/
void Flash_Write_Disable(void)
{
Flash_CS_L;
SPI0_MasterSendByte(P24Q40H_WriteDisable);
Flash_CS_H;
}
/*******************************************************************************
* Function Name : Flash_ReadID
* Description : P25Q40H Flash 读取芯片ID
* Input : None
* Return : 返回值如下:
0x8512:表示芯片型号为P25Q40H
0x8511:表示芯片型号为P25Q20H
0x8510:表示芯片型号为P25Q10H
0x8509:表示芯片型号为P25Q05H
*******************************************************************************/
uint16_t Flash_ReadID(void)
{
uint16_t temp=0;
Flash_CS_L;
SPI0_MasterSendByte(P24Q40H_ReadManufactureID);
SPI0_MasterRecvByte();
SPI0_MasterRecvByte();
SPI0_MasterRecvByte();
temp |= SPI0_MasterRecvByte();
temp |= SPI0_MasterRecvByte()<<8;
Flash_CS_H;
return temp;
}
/*******************************************************************************
* Function Name : Flash_Wait_Busy
* Description : 等待空闲
* Input : None
* Return : 1等待超时处于繁忙状态
0空闲状态
*******************************************************************************/
uint8_t Flash_Wait_Busy(void)
{
uint8_t temp=0;
uint16_t i=0;
temp = Flash_ReadSR();
while((temp&0x01)==0x01)
{
DelayUs(100);
temp = Flash_ReadSR();
i++;
if(i>3000) return 1;
};
return 0;
}
/*******************************************************************************
* Function Name : Flash_PowerDown
* Description : Flash 进入掉电模式
* Input : None
* Return : None
*******************************************************************************/
void Flash_PowerDown(void)
{
Flash_CS_L;
SPI0_MasterSendByte(P24Q40H_PowerDown);
DelayUs(3);
Flash_CS_H;
}
/*******************************************************************************
* Function Name : Flash_PowerDown
* Description : Flash 唤醒掉电模式
* Input : None
* Return : None
*******************************************************************************/
void Flash_Wakeup(void)
{
Flash_CS_L;
SPI0_MasterSendByte(P24Q40H_ReleasePowerDown);
DelayUs(3);
Flash_CS_H;
}
/*******************************************************************************
* Function Name : Flash_Erase_Chip
* Description : 擦除整个芯片
* Input : None
* Return : None
*******************************************************************************/
void Flash_Erase_Chip(void)
{
Flash_Write_Enable();
Flash_Wait_Busy();
Flash_CS_L;
SPI0_MasterSendByte(P24Q40H_ChipErase);
Flash_CS_H;
Flash_Wait_Busy();
}
/*******************************************************************************
* Function Name : Flash_Erase_Block
* Description : 擦除块
* Input : BLK_ID块号(0~31) 2M
* Return : None
*******************************************************************************/
void Flash_Erase_Block(uint32_t BLK_ID)
{
BLK_ID*=0x10000; //64K
Flash_Write_Enable();
Flash_Wait_Busy();
Flash_CS_L;
SPI0_MasterSendByte(P24Q40H_BlockErase);
SPI0_MasterSendByte((uint8_t)((BLK_ID)>>16));
SPI0_MasterSendByte((uint8_t)((BLK_ID)>>8));
SPI0_MasterSendByte((uint8_t)BLK_ID);
Flash_CS_H;
Flash_Wait_Busy();
}
/*******************************************************************************
* Function Name : Flash_Erase_Sector
* Description : 擦除扇区
* Input : DST_Addr扇区号(0~511) 2M
* Return : None
*******************************************************************************/
void Flash_Erase_Sector(uint32_t DST_ID)
{
DST_ID*=4096;
Flash_Write_Enable();
Flash_Wait_Busy();
Flash_CS_L;
SPI0_MasterSendByte(P24Q40H_SectorErase);
SPI0_MasterSendByte((uint8_t)((DST_ID)>>16));
SPI0_MasterSendByte((uint8_t)((DST_ID)>>8));
SPI0_MasterSendByte((uint8_t)DST_ID);
Flash_CS_H;
Flash_Wait_Busy();
}
/*******************************************************************************
* Function Name : Flash_Erase_Page
* Description : 擦除页区
* Input : Page_ID页号(0~8191)
* Return : None
*******************************************************************************/
void Flash_Erase_Page(uint32_t Page_ID)
{
Page_ID*=256;
Flash_Write_Enable();
Flash_Wait_Busy();
Flash_CS_L;
SPI0_MasterSendByte(P24Q40H_PageErase);
SPI0_MasterSendByte((uint8_t)((Page_ID)>>16));
SPI0_MasterSendByte((uint8_t)((Page_ID)>>8));
SPI0_MasterSendByte((uint8_t)Page_ID);
Flash_CS_H;
Flash_Wait_Busy();
}
/*******************************************************************************
* Function Name : Flash_Erase_Page
* Description : 擦除页区
* Input : Page_addr:地址
* Return : None
*******************************************************************************/
void Flash_Erase_Pageaddr(uint32_t Page_addr)
{
Flash_Write_Enable();
Flash_Wait_Busy();
Flash_CS_L;
SPI0_MasterSendByte(P24Q40H_PageErase);
SPI0_MasterSendByte((uint8_t)((Page_addr)>>16));
SPI0_MasterSendByte((uint8_t)((Page_addr)>>8));
SPI0_MasterSendByte((uint8_t)Page_addr);
Flash_CS_H;
Flash_Wait_Busy();
}
/*******************************************************************************
* Function Name : Flash_Read
* Description : P25Q40H Flash 指定地址开始读取指定长度的数据
* Input :
pBuffer数据存储区
NumByteToRead要读取的字节数(最大65535)
ReadAddr读取起始地址(24bit)
* Return : None
*******************************************************************************/
void Flash_Read(uint8_t* pBuffer,uint16_t NumByteToRead,uint32_t ReadAddr)
{
Flash_CS_L;
SPI0_MasterSendByte(P24Q40H_ReadData);
SPI0_MasterSendByte((uint8_t)((ReadAddr)>>16));
SPI0_MasterSendByte((uint8_t)((ReadAddr)>>8));
SPI0_MasterSendByte((uint8_t)ReadAddr);
SPI0_MasterRecv(pBuffer,NumByteToRead);
Flash_CS_H;
}
/*******************************************************************************
* Function Name : Flash_Write_Page
* Description : P25Q40H Flash 指定地址开始写指定长度的数据
* Input :
pBuffer数据存储区
NumByteToRead要写的字节数(最大256),该数不应该超过该页的剩余字节数!!!
ReadAddr读取起始地址(24bit)
* Return : None
*******************************************************************************/
void Flash_Write_Page(uint8_t* pBuffer,uint16_t NumByteToWrite,uint32_t writeAddr)
{
Flash_Write_Enable();
Flash_CS_L;
SPI0_MasterSendByte(P24Q40H_PageProgram);
SPI0_MasterSendByte((uint8_t)((writeAddr)>>16));
SPI0_MasterSendByte((uint8_t)((writeAddr)>>8));
SPI0_MasterSendByte((uint8_t)writeAddr);
SPI0_MasterTrans(pBuffer,NumByteToWrite);
Flash_CS_H;
Flash_Wait_Busy();
}
/*******************************************************************************
* Function Name : Flash_Write_NoCheck
* Description : 无检验写P25Q40H FLASH
注意必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
具有自动换页功能
在指定地址开始写入指定长度的数据,但是要确保地址不越界!
* Input :
pBuffer数据存储区
NumByteToRead要写的字节数(最大65535)
ReadAddr读取起始地址(24bit)
* Return : None
*******************************************************************************/
void Flash_Write_NoCheck(uint8_t* pBuffer,uint16_t NumByteToWrite,uint32_t writeAddr)
{
uint16_t pageremain;
pageremain=256-writeAddr%256; //单页剩余的字节数
if(NumByteToWrite<=pageremain) pageremain=NumByteToWrite;//不大于256个字节
while(1)
{
Flash_Write_Page(pBuffer,pageremain,writeAddr);
if(pageremain == NumByteToWrite) break; //写入完成
else {
pBuffer+=pageremain;
writeAddr+=pageremain;
NumByteToWrite-=pageremain;
if(NumByteToWrite>256) pageremain=256;
else pageremain=NumByteToWrite;
}
};
}
/*
由于本项目空间的本地SRAM空间有限因此为较少SRAM的开销将数据BUFF从4096改为256
以下两个一个是以扇区为单位进行擦除,另一个是以页为单位进行擦除
*/
#if 1
/*******************************************************************************
* Function Name : Flash_Write
* Description : 无检验写P25Q40H FLASH
注意必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
具有自动换页功能
在指定地址开始写入指定长度的数据,但是要确保地址不越界!
* Input :
pBuffer数据存储区
NumByteToRead要写的字节数(最大65535)
ReadAddr读取起始地址(24bit)
* Return : None
*******************************************************************************/
uint8_t Temp_Flash_Buff[4200];
void Flash_Write(uint8_t* pBuffer,uint16_t NumByteToWrite,uint32_t WriteAddr)
{
uint32_t secpos;
uint16_t secoff,secremain,i;
uint8_t* Write_Buff;
if(NumByteToWrite <= 256*2)
{
Write_Buff = Temp_Flash_Buff;
secpos = WriteAddr/256; //页区地址
secoff = WriteAddr%256; //在扇区内的偏移
secremain = 256 - secoff; //扇区剩余空间
if(NumByteToWrite<=secremain) secremain = NumByteToWrite; //当前页区剩余空间可以存放
while(1)
{
WDT_Feed();
Flash_Read(Write_Buff,256,secpos*256); //读取整个扇区的内容
for(i=0;i<secremain;i++) //校验数据,判断是否是要擦除扇区
{
if(Write_Buff[secoff+i]!=0xFF)break;
}
if(i<secremain) //需要擦除页区
{
Flash_Erase_Page(secpos); //擦除整个页区
for(i=0;i<secremain;i++) //复制
{
Write_Buff[i+secoff]=pBuffer[i];
}
Flash_Write_NoCheck(Write_Buff,256,secpos*256); //写入整个页区
}else {
if(secremain == 256)
{
Flash_Write_NoCheck(pBuffer,256,secpos*256); //写入整个页区
}else if(secremain < 256){
Flash_Write_NoCheck(pBuffer,secremain,WriteAddr); //不需要擦除可以直接,写入整个页区
}
}
if(NumByteToWrite == secremain) break; //写入完成
else //写入未结束
{
secpos++; //页区地址增1
secoff = 0; //页区偏移位置归零
pBuffer += secremain; //数据指针偏移
WriteAddr += secremain; //数据保存地址偏移
NumByteToWrite -= secremain; //剩余写入字节数递减
if(NumByteToWrite > 256) secremain = 256; //下一个页区还是写不完
else secremain = NumByteToWrite; //下一个页区可以写完
}
}
}
else
{
Write_Buff = Temp_Flash_Buff;
secpos = WriteAddr/4096; //扇区地址
secoff = WriteAddr%4096; //在扇区内的偏移
secremain = 4096 - secoff; //扇区剩余空间
if(NumByteToWrite<=secremain) secremain = NumByteToWrite; //当前扇区剩余空间可以存放
while(1)
{
WDT_Feed();
Flash_Read(Write_Buff,2048,secpos*4096); //读取整个扇区的内容
Flash_Read(Write_Buff+2048,2048,secpos*4096+2048); //读取整个扇区的内容
for(i=0;i<secremain;i++) //校验数据,判断是否是要擦除扇区
{
if(Write_Buff[secoff+i]!=0xFF)break;
}
if(i<secremain) //需要擦除扇区
{
Flash_Erase_Sector(secpos); //擦除整个扇区
for(i=0;i<secremain;i++) //复制
{
Write_Buff[i+secoff]=pBuffer[i];
}
Flash_Write_NoCheck(Write_Buff,2048,secpos*4096); //写入整个扇区
Flash_Write_NoCheck(Write_Buff+2048,2048,secpos*4096+2048); //写入整个扇区
}else {
if(secremain == 4096)
{
Flash_Write_NoCheck(pBuffer,2048,secpos*4096); //写入整个扇区
Flash_Write_NoCheck(pBuffer+2048,2048,secpos*4096+2048); //写入整个扇区
}else if(secremain < 4096){
Flash_Write_NoCheck(pBuffer,secremain,WriteAddr); //不需要擦除可以直接,写入整个扇区
}
}
if(NumByteToWrite == secremain) break; //写入完成
else //写入未结束
{
secpos++; //扇区地址增1
secoff = 0; //扇区偏移位置归零
pBuffer += secremain; //数据指针偏移
WriteAddr += secremain; //数据保存地址偏移
NumByteToWrite -= secremain; //剩余写入字节数递减
if(NumByteToWrite > 4096) secremain = 4096; //下一个扇区还是写不完
else secremain = NumByteToWrite; //下一个扇区可以写完
}
}
}
}
#else
/*******************************************************************************
* Function Name : Flash_Write
* Description : 无检验写P25Q40H FLASH
注意必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
具有自动换页功能
在指定地址开始写入指定长度的数据,但是要确保地址不越界!
* Input :
pBuffer数据存储区
NumByteToRead要写的字节数(最大65535)
ReadAddr读取起始地址(24bit)
* Return : None
*******************************************************************************/
uint8_t Flash_Buffer[256];
void Flash_Write(uint8_t* pBuffer,uint16_t NumByteToWrite,uint32_t WriteAddr)
{
uint32_t secpos;
uint16_t secoff,secremain,i;
uint8_t* Write_Buff;
Write_Buff = Flash_Buffer;
secpos = WriteAddr/256; //页区地址
secoff = WriteAddr%256; //在页区内的偏移
secremain = 256 - secoff; //页区剩余空间
if(NumByteToWrite<=secremain) secremain = NumByteToWrite; //当前页区剩余空间可以存放
while(1)
{
WDT_Feed();
Flash_Read(Write_Buff,256,secpos*256); //读取整个页区的内容
for(i=0;i<secremain;i++) //校验数据,判断是否是要擦除页区
{
if(Write_Buff[secoff+i]!=0xFF)break;
}
if(i<secremain) //需要擦除页区
{
Flash_Erase_Page(secpos); //擦除整个页区
for(i=0;i<secremain;i++) //复制
{
Write_Buff[i+secoff]=pBuffer[i];
}
Flash_Write_Page(Write_Buff,256,secpos*256); //写入整个页区
}else Flash_Write_Page(pBuffer,secremain,WriteAddr); //不需要擦除可以直接,写入整个页区
if(NumByteToWrite == secremain) break; //写入完成
else //写入未结束
{
secpos++; //页区地址增1
secoff = 0; //页区偏移位置归零
pBuffer += secremain; //数据指针偏移
WriteAddr += secremain; //数据保存地址偏移
NumByteToWrite -= secremain; //剩余写入字节数递减
if(NumByteToWrite > 256) secremain = 256; //下一个页区还是写不完
else secremain = NumByteToWrite; //下一个页区可以写完
}
};
}
#endif
/*******************************************************************************
* Function Name : Flash_APPDATA_Erase
* Description : Flash APP区数据全部擦除 APP代码中空间为218K
* Input :
*******************************************************************************/
void Flash_APPDATA_Erase(void)
{
/*APP固定区域0x08000 ~ 0x3FFFF*/
/*擦除代码区全片区域 32K*/
for(uint8_t i =8;i<16;i++)
{
WDT_Feed();
Flash_Erase_Sector(i);
}
/*擦除代码区全片区域 192K*/
for(uint8_t i =1;i<4;i++)
{
WDT_Feed();
Flash_Erase_Block(i);
}
}
/*******************************************************************************
* Function Name : Flash_LOGICDATA_Erase
* Description : Flash LOGIC区数据全部擦除 LOGIC代码中空间为448K
* Input :
*******************************************************************************/
void Flash_LOGICDATA_Erase(void)
{
/*LOGIC固定区域0x90000 ~ 0xFFFFF */
/*擦除逻辑文件区域 448K*/
for(uint8_t i =9;i<16;i++)
{
WDT_Feed();
Flash_Erase_Block(i);
}
}