将ATmega48的FLASH当EEPROM用,成功了哈
ATmega48没有Boot Loader,所以只要编程SELFPRGEN熔丝,SPM指令就可以在整个FLASH空间执行。也就是说可以修改整个FLASH空间。
#include<iom48v.h>
const char data1[];
char data; //M48的FLASH一页的大小为64B
void SDELFLASH(unsigned char page,unsigned char x);//选译性删除FLASH页
void WFLASH2B(unsigned int add,unsigned char data1,unsigned char data0); //写一字到缓冲区
void WFLASH(unsigned char page); //写一页
void RFLASH(unsigned char page); //读入一页
void Pdata(void); //改data[]中的内容
void IO_Init(void) //IO口初始化
{//I/O口
DDRB|=(1<<PB2)|(1<<PB1)|(0<<PB0);
//PB2=蓝色LED(OC1B)PB1=红色LED(OC1A) PB0=按键'左'
PORTB|=(0<<PB2)|(0<<PB1)|(1<<PB0);
//PC0-PC5 ADC
DDRC|=(1<<PC5)|(1<<PC4)|(1<<PC3)|(1<<PC2)|(1<<PC1)|(1<<PC0);
PORTC|=(0<<PC5)|(0<<PC4)|(0<<PC3)|(0<<PC2)|(0<<PC1)|(0<<PC0);
//PD6=RESET RS232 PD7=按键'右'
DDRD|=(1<<PD6)|(0<<PD7);
PORTD|=(1<<PD6)|(1<<PD7);
}
void main(void)
{
IO_Init();
PORTC|=(1<<5);
RFLASH(60); //读这页FLASH内容,读到data[]
Pdata(); //修改data[]的内容
WFLASH(60); //写这页FLASH内容,data[]写到FLASH
while(1);
}
///////////////////////////////////////////////////////////////
void Pdata(void) //改data[]中的内容
{ unsigned char n;
for(n=0;n<64;n++)
data=data+1;//全加1
}
///////////////////FLASH操作////////////////////////////////////
void RFLASH(unsigned char page) //读入一页data[]
{ unsigned char Dzh,Dzl,n,da; unsigned int add;
add=page*64;
for(n=0;n<64;n++)
{ Dzh=add>>8; Dzl=add;
asm("MOV R31,%Dzh");//ZHFlash地址
asm("MOV R30,%Dzl");//ZL
asm("LPM %da,Z");
data=da;
add++;
}
}
////////////////////////////////////////////////////////////////
void SDELFLASH(unsigned char page,unsigned char x) //选译性删除FLASH程序
{ //page为要删除的页码,x为要删除的页数
unsigned char n,dpageh; unsigned int dpage;
dpage=page*64;
for(n=0;n<x;n++)
{dpageh=dpage>>8;
asm("MOV R31,%dpageh");//ZHFlash地址
asm("MOV R30,%dpage");//ZL
SPMCSR=(1<<1)|(1<<0);
asm("SPM");
dpage+=64;}
}
////////////////////////////////////////////////////////
void WFLASH(unsigned char page) //写入一页
{unsigned char n; unsigned int add;
add=page*64;
for(n=0;n<32;n++) //将数据写入这页缓冲区
{
WFLASH2B(add,data,data);
add+=2;
}
SDELFLASH(page,1);//擦除这页FLASH
SPMCSR=0b00000101;//写这页FLASH
asm("SPM");
}
//////////////////////////////////////////////////////////////////////////
//将一个字写入缓冲区
void WFLASH2B(unsigned int add,unsigned char data1,unsigned char data0)
{unsigned char Dzh,Dzl;
Dzh=add>>8; Dzl=add;
asm("MOV R0,%data1");
asm("MOV R1,%data0");
asm("MOV R31,%Dzh");//ZHFlash地址
asm("MOV R30,%Dzl");//ZL
SPMCSR=(1<<0);
asm("SPM");}
////////////////////////////////////////////////////////////////////////
/////0xF00=38403840/64=60 第60页
#pragma abs_address:0xF00
const char data1[]="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
#pragma end_abs_address
http://cache.amobbs.com/bbs_upload782111/files_27/ourdev_539588.PNG
(原文件名:写入的数据)
http://cache.amobbs.com/bbs_upload782111/files_27/ourdev_539589.PNG
(原文件名:将数字读出后,+1处理,再写回去) mark 马克... 又见高手 您是说flash可以在应用程序中修改?我只测试可以自宫,但是没想到这么用,哈哈
C语言看不太懂,最终您测试写入的程序是这个引号中的部分么?
const char data1[]="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
那把您的思维拓展一下,我们可以用指针指向运算后的RAM区,把各种加密后的运算结果保存到Flash中,比如开始写一段自宫程序用来加密运算某密值,保存到Ram中再以一段表格的形式写回Flash;最后加密段自宫,程序投入使用。
不定期用算法校验Flash表,如果表有误则随机跳转乱执行./emotion/em035.gif,不要执行SPM,SPM命令太容易通过反汇编屏蔽掉了。
我以前的作法是把密表放在EP中。放在ep中有缺点,就是数据的安全性有点玄……而且可以通过不断修改ep内容测试加密方式和内联的运算关系。
随口乱说,请勿拍砖…… 记号 我将这些字符串放在首地址为0xF00 也就是FLASH空间的第60页
const char data1[]="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
这个完全可以不需要的
你也可以这么用,定义个数组data
然后送值给它,然后就可以直接写到FLASH了。
数据写入data[]后,执行 WFLASH(60); 就行了,这里的参数60表示FLASH空间的第60页,一页大小为64字节。
我上面写着
RFLASH(60); //读这页FLASH内容,读到data[]
Pdata(); //修改data[]的内容
WFLASH(60); //写这页FLASH内容,data[]写到FLASH
主要是为了只改其中的一部分,如一个字节,但FLASH要修改就要先擦除后才行,而擦除是以页为单位的。
因此要先读出来,防止无关数据丢失。 谢谢共享! mark,
但是FLASH的擦写次数很有限啊 mark 学习 高手!学习了! 马克 先收藏,以后肯定会有用,十分感谢! 顶,强顶哇 mark mark 顶,有用的东东,不知道有没有弊端 mark B向北走,NB,哈哈。 要是硬件支持分页写保护就好了,这样完全没保护的话用起来比较危险 mark MARK,,DING... mark 程序里有写FLASH操作时,记得开BOD。要不然AVR可能会自宫。 mark mark mark 啊……这让我想到了STC…… 牛人 强人,进来膜拜一下。 很有用的功能,但同时也是灰常灰常灰常危险滴。
不到万不得已,还是慎用。 牛A 和 牛C中间那个就是你 马克.m48.............. Nb 留个记号 mark MARK 先收藏,以后肯定会有用,十分感谢! 楼主我怎么编译通不过啊?用的是ICC6.31A
提示:
!W D:\avr_flash\flash.c(45): local variable 'da' has no initial value
!E D:\avr_flash\flash.c(86): Register not allocated to variable data0? referenced in inline asm. Please simplify function or delete reference in inline asm.D:\icc\bin\imakew.exe: Error code 1
Done: there are error(s). Exit code: 1
不知为什么.请解答.谢谢! 我没这种问题啊,有可能是 da,data0 这两个变量定交到RAM区了,所以不行。
dzh,dzl,da,data0等有被汇编代码用到的变量都在是放在寄存器上,如果在RAM上汇编代码就不能这么写了。
所以在dzh,dzl,da,data0等变量前加入register试下看
如:register unsigned char Dzh,Dzl,da; 请问楼主QQ是多少?按你说的我还是没调好,依然提示有错误。请一定告知。谢谢! mark~ 总感觉这玩意很危险,抗干扰不过关的话,不定哪天就自裁了,研究研究很有意思,产品里要用,还要多加考虑。 mark!
演示版本该自宫的时候就自宫啊。 【41楼】 221008
你确定都改好了?这个试下看,
#include<iom48v.h>
const char data1[];
unsigned char data; //M48的FLASH一页的大小为64B
void SDELFLASH(unsigned char page,unsigned char x);//选译性删除FLASH页
void WFLASH2B(unsigned int add,register unsigned char data1,register unsigned char data0); //写一字到缓冲区
void WFLASH(unsigned char page); //写一页
void RFLASH(unsigned char page); //读入一页
void Pdata(void); //改data[]中的内容
void main(void)
{
RFLASH(60); //读这页FLASH内容,读到data[]
Pdata(); //修改data[]的内容
WFLASH(60); //写这页FLASH内容,data[]写到FLASH
while(1);
}
///////////////////////////////////////////////////////////////
void Pdata(void) //改data[]中的内容
{ unsigned char n;
for(n=0;n<64;n++)
data=data+1;//全加1
}
///////////////////FLASH操作////////////////////////////////////
void RFLASH(unsigned char page) //读入一页data[]
{ unsigned char n; unsigned int add;
register unsigned char Dzh,Dzl,da;
add=page*64;
for(n=0;n<64;n++)
{ Dzh=add>>8; Dzl=add;
asm("MOV R31,%Dzh");//ZHFlash地址
asm("MOV R30,%Dzl");//ZL
asm("LPM %da,Z");
data=da;
add++;
}
}
////////////////////////////////////////////////////////////////
void SDELFLASH(unsigned char page,unsigned char x) //选译性删除FLASH程序
{ //page为要删除的页码,x为要删除的页数
register unsigned char n,dpageh; register unsigned int dpage;
dpage=page*64;
for(n=0;n<x;n++)
{dpageh=dpage>>8;
asm("MOV R31,%dpageh");//ZHFlash地址
asm("MOV R30,%dpage");//ZL
SPMCSR=(1<<1)|(1<<0);
asm("SPM");
dpage+=64;}
}
////////////////////////////////////////////////////////
void WFLASH(unsigned char page) //写入一页
{unsigned char n; unsigned int add;
add=page*64;
for(n=0;n<32;n++) //将数据写入这页缓冲区
{
WFLASH2B(add,data,data);
add+=2;
}
SDELFLASH(page,1);//擦除这页FLASH
SPMCSR=0b00000101;//写这页FLASH
asm("SPM");
}
//////////////////////////////////////////////////////////////////////////
//将一个字写入缓冲区
void WFLASH2B(unsigned int add,register unsigned char data1,register unsigned char data0)
{register unsigned char Dzh,Dzl;
Dzh=add>>8; Dzl=add;
asm("MOV R0,%data1");
asm("MOV R1,%data0");
asm("MOV R31,%Dzh");//ZHFlash地址
asm("MOV R30,%Dzl");//ZL
SPMCSR=(1<<0);
asm("SPM");}
////////////////////////////////////////////////////////////////////////
/////0xF00=38403840/64=60 第60页
#pragma abs_address:0xF00
const char data1[]="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
#pragma end_abs_address 嗯,要是有一天写坏了,芯片也就跟着坏了,得不偿失 【43楼】 elecboy
其实不需要当心的,程序跑飞的可能性很小,在执行SPM指令之前加入分支指令,如果程序跑飞到这随近也不怕。(除非刚好跑飞到SPM指令上)
而且只要带有自动更新的产品,都有擦写FLASH的程序。他们都不当心,我们当心什么? 擦写不要太频繁,FLASH的寿命只有EEPROM的十分之一。
FLASH坏也不可能都坏掉的,只是坏掉几个字节而以,写程序的时候绕开这些坏的字节就行了,就是麻烦。
不过芯片照样用。 Mark! mark 回家试一下 牛 !!!收藏了 !!! 楼主,我将以面程序中的:asm("MOV R1,%data0"); 改为:asm("MOV R1,%data1"); 就可以编译通过了.
末改的原程序为:
void WFLASH2B(unsigned int add,register unsigned char data1,register unsigned char data0)
{register unsigned char Dzh,Dzl;
Dzh=add>>8; Dzl=add;
asm("MOV R0,%data1");
asm("MOV R1,%data0");
asm("MOV R31,%Dzh");//ZHFlash地址
asm("MOV R30,%Dzl");//ZL
SPMCSR=(1<<0);
asm("SPM");}
这是为什么呢? mark 【53楼】 221008
怪...试下用其它变量代下看,改三句如:
void WFLASH2B(unsigned int add,unsigned char data1,unsigned char abc); //写一字到缓冲区
....
void WFLASH2B(unsigned int add,register unsigned char data1,register unsigned char abc)
.....
asm("MOV R1,%abc");
..... mark 我顶! mark 请问在iar avr里面以下代码应该怎么写:
Dzh=add>>8; Dzl=add;
asm("MOV R0,%data1");
asm("MOV R1,%data0");
asm("MOV R31,%Dzh");//ZHFlash地址
asm("MOV R30,%Dzl");//ZL
才能让上面的程序编译通过.
注:以上为ICCAVR可以编译的程序. Atmega8515是否可以这样操作? 可以的,只是要把程序放在BOOT区,程序应该也有点差别,没试过,看数据手册吧。 看过资料,SPM指令在应用程序区是无效的,将这“应用”程序定位到BOOT区是否可行? 应该是可以的,不知道软件支不技持,ICCAVR可以选译放在哪里。
#pragma abs_address:0xF00//地址
//程序
#pragma end_abs_address 好 mark 记录 mark mark mark mark ... mark mark 为什么我把上面的例子程序改程mega32的,软件模拟可以,但是实际写入芯片jtag调试和运行,却不行,反映的情况是擦除不掉和不能写入,软件模拟时SPMCR 置数后,指令 asm("SPM") 可以清零SPMCR ,jtag调试看到的却是SPMCR 置数后,指令 asm("SPM")不能清零SPMCR,SPMCR 还是原来的数,I_Automate_Out寄存器是外部输出指示灯,第一个数据没改时,是原来的00时第一个等亮,更改成功不是00时第二个灯亮,用来指示实际运行时的状态,原来我以为,是jtag调试时,是不能更改flash,实际运行也是一样是第一个灯亮就是还是00没有更改成功
#include <iom32.h>
#define N_Isp_PageStart 60 //开始页
#define N_Isp_PageSize 128 //一页字节数
static uint8 I_Isp_Buffer; //M48的FLASH一页的大小为64B
__regvar __no_init uint8 Reg_12 @ 12;
__regvar __no_init uint8 Reg_13 @ 13;
__regvar __no_init uint8 Reg_14 @ 14;
__regvar __no_init uint8 Reg_15 @ 15;
////////////////////////////////////////////////////////////////////////
__root__flash uint8 I_Isp_Rom@(N_Isp_PageStart*N_Isp_PageSize) ={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
uint8 fff = 0;
void SDELFLASH(uint8 page,uint8 x);//选译性删除FLASH页
void WFLASH2B(uint16 add,uint8 data1,uint8 data0); //写一字到缓冲区
void WFLASH(uint8 page); //写一页
void RFLASH(uint8 page); //读入一页
void Pdata(void); //改data[]中的内容
void main(void)
{
while(1)
{
if(fff==0x0)
{
RFLASH(N_Isp_PageStart); //读这页FLASH内容,读到data[]
if(I_Isp_Rom == 0)
{
I_Automate_Out = ~0x2;
Pdata(); //修改data[]的内容
WFLASH(N_Isp_PageStart); //写这页FLASH内容,data[]写到FLASH
RFLASH(N_Isp_PageStart); //读这页FLASH内容,读到data[]
if(I_Isp_Rom == 1)
{
I_Automate_Out = ~0x8;
}
else
{
I_Automate_Out = ~0x2;
}
}
else
{
I_Automate_Out = ~0x8;
}
//fff++;
}
else
{
fff = 0xff;
}
OSTimeDly(N_Isp_rwxmys); //任务休眠时间
}
}
///////////////////////////////////////////////////////////////
void Pdata(void) //改data[]中的内容
{ uint8 n;
for(n=0;n<N_Isp_PageSize;n++)
I_Isp_Buffer=I_Isp_Buffer+1;//全加1
}
///////////////////FLASH操作////////////////////////////////////
void RFLASH(uint8 page) //读入一页data[]
{
uint8 n; uint16 add;
add=page*N_Isp_PageSize;
for(n=0;n<N_Isp_PageSize;n++)
{
asm ("cli");
Reg_13=add>>8;
Reg_14=add;
asm("MOV R31,R13");//ZHFlash地址
asm("MOV R30,R14");//ZL
asm("LPM R15,Z");
I_Isp_Buffer=Reg_15;
asm ("sei");
add++;
}
}
////////////////////////////////////////////////////////////////
void SDELFLASH(uint8 page,uint8 x) //选译性删除FLASH程序
{ //page为要删除的页码,x为要删除的页数
uint8 n,dpageh;
uint16 dpage;
dpage=page*N_Isp_PageSize;
for(n=0;n<x;n++)
{
dpageh=dpage>>8;
asm ("cli");
Reg_14 = dpageh;
Reg_15 = dpage;
asm("MOV R31,R14");//ZHFlash地址
asm("MOV R30,R15");//ZL
SPMCR=(1<<1)|(1<<0);
asm("SPM");
asm ("sei");
dpage+=N_Isp_PageSize;
}
}
////////////////////////////////////////////////////////
void WFLASH(uint8 page) //写入一页
{
uint8 n;
uint16 add;
uint8 zjs;
while(SPMCR & 0x01 != 0 );//未处理好死循环
{
add = page*N_Isp_PageSize;
zjs = N_Isp_PageSize/2;
for(n=0;n<zjs;n++) //将数据写入这页缓冲区
{
WFLASH2B(add,I_Isp_Buffer,I_Isp_Buffer[(n*2)+1]);
add += 2;
}
SDELFLASH(page,1);//擦除这页FLASH
asm ("cli");
SPMCR = (1<<2)|(1<<0);//写这页FLASH
asm("SPM");
asm ("sei");
}
}
//////////////////////////////////////////////////////////////////////////
//将一个字写入缓冲区
void WFLASH2B(uint16 add,uint8 data1,uint8 data0)
{
asm ("cli");
Reg_12 = add>>8;
Reg_13 = add;
Reg_14 = data1;
Reg_15 = data0;
asm("MOV R0,R14");
asm("MOV R1,R15");
asm("MOV R31,R12");//ZHFlash地址
asm("MOV R30,R13");//ZL
SPMCR=(1<<0);
asm("SPM");
asm ("sei");
} 忘了说了,上面的程序是已经改成在IAR上运行了 改成单独的工程文件,上面那个程序是整个程序里拷出来的
#include <iom32.h>
#define N_Isp_PageStart 60 //开始页
#define N_Isp_PageSize 128 //一页字节数
__regvar __no_init unsigned char Reg_12 @ 12;
__regvar __no_init unsigned char Reg_13 @ 13;
__regvar __no_init unsigned char Reg_14 @ 14;
__regvar __no_init unsigned char Reg_15 @ 15;
unsigned char I_Isp_Buffer; //M48的FLASH一页的大小为64B
////////////////////////////////////////////////////////////////////////
__root__flash unsigned char I_Isp_Rom@(N_Isp_PageStart*N_Isp_PageSize) ={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
unsigned char fff = 0;
void SDELFLASH(unsigned char page,unsigned char x);//选译性删除FLASH页
void WFLASH2B(unsigned int add,unsigned char data1,unsigned char data0); //写一字到缓冲区
void WFLASH(unsigned char page); //写一页
void RFLASH(unsigned char page); //读入一页
void Pdata(void); //改data[]中的内容
int main(void)
{
while(1)
{
if(fff==0x0)
{
RFLASH(N_Isp_PageStart); //读这页FLASH内容,读到data[]
if(I_Isp_Rom == 0)
{
//I_Automate_Out = ~0x2;
Pdata(); //修改data[]的内容
WFLASH(N_Isp_PageStart); //写这页FLASH内容,data[]写到FLASH
RFLASH(N_Isp_PageStart); //读这页FLASH内容,读到data[]
if(I_Isp_Rom == 1)
{
//I_Automate_Out = ~0x8;
}
else
{
//I_Automate_Out = ~0x2;
}
}
else
{
//I_Automate_Out = ~0x8;
}
//fff++;
}
else
{
fff = 0xff;
}
}
}
///////////////////////////////////////////////////////////////
void Pdata(void) //改data[]中的内容
{ unsigned char n;
for(n=0;n<N_Isp_PageSize;n++)
I_Isp_Buffer=I_Isp_Buffer+1;//全加1
}
///////////////////FLASH操作////////////////////////////////////
void RFLASH(unsigned char page) //读入一页data[]
{
unsigned char n; unsigned int add;
add=page*N_Isp_PageSize;
for(n=0;n<N_Isp_PageSize;n++)
{
asm ("cli");
Reg_13=add>>8;
Reg_14=add;
asm("MOV R31,R13");//ZHFlash地址
asm("MOV R30,R14");//ZL
asm("LPM R15,Z");
I_Isp_Buffer=Reg_15;
asm ("sei");
add++;
}
}
////////////////////////////////////////////////////////////////
void SDELFLASH(unsigned char page,unsigned char x) //选译性删除FLASH程序
{ //page为要删除的页码,x为要删除的页数
unsigned char n,dpageh;
unsigned int dpage;
dpage=page*N_Isp_PageSize;
for(n=0;n<x;n++)
{
dpageh=dpage>>8;
asm ("cli");
Reg_14 = dpageh;
Reg_15 = dpage;
asm("MOV R31,R14");//ZHFlash地址
asm("MOV R30,R15");//ZL
SPMCR=(1<<1)|(1<<0);
asm("SPM");
asm ("sei");
dpage+=N_Isp_PageSize;
}
}
////////////////////////////////////////////////////////
void WFLASH(unsigned char page) //写入一页
{
unsigned char n;
unsigned int add;
unsigned char zjs;
while(SPMCR & 0x01 != 0 );//未处理好死循环
{
add = page*N_Isp_PageSize;
zjs = N_Isp_PageSize/2;
for(n=0;n<zjs;n++) //将数据写入这页缓冲区
{
WFLASH2B(add,I_Isp_Buffer,I_Isp_Buffer[(n*2)+1]);
add += 2;
}
SDELFLASH(page,1);//擦除这页FLASH
asm ("cli");
SPMCR = (1<<2)|(1<<0);//写这页FLASH
asm("SPM");
asm ("sei");
}
}
//////////////////////////////////////////////////////////////////////////
//将一个字写入缓冲区
void WFLASH2B(unsigned int add,unsigned char data1,unsigned char data0)
{
asm ("cli");
Reg_12 = add>>8;
Reg_13 = add;
Reg_14 = data1;
Reg_15 = data0;
asm("MOV R0,R14");
asm("MOV R1,R15");
asm("MOV R31,R12");//ZHFlash地址
asm("MOV R30,R13");//ZL
SPMCR=(1<<0);
asm("SPM");
asm ("sei");
} mark mark mark 再顶 还是不行,是不是控制字熔丝还要设置 【81楼】 rafd
好久没玩这个了,都忘差不多了,M32应该把程序定义在boot loader空间,否则SPM无法执行。
还有注意M32的FLASH的页大小可能跟M48不一样大,具体看数据手册。
熔丝默认是可以读写FLASH的。 牛X,mark mark 留意一下 这个有意思,哈哈 牛,mark 楼主,【81楼】 rafd 你们好,我现在也是只能读出不能写入,在IAR下编译的,发现读出的数据是对的。但是自己修改数据写入后再重新读出发现读出的数据还是原来的 mark mark mark mark . 谢谢分享!
页:
[1]