临时抱佛脚,恶补了下ICCAVR,把Mega128的BootLoader成功改成了Mega1280,能以XModem协议通信刷机,刷机过程看似正常,问题是刷机后的运行不正常,不知道是哪里的问题,请懂AVR的指点指点:
- /*****************************************************
- 采用串行接口实现Boot_load应用的实例 华东师大电子系 马 潮
- Compiler: ICC-AVR 7.22
- Target: Mega128 改 Mega1280
- Crystal: 16Mhz
- Used: T/C0,USART0
- 2024-5-13改部转义字符 '/' 为 '\' 和部分错误
- 2024-5-18修改为Mega1280能通信刷机,但刷完运行不正常
- *****************************************************/
- #include <iom1280v.h>
- #define SPM_PAGESIZE 256 //M128的一个Flash页为256字节(128字)
- #define BAUD 19200 //波特率采用38400bps
- #define CRYSTAL 16000000 //系统时钟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 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'
- //定义全局变量
- char data[DATA_BUFFER_SIZE];
- long address = 0;
- //擦除(code=0x03)和写入(code=0x05)一个Flash页
- void boot_page_ew(long p_address, char code)
- {
- asm("mov r30,r16\n"
- "mov r31,r17\n"
- "out 0x3b,r18\n"); //将页地址放入Z寄存器和RAMPZ的Bit0中
- SPMCSR = code; //寄存器SPMCSR中为操作码
- asm("spm\n"); //对指定Flash页进行操作
- }
- //填充Flash缓冲页中的一个字
- void boot_page_fill(unsigned int address, int data)
- {
- asm("mov r30,r16\n"
- "mov r31,r17\n" //Z寄存器中为填冲页内地址
- "mov r0,r18\n"
- "mov r1,r19\n"); //r0R1中为一个指令字
- SPMCSR = 0x01;
- asm("spm\n");
- }
- //等待一个Flash页的写完成
- void wait_page_rw_ok(void)
- {
- while(SPMCSR & 0x40)
- {
- while(SPMCSR & 0x01);
- SPMCSR = 0x11;
- asm("spm\n");
- }
- }
- //更新一个Flash页的完整处理
- void write_one_page(void)
- {
- int i;
- boot_page_ew(address, 0x03); //擦除一个Flash页
- wait_page_rw_ok(); //等待擦除完成
- for(i = 0; i < SPM_PAGESIZE; i += 2) //将数据填入Flash缓冲页中
- {
- boot_page_fill(i, data[i] + (data[i + 1] << 8));
- }
- boot_page_ew(address, 0x05); //将缓冲页数据写入一个Flash页
- wait_page_rw_ok(); //等待写入完成
- }
- //从RS232发送一个字节
- void uart_putchar(char c)
- {
- while(!(UCSR0A & 0x20));
- UDR0 = c;
- }
- //从RS232接收一个字节
- int uart_getchar(void)
- {
- unsigned char status, res;
- if(!(UCSR0A & 0x80)) return -1; //no data to be received
- status = UCSR0A;
- res = UDR0;
- 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');
- //while(!(UCSR0A & 0x20)); //等待结束提示信息回送完成
- MCUCR = 0x01;
- MCUCR = 0x00; //将中断向量表迁移到应用程序区头部
- RAMPZ = 0x00; //rAMPZ清零初始化
- asm("jmp 0x0000\n"); //跳转到Flash的0x0000处,执行用户的应用程序
- }
- //UART0 initialize
- // desired baud rate: 19200
- // actual: baud rate:19231 (0.2%)
- // char size: 8 bit
- // parity: Disabled
- void uart0_init(void)
- {
- UCSR0B = 0x00; //disable while setting baud rate
- UCSR0A = 0x00;
- UCSR0C = 0x06;
- UBRR0H = BAUD_H;
- UBRR0L = BAUD_L; //Set baud rate
- UCSR0B = 0x18;
- }
- //TIMER0 initialize - prescale:1024
- // desired value: 15mSec
- // actual value: 14.976mSec (0.2%)
- void timer0_init(void)
- {
- TCCR0B = 0x00; //stop
- TCNT0 = 0x16; //set count
- OCR0A = 0xEA;
- TCCR0A = 0x00; //start timer
- TCCR0B = 0x05; //start timer
- }
- //主程序
- void main(void)
- {
- int i = 0;
- unsigned char timercount = 0;
- unsigned char packNO = 1;
- int bufferPoint = 0;
- unsigned int crc;
- uart0_init();
- timer0_init();
- //3秒种等待PC下发"d",否则退出Bootloader程序,从0x0000处执行应用程序
- while(1)
- {
- if(uart_getchar() == 'd')
- {
- uart_putchar(XMODEM_RECIEVING_WAIT_CHAR);
- break;
- }
- if (TIFR0 & 0x02) //timer0 over flow
- {
- if (++timercount > 200)
- quit(); //200*15ms = 3s
- TIFR0 = TIFR0 | 0x02;
- }
- }
- //每秒向PC机发送一个控制字符"C",等待控制字〈soh?
- while(uart_getchar() != XMODEM_SOH) //receive the start of Xmodem
- {
- if(TIFR0 & 0x02) //timer0 over flow
- {
- if(++timercount > 80) //wait about 1 second
- {
- uart_putchar(XMODEM_RECIEVING_WAIT_CHAR); //send a "C"
- timercount = 0;
- }
- TIFR0 = TIFR0 | 0x02;
- }
- }
- //开始接收数据块
- do
- {
- if ((packNO == uart_waitchar()) && (packNO == (~uart_waitchar())))
- {
- //核对数据块编号正确
- for(i = 0; i < 128; i++) //接收128个字节数据
- {
- data[bufferPoint] = uart_waitchar();
- bufferPoint++;
- }
- crc = (uart_waitchar() << 8);
- crc += uart_waitchar(); //接收2个字节的CRC效验字
- if(calcrc(&data[bufferPoint - 128], 128) == crc) //CRC校验验证
- {
- //正确接收128个字节数据
- while(bufferPoint >= SPM_PAGESIZE)
- {
- //正确接受256个字节的数据
- write_one_page(); //收到256字节写入一页Flash中
- address += SPM_PAGESIZE; //Flash页加1
- 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处执行应用程序
- }
复制代码
|