搜索
bottom↓
回复: 21

大家帮忙看下M8的bootloader程序(1)

[复制链接]

出0入0汤圆

发表于 2005-12-23 12:44:55 | 显示全部楼层 |阅读模式
最近看了几天的bootloader程序,然后自己动手写了个基于xmodem传输协议,直接对hex解码,然后烧写.

不过其中遇到一些问题.

我先讲讲我的bootloader的烧写部分的想法,根据xmodem协议接收128字节数据,按照intel hex格式将字符转化为16进制格式,这里面牵涉到intel hex本身格式,这里我先大致介绍下(具体的大家可以查资料):

Intel hex 文件格式

Intel hex 文件常用来保存单片机或其他处理器的目标程序代码。它保存物理程序存储区中的目标代码映象。一般的编程器都支持这种格式。

Intel hex 文件全部由可打印的ASCII字符组成,如下例所示:

:2000000012014c75a800e4f508f509780a7a78e4f608dafcd283fcfded240af9a7050dbd81

:2000200000010ced2488ec34ff50edc283e4fcfded240af9e76d7013ed33e43c700d0dbd2a

:2000400000010ced2488ec34ff50e50509e50970020508e50924a8e50834fd50aee4f50874



Intel hex 由一条或多条记录组成,每条记录都由一个冒号“:”打头,其格式如下:



:CCAAAARR...ZZ



其中:

CC

本条记录中的数据字节数



AAAA

本条记录中的数据在存储区中的起始地址



RR

记录类型:

00 数据记录 (data record)

01 结束记录 (end record)

02 段记录 (paragraph record)

03 转移地址记录 (transfer address record)

数据域

ZZ

数据域校验和

是效验和域,表示记录的效验和,计算方法是将本条记录冒号开始的所有对字母<不包括本效验字和冒号>所表示的十六进制数字<一对字母表示一个十六进制数,这样的一个十六进制数为一个字节>都加起来然后模除256得到的余数最后求出余数的补码即是本效验字节cc.

例如:

:0300000002005E9D

ZZ=0x01+NOT((0x03+0x00+0x00+0x00+0x02+0x00+0x5E)%0x100)=0x01+0x9C=0x9D

C语言描述:

UCHAR cc;

ZZ=(UCHAR)~(0x03+0x00+0x00+0x00+0x02+0x00+0x5E);

ZZ++;



Intel hex文件记录中的数字都是16进制格式,两个16进制数字代表一个字节。CC域是数据域中的实际字节数,地址、记录类型和校验和域没有计算在内。校验和是取记录中从数据字节计数域(CC)到数据域(...)最后一个字节的所有字节总和的2的补码

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

 楼主| 发表于 2005-12-23 13:02:30 | 显示全部楼层
针对intel hex格式,依照xmodem协议接受到128字节数据,后存储在在一个数据里面,根据':'引导标号,找出每一条hex记录,因为intel hex格式 :CCAAAARR...ZZ(各自意思见上面),我们可以由数据长度CC和偏移地址AAAA得到该数据记录在flash一页中的位置,具体情况如下(假设每一页flash的大小为pagesize):

    该条记录的长度len : CC

    该条记录所属flash的整个页中的位置:AAAA / pagesize

    该条记录的数据在所属于页(M8一页为64  bytes)中的位置:AAAA % pagesize

    判断该条记录是在一页内,还是被分在了两页内:

        如果 (AAAA % pagesize) + CC < pagesize,那么记录在一页内,

        反之 (AAAA % pagesize) + CC < pagesize,那么记录分在两页,



我们对传过来的128字节进行hex解码,并把结果存储在pagebuffer[pagesize]数组里,如果pagebuffer满pagesize大小了,那么就进行flash页烧写,并且烧写完之后,重新将pagebuffer[pagesize]填充为0xff,数组不满的话,继续将记录填入,这里面有两中情况可以将pagebuffer[pagesize]进行烧写:

        1.如果前一条记录与后一条记录不在同一个页内,那么可以对pagebuffer[pagesize]进行烧写

        2.如果数组在填充数据时,已经到达数组末尾,那么该pagebuffer[pagesize]可以烧写



前一条记录和后一条记录在不在同一个页内可以这样子判断:

        (reserved_offset / pagesize) != (offset / pagesize)

这里的offset就是intel hex记录里的 AAAA.



这部分的内容我自己测试过,纯粹是分段并打印出来,在PC机上调试过,给出源代码如下:

    

出0入0汤圆

 楼主| 发表于 2005-12-23 13:02:44 | 显示全部楼层
#include <stdio.h>

#define SPM_PAGESIZE 64

unsigned char PageBuffer[64];



int toint(char c)

{

    if(c<58 && c>47)

            return (int)(c - 48);

        if(c<71 && c>64)

            return (int)(c - 65 + 10);

        if(c<103 && c>96)

            return (int)(c - 97 + 10);

        else

            return -1;

}



unsigned char hex2char(char c1,char c2)

{



   return (char) (toint(c1) <<4) + (char) toint(c2) ;

}



main()

{





        int i = 0;

        int j;

    unsigned char timercount = 0;

    unsigned char packNO = 1;

    int bufferPoint = 0;

    unsigned int crc;



        unsigned char len;

    unsigned char record_type;

    unsigned int offset;

    unsigned int reserved_offset=0;

    char checksum;





        char *data=":040000000C945A0002:14005400B5B1C7B0B0B4BCFCCAC7A3BA004D41494C20544FCB:140068003A736C6C6740736C2E636F6D2E636E0048545450CD:14007C";

        /*char *data=":0200000042C0FC:14002600B5B1C7B0B0B4BCFCCAC7A3BA004D41494C20544FF9:14003A003A736C6C6740736C2E636F6D2E636E0048545450FB:14004E003A";*/

        printf("



new Begin....
");



                for(j=0;j<SPM_PAGESIZE;j++) PageBuffer[j] = 0xff;

                i=0;

                            while(i<128)

                                {

                                        printf("new record...
");

                                while( data[i++] != ':');



                                    len = hex2char(data,data[i+1]);

                    i+=2;

                    offset = hex2char(data,data[i+1]);

                    offset <<= 8;

                    i+=2;

                    offset |= hex2char(data,data[i+1]);

                    i+=2;

                    record_type = hex2char(data,data[i+1]);

                    i+=2;



                                        if((reserved_offset/SPM_PAGESIZE) != offset/SPM_PAGESIZE)

                                        {

                                            printf("
");

                                            for(j=0;j<SPM_PAGESIZE;)

                                            {

                                                        printf("%02x ",PageBuffer[j]);

                                                        PageBuffer[j++]=0xff;

                                                        if(!(j%16) && (j!=0))printf("
");



                                            }

                                        }

                               

                                                       



                                        reserved_offset = offset;



                            if((offset % SPM_PAGESIZE + len) < SPM_PAGESIZE)

                                        {

                                for(j=0;j<len;j++)

                                {

                            PageBuffer[(offset % SPM_PAGESIZE)+j]=hex2char(data,data[i+1]);

                                        /*printf("PageBuffer[%d] is: %02x ",j,PageBuffer[j]);  */

                                        i+=2;

                        }

                                        }

                            else

                            {

                                    for(j=(offset%SPM_PAGESIZE);j<SPM_PAGESIZE;j++)

                                    {

                            PageBuffer[j]=hex2char(data,data[i+1]);

                                        i+=2;

                        }

                                                printf("
Pagebuffer context:
");

                                            for(j=0;j<SPM_PAGESIZE;)

                                            {

                                                        printf("%02x ",PageBuffer[j]);

                                                        PageBuffer[j++]=0xff;

                                                        if(!(j%16))printf("
");

                                            }



                                        

                                                       

                                for(j=0;j<len-(SPM_PAGESIZE -offset%SPM_PAGESIZE);j++)

                        {

                                        PageBuffer[j]=hex2char(data,data[i+1]);

                            i+=2;

                        }

                                    }

                                    checksum = hex2char(data,data[i+1]);

                                        i+=2;

                                }

}



出0入0汤圆

 楼主| 发表于 2005-12-23 13:03:40 | 显示全部楼层
我是用的 TC 2.0调试的,就是将128字节的数据分别转化为hex后填充到pagebuffer里面去

出0入0汤圆

 楼主| 发表于 2005-12-23 13:07:51 | 显示全部楼层
下面给出整个代码,这段代码有问题,希望大家能帮忙找找问题所在,现在的问题就是基本上第一页写入flash没问题的,而后面就有问题了,位置不对.整个是采用超级终端,选取xmodem协议(参考了马潮老师的m128的IAP应用),选择编译后的hex文件传输过去烧写.



/*****************************************************

采用串行接口实现Boot_load应用的实例

参考华东师大电子系 马 潮 2004.07

Compiler:    ICC-AVR 6.31

Target:    Mega8

Crystal:    7.3728Mhz

Used:        T/C0,USART

*****************************************************/

#include <iom8v.h>

#include "assembly.h"

#define SPM_PAGESIZE 64              //M8的一个Flash页为64字节(32字)

#define BAUD 9600                //波特率采用38400bps

#define CRYSTAL 7372800           //系统时钟16MHz

//计算和定义M128的波特率设置参数

#define BAUD_SETTING (unsigned char)((unsigned long)CRYSTAL/(16*(unsigned long)BAUD)-1)

#define BAUD_H (unsigned char)(BAUD_SETTING>>8)

#define BAUD_L (unsigned char)BAUD_SETTING



#define DATA_BUFFER_SIZE 128        //定义接收缓冲区长度

//定义Xmoden控制字符

#define XMODEM_NUL 0x00

#define XMODEM_SOH 0x01

#define XMODEM_STX 0x02

#define XMODEM_EOT 0x04

#define XMODEM_ACK 0x06

#define XMODEM_NAK 0x15

#define XMODEM_CAN 0x18

#define XMODEM_EOF 0x1A

#define XMODEM_RECIEVING_WAIT_CHAR 'C'

//定义全局变量

const char startupString[]="Type 'd' download, Others run app.
\r\0";

char data[DATA_BUFFER_SIZE];

unsigned char PageBuffer[SPM_PAGESIZE];

long address = 0;



//字符转化为整数,'0' = 48 ;'A' = 65 (A-F) ;'a' = 97 (a-f)

int toint(char c)

{

    if(c<58 && c>47)  

            return (int)(c - 48);

        if(c<71 && c>64)  

            return (int)(c - 65 + 10);   //A->10,B->11....

        if(c<103 && c>96)

            return (int)(c - 97 + 10);

        else

            return -1;

}



unsigned char hex2char(char c1,char c2)

{   

   // convert to a single 8 bit result

   return (char) (toint(c1) <<4) + (char) toint(c2) ;

}



//更新一个Flash页的完整处理

void write_one_page(void)

{

    int i;

    for(i=0;i<SPM_PAGESIZE;i+=2)

        {

        fill_temp_buffer( PageBuffer+(PageBuffer[i+1]<<8),i);

    }

    write_page(address,0x03);       //擦除页

    write_page(address,0x05);       //写页数据

}         

//从RS232发送一个字节

void uart_putchar(char c)

{

    while(!(UCSRA&(1<<UDRE)));

    UDR = c;

}

//从RS232接收一个字节

int uart_getchar(void)

{

    unsigned char status,res;

    if(!(UCSRA& (1<<RXC))) return -1;       //no data to be received

    status = UCSRA;

    res = UDR;

    if (status & 0x1c) return -1;        // If error, return -1

    return res;

}

//等待从RS232接收一个有效的字节

char uart_waitchar(void)

{

    int c;

    while((c=uart_getchar())==-1);

    return (char)c;

}

//计算CRC

int calcrc(char *ptr, int count)

{

    int crc = 0;

    char i;

     

    while (--count >= 0)

    {

        crc = crc ^ (int) *ptr++ << 8;

        i = 8;

        do

        {

        if (crc & 0x8000)

            crc = crc << 1 ^ 0x1021;

        else

            crc = crc << 1;

        } while(--i);

    }

    return (crc);

}

//退出Bootloader程序,从0x0000处执行应用程序

void quit(void)

{

     uart_putchar('O');uart_putchar('K');

     uart_putchar(0x0d);uart_putchar(0x0a);

     while(!(UCSRA & 0x20));           //等待结束提示信息回送完成

     MCUCR = 0x01;

     MCUCR = 0x00;                   //将中断向量表迁移到应用程序区头部

//     RAMPZ = 0x00;                    //RAMPZ清零初始化

     asm("jmp 0x0000
");               //跳转到Flash的0x0000处,执行用户的应用程序

}

//主程序

void main(void)

{

    int i = 0;

        int j;

    unsigned char timercount = 0;

    unsigned char packNO = 1;

    //int bufferPoint = 0;

    unsigned int crc;

       

        unsigned char len;                     // holds the HEX record length field

    unsigned char record_type;             // holds the HEX record type field

    unsigned int offset;                   // holds the HEX record offset field

                                          // this is the starting address of

                                          // the code image contained in the

                                          // recor

        unsigned int reserved_offset=0;



    char checksum;

//初始化M128的USART0

    UCSRB=(1<<RXEN)|(1<<TXEN);//允许发送和接收

    UBRRL=BAUD_L;

    UBRRH=BAUD_H;

    UCSRC=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);//8位数据+1位STOP位

//初始化M128的T/C0,15ms自动重载

  //OCR0 = 0xEA;

    TCCR0 = 0x05;  //1024分频

        TCNT0 = 0x6C;

        TIMSK |=0x01;   

       

//向PC机发送开始提示信息

    for(j=0;j<SPM_PAGESIZE;j++) PageBuffer[j] = 0xff;

    while(startupString!='\0')

    {

        uart_putchar(startupString);

        i++;

    }

//3秒种等待PC下发"d",否则退出Bootloader程序,从0x0000处执行应用程序

    while(1)

    {

        if(uart_getchar()== 'd') break;

/*        if (TIFR & 0x02)                        //timer0 over flow

        {

               if (++timercount > 200) quit();       //200*15ms = 3s

            TIFR = TIFR|0x02;

        }

*/    }

    //每秒向PC机发送一个控制字符"C",等待控制字〈soh〉

    while(uart_getchar()!=XMODEM_SOH)        //receive the start of Xmodem

    {

         if(TIFR & 0x01)                    //timer0 over flow

        {

                    TCNT0 = 0x6C;

            if(++timercount > 67)                        //wait about 1 second

            {

                uart_putchar(XMODEM_RECIEVING_WAIT_CHAR);    //send a "C"

                timercount=0;

            }

            TIFR=TIFR | 0x02;

        }

    }

        for(j=0;j<SPM_PAGESIZE;j++) PageBuffer[j] = 0xff;

  //开始接收数据块

    do

    {

        if ((packNO == uart_waitchar()) && (packNO ==(~uart_waitchar())))

        {    //核对数据块编号正确

            for(j=0;j<128;j++)                //接收128个字节数据

            {

                data[j]= uart_waitchar();

                //bufferPoint++;     

            }

            crc = (uart_waitchar()<<8);

            crc += uart_waitchar();            //接收2个字节的CRC效验字

            if(calcrc(&data[0],128)==crc)    //CRC校验验证

            {   //正确接收128个字节数据

                //接收到正确的128字节后任何填充PageBuffer[]?

                               

                i=0;

                            while(i<128)

                                {

                                while( data[i++] != ':');



                                    len = hex2char(data,data[i+1]);

                    i+=2;

                    offset = hex2char(data,data[i+1]);

                    offset <<= 8;

                    i+=2;

                    offset |= hex2char(data,data[i+1]);

                    i+=2;

                    record_type = hex2char(data,data[i+1]);

                    i+=2;



                                        if((reserved_offset/SPM_PAGESIZE) != offset/SPM_PAGESIZE)

                                        {

                                            //printf("
");

                                                write_one_page();

                                                address += SPM_PAGESIZE;    //Flash????1

                                            for(j=0;j<SPM_PAGESIZE;)

                                            {

                                                        //uart_putchar(PageBuffer[j]);

                                                        PageBuffer[j++]=0xff;

                                                        //if(!(j%16) && (j!=0))printf("
");



                                            }

                                        }

                               

                                        reserved_offset = offset;



                            if((offset % SPM_PAGESIZE + len) < SPM_PAGESIZE)

                                for(j=0;j<len;j++)

                                {

                            PageBuffer[(offset % SPM_PAGESIZE)+j]=hex2char(data,data[i+1]);

                                        /*printf("PageBuffer[%d] is: %02x ",j,PageBuffer[j]);  */

                                        i+=2;

                        }

                            else

                            {

                                    for(j=(offset%SPM_PAGESIZE);j<SPM_PAGESIZE;j++)

                                    {

                            PageBuffer[j]=hex2char(data,data[i+1]);

                                        i+=2;

                        }

                                                write_one_page();

                                                address += SPM_PAGESIZE;    //Flash????1

                                                //printf("
Pagebuffer context:
");

                                            for(j=0;j<SPM_PAGESIZE;)

                                            {

                                                        //uart_putchar(PageBuffer[j]);

                                                        PageBuffer[j++] = 0xff;

                                                        //if(!(j%16))printf("
");

                                            }

       

                                for(j=0;j<len-(SPM_PAGESIZE -offset%SPM_PAGESIZE);j++)

                        {

                                        PageBuffer[j]=hex2char(data,data[i+1]);

                            i+=2;

                        }

                                    }

                                    checksum = hex2char(data,data[i+1]);

                                        i+=2;

                                }

                                       

                                  uart_putchar(XMODEM_ACK);        //正确收到一个数据块

                packNO++;  

                        }                     //数据块编号加1

            else

            {

                uart_putchar(XMODEM_NAK);        //要求重发数据块

            }

        }

        else

        {

            uart_putchar(XMODEM_NAK);                //要求重发数据块

        }

    }while(uart_waitchar()!=XMODEM_EOT);               //循环接收,直到全部发完

    uart_putchar(XMODEM_ACK);                       //通知PC机全部收到

     

    //if(bufferPoint) write_one_page();                //把剩余的数据写入Flash中

    quit();                  //退出Bootloader程序,从0x0000处执行应用程序



}

出0入0汤圆

 楼主| 发表于 2005-12-23 13:11:18 | 显示全部楼层
最后我把东西打包一下,希望各位能帮调试解决问题,不胜感谢,我的QQ:3813627

email: icecooljw@hotmail.com ;icecooljw@sina.com



点击此处下载armok0193766.rar

出0入0汤圆

发表于 2005-12-23 13:26:49 | 显示全部楼层
意义不是很大.

BIN更简单方便,反正都是明文传输。

不如考虑如何使用加解密技术?

出0入0汤圆

发表于 2005-12-23 14:33:56 | 显示全部楼层
不要攪hex了, 算法加大了bood區的佔用! 我之前改了範例的boodleader, 剛好996byte!! 放在m8上很爽, 6k的程序3妙攪定..

出0入0汤圆

 楼主| 发表于 2005-12-23 16:11:32 | 显示全部楼层
M8上我试过了啊,选用的1K word,反正是学习玩玩,大家就帮看看好了,加个hex解码也不是很麻烦啊

出0入0汤圆

 楼主| 发表于 2005-12-23 16:13:31 | 显示全部楼层
avrboy 單片王子,能把你M8上的代码发我看看么

出0入0汤圆

发表于 2005-12-23 16:45:48 | 显示全部楼层
http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=559585&bbs_page_no=1&bbs_id=1000

出0入0汤圆

发表于 2005-12-23 23:50:31 | 显示全部楼层
hex解码可以在PC端搞,一般不要加重单片机的负担。

hex2bin代码在sourceforge上,可以下载使用。

http://sourceforge.net/projects/hex2bin

自己做个PC端就可以搞定了。

出0入0汤圆

 楼主| 发表于 2005-12-25 21:06:35 | 显示全部楼层
再请教诸位,我根据马潮老师的Bootloader程序改了下,程序能烧进去,但是有一个问题,就是在用xmodem协议传输到最后的时候,总是不显示结束,而是一直在等待,可能是把最后128字节写入flash的时候好象有问题,写最后一页好象一直不结束,所以PC得不到回复,比较奇怪,但是烧写完回读之后结果是正确烧入的.代码如下:



#include <iom8v.h>

#include "assembly.h"

#define SPM_PAGESIZE 64              //M8的一个Flash页为64字节(32字)

#define BAUD 9600                //波特率采用38400bps

#define CRYSTAL 7372800           //系统时钟16MHz

//计算和定义M128的波特率设置参数

#define BAUD_SETTING (unsigned char)((unsigned long)CRYSTAL/(16*(unsigned long)BAUD)-1)

#define BAUD_H (unsigned char)(BAUD_SETTING>>8)

#define BAUD_L (unsigned char)BAUD_SETTING



#define DATA_BUFFER_SIZE 128        //定义接收缓冲区长度

//定义Xmoden控制字符

#define XMODEM_NUL 0x00

#define XMODEM_SOH 0x01

#define XMODEM_STX 0x02

#define XMODEM_EOT 0x04

#define XMODEM_ACK 0x06

#define XMODEM_NAK 0x15

#define XMODEM_CAN 0x18

#define XMODEM_EOF 0x1A

#define XMODEM_RECIEVING_WAIT_CHAR 'C'

//定义全局变量

const char startupString[]="Type 'd' download, Others run app.
\r\0";

char data[DATA_BUFFER_SIZE];

unsigned char PageBuffer[SPM_PAGESIZE];

long address = 0;





//擦除(code=0x03)和写入(code=0x05)一个Flash页

void boot_page_ew(long p_address,char code)

{

    asm("mov r30,r16
"

        "mov r31,r17
"

        "out 0x3b,r18
");            //将页地址放入Z寄存器和RAMPZ的Bit0中

    SPMCR = code;                //寄存器SPMCSR中为操作码

    asm("spm
");                    //对指定Flash页进行操作

}         

//填充Flash缓冲页中的一个字

void boot_page_fill(unsigned int address,int data)

{

    asm("mov r30,r16
"

        "mov r31,r17
"             //Z寄存器中为填冲页内地址

        "mov r0,r18
"

        "mov r1,r19
");            //R0R1中为一个指令字

    SPMCR = 0x01;

    asm("spm
");

}

//等待一个Flash页的写完成

void wait_page_rw_ok(void)

{

      while(SPMCR & 0x40)

     {

         while(SPMCR & 0x01);

         SPMCR = 0x11;

         asm("spm
");

     }

}

//更新一个Flash页的完整处理

void write_one_page(char *data)

{

    int i=0;

        boot_page_ew(address,0x03);                    //擦除一个Flash页

    wait_page_rw_ok();                             //等待擦除完成

    for(i=0;i<SPM_PAGESIZE;i+=2)                   //将数据填入Flash缓冲页中

    {

        boot_page_fill(i, data+(data[i+1]<<8));

        }

        boot_page_ew(address,0x05);                    //将缓冲页数据写入一个Flash页

    wait_page_rw_ok();                             //等待写入完成

          

}      

//从RS232发送一个字节

void uart_putchar(char c)

{

    while(!(UCSRA&(1<<UDRE)));

    UDR = c;

}

//从RS232接收一个字节

int uart_getchar(void)

{

    unsigned char status,res;

    if(!(UCSRA& (1<<RXC))) return -1;       //no data to be received

    status = UCSRA;

    res = UDR;

    if (status & 0x1c) return -1;        // If error, return -1

    return res;

}

//等待从RS232接收一个有效的字节

char uart_waitchar(void)

{

    int c;

    while((c=uart_getchar())==-1);

    return (char)c;

}

//计算CRC

int calcrc(char *ptr, int count)

{

    int crc = 0;

    char i;

     

    while (--count >= 0)

    {

        crc = crc ^ (int) *ptr++ << 8;

        i = 8;

        do

        {

        if (crc & 0x8000)

            crc = crc << 1 ^ 0x1021;

        else

            crc = crc << 1;

        } while(--i);

    }

    return (crc);

}

//退出Bootloader程序,从0x0000处执行应用程序

void quit(void)

{

     uart_putchar('O');uart_putchar('K');

     uart_putchar(0x0d);uart_putchar(0x0a);

     while(!(UCSRA & 0x20));           //等待结束提示信息回送完成

     MCUCR = 0x01;

     MCUCR = 0x00;                   //将中断向量表迁移到应用程序区头部

//     RAMPZ = 0x00;                    //RAMPZ清零初始化

     asm("jmp 0x0000
");               //跳转到Flash的0x0000处,执行用户的应用程序

}

//主程序

void main(void)

{

    int i = 0;

        int j;

    unsigned char timercount = 0;

    unsigned char packNO = 1;

    int bufferPoint = 0;

    unsigned int crc;



//初始化M128的USART0

    UCSRB=(1<<RXEN)|(1<<TXEN);//允许发送和接收

    UBRRL=BAUD_L;

    UBRRH=BAUD_H;

    UCSRC=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);//8位数据+1位STOP位

//初始化M128的T/C0,15ms自动重载

  //OCR0 = 0xEA;

    TCCR0 = 0x05;  //1024分频

        TCNT0 = 0x6C;

        TIMSK |=0x01;   

       

//向PC机发送开始提示信息



    while(startupString!='\0')

    {

        uart_putchar(startupString);

        i++;

    }

//3秒种等待PC下发"d",否则退出Bootloader程序,从0x0000处执行应用程序

    while(1)

    {

        if(uart_getchar()== 'd') break;

/*        if (TIFR & 0x02)                        //timer0 over flow

        {

               if (++timercount > 200) quit();       //200*15ms = 3s

            TIFR = TIFR|0x02;

        }

*/    }

    //每秒向PC机发送一个控制字符"C",等待控制字〈soh〉

    while(uart_getchar()!=XMODEM_SOH)        //receive the start of Xmodem

    {

         if(TIFR & 0x01)                    //timer0 over flow

        {

                    TCNT0 = 0x6C;

            if(++timercount > 67)                        //wait about 1 second

            {

                uart_putchar(XMODEM_RECIEVING_WAIT_CHAR);    //send a "C"

                timercount=0;

            }

            TIFR=TIFR | 0x02;

        }

    }



  //开始接收数据块

    do

    {

        if ((packNO == uart_waitchar()) && (packNO ==(~uart_waitchar())))

        {    //核对数据块编号正确

            for(j=0;j<128;j++)                //接收128个字节数据

            {

                data[j]= uart_waitchar();

                bufferPoint++;     

            }

            crc = (uart_waitchar()<<8);

            crc += uart_waitchar();            //接收2个字节的CRC效验字

            if(calcrc(data,128)==crc)    //CRC校验验证

            {   //正确接收128个字节数据

                //接收到正确的128字节后任何填充PageBuffer[]?

                                while(bufferPoint >= SPM_PAGESIZE)

                                {   

                    write_one_page(&data[128-bufferPoint]);            

                    address += SPM_PAGESIZE;   

                    bufferPoint -=SPM_PAGESIZE ;

                }     



                                       

                                  uart_putchar(XMODEM_ACK);        //正确收到一个数据块

                packNO++;  

                        }                     //数据块编号加1

            else

            {

                uart_putchar(XMODEM_NAK);        //要求重发数据块

            }

        }

        else

        {

            uart_putchar(XMODEM_NAK);                //要求重发数据块

        }

    }while(uart_waitchar()!=XMODEM_EOT);               //循环接收,直到全部发完

    uart_putchar(XMODEM_ACK);                       //通知PC机全部收到

     

    //if(bufferPoint) write_one_page();                //把剩余的数据写入Flash中

    quit();                  //退出Bootloader程序,从0x0000处执行应用程序



}
-----此内容被icecool于2005-12-25,21:10:22编辑过

出0入0汤圆

发表于 2005-12-26 09:28:46 | 显示全部楼层
你完成一頁後沒有對bufferPoint清零, 這樣可能出問題;

出0入0汤圆

 楼主| 发表于 2005-12-26 09:57:37 | 显示全部楼层
我清过0,我原先还特意在

            while(bufferPoint >= SPM_PAGESIZE)  

            {   

                    write_one_page(&data[128-bufferPoint]);              

                    address += SPM_PAGESIZE;     

                    bufferPoint -=SPM_PAGESIZE ;

                }      

后面补充了一下bufferPoint =0;

不过没什么用

出0入0汤圆

 楼主| 发表于 2005-12-26 10:04:23 | 显示全部楼层
while(bufferPoint >= SPM_PAGESIZE)   

            {     

                    write_one_page(&data[128-bufferPoint]);               

                    address += SPM_PAGESIZE;      

                    bufferPoint -=SPM_PAGESIZE ;  

            }

这一段就是对  bufferPoint 清零了

而且当前的程序烧写的整个结果是对的,就是烧写到最后一页结束后,xmodem传输收不到最后一个应答信号,问题是出在最后一次调用write_one_page上,一直没结束,但想不出为什么

出0入0汤圆

发表于 2005-12-26 10:25:42 | 显示全部楼层
不过建议多考虑加密,这样可以直接把编译好的hex文件本地加密后发给客户(如果程序有问题的话),客户可以自己升级,升级的时候由Bootlaoder完成解密,这样就不用去现场服务,也不用把产品寄回来,加密就很重要了,因为你要把程序直接交给客户(如果没有解密那也是一段没有用的数字),还有就是要多考虑AVR被烤片解密后的保密,如何能得知道程序被解密了就不运行程序也很重要,如果有大侠得知可共同学习!~!!!!!

出0入0汤圆

发表于 2005-12-26 12:49:45 | 显示全部楼层
}while(uart_waitchar()!=XMODEM_EOT);

不用這個判斷, 改用文件是否寫完來判斷.

}while(address>=0x1c00);

出0入0汤圆

 楼主| 发表于 2005-12-26 22:54:58 | 显示全部楼层
不是吧??烧写文件到最后的地址未必address>=0x1c00啊,应该说根本不会大于这个的.文件是否写完是应该用uart_waitchar()!=XMODEM_EOT来判断的,但使用这个条件的时候我现在发现一些烧写的bin文件非常正常的烧写结束,一些就烧写不结束,手动结束传输之后,发现烧写的结果也是对的,问题比较奇怪,照理每次都是128字节,不论对错,总归应该能烧写结束,然后给上位机回复信息.

出0入0汤圆

 楼主| 发表于 2005-12-26 23:23:12 | 显示全部楼层
这里说一下关于 hex烧写的问题,原来的程序判断条件有问题,所以结果不对,不过因为是按照128字节块传输的,所以前后两个数据块之间的那条hex record解码将会非常麻烦,这里给出一个调试的代码,如果改成上位机读写文件将不会有太大问题:

#include <stdio.h>

#define SPM_PAGESIZE 64

unsigned char PageBuffer[64];



int toint(char c)

{

    if(c<58 && c>47)

            return (int)(c - 48);

        if(c<71 && c>64)

            return (int)(c - 65 + 10);

        if(c<103 && c>96)

            return (int)(c - 97 + 10);

        else

            return -1;

}



unsigned char hex2char(char c1,char c2)

{



   return (char) (toint(c1) <<4) + (char) toint(c2) ;

}



main()

{





        int i = 0;

        int j;

    unsigned char timercount = 0;

    unsigned char packNO = 1;

    int bufferPoint = 0;

    unsigned int crc;



        unsigned char len;

    unsigned char record_type;

    unsigned int offset;

    unsigned int reserved_offset=0;

    char checksum;

    char pagenumber=0;

        char trans=0;



        /*char *data=":040000000C945A0002:14005400B5B1C7B0B0B4BCFCCAC7A3BA004D41494C20544FCB:140068003A736C6C6740736C2E636F6D2E636E0048545450CD:14007C";*/

        /*char *data=":0200000042C0FC:14002600B5B1C7B0B0B4BCFCCAC7A3BA004D41494C20544FF9:14003A003A736C6C6740736C2E636F6D2E636E0048545450FB:14004E003A";*/

          char *data=":0200000042C0FC:14002600B5B1C7B0B0B4BCFCCAC7A3BA004D41494C20544FF9:14003A003A736C6C6740736C2E636F6D2E636E0048545450FB:14004E003A\

2F2F5757572E534C2E434F4D2E434E00B9E3D6F6:14006200DDCCECBAD3CBABC1FAB5E7D7D3B9ABCBBE5253322D:0F0076003332CDA8D0C5D1DDCABEB3CCD0F2\

0095:14008600CFE5D4E0CDBFDEBFC051D0400AEA08830024EFEB37:14009A00F0E010E0EF3BF10711F00192FBCF0083E6E2F0E0F7:1400AE00A0E6B0E010E0E\

538F10721F0C89531960D92F9CF87:1400C20034D0FFCF5D9BFECF0CB908955F9BFECF0CB1089510:1400D60051D0A80105C0FA010081F2DF4F5F5F4FFA01208";



       

        printf("



new Begin....
");



                for(j=0;j<SPM_PAGESIZE;j++) PageBuffer[j] = 0xff;

                i=0;

                            while(i<512)

                                {

                                while( data[i++] != ':');



                                    len = hex2char(data,data[i+1]);

                    i+=2;

                    offset = hex2char(data,data[i+1]);

                    offset <<= 8;

                    i+=2;

                    offset |= hex2char(data,data[i+1]);

                    i+=2;

                    record_type = hex2char(data,data[i+1]);

                    i+=2;



                                        if(((reserved_offset/SPM_PAGESIZE) != offset/SPM_PAGESIZE) && !trans)

                                        {

                                                printf("
overflow to two page %d...address:%d
",reserved_offset/SPM_PAGESIZE,(reserved_offset/SPM_PAGESIZE)*SPM_PAGESIZE);

                                            for(j=0;j<SPM_PAGESIZE;)

                                            {

                                                        printf("%02x ",PageBuffer[j]);

                                                        PageBuffer[j++]=0xff;

                                                        if(!(j%16) && (j!=0))printf("
");



                                            }

                                               

                                        }

                               

                                                       



                                        reserved_offset = offset;



                            if((offset % SPM_PAGESIZE + len) < SPM_PAGESIZE)

                                        {

                                for(j=0;j<len;j++)

                                {

                            PageBuffer[(offset % SPM_PAGESIZE)+j]=hex2char(data,data[i+1]);

                                        /*printf("PageBuffer[%d] is: %02x ",j,PageBuffer[j]);  */

                                        i+=2;

                        }

                                                trans=0;

                                        }

                            else

                            {

                                    for(j=(offset%SPM_PAGESIZE);j<SPM_PAGESIZE;j++)

                                    {

                            PageBuffer[j]=hex2char(data,data[i+1]);

                                        i+=2;

                        }

                                               

                                                trans=1;

                                                printf("
Pagebuffer context on page: %d...address:%d...
",offset/SPM_PAGESIZE,(offset/SPM_PAGESIZE)*SPM_PAGESIZE);

                                            for(j=0;j<SPM_PAGESIZE;)

                                            {

                                                        printf("%02x ",PageBuffer[j]);

                                                        PageBuffer[j++]=0xff;

                                                        if(!(j%16))printf("
");

                                            }



                                        

                                                       

                                for(j=0;j<len-(SPM_PAGESIZE -offset%SPM_PAGESIZE);j++)

                        {

                                        PageBuffer[j]=hex2char(data,data[i+1]);

                            i+=2;

                        }

                                    }

                                    checksum = hex2char(data,data[i+1]);

                                        i+=2;

                                }

}



这段代码仅调试用.因为判断调试是while( data[i++] != ':');对于xmodem协议传输的128字节这样子的判断会丢失数据.

出0入0汤圆

 楼主| 发表于 2005-12-27 13:17:32 | 显示全部楼层
问一下诸位,用xmodem协议传输数据烧入flash之后,最后不足128字节,xmodem进行填充,烧写到flash里面,回读到的是什么数据?我回读到的是0x1A,比较奇怪,照理是填充null,应该 是0才对啊

出0入0汤圆

发表于 2005-12-27 13:27:18 | 显示全部楼层
如果最后需要发送的数据不足128个字节,用<eof>填满一个数据块

#define XMODEM_EOF                         0x1A
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-26 05:21

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表