xwkm 发表于 2012-9-16 00:07:23

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 00:18:12

本帖最后由 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的。

xwkm 发表于 2012-9-16 00:21:01

至于读命令,就是命令字段为0xB8和0xBC。记住一定要执行两次。
第一次的结果是错误的。有可能是设置内部寄存器的指令,第二条才是真正读。
然后读出的2bytes还是middle-endian的。需要swap。并且每读8bytes(4次)要用0xA0命令停一下,然后继续往后读。
可以在读AP的时候顺带把EEP也读出来。

xwkm 发表于 2012-9-16 00:23:33

在使用Makefile的时候,LDFLAGS一定要设置堆栈。否则可能出现爆掉的状况。
并且把mcu类型设置为atmega164p。这样gcc才不会报错
LDFLAGS = -Wl,--defsym=__stack=0x8002ff #LGT设置堆栈2FF
MACHINE= atmega164p

xwkm 发表于 2012-9-16 00:37:20

至少对于LGT8F08A,如果能够长期供货保持如此低的价格的话。入门的门槛是很低的。
只要一块能写入程序的无论什么单片机,甚至有DTR和RTS的串口/EPP并口,就可以用来编程LGT。
找一块洞洞板废料,飞一点线就可以在面包板上做实验了。还是比较方便的。
因为这个最小系统只需要一个单片机和一个电容(甚至也可以不要)就可以了。
不过我强烈建议官方别在新的LGT上去掉ISP功能。第一会导致批量写入程序的麻烦。
第二就是,SWD协议远远比SPI复杂的多。一般的单片机模拟会有一些问题。
这样就会显著的提升入门的门槛。我认为这不是好事情。
另外就是LGT的IO口可以 直接和有弱上拉的5V IO连接,无需电平转换。

ttoto 发表于 2012-9-16 00:43:56

lz是高中生呢,好厉害了。

logicgreen 发表于 2012-9-16 01:09:44

值得肯定的,很有潜力的牛人!

xwkm 发表于 2012-9-16 09:49:56

本帖最后由 xwkm 于 2012-9-16 10:14 编辑

FUSE->OSCCAL 已经找出:
读出FUSE的命令是:
B8 3C 07 00 00 BC 3C 07 00 00
返回的第二个字节即为OSCCAL值!

xwkm 发表于 2012-9-16 09:55:36

熔丝使能应该是在楼上第一个字节的低四位。

chengzepeng 发表于 2012-9-16 13:48:03

      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()函数算了!

xwkm 发表于 2012-9-16 16:06:02

chengzepeng 发表于 2012-9-16 13:48 static/image/common/back.gif
还不如弄多个delay_ms()函数算了!

这个仅仅是测试代码

goodcode 发表于 2012-9-16 19:40:57

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 未使用

goodcode 发表于 2012-9-16 19:43:12

要是5v弱上拉能兼容就可以试试手里的1602了{:lol:}

vows 发表于 2012-9-17 20:57:31

强大的代码,大家原来都睡那么晚

ybx520 发表于 2012-9-17 21:04:26

顶         

halloocc 发表于 2012-9-18 10:10:51

lz是高中生? {:shocked:} 功力不错了。我高中的时候只能玩z80 {:lol:}

xwkm 发表于 2012-9-22 14:37:24

goodcode 发表于 2012-9-16 19:43 static/image/common/back.gif
要是5v弱上拉能兼容就可以试试手里的1602了

我试过直接接12232和1602,暂时没问题。
反正我现在直接用STC的上拉链接一点事都木有。

liujian6f 发表于 2013-5-10 21:36:53

佩服佩服牛人
页: [1]
查看完整版本: LGT的基本写入/读出已经分析完成,下个星期回家后分析FUSE