我的bootloader,死活写不了程序
本帖最后由 guew 于 2013-5-23 21:01 编辑参照马老师的程序,用cvavr给mega32写bootloader,上位机通讯正常,数据传送成功,单步调试确认接受到的数据也正常。但从0x0000开始的flash就是没有数据,那三个加载、页写,等待函数看不出有什么问题,好心人帮帮我。。。/*****************************************************
This program was produced by the
CodeWizardAVR V2.05.0 Professional
Automatic Program Generator
?Copyright 1998-2010 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Chip type : ATmega32
Program type : Boot Loader - Size:512words
AVR Core Clock frequency: 12.000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 512
*****************************************************/
#include <mega32.h>
#include <dtype.h>
#define PAGE_SIZE 128
#define DATA_BUFFER_SIZE PAGE_SIZE
#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'
flash uint8 startup_message[] = "type 'd' download, others run app.\0";
uint8 data;
uint16 address = 0;
//擦除(code = 0x03)和写入(code = 0x05)一个flash页
void write_page(uint16 p_address,uint8 p_code)
{
#asm("lds r30,$025a"); //将p_address的低八位放入Y寄存器的低八位
#asm("lds r31,$025b"); //将p_address的高八位放入Y寄存器的高八位
SPMCR = p_code; //给SPMCR寄存器赋擦除控制指令
#asm("spm"); //擦除指令生效
}
// 填充一个flash缓冲页中的一个字
void page_fill(uint16 p_address,uint16 p_data)
{
#asm("lds r30,$025a"); //将p_address的低八位放入Y寄存器的低八位
#asm("lds r31,$025b"); //将p_address的高八位放入Y寄存器的高八位
#asm("lds r0,$0258"); //将data的低八位放入r0寄存器
#asm("lds r1,$0259"); //将data的高八位放入r1寄存器
SPMCR = 0x01; //给SPMCR寄存器赋加载页指令
#asm("spm"); //加载页指令生效
}
//等待一个flash页的写完成
void wait_page_write_done(void)
{
while(SPMCR & 0x40) //如果正在擦除或页写RWWSB置位,执行while
{
while(SPMCR & 0x01); //如果正在擦除,等待
SPMCR = 0x11; //给SPMCR寄存器写入RWW区使能(读)命令 ,并清除RWWSB,while结束,跳出等待
#asm("spm"); //使能指令生效
}
}
//更新一个flash页的完整处理
void write_one_page(void)
{
uint16 i;
write_page(address,0x03); //擦除一个flash页
wait_page_write_done(); //等待擦除完成
for(i = 0;i < PAGE_SIZE;i += 2) //将数据填入flash缓冲页中
{
page_fill(i,data+(data << 8));
}
write_page(address,0x05); //将缓冲数据写入一个flash页
wait_page_write_done(); //等待写入完成
}
//从RS232发送一个字节
void uart_putchar(uint8 c)
{
while(!(UCSRA & 0x20)); //等待上一个发送完成
UDR = c; //发送一个数据
}
//从RS232接受一个字节
int16 uart_getchar(void)
{
uint8 status,res;
if(!(UCSRA & 0x80)) //如果没有数据,返回-1
return -1;
status = UCSRA;
res = UDR;
if(status & 0x1c) //如果通信硬件有错误
return -1;
return res; //如果没有错误,返回收到的结果
}
//等待从RS232接收一个有效字节
uint8 uart_waitchar(void)
{
int16 c;
while((c = uart_getchar()) == -1);
return (uint8)c;
}
//计算CRC
int16 cal_crc(uint8 *ptr, int16 counter)
{
int16 crc = 0;
uint8 i;
while(--counter >= 0)
{
crc = crc^(int16)*ptr++ << 8;
i = 8;
do
{
if(crc & 0x8000)
crc = crc << 1^0x1021;
else
crc = crc << 1;
}while(--i);
}
return crc;
}
//退出bootlaoder程序,从0x0000处执行应用程序
void quit(void)
{
uart_putchar('O');
uart_putchar('K');
uart_putchar(0x0d);
uart_putchar(0x0a);
while(!(UCSRA & 0x20));//等待结束提示信息发送完成
GICR = 0x01; //打开中断迁移允许开关
GICR = 0x00; //将中断向量表迁回到应用程序区头部
#asm("jmp $0000"); //转跳到flash的0x0000处,执行用户的应用程序
}
void main(void)
{
uint8 i = 0;
uint8 timercount = 0;
uint8 pack_no = 1;
uint16 buffer_pointer = 0;
uint16 crc;
//GICR = 0x01; //打开中断迁移允许开关
//GICR = 0x02; //将中断向量表迁回到应用程序区头部
UBRRL = 0x4d; //波特率9600
UCSRB = 0x18; //使能传输与发送
UCSRC = 0x86; //8个数据位,1个stop位
OCR0 = 0xea; //(234+1) 30ms计时
TCCR0 = 0x0d; //CTC模式,1024分频
//#asm("sei");
//向PC发送开始提示信息
while(startup_message != '\0')
{
uart_putchar(startup_message);
i++;
}
//3秒钟等待PC下发'd',否则退出bootloader程序,从0x0000处执行应用程序
while(1)
{
if(uart_getchar() == 'd')
break;
if(TIFR & 0x02) //timer0 overflow
{
if(++timercount > 250) //100*30ms = 3s到点
quit();
TIFR = TIFR | 0x02;
}
}
//每秒向PC机发送一个控制字符'C',等待控制字符 <soh>
while(uart_getchar() != XMODEM_SOH) //没有收到开始字符就等待
{
if(TIFR & 0x02)
{
if(++timercount > 100)
{
uart_putchar(XMODEM_RECIEVING_WAIT_CHAR); //发送'C'
timercount = 0;
}
TIFR |= 0x02;
}
}
do
{
if((pack_no == uart_waitchar()) && (pack_no == (~uart_waitchar())))//校对阴阳两个数据包号
{
for(i = 0; i < 128;i++)
{
data = uart_waitchar();
buffer_pointer++;
}
crc = (uart_waitchar() << 8);
crc += uart_waitchar();
if(cal_crc(&data,128) == crc) //CRC校验
{
while(buffer_pointer >= PAGE_SIZE)
{
write_one_page();
address += PAGE_SIZE;
buffer_pointer = 0;
}
uart_putchar(XMODEM_ACK);
pack_no++;
}
else
{
uart_putchar(XMODEM_NAK); //要求重发数据块
}
}
else
{
uart_putchar(XMODEM_ACK); //要求重发数据块
}
}
while(uart_waitchar() != XMODEM_EOT);
uart_putchar(XMODEM_ACK); //通知PC全部数据收到
if(buffer_pointer)
write_one_page(); //写最后一页零散数据???
quit(); //退出bootloader程序,从0x0000处执行应用程序
} 问题解决了!~
原来是CVAVR编译器在编译“SPMCR = 0x01”时,也用到了r30寄存器(见图)。这样一来,本应用来给spm寻址的Z寄存器(r30,r31)中的地址就被破坏了,程序自然就不能正常运行了。
楼主这是没保护好现场啊 本帖最后由 guew 于 2013-5-30 20:23 编辑
guew 发表于 2013-5-30 20:16 static/image/common/back.gif
问题解决了!~
原来是CVAVR编译器在编译“SPMCR = 0x01”时,也用到了r30寄存器(见图)。这样一来,本应用 ...
这是修改后的代码void page_fill(uint16 p_address,uint16 p_data)
{
#asm("lds r30,$025b"); //将p_address的低八位放入Z寄存器的低八位
#asm("lds r31,$025c"); //将p_address的高八位放入Z寄存器的高八位
#asm("lds r0,$0259"); //将data的低八位放入r0寄存器
#asm("lds r1,$025a"); //将data的高八位放入r1寄存器
#asm("ldi r22,0x01");
#asm("sts $57,r22");
#asm("spm"); //加载页指令生效
}
页:
[1]