搜索
bottom↓
回复: 41

修正AVR通用Bootloader的两个bug

  [复制链接]

出0入0汤圆

发表于 2012-6-3 21:39:59 | 显示全部楼层 |阅读模式
自从V4.5版发布后,有较长时间没有更新了。最近在AVR通用Bootloader中发现了两个比较大的bug,在某些情况下会引起一些问题。因为完整的更新文件还没有整理,所以先发布一下错误修正:

Bug1:

在SafeMode下,跳转到Bootloader的地址计算错误。

解决方法:

将文件Bootldr.c中的语句
  (*((void(*)(void))(BootStart)))();       //跳转到 bootloader
改为
  (*((void(*)(void))(BootStart/2)))();     //跳转到 bootloader

共有三处。

Bug2:
这个错误是国外网友Ben Wilson发现的,是一个比较严重的错误,在CRC校验错误时,将引起下载失败。在这种情况下,原来应该可以通过重新发送数据解决问题的,但因为这个bug,使得重发机制失效,容易出现“重试次数太多”。引起的原因是因为没有修正缓冲区指针,使得即使发送了新数据也没有保存到缓冲区的正确位置。

解决方法

在文件bootldr.c中,在第475和499行(V4.5版,其它版本行数可能不同),增加如下代码:

            bufptr -= BUFFERSIZE;             //修改缓冲区地址

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

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2012-6-3 21:49:45 | 显示全部楼层
顶,支持,感谢楼主的贡献,我也用过这个通用的BootLoader,帮了大忙

出0入0汤圆

发表于 2012-6-3 21:53:14 | 显示全部楼层
原帖在哪里?

出0入0汤圆

发表于 2012-6-3 22:50:02 | 显示全部楼层
顶一下!

出0入0汤圆

发表于 2012-6-3 23:05:42 | 显示全部楼层
感谢!!!辛苦了。。
话说俺还是在国外网站知道楼主的呢。。。

出0入0汤圆

发表于 2012-6-4 08:19:28 | 显示全部楼层
期待楼主的最新版

出0入12汤圆

发表于 2012-6-4 08:41:34 | 显示全部楼层
本帖最后由 skynet 于 2012-6-4 08:51 编辑


修正编译过的

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出1070入962汤圆

发表于 2012-6-4 09:01:44 | 显示全部楼层
顶!作为通用bootloader的老用户,感谢楼主所做的工作!

出0入0汤圆

发表于 2012-6-4 09:39:10 | 显示全部楼层
这个可以有,呵呵。。!

出0入0汤圆

发表于 2012-6-4 09:45:29 | 显示全部楼层
大牛好久不见啊,我的第一个项目就是用的这个BOOTLOADER,最近正好用在使用了!

出0入0汤圆

发表于 2012-6-4 10:38:07 | 显示全部楼层
顶楼主,作品非常好。

出0入12汤圆

发表于 2012-6-4 17:26:13 | 显示全部楼层
MicroPLC 发表于 2012-6-4 10:38
顶楼主,作品非常好。

童鞋,你这头像是哪位大妹妹噢???

出0入0汤圆

发表于 2012-6-4 19:38:59 | 显示全部楼层
感谢老师,已经修改好啦

出0入0汤圆

发表于 2012-6-8 15:26:39 | 显示全部楼层
我觉得还有一个bug,退出while(WaitCom() != XMODEM_EOT);时,如果bufptr不等于0,即接收的数据不够一个页时,flash就会少写入这部分数据。应该再一次判断bufptr,做相应的动作。

出0入0汤圆

发表于 2012-6-8 15:39:55 | 显示全部楼层
顶顶顶顶

出0入0汤圆

发表于 2012-6-9 18:39:45 | 显示全部楼层
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

出0入0汤圆

发表于 2012-6-10 12:20:08 | 显示全部楼层
学习了!!感谢!

出0入0汤圆

发表于 2012-6-15 00:11:32 | 显示全部楼层
我新学习的~~~~

出0入0汤圆

发表于 2012-6-25 15:02:53 | 显示全部楼层
学习了,楼主辛苦了,谢谢!

出0入0汤圆

发表于 2012-6-26 10:24:50 | 显示全部楼层
楼主厉害呀!!!!!!!!

出0入0汤圆

发表于 2012-6-26 11:17:55 | 显示全部楼层
呵呵,多谢LZ

出0入0汤圆

发表于 2012-6-26 14:33:52 | 显示全部楼层
多谢!请问各位,是不是有一个专门的软件用来下载应用程序的bin文件?

出0入0汤圆

发表于 2012-6-27 09:24:32 | 显示全部楼层
本帖最后由 yklstudent 于 2012-6-27 09:25 编辑

前辈们 求请教下
我参照别人改写的bootloader程序
但是用XP系统下的超级终端下载程序时
总是会提示远程通信取消
我查看AVR32的运用区,发现程序是下载进去了
但是没有下载完全
不知道怎么弄的,求前辈们帮忙分析下
程序如下:
//        软件功能介绍:
//                本BOOTLOADER程序根据OURAVR忘得BOOTLOADER范例修改,
//        原为M8现改为M32使用;
//        时钟定为内部时钟8Mhz,F_CPU=8000000使用USART,19200bps
//        熔丝位设定:BOOTRST = 0 (复位地址设为BOOT区),
//                                BOOTSZ1 = 0,BOOTSZ0 = 0(BOOT区大小为2028字,4056字节)
//        Time:        2012年06月23日

#include<avr/io.h>
#include<avr/boot.h>
#include<util/crc16.h>
#include<util/delay.h>

//USART引脚定义
#define PIN_RXD         0        //PD0
#define PIN_TXD                1        //PD1

#define TXEN                3        //PC3

//常数定义
#ifndef SPM_PAGESIZE
#define SPM_PAGESIZE        128                //M32的一个FLASH页为128字节(64字)
#endif

#define PROG_START        0x0000
#define BAUDRATE         9600
       
//定义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_WAIT_CHAR        'C'

//定义全局变量
struct str_XMODEM
{
        unsigned char SOH;                        //起始字节
        unsigned char BlockNo;                //数据块编号
        unsigned char nBlockNo;                //数据块编号反码
        unsigned char Xdata[128];        //数据128字节
        unsigned char CRC16hi;                //CRC16校验码高位
        unsigned char CRC16lo;                //CRC16校验码低位
}strXMODEM;                                                //XMODEN的接受数据结构变量

unsigned int FlashAddress;                //FLASH地址

#define BootAdd                0x3800                //Boot区的首地址(运用区的最高地址)
//*        GCC-AVR里面地址使用32位长度,适用所有AVR的容量

unsigned char BlockCount;                //数据块累计(仅8位,无须考虑溢出)

unsigned char STATUS;                        //运行状态

#define ST_WAIT_START        0x00        //等待启动
#define ST_BLOCK_OK                0x01        //接受一个数据块完成
#define ST_BLOCK_FAIL        0x02        //接受一个数据块失败
#define ST_OK                        0x03        //完成

//长延时Max(65535ms)
void delay_ms(unsigned int t)
{
        while(t--)
        {
                _delay_ms(1);
        }
}

//更新一个Flash页的完整处理
void write_one_page(void)
{
        unsigned char i;
        unsigned int w;
        boot_page_erase(FlashAddress);                //擦出一个Flash页
        boot_spm_busy_wait();                                //等待页擦出完成
        for(i=0;i<SPM_PAGESIZE;i+=2)
        {
                w =  strXMODEM.Xdata|(strXMODEM.Xdata[i+1]<<8);
                boot_page_fill(i,w);                        //只是低7位(128字节/页)有效
        }
        boot_page_write(FlashAddress);                //将缓冲页数据写入一个Flash页
        boot_spm_busy_wait();                                //等待页编程完成
}
/*
void write_one_page(unsigned char buf_start)
{
        unsigned char i;
        unsigned char *buf;
        unsigned int w;
        boot_page_erase(FlashAddress);                //擦出一个Flash页
        boot_spm_busy_wait();                                //等待页擦出完成
        buf = &strXMODEM.Xdata[buf_start];
        for(i=0;i<SPM_PAGESIZE;i+=2)
        {
                w = *buf++;                                                //数据低位
                w += ((*buf++)<<8);                                //数据高位
                boot_page_fill(i,w);                        //只是低7位(128字节/页)有效
        }
        boot_page_write(FlashAddress);                //将缓冲页数据写入一个Flash页
        boot_spm_busy_wait();                                //等待页编程完成
}
*/

//跳转到用户程序
void quit(void)
{
        boot_rww_enable();                                                //RWW区读允许,否则无法马上执行用户的应用程序
        asm volatile("rjmp 0x0000"::);                        //跳转到Flash的0x0000处,执行用户的应用程序
}

//发送采用查询方式
void put_c(unsigned char c)                                //发送采用查询方式
{
        loop_until_bit_is_set(UCSRA,UDRE);
        UDR = c;
}

//发送字符串
void put_s(unsigned char *ptr)
{
        while(*ptr)
        {
                put_c(*ptr++);
        }
        put_c(0x0D);
        put_c(0x0A);                                                //结尾发送回车换行
}

//接收指定字节数据(带超时控制,Timer0的1ms时基)
//        *ptr                数据缓冲区
//        len                        数据长度
//        timeout                超时设定,最长65.526S
//        返回值                已接收字节数目
unsigned char get_data(unsigned char *ptr,unsigned char len,unsigned int timeout)
{
        unsigned char count = 0;
        do
        {
                if(UCSRA&(1<<RXC))                //缓冲区有数据未读出
                {
                        *ptr++ = UDR;                        //如果接收到数据,读出
                        count ++;
                        if(count>=len)
                        {
                                break;                        //够了?保存
                        }
                }
                if(TIFR&(1<<OCF2))                //T2溢出1ms
                {
                        TIFR |= (1<<OCF2);        //清除标志位
                        timeout --;                        //倒计时
                }
        }while(timeout);       
        return count;
}       

//计算CRC16
/*
Optimized CRC-XMODEM calculation.

    Polynomial: x^16 + x^12 + x^5 + 1 (0x1021)<br>
    Initial value: 0x0

    This is the CRC used by the Xmodem-CRC protocol.

    The following is the equivalent functionality written in C.
*/
unsigned int calcrc(unsigned char *ptr,unsigned char count)
{
        unsigned int crc = 0;
        while(count--)
        {
                crc = _crc_xmodem_update(crc,*ptr++);
        }
        return(crc);
}

int main(void)
{
        unsigned char c;
        unsigned char i;
        unsigned int crc;
        //考虑到BootLoader可能由应用程序中跳转过来,所以所用到的模块需要全面初始化
        DDRB = 0x00;
        DDRC = 0x00;                                        //不用的管脚使能内部上拉电阻
        PORTB = 0xFF;
        PORTC = 0xFF;
        PORTD = 0xFF;
        DDRD = (1<<PIN_TXD);                        //串口的输出               
        GICR = (1<<IVCE);
        GICR = (0<<IVCE)|(1<<IVSEL);        //将中断向量表迁移到Boot区头部       
        asm volatile("cli"::);                        //关全局中断
        //这个BootLoader没有使用中断
        //初始化USART 19200 8,n,1        PC上位机软件(超级终端)也要设成同样的设置才能通信
        UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);        //异步,8位数据,无奇偶校验,一个停止位,无倍速
        UBRRL = (F_CPU/BAUDRATE/16-1)%256;        //
        UBRRH = (F_CPU/BAUDRATE/16-1)/256;
        UCSRA = 0x00;
        UCSRB = (1<<RXEN)|(1<<TXEN);
        //初始化T/C2,CTC模式,256分频,1ms自动重载
        TCNT2 = 0xE4;
        OCR2 = 0x1C;
        TCCR2 = (1<<WGM21)|(1<<CS22)|(1<<CS21)|(1<<CS20);
        //CTC模式下,溢出标志是输出比较匹配0CF0,对应的中断是输出比较匹配中断;

        //向PC机发射开始提示信息
        //put_s("3秒内按下d键更新");
        put_s("It begin to Update in middle of three minutes!");
        //put_s("如果更新用户程序,请在3秒钟内按下[d]键,否则3秒后运行用户程序");
       
        //3秒钟等待PC下发"d",否则退出Bootloader程序,从0x0000处执行应用程序
        c = 0;
        get_data(&c,1,3000);                        //限时3秒,接收一个数据
        if((c=='d')||(c=='D'))
        {
                STATUS = ST_WAIT_START;                //并且数据=‘d’或‘D’,进入XMODEM
                //put_s("BIN文档最大14KB");
                put_s("the max of BIN is 14 KB!");
        }
        else
        {
                STATUS = ST_OK;                                //退出Bootloader程序
        }
        //进入XMODEM模式
        FlashAddress = 0x0000;
        BlockCount = 0x01;
        while(STATUS!=ST_OK)                        //循环接收,直到全部发完
        {
                if(STATUS==ST_WAIT_START)
                {
                        put_c(XMODEM_WAIT_CHAR);        //发射请求XMODEM_WAIT_CHAR
                }
                i = get_data(&strXMODEM.SOH,133,1000);        //限时1秒,接收133字节数据
                if(i)
                {
                        //分析数据包的第一个资料SOH/EOT/CAN
                        switch(strXMODEM.SOH)
                        {
                                case XMODEM_SOH:                                //收到开始符SOH
                                {
                                        if(i>=133)
                                        {
                                                STATUS = ST_BLOCK_OK;       
                                        }
                                        else
                                        {
                                                STATUS = ST_BLOCK_FAIL;                //如果数据不足,要求重发当前数据块
                                                put_c(XMODEM_NAK);
                                        }
                                        break;
                                }
                                case XMODEM_EOT:                                //收到结束符EOT
                                {
                                        put_c(XMODEM_ACK);                        //通知PC机全部收到
                                        STATUS = ST_OK;
                                        //put_s("升级OK");
                                        put_s("It is OK!");
                                        break;
                                }
                                case XMODEM_CAN:                                //收到取消符CAN
                                {
                                        put_c(XMODEM_ACK);                        //回应PC机
                                        STATUS = ST_OK;
                                        //put_s("升级fail");
                                        put_s("It is Fail!");
                                        //put_s("警告:用户取消升级,用户程序可能不完整");
                                        break;
                                }
                                default:
                                {
                                        put_c(XMODEM_NAK);                        //要求重发当前数据块
                                        STATUS = ST_BLOCK_FAIL;
                                        break;
                                }
                        }
                }
                if(STATUS==ST_BLOCK_OK)                                        //收到133字节OK,且起始字节正确
                {
                        if(BlockCount!=strXMODEM.BlockNo)        //核对数据块编号正确
                        {
                                put_c(XMODEM_NAK);                                //数据块编号错误,要求重发当前数据块
                                continue;
                        }
                        if(BlockCount!=(unsigned char)(~strXMODEM.nBlockNo))       
                        {
                                put_c(XMODEM_NAK);                                //数据块编号反码错误,要求重发当前数据
                                continue;
                        }
                        crc = strXMODEM.CRC16hi<<8;
                        crc += strXMODEM.CRC16lo;
                        //AVR的16位整数是低位在前,XMODEM的CRC16是高位在前
                        if(calcrc(&strXMODEM.Xdata[0],128)!=crc)
                        {
                                put_c(XMODEM_NAK);                                //CRC错误,要求重发当前数据块
                                continue;
                        }
                        //正确接收128个字节数据,刚好事M32的一页
                        if(FlashAddress<(BootAdd-SPM_PAGESIZE))
                        {
                                //如果地址在应用区内
                                write_one_page();                                //将接收的0-127字节写入一页Flash中
                                FlashAddress += SPM_PAGESIZE;
                        }
                        else
                        {
                                put_c(XMODEM_CAN);                                //程序已满,取消传送
                                put_c(XMODEM_CAN);
                                put_c(XMODEM_CAN);
                                STATUS = ST_OK;
                                //put_s("程序已满");
                                put_s("It is Full!");
                                break;
                        }
                        put_c(XMODEM_ACK);                                        //回应已正确收到一个数据块
                        BlockCount ++;                                                //数据块累计加1
                }
        }
        //退出Bootloader程序,从0x0000处执行应用程序
        put_s("GO");
        delay_ms(500);                                                                //很奇怪,见顶部的说明
        loop_until_bit_is_set(UCSRA,UDRE);                        //等待结束提示信息回送完成
        GICR = (1<<IVCE);
        GICR = (0<<IVCE)|(0<<IVSEL);                                //将中断向量表迁移到应用程序区头部
        //无论Bootloader是否使用中断,将中断向量表迁移到应用程序区头部,
        //会增强程序的健壮性
        //boot_rww_enable();                                                        //RWW区读允许,否则无法马上执行用户的应用程序
        //asm volatile("rjmp 0x0000"::);                                //跳转到Flash的0x0000处,执行用户的应用程序       
        quit();                                                                                //退出,返回到用户应用程序
        return(0);       
}

出0入0汤圆

发表于 2012-7-5 08:13:22 | 显示全部楼层
感谢邵老师!感谢7楼懒洋洋

出0入0汤圆

发表于 2012-7-5 08:49:42 | 显示全部楼层
mark,好细心啊

出0入0汤圆

发表于 2012-7-5 08:55:01 | 显示全部楼层
好东西!我自己写个试试看。

出0入0汤圆

发表于 2012-7-5 10:39:56 | 显示全部楼层
支持楼主
这么长时间,发现bug还不忘提醒大家

出0入0汤圆

发表于 2012-7-24 13:17:49 | 显示全部楼层
求更新4.6版、、、

出0入0汤圆

发表于 2012-7-25 00:45:55 | 显示全部楼层
回头尝试用一下,体会体会,先谢了

出0入0汤圆

发表于 2013-1-9 13:37:17 | 显示全部楼层
AVR通用Bootloader的两个bug

出0入70汤圆

发表于 2013-1-9 13:53:23 | 显示全部楼层
本帖最后由 SkyGz 于 2013-1-9 14:38 编辑

说的是哪个?

看了不是bootloadHID的,  在哪下载?

出0入0汤圆

发表于 2013-3-4 15:43:08 | 显示全部楼层
感谢!

出0入0汤圆

发表于 2013-3-4 15:43:27 | 显示全部楼层
学习一下!

出0入0汤圆

发表于 2013-3-13 12:37:07 | 显示全部楼层
mega8 没有JMP直接跳转指令,我用的是MEGA8,程序无法从boot loader中跳出进入应用程序区。  求解?

出0入0汤圆

发表于 2013-4-13 16:35:37 | 显示全部楼层
顶一下,收藏先。

出0入0汤圆

发表于 2013-4-13 16:38:07 | 显示全部楼层
有必要看看

出0入0汤圆

发表于 2013-4-13 19:00:00 | 显示全部楼层
顶一下,收藏先。

出0入0汤圆

发表于 2014-4-4 17:26:50 | 显示全部楼层
BLB0加密为3后可以在引导程序中解锁码?
我在用BootLoader下载程序后给BLB0加密为3,然后下次下载程序时必须要解锁。因为解不了锁。而不能再次下载。搞了好久了,没思路,特来求个思路,谢谢

出0入0汤圆

发表于 2014-4-7 12:20:34 | 显示全部楼层
thanks a lot

出0入0汤圆

发表于 2014-4-8 15:15:59 | 显示全部楼层
图片中ChipCheck校验下载的数据是采用什么方法校验的?可以分享下吗?

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2020-2-15 15:40:03 | 显示全部楼层
诸位有没有遇到这样一个情况:远程升级如果通过TPLINK路由器就会出错,有时候能升级成功但写入FLASH的数据却不正确,CRC校验和读出比较都不能发现错误。

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-4-27 07:29

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

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