📄 flash.c
字号:
//[Flash.c]Flash擦写-------------------------------------------------------*
//本文件包含: *
// (1)Flash_Erase_Sector:擦除一个指定的扇区 *
// (2)Flash_Write_Nword:向一个指定的区域写入若干个字 *
// (3)Flash_unsecured:使用后门机制解除Flash的安全状态 *
// (4)Flash_SetKey:设置后门钥匙 *
// (5)Flash_SetStatus:设置Flash的安全状态 *
//-------------------------------------------------------------------------*
//头文件
#include "Flash.h" //Flash擦写头文件
//内部调用函数声明
void Erase_Write_Pretreat(uchar page); //擦写子函数内部调用的函数声明
//页所对应的块对照表
//两个flash块,每块4页 flash0 flash1
const uchar pagetable[2][4] = {{0x3C,0x3D,0x3E,0x3F},{0x38,0x39,0x3A,0x3B}};
//由于在Flash擦写时会在Flash区产生高压,造成擦写不稳定,本工程把在高压时执行
//的程序转换成机器码存放在RAM区,在执行擦写操作时,执行RAM区0的机器码,
//擦写操作稳定,该机器码存放在下面数组中,其中'0x3D'是'RTS'的机器码
const uchar P[18] = {0x18,0x0B,0x80,0x01,0x05,0xF6,0x01,0x05,0x87,
0x87,0xC4,0x40,0x8C,0x00,0x00,0x27,0xF4,0x0A};
//FSTAT=0x80;
//while(!(FSTAT&0x80));
uchar PrgOfRam[18]; /*存放RAM区执行的的机器码 */
void PrgToRAM(void)
{
uchar i=0x00;
for (i=0; i<18; i++)
PrgOfRam[i] = P[i];
}
//Flash_Erase_Sector:擦除指定的扇区----------------------------------------*
//功 能:对页号为page,扇区首地址为addr的一个扇区进行擦除 *
//参 数:page--页映射地址(0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F) *
// addr--扇区首地址(偶数) *
//返 回:无 *
//注 意:调用该函数之前,必须确定要擦除的区域可擦除 *
//-------------------------------------------------------------------------*
void Flash_Erase_Sector(uchar page,uint addr)
{
//1 判断是否已分频、清相关错误标志、根据页号选择相应的flash块
//2 向要擦除的扇区首地址写任意值(注意:经实验证实,不可以写0x0000)
//3 向命令寄存器写扇区擦除命令
//4 在加高压期间,调用RAM区的机器码,相当于两条语句:
// FSTAT=0x08;
// while(!(FSTAT&0x40));
Erase_Write_Pretreat(page); //擦写子函数共同调用的内部子函数
*(uint *)addr = 0xFFFF;
FCMD = 0x40;
_asm("CALL PrgOfRam");
}
//-------------------------------------------------------------------------*
//Flash_Write_Nword:向指定的扇区写入若干个字-------------------------------*
//功 能:将从address_source开始的len个字,写入页号为 page,起始地址为 *
// address_destination的扇区 *
//参 数:page--页映射地址(0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F) *
// address_destination--目标扇区首地址(偶数) *
// address_source--源地址 *
// len--字节数 *
//返 回:无 *
//注 意:调用该函数之前,必须确定要写入的区域可写入 *
//-------------------------------------------------------------------------*
void Flash_Write_Nword(uchar page,uint address_destination,
uint address_source,uint len)
{
//1 判断是否已分频、清相关错误标志、根据页号选择相应的flash块
//2 写入若干个字
// (1)将源地址的一个字写入目标地址
// (2)向命令寄存器写字写入命令
// (3)在加高压期间,调用RAM区的机器码,相当于两条语句:
// FSTAT=0x08;
// while(!(FSTAT&0x40));
// (4)源地址和目标地址同时向后移一个字
uint m;
Erase_Write_Pretreat(page); //擦写子函数共同调用的内部子函数
PPAGE = page; //设置页寄存器
for (m=0; m<len; m++)
{
*(uint *)address_destination = *(uint *)address_source;
FCMD = 0x20;
asm("CALL PrgOfRam");
address_destination = address_destination+2;
address_source = address_source+2;
}
}
//-------------------------------------------------------------------------*
//Flash_Erase_Nsector:擦除多个扇区-----------------------------------------*
//功 能:以len个字为依据计算所需擦除的扇区量 *
//参 数:page--页映射地址(0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F) *
// address_destination--目标扇区首地址(偶数) *
// len--字节数 *
//返 回:无 *
//注 意:此函数可擦除多扇区(一页),但须保证最后一个字不 *
// 能超出指定页,即地址不能大于0xBFFE * *
//-------------------------------------------------------------------------*
void Flash_Erase_Nsector(uchar page,uint address_destination,uint len)
{
//1 判断是否已分频、清相关错误标志、根据页号选择相应的flash块
//2 计算要存储数据所占用地址的扇区量
//3 擦除扇区
uchar Fi,Fn;
Erase_Write_Pretreat(page);
if(len%256==0)
Fn=len/256;
else
Fn=len/256+1;
if(Fn==0) return;
for(Fi=0x00;Fi<Fn;Fi++)
{
Flash_Erase_Sector(page,(address_destination+512*Fi));
}
}
//-------------------------------------------------------------------------*
//Erase_Write_Pretreat:开始擦除或写入前的公共操作序列子函数----------------*
//功 能:判断是否已分频;清相关错误标志;根据页号选择相应的flash块;如果页号不*
// 为0,则设置PPAGE寄存器 *
//参 数:page--页映射地址(0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F) *
//返 回:无 *
//-------------------------------------------------------------------------*
void Erase_Write_Pretreat(uchar page)
{
//1 判断是否设置时钟分频,若无分频,则先分频
//2 清保护错误和访问错误标志位
//3 查表、选择块号
uchar i,j;
if ((FCLKDIV&0x80) == 0)
FCLKDIV |= 0x4A; //设置分频系数
FCNFG |= 0x01; //FCNFG的第0位置1,选择BLOCK1
FSTAT |= 0x30; //清保护错误和访问错误标志位
FCNFG &= 0xFE; //FCNFG的第0位置0,选择BLOCK0
FSTAT |= 0x30; //清保护错误和访问错误标志位
if (page != 0)
{
for (i = 0;i < 2;i++)
{
for (j = 0;j < 4;j++)
{
if (page == pagetable[i][j])
break;
}
if (j < 4)
break;
}
if (i == 0) FCNFG &= 0xFE; //页号3C~3F,选择BLOCK0
if (i == 1) FCNFG |= 0x01; //页号38~3B,选择BLOCK1
}
PPAGE=page;
}
//-------------------------------------------------------------------------*
//Flash_Read_Sector:读指定Flash地址中的内容--------------------------------*
//功 能:读取指定页号为page,首地址为addr的连续len个字节,写入到ch[]数组中 *
//参 数:page--页映射地址(0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F) *
// addr--源目标首地址 *
// ch[]--目标首地址 *
// len --字节个数 *
//返 回:无 *
//注 意:FLASH存储区的两个字节表示一个字 *
//-------------------------------------------------------------------------*
void Flash_Read_Sector(uchar page,uint addr,uint ch[],uint len)
{
uint m;
uchar i,j;
if (page != 0)
{
for (i = 0;i < 2;i++)
{
for (j = 0;j < 4;j++)
{
if (page == pagetable[i][j])
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -