Files
origincar_controller/HARDWARE/stmflash.c
MobKBK 460e0e9e73 init
2026-06-20 21:22:34 +08:00

221 lines
5.6 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.
#include "stmflash.h"
#include "delay.h"
#include "stmflash.h"
#define FLASH_SAVE_ADDR 0X0800E000 //设置FLASH 保存地址(必须为偶数且其值要大于本代码所占用FLASH的大小+0X08000000)
//解锁STM32的FLASH
void STMFLASH_Unlock(void)
{
FLASH->KEYR=FLASH_KEY1;//写入解锁序列.
FLASH->KEYR=FLASH_KEY2;
}
//flash上锁
void STMFLASH_Lock(void)
{
FLASH->CR|=1<<7;//上锁
}
//得到FLASH状态
u8 STMFLASH_GetStatus(void)
{
u32 res;
res=FLASH->SR;
if(res&(1<<0))return 1; //忙
else if(res&(1<<2))return 2; //编程错误
else if(res&(1<<4))return 3; //写保护错误
return 0; //操作完成
}
//等待操作完成
//time:要延时的长短
//返回值:状态.
u8 STMFLASH_WaitDone(u16 time)
{
u8 res;
do
{
res=STMFLASH_GetStatus();
if(res!=1)break;//非忙,无需等待了,直接退出.
delay_us(1);
time--;
}while(time);
if(time==0)res=0xff;//TIMEOUT
return res;
}
//擦除页
//paddr:页地址
//返回值:执行情况
u8 STMFLASH_ErasePage(u32 paddr)
{
u8 res=0;
res=STMFLASH_WaitDone(0X5FFF);//等待上次操作结束,>20ms
if(res==0)
{
FLASH->CR|=1<<1;//页擦除
FLASH->AR=paddr;//设置页地址
FLASH->CR|=1<<6;//开始擦除
res=STMFLASH_WaitDone(0X5FFF);//等待操作结束,>20ms
if(res!=1)//非忙
{
FLASH->CR&=~(1<<1);//清除页擦除标志.
}
}
return res;
}
//在FLASH指定地址写入半字
//faddr:指定地址(此地址必须为2的倍数!!)
//dat:要写入的数据
//返回值:写入的情况
u8 STMFLASH_WriteHalfWord(u32 faddr, u16 dat)
{
u8 res;
res=STMFLASH_WaitDone(0XFF);
if(res==0)//OK
{
FLASH->CR|=1<<0;//编程使能
*(vu16*)faddr=dat;//写入数据
res=STMFLASH_WaitDone(0XFF);//等待操作完成
if(res!=1)//操作成功
{
FLASH->CR&=~(1<<0);//清除PG位.
}
}
return res;
}
//读取指定地址的半字(16位数据)
//faddr:读地址
//返回值:对应数据.
u16 STMFLASH_ReadHalfWord(u32 faddr)
{
return *(vu16*)faddr;
}
#if STM32_FLASH_WREN //如果使能了写
//不检查的写入
//WriteAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数
void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{
u16 i;
for(i=0;i<NumToWrite;i++)
{
STMFLASH_WriteHalfWord(WriteAddr,pBuffer[i]);
WriteAddr+=2;//地址增加2.
}
}
//从指定地址开始写入指定长度的数据
//WriteAddr:起始地址(此地址必须为2的倍数!!)
//pBuffer:数据指针
//NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
#if STM32_FLASH_SIZE<256
#define STM_SECTOR_SIZE 1024 //字节
#else
#define STM_SECTOR_SIZE 2048
#endif
u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];//最多是2K字节
void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{
u32 secpos; //扇区地址
u16 secoff; //扇区内偏移地址(16位字计算)
u16 secremain; //扇区内剩余地址(16位字计算)
u16 i;
u32 offaddr; //去掉0X08000000后的地址
if(WriteAddr<STM32_FLASH_BASE||(WriteAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址
STMFLASH_Unlock(); //解锁
offaddr=WriteAddr-STM32_FLASH_BASE; //实际偏移地址.
secpos=offaddr/STM_SECTOR_SIZE; //扇区地址 0~127 for STM32F103RBT6
secoff=(offaddr%STM_SECTOR_SIZE)/2; //在扇区内的偏移(2个字节为基本单位.)
secremain=STM_SECTOR_SIZE/2-secoff; //扇区剩余空间大小
if(NumToWrite<=secremain)secremain=NumToWrite;//不大于该扇区范围
while(1)
{
STMFLASH_Read(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容
for(i=0;i<secremain;i++)//校验数据
{
if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除
}
if(i<secremain)//需要擦除
{
STMFLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除这个扇区
for(i=0;i<secremain;i++)//复制
{
STMFLASH_BUF[i+secoff]=pBuffer[i];
}
STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区
}else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间.
if(NumToWrite==secremain)break;//写入结束了
else//写入未结束
{
secpos++; //扇区地址增1
secoff=0; //偏移位置为0
pBuffer+=secremain; //指针偏移
WriteAddr+=secremain*2; //写地址偏移(16位数据地址,需要*2)
NumToWrite-=secremain; //字节(16位)数递减
if(NumToWrite>(STM_SECTOR_SIZE/2))secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完
else secremain=NumToWrite;//下一个扇区可以写完了
}
};
STMFLASH_Lock();//上锁
}
#endif
//从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数
void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)
{
u16 i;
for(i=0;i<NumToRead;i++)
{
pBuffer[i]=STMFLASH_ReadHalfWord(ReadAddr);//读取2个字节.
ReadAddr+=2;//偏移2个字节.
}
}
//WriteAddr:起始地址
//WriteData:要写入的数据
void Test_Write(u32 WriteAddr,u16 WriteData)
{
STMFLASH_Write(WriteAddr,&WriteData,1);//写入一个字
}
/**************************************************************************
函数功能从Flash读取指定数据
入口参数:无
返回 值:无
**************************************************************************/
void Flash_Read(void)
{
STMFLASH_Read(FLASH_SAVE_ADDR,(u16*)PID_Parameter,10);
if(PID_Parameter[0]==65535&&PID_Parameter[1]==65535&&PID_Parameter[2]==65535&&PID_Parameter[3]==65535&&PID_Parameter[4]==65535&&PID_Parameter[5]==65535&&PID_Parameter[6]==65535)
{
RC_Velocity=30;
Velocity_KP=12;
Velocity_KI=12;
}
else
{
RC_Velocity=PID_Parameter[0];//从Flash里面读取数据
Velocity_KP=PID_Parameter[1];
Velocity_KI=PID_Parameter[2];
}
}
/**************************************************************************
函数功能向Flash写入指定数据
入口参数:无
返回 值:无
**************************************************************************/
void Flash_Write(void)
{
Flash_Parameter[0]=RC_Velocity; //写入数据
Flash_Parameter[1]=Velocity_KP; //
Flash_Parameter[2]=Velocity_KI; //
STMFLASH_Write(FLASH_SAVE_ADDR,(u16*)Flash_Parameter,10);
}