bootloader引导程序问题
有没有人帮我看下我的bootloader引导程序怎么都没有成功,问题出在哪里了,BIN文件可以下载,但是程序一直没有运行APP区,一直在BOOT LOADER,难道程序没下载到APP区或者说下载的数据不对?经过ISP读取flash内容,发现地址0x0000开始的内容出来前两个字节为0x00,其余为0xff;我用CVAVR编译器,ATMEGA88V芯片;谢谢了;//#include <tiny13.h>
#include <mega88.h>
#include <delay.h>
#define uchar unsigned char
#define uint unsigned int
#define SPM_PAGESIZE 128 //M16的一个Flash页为128字节(64字)
#define DATA_BUFFER_SIZE SPM_PAGESIZE //定义接收缓冲区长度
//定义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'
//函数申明
void uart_putchar(char c);
int uart_getchar(void);
void quit(void);
char uart_waitchar(void);
void boot_page_ew(int p_address,char code);
void boot_page_fill(uint address,int data);
void wait_page_rw_ok(void);
void write_one_page(void);
int calcrc(char *ptr, int count);
const uchar startupString[]="Type 'd' download, Others run app.\n\r\0";
char data ={1,2,34,56,79,234,456,3321,3469};
int address = 0;
void main(void)
{
int i;
//uchar m=0;;
uint timercount = 0;
uchar packNO = 1;
int bufferPoint = 0;
uint crc;
delay_ms(100);
PORTD=0xff;
DDRD=0x1e;
/************mega88_USART_Init********/
UBRR0H =0;
UBRR0L =0x19; //0x0C:波特率38400 0x19:19200
//UCSR0A =0x20;
UCSR0B =0x18; //发送和接受使能
UCSR0C =0x0E; //00001110 寄存器选择UCSRC 异步 无校验 2个停止位 8位数据
/********TC2_CTC_Init***********************/
OCR0A =0x75; //15ms自动重载 0x75=117117/(8000/1024)=117/7.8125=14.976ms
TCCR0A=0x02;//CTC 1024分频
TCCR0B=0x05;
//MCUCR =0x01; //MCUCR:通用中断控制寄存器
//MCUCR =0x10;
while(1)
{
while(startupString!='\0')
{
uart_putchar(startupString);
i++;
}
while(1)//3秒种等待PC下发“d”,否则退出Bootloader程序,从0x0000处执行应用程序
{
if(uart_getchar()== 'd') break; //如果接收到PC发送来的"d"就退出本while( )循环
if(TIFR0 & 0x02) //如果定时器中断标志寄存器TIFR位OCF2被置位
{
if (++timercount > 200) quit(); //200*15ms = 3s 超过,就退出本while( )循环
TIFR0 |=0x02; //清除标志位OCF2 继续等待
}
}
//每秒向PC机发送一个控制字符“C”,等待控制字〈soh〉
/*while(1)
{
uart_putchar(uart_getchar());
} */
while(uart_getchar()!=XMODEM_SOH) //receive the start of Xmodem
{ PORTD.4=0;
if(TIFR0 & 0x02) //timer0 over flow
{
if(++timercount > 67) //wait about 1 second
{
uart_putchar(XMODEM_RECIEVING_WAIT_CHAR); //send a "C"
//uart_putchar(0x22);
timercount=0;
}
TIFR0=TIFR0 | 0x02;
}
//uart_putchar(1);
}
/*while(1)
{
PORTD.3=0;
} */
//开始接收数据块
do
{
if ((packNO == uart_waitchar()) && (packNO ==(~uart_waitchar())))
{ //核对数据块编号正确
for(i=0;i<128;i++) //接收128个字节数据
{
data= uart_waitchar();
bufferPoint++;
}
//crc=0;
crc = uart_waitchar();
//crc = (uart_waitchar()<<8);
crc<<=8;
crc += uart_waitchar(); //接收2个字节的CRC效验字
if(calcrc(&data,128)==crc) //CRC校验验证
{
while(bufferPoint >= SPM_PAGESIZE) //正确接收128个字节数据
{
write_one_page(); //收到32字节写入一页Flash中
//Flash页加1 (32字节/页)等于是将 flash地址每次加128
bufferPoint = 0;
}
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处执行应用程序
}
}
//从RS232发送一个字节
void uart_putchar(char c)
{
while(!(UCSR0A & 0x20));
UDR0 = c;
}
//从RS232接收一个字节
int uart_getchar(void)
{
unsigned char status,res;//status,
if(!(UCSR0A & 0x80))return -1; //接收缓冲器中有未读出的数据时RXC 置位
status =UCSR0A;
res =UDR0;
/*while (UCSR0A & 0x80)
{
res =UDR0;
}*/
status =UCSR0A;
if (status & 0x1c) return -1; //EF DOR PE(帧错误 溢出错误 奇偶错误 )
return res;
}
//等待从RS232接收一个有效的字节
char uart_waitchar(void)
{
int c;
while((c=uart_getchar())==-1);
return (char)c;
}
//退出Bootloader程序,从0x0000处执行应用程序
void quit (void)
{
//#asm("cli");
uart_putchar('O');uart_putchar('K');
uart_putchar(0x0d);uart_putchar(0x0a);
while(!(UCSR0A & 0x20)); //UDRE:1表示数据寄存器空 可以接收
MCUCR =0x01; //MCUCR:通用中断控制寄存器
MCUCR =0x00; //将中断向量表迁移到应用程序区头部
#asm("ldi r30,0x00")
#asm("ldi r31,0x00")
#asm("ijmp") //跳转到Flash的0x0000处,执行用户的应用程序
}
//擦除(code=0x03)和写入(code=0x05)一个Flash页
#pragma warn-
void boot_page_ew(int p_address,char code)
{
#asm(" LDD r30,Y+1");//将页地址放入Z寄存器和RAMPZ的Bit0中
#asm(" LDD r31,Y+2"); //除M128外,其他小flash芯片无RAMPZ
SPMCSR = code; //寄存器SPMCSR中为操作码
#asm("spm "); //对指定Flash页进行操作
}
#pragma warn+
//填充Flash缓冲页中的一个字
#pragma warn-
void boot_page_fill(unsigned int address,int data)
{
#asm("LDD r30,Y+2"); //(R30,R31)<--data,(--Y)<--R31,(--Y)<--R30; //Z寄存器中为填冲页内地址
#asm("LDD r31,Y+3"); //CVAVRz中,第一个参数存放在Y+2,Y+3的SRAM处
#asm("LD r0,Y"); //因为编译器CVAVR在传递2个函数参数时,先传递第一个,后传递第2个!
#asm("LDD r1,Y+1"); //(R30,R31)<--address,(--Y)<--R31,(--Y)<--R30;
//#asm("mov r0,r30"); //因为编译器CVAVR在传递2个函数参数时,先传递第一个,后传递第2个!
//#asm("mov r1,r31"); //R0R1中为一个指令字
SPMCSR = 0x01;
#asm("spm");
}
#pragma warn+
//擦除(code=0x03)和写入(code=0x05)一个Flash页
//等待一个Flash页的写完成
void wait_page_rw_ok(void)
{
while(SPMCSR & 0x40) //RWWSB: RWW区忙标志位
{
while(SPMCSR & 0x01); //SPMEN:操作flash使能位,忙时为1,要使能置1;不忙硬件自动清零
SPMCSR = 0x11; //使能读RWW区
#asm("spm");
}
}
//更新一个Flash页的完整处理
void write_one_page(void)
{
uint i;
intj;
uint m;
j=0;
boot_page_ew(address,0x03); //擦除一个Flash页
wait_page_rw_ok(); //等待擦除完成
for(i=0;i<SPM_PAGESIZE/2;i+=2) //将数据填入Flash缓冲页中
{
//j=(data<<8);
j=data;
j<<=8;
j+=data;
boot_page_fill(i, j);
}
boot_page_ew(address,0x05); //将缓冲页数据写入一个Flash页
wait_page_rw_ok(); //等待写入完成
address += SPM_PAGESIZE/2;
j=0;
boot_page_ew(address,0x03); //擦除一个Flash页
wait_page_rw_ok(); //等待擦除完成
for(i=SPM_PAGESIZE/2;i<SPM_PAGESIZE;i+=2) //将数据填入Flash缓冲页中
{
//j=(data<<8);
j=data;
j<<=8;
j+=data;
m=i-SPM_PAGESIZE/2;
boot_page_fill(m, j);
//PORTD.4=0;
}
boot_page_ew(address,0x05); //将缓冲页数据写入一个Flash页
wait_page_rw_ok();
address += SPM_PAGESIZE/2; //等待写入完成
}
//计算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);
} 这段代码原本出于我的手,是用ICCAVR写的,配合M128。(原帖:http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=156462&bbs_page_no=1&bbs_id=1003)
网上很多朋友在此基础上改写,用于其他型号的AVR。
改写是必须,因为芯片本身有不同的地方。
你搬了代码,至少要弄明白,做些稍微的改动,适合你用的型号,不能直接用。
我看到第5行就明白了;
#define SPM_PAGESIZE 128 //M16的一个Flash页为128字节(64字)
至少你要知道ATMEGA88V的一个Flash页是几个字节吧?
自己认真的学习学习吧。 machao 发表于 2012-2-16 19:50 static/image/common/back.gif
这段代码原本出于我的手,是用ICCAVR写的,配合M128。(原帖:http://www.ourdev.cn/bbs/bbs_content.jsp?b ...
马老师 请问你一个问题
我参照别人改写的AVR32的bootloader
现在可以下载程序到APP区了
可是好像现在AVR32没法从bootloader区跳到APP区运行程序
不知道哪里出了问题
所以想请教下
WINAVR2006
bootloader程序如下:
// 南京科力赛克安全设备有限公司
// 技术部:YKLSTUDENT
// 电话:18951759970
// 软件功能介绍:
// 本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字节
unsigned char CRC16hi; //CRC16校验码高位
unsigned char CRC16lo; //CRC16校验码低位
}strXMODEM; //XMODEN的接受数据结构变量
unsigned int FlashAddress; //FLASH地址
#define BootAdd 0x7000 //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<<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;
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秒钟内按下键,否则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,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);
}
楼上的,你是抄“南京科力赛克安全设备有限公司”的代码,还是在这个公司工作?
2楼就是我的回复。
本帖最后由 yklstudent 于 2012-6-30 15:22 编辑
machao 发表于 2012-6-29 21:34 static/image/common/back.gif
楼上的,你是抄“南京科力赛克安全设备有限公司”的代码,还是在这个公司工作?
2楼就是我的回复。
哦 那个是我公司
马老师 还能重新给个链接地址 那给的地址打不开 在本栏的精华帖中《自引导IAP(boot load)的应用设计--armok转贴》http://www.amobbs.com/forum.php?mod=viewthread&tid=156462&extra=page%3D1%26filter%3Ddigest%26digest%3D1%26digest%3D1 标记一下!
页:
[1]