LGT的基本写入/读出已经分析完成,下个星期回家后分析FUSE
这里仅仅是一个实例程序。用计数值填充LGT的整个FLASH空间的程序。现在已经做好串口ISP,可以上马/自制脱机编程器了。只是熔丝会有点稍稍的麻烦。这个是51代码。但是事实上只要更换IO操作函数是可以在别的机器上用的。
Test函数中有说明如何写入。
感谢bbsniua网友和goodcode的ISP(反汇编+逻辑分析仪发现退出编程的命令有点问题)以及官方ISP程序。
等到下次回家以后搞定熔丝位。毕竟现在熔丝位看起来很奇怪。貌似不是以明文形式表示的OSCCAL。
OK废话少说上代码:#include <hwconfig.h>//包含硬件配置
#include <type-def.h>//包含一些定义
BYTE OutBuf;//发送命令缓冲
BYTE InBuf;//接收缓冲
//BYTE ComBuf;// |SOT|CMD|Data(32bytes)|ChkSum|EOT|
void SendSPI(BYTE nByte)//用MOSI串行发送命令的同时用MISO接收相关数据
{
BYTE n;
for(n=0;n<nByte;n++)//发送nByte个字节
{
//RESET=0;
ACC=OutBuf;
SCLK=0;
MOSI=A_7;//低电平时输出一位
SCLK=1;
B_7=MISO;//高电平时接收一位
SCLK=0;
MOSI=A_6;
SCLK=1;
B_6=MISO;
SCLK=0;
MOSI=A_5;
SCLK=1;
B_5=MISO;
SCLK=0;
MOSI=A_4;
SCLK=1;
B_4=MISO;
SCLK=0;
MOSI=A_3;
SCLK=1;
B_3=MISO;
SCLK=0;
MOSI=A_2;
SCLK=1;
B_2=MISO;
SCLK=0;
MOSI=A_1;
SCLK=1;
B_1=MISO;
SCLK=0;
MOSI=A_0;
SCLK=1;
B_0=MISO;
SCLK=0;
InBuf=B;
//RESET=1;
}
}
void Delay(BYTE n)
{//不精确延时
while(n--);
}
BOOL CheckAck() //检查
{
if(InBuf!=0x55) return FALSE;
if(InBuf!=0xAA) return FALSE;
return TRUE;
}
BOOL Reset_Target()
{//重启目标
SCLK=0;
MOSI=0;
MISO=1;
Delay(1);
RESET=0;
Delay(255);
OutBuf=0xE0;//开启编程
OutBuf=0x5A;
OutBuf=0xA5;
OutBuf=0xAA;
OutBuf=0x00;
SendSPI(5);//发送数据
if(InBuf!=0x5A) return FALSE;
return TRUE;
}
void Read_8F08(BYTE Bank,BYTE Addr)
{
OutBuf=0xB8;
OutBuf=Addr;
OutBuf=Bank;
OutBuf=0x00;
OutBuf=0x00;
SendSPI(5);
OutBuf=0xBC;
SendSPI(5);
//And you got it in InBuf,InBuf
}
BOOL Write_8F08(BYTE Bank,BYTE Addr)
{
OutBuf=0x90;
OutBuf=0xC0 | Addr ;//B1000 0000 Or Addr
OutBuf=Bank;
//OutBuf
//OutBuf//送入数据
SendSPI(5);
if(!CheckAck()) return FALSE;
OutBuf=0x98;
SendSPI(5);
if(!CheckAck()) return FALSE;
OutBuf=0x90;
SendSPI(5);
if(!CheckAck()) return FALSE;
return TRUE;
}
BOOL Erase_8F08()
{
OutBuf=0xB8;
OutBuf=0x3F;
OutBuf=0x07;
OutBuf=0x00;
OutBuf=0x00;
SendSPI(5);
OutBuf=0xBC;
SendSPI(5);
OutBuf=0xA0;
OutBuf=0x00;
OutBuf=0x00;
SendSPI(5);
Delay(10);
//清除标志位,RDY
//----EARSE
OutBuf=0x93;
OutBuf=0x00;
OutBuf=0x00;
OutBuf=0x00;
OutBuf=0x00;
SendSPI(5);
if(!CheckAck()) return FALSE;
OutBuf=0x40;
SendSPI(5);
if(!CheckAck()) return FALSE;
Delay(255);Delay(255);Delay(255);Delay(255);
OutBuf=0x91;
SendSPI(5);
if(!CheckAck()) return FALSE;
OutBuf=0x00;
SendSPI(5);
if(!CheckAck()) return FALSE;
OutBuf=0x80;
SendSPI(5);
if(!CheckAck()) return FALSE;
Delay(255);//保险延时
return TRUE;
}
BOOL Prep_W8F08(BYTE Bank,BYTE Addr)
{
/*MOSI 90 80 00 00 00
MISO AA AA AA 55 AA
MOSI 90 C0 00 00 00
MISO AA AA AA 55 AA*/
OutBuf=0x90;
OutBuf=0x80 | Addr;
OutBuf=Bank;
OutBuf=0x00;
OutBuf=0x00;
SendSPI(5);
if(!CheckAck()) return FALSE;
//OutBuf=0x90;
OutBuf=0xC0 | Addr;
SendSPI(5);
if(!CheckAck()) return FALSE;
return TRUE;
}
BOOL Stop_W8F08(BYTE Bank,BYTE Addr)
{
/*MOSI 90 80 00 00 00
MISO AA AA AA 55 AA
MOSI 90 C0 00 00 00
MISO AA AA AA 55 AA*/
OutBuf=0x90;
OutBuf=Addr | 0x40;
OutBuf=Bank;
//OutBuf=0x00;
//OutBuf=0x00;
SendSPI(5);
if(!CheckAck()) return FALSE;
//OutBuf=0x90;
OutBuf=Addr;
SendSPI(5);
if(!CheckAck()) return FALSE;
OutBuf=0x80;
SendSPI(5);
if(!CheckAck()) return FALSE;
return TRUE;
}
void Stop_R8F08()
{
OutBuf=0xA0;
OutBuf=0x00;
OutBuf=0x00;
OutBuf=0x00;
OutBuf=0x00;
SendSPI(5);
}
void Test()
{
BYTE addr,page,cyc,test=0;
if(!Reset_Target()) return;
OutBuf=0xE5;
OutBuf=0x53;
OutBuf=0x35;
OutBuf=0x5E;
OutBuf=0x00;
SendSPI(5);
SendSPI(5);
//写8K
/*
if(!Erase_8F08()) return;
Delay(100);
for(page=0;page<=0x7F;page++)
{//
for(cyc=0;cyc<8;cyc++)
{
addr=0;
if(!Prep_W8F08(page,cyc*4)) return;
for(;addr<4;addr++)
{
OutBuf=test+1;
OutBuf=test;
test+=2;
if(!Write_8F08(page,cyc*4+addr)) return;
}
addr--;
if(!Stop_W8F08(page,cyc*4+addr)) return;
Delay(255);
}
Delay(255);
}
Delay(255);
*/
Delay(255);Delay(255);Delay(255);Delay(255);
Delay(255);Delay(255);Delay(255);Delay(255);
Delay(255);Delay(255);Delay(255);Delay(255);
Delay(255);Delay(255);Delay(255);Delay(255);
Delay(255);Delay(255);Delay(255);Delay(255);
//读8K
for(page=0;page<=0x7F;page++)
{//
for(cyc=0;cyc<8;cyc++)
{
addr=0;
for(;addr<4;addr++)
{
Read_8F08(page,cyc*4+addr);
}
addr--;
Stop_R8F08();
Delay(255);
}
Delay(255);
}
Delay(255);
}
//=============主函数,无返回值与输入值
void main()
{//主函数
//OutBuf=0x00;
//OutBuf=0xFF;
Test();
RESET=1;
SCLK=1;
MOSI=1;
/*SCLK=0;
MOSI=0;
MISO=1;
//Delay(255);
RESET=0;
Delay(255);
OutBuf=0xE0;
OutBuf=0x5A;
OutBuf=0xA5;
OutBuf=0xAA;
OutBuf=0x00;
SendSPI(5);
RESET=1;
SCLK=1;
MOSI=1;*/
/*OutBuf=0xE5;
OutBuf=0x53;
OutBuf=0x35;
OutBuf=0x5E;
OutBuf=0x00;*/
while(1)
{
//SendSPI(5);
//Delay(100);
}
}
本帖最后由 xwkm 于 2012-9-16 08:23 编辑
LGT的SPI口不同于AT89S52的。在复位拉下前SCLK必须拉低,否则会被认为是脉冲上升沿导致数据错位。(谢谢bbsniua的提醒)
这个错误折腾了我整整一个下午。
这个数据包比较简单和规律。每5个BYTE一个帧。前面第一BYTE位命令。第二为地址。第三为页。第四第五是数据。注意第四第五这个WORD值其实是用Middle-Endian表示的INT值。
那么实际上MCU返回的0x55AA就是0xAA55。一样的。
至于如果熔丝加锁以后的解锁办法也简单。初始化后,单单执行earse即可。
判断加了密的芯片,看返回值,如果是0xBD即可证明是加密的。如果在清除状态时发现0xBD的返回可以直接PASS掉芯片不用继续读。因为继续读还是0xBD。
我刚开始的时候是以为在E5 53 35 5E以后直接发送擦除命令即可实现擦除的。没有想到返回值全是F,根本没有成功。
后来发现需要发送这几个命令,可能是清除状态的命令:
B8 3F 07 00 00/BC 3F 07 00 00/A0 00 00 00 00
接着就是擦除命令了。在程序中有。
然后写入的话,使用0x90,0x98这个命令。连续写4次(8BYTES)要停下来,接着重复四次,然后换页继续写。一共是0x80个页,一个页是0x20个WORD,也就是64B,即8K的闪存。
至于EEPROM的话就很简单了。在起始的0x10个页中,其实地址范围从0x00~0x2F,0x00~0x1F给整个用户的flash用。至于0x20~0x2F这个地址是给EEPROM的。 至于读命令,就是命令字段为0xB8和0xBC。记住一定要执行两次。
第一次的结果是错误的。有可能是设置内部寄存器的指令,第二条才是真正读。
然后读出的2bytes还是middle-endian的。需要swap。并且每读8bytes(4次)要用0xA0命令停一下,然后继续往后读。
可以在读AP的时候顺带把EEP也读出来。 在使用Makefile的时候,LDFLAGS一定要设置堆栈。否则可能出现爆掉的状况。
并且把mcu类型设置为atmega164p。这样gcc才不会报错
LDFLAGS = -Wl,--defsym=__stack=0x8002ff #LGT设置堆栈2FF
MACHINE= atmega164p 至少对于LGT8F08A,如果能够长期供货保持如此低的价格的话。入门的门槛是很低的。
只要一块能写入程序的无论什么单片机,甚至有DTR和RTS的串口/EPP并口,就可以用来编程LGT。
找一块洞洞板废料,飞一点线就可以在面包板上做实验了。还是比较方便的。
因为这个最小系统只需要一个单片机和一个电容(甚至也可以不要)就可以了。
不过我强烈建议官方别在新的LGT上去掉ISP功能。第一会导致批量写入程序的麻烦。
第二就是,SWD协议远远比SPI复杂的多。一般的单片机模拟会有一些问题。
这样就会显著的提升入门的门槛。我认为这不是好事情。
另外就是LGT的IO口可以 直接和有弱上拉的5V IO连接,无需电平转换。 lz是高中生呢,好厉害了。 值得肯定的,很有潜力的牛人! 本帖最后由 xwkm 于 2012-9-16 10:14 编辑
FUSE->OSCCAL 已经找出:
读出FUSE的命令是:
B8 3C 07 00 00 BC 3C 07 00 00
返回的第二个字节即为OSCCAL值! 熔丝使能应该是在楼上第一个字节的低四位。 Delay(255);Delay(255);Delay(255);Delay(255);
Delay(255);Delay(255);Delay(255);Delay(255);
Delay(255);Delay(255);Delay(255);Delay(255);
Delay(255);Delay(255);Delay(255);Delay(255);
Delay(255);Delay(255);Delay(255);Delay(255);{:titter:}
还不如弄多个delay_ms()函数算了! chengzepeng 发表于 2012-9-16 13:48 static/image/common/back.gif
还不如弄多个delay_ms()函数算了!
这个仅仅是测试代码 C6 F0 72 A6 0C 55 AA 55
C6 11000110 OSCCAL – RC 精调控制寄存器
7:保留
6:RPEST R/W 只在 14 脚和 8 脚封装时有效 当设置 PRESETN位为“1”时,复用复位功能的引脚使能复位功能。 当设置 PRESETN位为“0”时,复用复位功能的引脚禁止复位功能。(ISP软件-外部复位使能位)
5:0 RCCAL 16MHz RC 精调控制位 (ISP软件-RC时钟校准配置)
55 AA 55
F0 熔丝位 (ISP软件-ISP/LOCK 使能位, 熔丝配置使能位)
-FF 11111111 默认 ISP/LOCK 使能位 解锁 熔丝配置使能位 禁用
-F0 11110000 熔丝配置使能位 启用
72 A6 0C 55 GUID 十六进制0x550CA672
AA 55 未使用 要是5v弱上拉能兼容就可以试试手里的1602了{:lol:} 强大的代码,大家原来都睡那么晚 顶 lz是高中生? {:shocked:} 功力不错了。我高中的时候只能玩z80 {:lol:} goodcode 发表于 2012-9-16 19:43 static/image/common/back.gif
要是5v弱上拉能兼容就可以试试手里的1602了
我试过直接接12232和1602,暂时没问题。
反正我现在直接用STC的上拉链接一点事都木有。 佩服佩服牛人
页:
[1]