在看无名的Flash之前先看一下如何操作Flash
STM32 FLASH操作步骤
1. FLASH解锁
在对 FLASH 进行写操作前必须先解锁,固件库函数实现很简单:
FLASH_Unlock();//解锁
2. 清除相关的标志位
FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);//清除标志位
3. 擦除函数
固件库提供三个 FLASH 擦除函数:
FLASH_Status FLASH_ErasePage(uint32_t Page_Address);
FLASH_Status FLASH_EraseAllPages(void);
FLASH_Status FLASH_EraseOptionBytes(void);
这三个函数可以顾名思义了,非常简单。
4. 写操作函数
固件库提供了三个 FLASH 写函数:
FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);
FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);
顾名思义分别为: FLASH_ProgramWord 为 32 位字写入函数, 其他分别为 16 位半字写入和 8位字节写入函数。这里需要说明, 32 位字节写入实际上是写入的两次 16 位数据,写完第一次后地址+2。 写入 8 位实际也是占用的两个地址了,跟写入 16 位基本上没啥区别。
5. 锁定函数
在对 FLASH 写操作完成之后,我们要锁定 FLASH,使用的库函数是:
void FLASH_Lock(void);
而飞控里面在Parameter_Init函数里面调用了ReadFlashThreeFloat
定义:
uint8_t ReadFlashThreeFloat(uint32_t ReadAddress,
float *WriteData1,
float *WriteData2,
float *WriteData3)
{
uint8_t buf[12];
uint16_t i=0;
uint8_t flag=0x00;
ReadAddress = (uint32_t)STARTADDR + ReadAddress;
*WriteData1=*(float *)(ReadAddress);
*WriteData2=*(float *)(ReadAddress+4);
*WriteData3=*(float *)(ReadAddress+8);
FLASH_LockBank1();
for(i=0;i<12;i++)//单字节数据
{
*(buf+i)=*(__IO uint8_t*) ReadAddress++;
}
if((buf[0]==0xff&&buf[1]==0xff&&buf[2]==0xff&&buf[3]==0xff))
flag=flag|0x01;
if((buf[4]==0xff&&buf[5]==0xff&&buf[6]==0xff&&buf[7]==0xff))
flag=flag|0x02;
if((buf[8]==0xff&&buf[9]==0xff&&buf[10]==0xff&&buf[11]==0xff))
flag=flag|0x04;
return flag;
}
一次读三个字节,并将值赋给输入参数
对于函数:
Parameter_Flag Parameter_Read_Flag;
bool Parameter_Init(void)
{
bool success=true;
/************加速度计零偏与标度值*******/
Parameter_Read_Flag.accel_off=ReadFlashThreeFloat(Accel_Offset_Address,
&Accel_Offset_Read.x,
&Accel_Offset_Read.y,
&Accel_Offset_Read.z);
Parameter_Read_Flag.accel_scale=ReadFlashThreeFloat(Accel_Scale_Address,
&Accel_Scale_Read.x,
&Accel_Scale_Read.y,
&Accel_Scale_Read.z);
/************磁力计零偏****************/
Parameter_Read_Flag.mag=ReadFlashThreeFloat(Mag_Offset_Address,
&Mag_Offset_Read.x,
&Mag_Offset_Read.y,
&Mag_Offset_Read.z);
// sanity check scale
if(ABS(Accel_Scale_Read.x-1.0f)>0.2f
|| ABS(Accel_Scale_Read.y-1.0f)>0.2f
|| ABS(Accel_Scale_Read.z-1.0f)>0.2f)
{
success = false;
}
// sanity check offsets (3.5 is roughly 3/10th of a G, 5.0 is roughly half a G)
if(ABS(Accel_Offset_Read.x) > 3.5f
|| ABS(Accel_Offset_Read.y) > 3.5f
|| ABS(Accel_Offset_Read.z) > 3.5f)
{
success = false;
}
if(success==true
&&Parameter_Read_Flag.accel_off!=0x07
&&Parameter_Read_Flag.accel_scale!=0x07)//Flash内数据正常,更新加速度校正值
{
B[0]=Accel_Offset_Read.x*One_G_TO_Accel;
B[1]=Accel_Offset_Read.y*One_G_TO_Accel;
B[2]=Accel_Offset_Read.z*One_G_TO_Accel;
K[0]=Accel_Scale_Read.x;
K[1]=Accel_Scale_Read.y;
K[2]=Accel_Scale_Read.z;
}
/**********磁力计中心偏执获取************/
if(Parameter_Read_Flag.mag!=0x07)
{
Mag_Offset[0]=(int16_t)(Mag_Offset_Read.x);
Mag_Offset[1]=(int16_t)(Mag_Offset_Read.y);
Mag_Offset[2]=(int16_t)(Mag_Offset_Read.z);
}
return success;
}
它首先定义了一个结构体,
Parameter_Flag Parameter_Read_Flag;
结构体内部:
typedef struct
{
uint8_t accel_off;
uint8_t accel_scale;
uint8_t mag;
}Parameter_Flag;
首先应有三个结构体定义:
Mag_Unit Mag_Offset_Read={
0,0,0,
};
Acce_Unit Accel_Offset_Read={
0,0,0,
};
Acce_Unit Accel_Scale_Read={
0,0,0,
};
其中:typedef struct
{
float x;
float y;
float z;
}Acce_Unit;类外一个类似
整个函数的过程就是将读取的数据赋给Mag_Offset_Read,Accel_Scale_Read,Accel_Offset_Read结构体里面,并返回是否读取到数据的标志
得到的数组B[3],K[3],Mag_Offset[3],