请教马潮老师bootloader的问题
马老师,您好,我按照你的M128的IAP例程改了一下用在M8上,用xmodem传输bin文件的时候出了点问题,一些时候文件好象传输不结束,上位机收不到回复信息来结束文件传输,而且这种情况总是出现在最后,如果手动结束的话,通过回读会发现文件已经正确烧写,有些时候烧写别的bin文件情况又会比较正常,请教马老师,这个问题是怎么回事呢?在写最后一页好象结束不了.源代码如下:/****************************************************
采用串行接口实现Boot_load应用的实例
华东师大电子系 马 潮 2004.07
Compiler: ICC-AVR 6.31
Target: Mega8
Crystal: 7.3728Mhz
Used: T/C0,USART0
*****************************************************/
#include <iom8v.h>
#define SPM_PAGESIZE 64 //M8的一个Flash页为64字节(32字)
#define BAUD 9600 //波特率采用9600bps
#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;
unsigned char PageBuffer;
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<<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;
}
void erase_flash(void)
{
int i=0;
printf("
*** Erasing flash from 0x0000 to 0x1C00 (0x70 pages)");
for(i=0;i<70;i++)
{
boot_page_ew(i*SPM_PAGESIZE,0x03); //擦除一个Flash页
wait_page_rw_ok();
uart_putchar('#');
}
}
//字符串输出函数
void printf(char str[])
{
if (!str) return;
while (*str)
uart_putchar(*str++);
}
//计算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)
{
printf("...OK");
//uart_putchar('O');uart_putchar('K');
//uart_putchar(0x0d);uart_putchar(0x0a);
//while(!(UCSRA & 0x20)); //等待结束提示信息回送完成
//MCUCR = 0x01;
//MCUCR = 0x00; //将中断向量表迁移到应用程序区头部
//RAMPZ = 0x00; //RAMPZ清零初始化
GICR = (1<<IVCE);
GICR = (0<<IVCE)|(0<<IVSEL); //将中断向量表迁移到应用程序区头部
asm("jmp 0x0000
"); //跳转到Flash的0x0000处,执行用户的应用程序
}
//主程序
void main(void)
{
int i = 0;
int j;
char tmp;
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++;
//}
printf("
Type 'd' download, Others run app.
");
printf("
Type 'e' erase flash
");
printf("
Type 'g' to app code
");
//3秒种等待PC下发"d",否则退出Bootloader程序,从0x0000处执行应用程序
while(1)
{
if((tmp=uart_getchar())== 'd')
break;
else if(tmp=='e')
{
printf("erase flash");
erase_flash();
}
else if(tmp=='g')
quit();
/* 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= uart_waitchar();
bufferPoint++;
}
crc = (uart_waitchar()<<8);
crc += uart_waitchar(); //接收2个字节的CRC效验字
if(calcrc(data,128)==crc) //CRC校验验证
{ //正确接收128个字节数据
while(bufferPoint >= SPM_PAGESIZE)
{
write_one_page(&data);
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机全部收到
//当SPM_PAGE>128的时候是需要的
//if(bufferPoint) write_one_page(); //把剩余的数据写入Flash中
quit(); //退出Bootloader程序,从0x0000处执行应用程序
}
-----此内容被icecool于2005-12-26,23:14:37编辑过 这里面有个现象,依照xmodem协议传输后,最后用来填充满128字节的数据烧写到flash里面是0X1A,比较奇怪
页:
[1]