📄 iap_sstmcu.c
字号:
/***********************************************************************************************************
* IAP_SSTMCU.c - SST89X564/554 SST89X516/58/54/52RD2的IAP在使用中编程的常用函数
* 弘微科技(SPAC) 田伯运
* WEB: www.spacltd.com.cn TEL:0755-26010579 E-MAIL:andy.tian@spacltd.com.cn
* 功能介绍:
* SST的MCU内部FLASH的基本操作函数,包括扇区擦除,字节编程,字节校验等常用基本函数,
* 还有三个外部常用到的数据存储的函数(不用考虑具体FLASH的操作命令,注意要将IAP_SSMCU.C文件加入到你的项目中即可):
* 1. modify_single_byte_flash(ADDR,DATA)函数便可对指定的FLASH单元的内容进行改写;
* 2. modify_multi_byte_flash(begin_ADDR,counter,DATA_array)函数便可对指定起始地址的多个FLASH单元的内容进行改写;
* 3. Flash_byte_read(Address); 读FLASH地址单元内容的函数
* 从而很简单的实现数据存储等功能.
***********************************************************************************************************/
#include <SST89x5xxRD2.H> //加入SST MCU单片机的头文件,这样就剩去了许多的特殊寄存器的声明
#include <stdio.h>
/***********************************************************************************************************
* 设置SST单片机的型号:是52-58,还是516/564?因其BLOCK1的地址是不同的
***********************************************************************************************************/
#define SST89X5XRD 0 //判断MCU的容量,SST89X5XRD=1:是52-58RD的,BLOCK1的地址:0E000H-0FFFFH
//SST89X5XRD=0:是516/564RD的,BLOCK1的地址:01000H-01FFFH
#define DATAFLASH_BLOCK1 1 //DATAFLASH_BLOCK1=1:选择是DATA存放在BLOCK1存储区域
//DATAFLASH_BLOCK1=0:选择是DATA存放在BLOCK0存储区域
/***********************************************************************************************************
* 定义 SST单片机的各种IAP命令
***********************************************************************************************************/
#define SFCM_SE 0x0B; /* 扇区擦除命令字(Sector-Erase)为0X0B */
#define SFCM_VB 0x0C; /* 字节校验命令字(Byte-Verify)为0X0C */
#define SFCM_PB 0x0E; /* 字节校验命令字(Byte-Program)为0X0E */
/***********************************************************************************************************
* Function Prototype,用到的函数声明
***********************************************************************************************************/
void Flash_sector_erase(unsigned short int dataAddr); //扇区擦除函数,擦除的地址为dataAddr
void Flash_byte_program(unsigned short int dataAddr, unsigned char dataByte);//字节编程函数
bit modify_single_byte_flash(unsigned short int dataAddr,unsigned char dataByte);//修改一个FLASH地址单元的内容
bit modify_multi_byte_flash(unsigned int Begin_Addr, unsigned char counter, unsigned int array[]);//修改多个FLASH地址单元的内容
unsigned char Flash_byte_read(unsigned short int dataAddr); //字节校验函数
unsigned char ready(); //检查是否擦除或编程的操作是否已经完成
void error(); //超时错误
/**************************** SST单片机的IAP函数 **********************************************/
/***********************************************************************************************************
* 扇区擦除函数--Flash_sector_erase(unsigned short int dataAddr)
* 输入参数: dataAddr---擦除的扇区地址
***********************************************************************************************************/
void Flash_sector_erase(unsigned short int dataAddr)
{
unsigned short int Dest_Addr = dataAddr;
SFCF = SFCF | 0x40; // SFCF.6=1: IAP功能使能
SFAH = Dest_Addr>>8; // 将扇区地址的高8位装入FLASH的高8位地址寄存器(SFAH)中
SFAL = Dest_Addr; // 将扇区地址的低8位装入FLASH的低8位地址寄存器(SFAL)中
SFCM = SFCM_SE; // 在FLASH的命令寄存器(SFCM)中填入扇区擦除命令--SFCM_SE=0X0B
SFAL = Dest_Addr; // 将扇区地址的低8位装入FLASH的低8位地址寄存器(SFAL)中
if(!ready()) // 等待擦除完毕
error(); // 等待超时--错误
SFCF = SFCF & ~0x40; // SFCF.6=0: IAP功能禁止
return;
}
/***********************************************************************************************************
* 字节编程函数---Flash_byte_program()
* 输入参数: dataAddr---编程的字节地址
* 输入参数: dataByte---编程的数据
***********************************************************************************************************/
void Flash_byte_program(unsigned short int dataAddr, unsigned char dataByte)
{
unsigned short int Dest_Addr = dataAddr;
SFCF = SFCF | 0x40; // SFCF.6=1: IAP功能使能
SFAH = Dest_Addr>>8; // 将扇区地址的高8位装入FLASH的高8位地址寄存器(SFAH)中
SFAL = Dest_Addr; // 将扇区地址的低8位装入FLASH的低8位地址寄存器(SFAL)中
SFDT = dataByte; // 在FLASH的数据寄存器(SFDT)中填入编程的数据--dataByte
SFCM = SFCM_PB; // 在FLASH的命令寄存器(SFCM)中填入字节编程命令--SFCM_PB=0X0E
if(!ready()) // 等待编程完毕
error(); // 等待超时--错误
SFCF = SFCF & ~0x40; // SFCF.6=0: IAP功能禁止
return;
}
/***********************************************************************************************************
* 字节校验读函数---Flash_byte_read()
* 输入参数: dataAddr---校验读的字节地址
* 返回参数: readByte---读出的单元数值
***********************************************************************************************************/
unsigned char Flash_byte_read(unsigned short int dataAddr)
{
unsigned short int Dest_Addr = dataAddr;
unsigned char readByte;
SFCF = SFCF | 0x40; // SFCF.6=1: IAP功能使能
SFAH = Dest_Addr>>8; // 将扇区地址的高8位装入FLASH的高8位地址寄存器(SFAH)中
SFAL = Dest_Addr; // 将扇区地址的低8位装入FLASH的低8位地址寄存器(SFAL)中
SFCM = SFCM_VB; // 在FLASH的命令寄存器(SFCM)中填入字节校验命令--SFCM_PB=0X0E
readByte = SFDT; // 取得读到的单元数据
SFCF = SFCF & 0xBF; // SFCF.6=0: 关闭IAP功能
SFDT = 0;
return readByte; //返回读到的数据
}
/***********************************************************************************************************
* 检查IAP操作是否完成函数---ready()
* 输入参数: 无
* 返回参数: 1--IAP操作(FLASH擦除或字节编程)完成成功标志
* 0--IAP操作超时错误退出
***********************************************************************************************************/
unsigned char ready()
{
unsigned int TimeOut = 0;
while (TimeOut < 10000) //要设的等待时间足够长,否则有些芯片的擦除时间可能不够,引起错误的编程信息.
{
if ((SFST&4) == 0) //SFST.2=0:IAP操作完成
{
SFCF = SFCF & 0xBF; //IAP操作完成,关闭IAP功能--SFCF.6=0
SFDT = 0;
return 1; //返回成功标志--1
}
TimeOut++;
}
SFCF = SFCF & 0xBF; //时间超时,关闭IAP功能--SFCF.6=0
SFDT = 0; /*any value other than 0x55*/
return 0; //返回失败标志--0
}
/***********************************************************************************************************
* IAP操作失败指示函数,
***********************************************************************************************************/
void error()
{
//ErrorCode=1; //置IAP失败标志--ErrorCode=1
//LED_ERR=0; //点亮错误灯,关闭成功灯,表示编程出错失败.
//LED_OK=1;
while(1) //程序停止
{}
}
/***********************************************************************************************************
* 字节编程函数---modify_single_byte_flash()
* 输入参数: dataAddr---编程的字节地址
* 输入参数: dataByte---编程的数据
***********************************************************************************************************/
bit modify_single_byte_flash(unsigned int dataAddr, unsigned char dataByte)
{
unsigned int xdata Flash_addr; // = dataAddr+DATAFLASH_ADDR_START; //将FLASH的DATA存储地址由原来的相对地址转换为具体芯片的FLASH绝对地址
unsigned int xdata Addr_Sector; // = Dest_Addr & 0xff80; //要修改数据所站的扇区的起始地址
unsigned char xdata temp,counter=0x80; //作为计数器,一个扇区
unsigned char xdata Sector_Buffer[0x80]; //定义内部扩展RAM的0x80个单元作为一个扇区数据的缓冲区
#if SST89X5XRD //如果是SST89X52-58,BLOCK1在0XE000--0XFFFF区间
Flash_addr = dataAddr+0xe000; //且当前的BOOT CODE处于BLOCK0,IAP编程的范围只能在BLOCK1的0xe000-0xffff范围内
#else //如果是SST89X516/564,BLOCK1在0X1000--0X1FFF区间
Flash_addr = dataAddr+0x0000; //且当前的BOOT CODE处于BLOCK0,IAP编程的范围只能在BLOCK1的0x1000-0x1fff范围内
#endif
if(dataByte==(dataByte&(Flash_byte_read(Flash_addr)))) //如果要写的单元原来内容只需1->0的过程,而没有0->1的过程,
{ //就不用擦除整个扇区,而只需使用字节编程命令即可,减少FLASH的擦写次数,延长FLASH的使用寿命
Flash_byte_program(Flash_addr,dataByte);
if (dataByte==Flash_byte_read(Flash_addr)) return 1; //读出的数据等于要写的数据,返回1
else return 0; //读出的数据不等于要写的数据,返回0
}
else //如果有0->1的过程,就必须进行扇区擦除,将整个扇区的内容,重新写一遍.
temp = AUXR; //暂存AUXR辅助寄存器.以便用完128个RAM的BUFFER后恢复.
AUXR = 0x00; //使用SST89E516内部的768 RAM,EXRAM=0,
Addr_Sector = Flash_addr & 0xff80; //计算出要修改数据所站的扇区的起始地址
counter=0x80; //一个扇区有128个存储单元,
for (counter=0;counter<0x80;counter++) //读一个扇区(128个字节)的内容到扩展RAM缓冲区中
{
Sector_Buffer[counter]=Flash_byte_read(Addr_Sector);
Addr_Sector++;
}
Sector_Buffer[Flash_addr&0x007f]=dataByte; //在RAM缓冲区中写入新的修改后数据
Addr_Sector=Flash_addr&0xff80; //重新置要修改扇区的首地址
Flash_sector_erase(Addr_Sector); //将这个要修改单元所在的扇区进行全部擦除
for (counter=0;counter<0x80;counter++) //将修改后的扇区内容重新写回到这个扇区内
{
Flash_byte_program(Addr_Sector,Sector_Buffer[counter]); //对扇区中的单元写入一个扇区更改后的内容
Addr_Sector++; //指向下一个地址单元
}
AUXR = temp; //恢复为占用前的AUXR
if (dataByte==Flash_byte_read(Flash_addr)) return 1; //读出的数据等于要写的数据,返回1
else return 0; //读出的数据不等于要写的数据,返回0
}
/*-----------------------------------------------------------------------------------*/
/* 修改多个单元的Flash存储器内容, 只在同一个扇区内写,保留同一扇区中不需修改的数据 */
/* Begin_Addr,被写数据Flash开始地址;counter,连续写多少个字节; array[],数据来源 */
/*-----------------------------------------------------------------------------------*/
bit modify_multi_byte_flash(unsigned int Begin_Addr, unsigned char counter, unsigned int array[])
{
unsigned int xdata Dest_Addr,Flash_addr; // = dataAddr+DATAFLASH_ADDR_START; //将FLASH的DATA存储地址由原来的相对地址转换为具体芯片的FLASH绝对地址
unsigned int xdata Addr_Sector,Addr_Flash; // = Dest_Addr & 0xff80; //要修改数据所站的扇区的起始地址
unsigned char xdata temp,i;//,counter=0x80; //作为计数器,一个扇区
unsigned char xdata Sector_Buffer[0x80]; //定义内部扩展RAM的0x80个单元作为一个扇区数据的缓冲区
#if SST89X5XRD //如果是SST89X52-58,BLOCK1在0XE000--0XFFFF区间
Flash_addr = Begin_Addr+0xe000; //且当前的BOOT CODE处于BLOCK0,IAP编程的范围只能在BLOCK1的0xe000-0xffff范围内
#else //如果是SST89X516/564,BLOCK1在0X1000--0X1FFF区间
Flash_addr = Begin_Addr+0x0000; //且当前的BOOT CODE处于BLOCK0,IAP编程的范围只能在BLOCK1的0x1000-0x1fff范围内
#endif
if(counter > 0x80) return 0; //只允许最大是一个扇区(0x80=128个字节)空间的数据修改
if((Flash_addr&0x007f+counter) > 0x80) return 0; //修改的起始地址+修改的个数也不能超过一个扇区(128字节)的数目
temp = AUXR; //暂存AUXR辅助寄存器.以便用完128个RAM的BUFFER后恢复.
AUXR = 0x00; //使用SST89E516内部的768 RAM,EXRAM=0,
Addr_Sector = Flash_addr & 0xff80; //计算出要修改数据所站的扇区的起始地址
//--------------第1步:读一个扇区(128个字节)的内容到扩展RAM缓冲区中--------------
Addr_Flash=Flash_addr&0xff80; //置FLASH编程的地址指针
i=0x80; //一个扇区有128个存储单元,
for (i=0;i<0x80;i++) //读一个扇区(128个字节)的内容到扩展RAM缓冲区中
{
Sector_Buffer[i]=Flash_byte_read(Addr_Flash);
Addr_Flash++;
}
//--------------第2步:将要修改的内容写入扇区缓冲区内,共修改COUNTER个--------------
Dest_Addr=Flash_addr&0x007f; //转为一个扇区内的相对地址(只取低7位)
for (i=0;i<counter;i++) //将要修改的内容写入扇区缓冲区内,共修改COUNTER个
{
Sector_Buffer[Dest_Addr]=array[i]; //将要修改的内容写入扇区缓冲区的对应地址
Dest_Addr++; //指向下一个缓冲地址
}
//-------------第3步:擦除要修改地址所在的扇区---------------------------------------
Addr_Sector=Flash_addr&0xff80; //重新置要修改扇区的首地址
Flash_sector_erase(Addr_Sector); //将这个要修改单元所在的扇区进行全部擦除
//-------------第4步:将修改后的缓冲区内容重新写回到FLASH中--------------------------
Addr_Flash=Flash_addr&0xff80; //置FLASH编程的地址指针
for (i=0;i<0x80;i++) //将修改后的扇区内容重新写回到这个扇区内
{
Flash_byte_program(Addr_Flash,Sector_Buffer[i]); //对扇区中的单元写入一个扇区更改后的内容
if ((Flash_byte_read(Addr_Flash)) != Sector_Buffer[i]) //对刚写入的FLASH单元进行读出校验,
return 0; //如果不等于刚写入的内容,则错误返回
Addr_Flash++; //校验正确,指向下一个FLASH地址单元,继续FLASH编程
}
AUXR = temp; //恢复为占用前的AUXR
return 1; //整个扇区128个字节全部编程成功,返回1
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -