Files
RCU_C1P_Module/MCU_Driver/spi_flash.c
caocong cc8783e9f8 feat:新增TFTP IAP升级功能
修改事项:
1、新增TFTP IAP升级功能,只是代码移植完毕,没有测试使用
2、代码空间编译优化,零等待区域空间已满,而应用层代码已全部挪移到非零等待区域中,但还是会增加零等待区的空间占用。 待优化
2025-12-10 14:06:45 +08:00

521 lines
18 KiB
C
Raw Permalink 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.
/*
* spi_flash.c
*
* Created on: May 20, 2025
* Author: cc
*/
#include "spi_flash.h"
#include "debug.h"
uint8_t Temp_Flash_Buff[4100]; //FLash 写入缓存BUFF
__attribute__((section(".non_0_wait"))) void SPI_FLASH_Init(void)
{
/* SPI Flash 与 SPI SRAM 共用SPI引脚
* 因此 SPI Flash 无需引脚初始化
* */
Dbg_Println(DBG_BIT_SYS_STATUS_bit,"SPI Flash ID:0x%04x\r\n",Flash_ReadID());
}
/*******************************************************************************
* 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
*******************************************************************************/
__attribute__((section(".non_0_wait"))) 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
*******************************************************************************/
__attribute__((section(".non_0_wait"))) 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
*******************************************************************************/
__attribute__((section(".non_0_wait"))) 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
*******************************************************************************/
__attribute__((section(".non_0_wait"))) 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
*******************************************************************************/
__attribute__((section(".non_0_wait"))) 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()<<8;
temp |= SPI0_MasterRecvByte();
Flash_CS_H;
return temp;
}
/*******************************************************************************
* Function Name : Flash_Wait_Busy
* Description : 等待空闲
* Input : None
* Return : 1等待超时处于繁忙状态
0空闲状态
*******************************************************************************/
__attribute__((section(".non_0_wait"))) uint8_t Flash_Wait_Busy(void)
{
uint8_t temp=0;
uint16_t i=0;
temp = Flash_ReadSR();
while((temp&0x01)==0x01)
{
FEED_DOG(); //喂狗
Delay_Us(100);
temp = Flash_ReadSR();
i++;
if(i>3000) return 1;
};
return 0;
}
/*******************************************************************************
* Function Name : Flash_PowerDown
* Description : Flash 进入掉电模式
* Input : None
* Return : None
*******************************************************************************/
__attribute__((section(".non_0_wait"))) void Flash_PowerDown(void)
{
Flash_CS_L;
SPI0_MasterSendByte(P24Q40H_PowerDown);
Delay_Us(3);
Flash_CS_H;
}
/*******************************************************************************
* Function Name : Flash_PowerDown
* Description : Flash 唤醒掉电模式
* Input : None
* Return : None
*******************************************************************************/
__attribute__((section(".non_0_wait"))) void Flash_Wakeup(void)
{
Flash_CS_L;
SPI0_MasterSendByte(P24Q40H_ReleasePowerDown);
Delay_Us(3);
Flash_CS_H;
}
/*******************************************************************************
* Function Name : Flash_Erase_Chip
* Description : 擦除整个芯片
* Input : None
* Return : None
*******************************************************************************/
__attribute__((section(".non_0_wait"))) 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
*******************************************************************************/
__attribute__((section(".non_0_wait"))) void Flash_Erase_Block(uint32_t BLK_ID)
{
uint8_t flash_buff[5];
BLK_ID*=0x10000; //64K
flash_buff[0] = P24Q40H_BlockErase;
flash_buff[1] = (uint8_t)((BLK_ID >> 16) & 0xFF);
flash_buff[2] = (uint8_t)((BLK_ID >> 8) & 0xFF);
flash_buff[3] = (uint8_t)((BLK_ID) & 0xFF);
flash_buff[4] = 0x00;
Flash_Write_Enable();
Flash_Wait_Busy();
Flash_CS_L;
SPI0_DMATrans(flash_buff,0x04);
Flash_CS_H;
Flash_Wait_Busy();
}
/*******************************************************************************
* Function Name : Flash_Erase_Sector
* Description : 擦除扇区
* Input : DST_Addr扇区号(0~511) 2M
* Return : None
*******************************************************************************/
__attribute__((section(".non_0_wait"))) void Flash_Erase_Sector(uint32_t DST_ID)
{
uint8_t flash_buff[5];
DST_ID*=4096;
flash_buff[0] = P24Q40H_SectorErase;
flash_buff[1] = (uint8_t)((DST_ID >> 16) & 0xFF);
flash_buff[2] = (uint8_t)((DST_ID >> 8) & 0xFF);
flash_buff[3] = (uint8_t)((DST_ID) & 0xFF);
flash_buff[4] = 0x00;
Flash_Write_Enable();
Flash_Wait_Busy();
Flash_CS_L;
SPI0_DMATrans(flash_buff,0x04);
Flash_CS_H;
Flash_Wait_Busy();
}
/*******************************************************************************
* Function Name : Flash_Erase_Page
* Description : 擦除页区
* Input : Page_ID页号(0~8191)
* Return : None
*******************************************************************************/
__attribute__((section(".non_0_wait"))) void Flash_Erase_Page(uint32_t Page_ID)
{
uint8_t flash_buff[5];
Page_ID*=256;
flash_buff[0] = P24Q40H_PageErase;
flash_buff[1] = (uint8_t)((Page_ID >> 16) & 0xFF);
flash_buff[2] = (uint8_t)((Page_ID >> 8) & 0xFF);
flash_buff[3] = (uint8_t)((Page_ID) & 0xFF);
flash_buff[4] = 0x00;
Flash_Write_Enable();
Flash_Wait_Busy();
Flash_CS_L;
SPI0_DMATrans(flash_buff,0x04);
Flash_CS_H;
Flash_Wait_Busy();
}
/*******************************************************************************
* Function Name : Flash_Erase_Page
* Description : 擦除页区
* Input : Page_addr:地址
* Return : None
*******************************************************************************/
__attribute__((section(".non_0_wait"))) void Flash_Erase_Pageaddr(uint32_t Page_addr)
{
uint8_t flash_buff[5];
flash_buff[0] = P24Q40H_PageErase;
flash_buff[1] = (uint8_t)((Page_addr >> 16) & 0xFF);
flash_buff[2] = (uint8_t)((Page_addr >> 8) & 0xFF);
flash_buff[3] = (uint8_t)((Page_addr) & 0xFF);
flash_buff[4] = 0x00;
Flash_Write_Enable();
Flash_Wait_Busy();
Flash_CS_L;
SPI0_DMATrans(flash_buff,0x04);
Flash_CS_H;
Flash_Wait_Busy();
}
/*******************************************************************************
* Function Name : Flash_Read
* Description : P25Q40H Flash 指定地址开始读取指定长度的数据
* Input :
pBuffer数据存储区
NumByteToRead要读取的字节数(最大65535)
ReadAddr读取起始地址(24bit)
* Return : None
*******************************************************************************/
__attribute__((section(".non_0_wait"))) void Flash_Read(uint8_t* pBuffer,uint16_t NumByteToRead,uint32_t ReadAddr)
{
uint8_t flash_buff[5];
flash_buff[0] = P24Q40H_ReadData;
flash_buff[1] = (uint8_t)((ReadAddr >> 16) & 0xFF);
flash_buff[2] = (uint8_t)((ReadAddr >> 8) & 0xFF);
flash_buff[3] = (uint8_t)((ReadAddr) & 0xFF);
flash_buff[4] = 0x00;
Flash_CS_L;
SPI0_DMATrans(flash_buff,0x04);
SPI0_DMARecv(pBuffer,NumByteToRead);
Flash_CS_H;
}
/*******************************************************************************
* Function Name : Flash_Write_Page
* Description : P25Q40H Flash 指定地址开始写指定长度的数据
* Input :
pBuffer数据存储区
NumByteToRead要写的字节数(最大256),该数不应该超过该页的剩余字节数!!!
ReadAddr读取起始地址(24bit)
* Return : None
*******************************************************************************/
__attribute__((section(".non_0_wait"))) void Flash_Write_Page(uint8_t* pBuffer,uint16_t NumByteToWrite,uint32_t writeAddr)
{
uint8_t flash_buff[5];
flash_buff[0] = P24Q40H_PageProgram;
flash_buff[1] = (uint8_t)((writeAddr >> 16) & 0xFF);
flash_buff[2] = (uint8_t)((writeAddr >> 8) & 0xFF);
flash_buff[3] = (uint8_t)((writeAddr) & 0xFF);
flash_buff[4] = 0x00;
Flash_Write_Enable();
Flash_CS_L;
SPI0_DMATrans(flash_buff,0x04);
SPI0_DMATrans(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
*******************************************************************************/
__attribute__((section(".non_0_wait"))) 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)
{
FEED_DOG(); //喂狗
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;
}
};
}
/*******************************************************************************
* Function Name : Flash_Write
* Description : 无检验写P25Q40H FLASH
注意必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
具有自动换页功能
在指定地址开始写入指定长度的数据,但是要确保地址不越界!
* Input :
pBuffer数据存储区
NumByteToRead要写的字节数(最大65535)
ReadAddr读取起始地址(24bit)
* Return : None
*******************************************************************************/
__attribute__((section(".non_0_wait"))) 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)
{
FEED_DOG(); //喂狗
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)
{
FEED_DOG(); //喂狗
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; //下一个扇区可以写完
}
}
}
}
/*******************************************************************************
* Function Name : SPI_FLASH_APP_Data_Erase
* Description : 外部Flash APP空间擦除
* APP空间大小 Size: 0x00070000 地址范围0x00000000 ~ 0x0006FFFF
*******************************************************************************/
__attribute__((section(".non_0_wait"))) void SPI_FLASH_APP_Data_Erase(void)
{
for(uint8_t i = 0;i < 7;i++)
{
Flash_Erase_Block(i);
}
}
/*******************************************************************************
* Function Name : SPI_FLASH_Logic_File_Erase
* Description : 外部Flash 配置文件空间擦除
* APP空间大小 Size: 0x00090000 地址范围0x00070000 ~ 0x000FFFFF
*******************************************************************************/
__attribute__((section(".non_0_wait"))) void SPI_FLASH_Logic_File_Erase(void)
{
for(uint8_t i = 7;i < 16;i++)
{
Flash_Erase_Block(i);
}
}