×
单片机 > 单片机程序设计 > 详情

AVR_M8 BootLoader应用范例

发布时间:2020-06-08 发布时间:
|
//meg8 bootloader 
//BOOTSZ1 BOOTSZ0=00 
//meg8 bootloader 
//BOOTSZ1 BOOTSZ0=00 
#include   
#define SPM_PAGESIZE 64              //M8的一个Flash页为64字节(32字)  

#define BAUD 38400                //波特率采用38400bps  
#define CRYSTAL 8000000            //系统时钟8MHz  
//计算和定义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.\n\r\0";  
const char loadString[]="download over\n\r\0";  
char data[DATA_BUFFER_SIZE];  
unsigned int address = 0;  
//擦除(code=0x03)和写入(code=0x05)一个Flash页  
void boot_page_ew(unsigned int p_address,char code)  
{  
    asm("mov r30,r16\n"  
        "mov r31,r17\n"  
      //  "out 0x3b,r18\n");      
     );       //将页地址放入Z寄存器和RAMPZ的Bit0中  
    SPMCR = 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中为一个指令字  
    SPMCR = 0x01;  
    asm("spm\n");  
}  
//等待一个Flash页的写完成  
void wait_page_rw_ok(void)  
{  
      while(SPMCR & 0x40)  
     {  
         while(SPMCR & 0x01);  
         SPMCR = 0x11;  
         asm("spm\n");  
     }  
}  
//更新一个Flash页的完整处理  
void write_two_page(void)  
{  
   //128字节分两页 
    int i;  
    boot_page_ew(address,0x03);                    //擦除一个Flash页  
    wait_page_rw_ok();                            //等待擦除完成  
    for(i=0;i     {  
        boot_page_fill(i, data[i]+(data[i+1]<<8));  
    }  
    boot_page_ew(address,0x05);                    //将缓冲页数据写入一个Flash页  
    wait_page_rw_ok();                            //等待写入完成  
    
   //写第2页 
   address += SPM_PAGESIZE;    //Flash页加1  
    boot_page_ew(address,0x03);                    //擦除一个Flash页  
    wait_page_rw_ok();                            //等待擦除完成  
    for(i=0;i     {  
        boot_page_fill(i, data[SPM_PAGESIZE+i]+(data[SPM_PAGESIZE+i+1]<<8));  
    }  
    
    boot_page_ew(address,0x05);                    //将缓冲页数据写入一个Flash页  
    wait_page_rw_ok();                            //等待写入完成  
    
}          
//从RS232发送一个字节  
void uart_putchar(char c)  
{  
    while(!(UCSRA & 0x20));  
    UDR = c;  
}  
//从RS232接收一个字节  
int uart_getchar(void)  
{  
    unsigned char status,res;  
    if(!(UCSRA & 0x80)) 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;  
}  
//计算CRC  
int calcrc(char *ptr, int count)  
{  
    int crc = 0;  
    char i;  
      
    while (--count >= 0)  
    {  
        crc = crc ^ (int) *ptr++ <         i = 8;  
        do  
        {  
        if (crc & 0x8000)  
            crc = crc <         else  
            crc = crc <         } while(--i);  
    }  
    return (crc);  
}  
//退出Bootloader程序,从0x0000处执行应用程序  
void quit(void)  
{  
     uart_putchar('O');uart_putchar('K');  
     uart_putchar(0x0d);uart_putchar(0x0a);  
    uart_putchar(0x0d);uart_putchar(0x0a);  
     while(!(UCSRA & 0x20));            //等待结束提示信息回送完成  
     MCUCR = 0x01;  
    MCUCR = 0x00;                    //将中断向量表迁移到应用程序区头部  
   //  RAMPZ = 0x00;                    //RAMPZ清零初始化  
     asm("jmp 0x0000\n");                //跳转到Flash的0x0000处,执行用户的应用程序  
}  
//主程序  
void main(void)  
{  
    int i = 0;  
    unsigned char timercount = 0;  
    unsigned char packNO = 1;  
    int bufferPoint = 0;  
    unsigned int crc;  
//初始化M128的USART0  
    UBRRH = BAUD_H;      
    UBRRL = BAUD_L;            //Set baud rate  
    UCSRB = 0x18;            //Enable Receiver and Transmitter  
  //  UCSRC = 0x06;            //Set frame format: 8data, 2stop bit  
   UCSRC=0x8e;//8位数据+2位STOP位,m8与m128的URSEL不同 
   //UCSRC=0x86;//8位数据+1位STOP位,m8与m128的URSEL不同 
//初始化M8的T/C2,15ms自动重载  
  OCR2 = 0xEA;   
  TCCR2 = 0x0F;      
//向PC机发送开始提示信息  
    while(startupString[i]!='\0')  
    {  
        uart_putchar(startupString[i]);  
        i++;  
    }  
//3秒种等待PC下发“d”,否则退出Bootloader程序,从0x0000处执行应用程序  
  
   while(1)  
    {  
        if(uart_getchar()== 'd') break;  
        if (TIFR & 0x80)                        //timer2 over flow  
        {  
              if (++timercount > 200) quit();        //200*15ms = 3s  
            TIFR = TIFR|0x80;  
        }  
    }  
    //每秒向PC机发送一个控制字符“C”,等待控制字〈soh〉  
    while(uart_getchar()!=XMODEM_SOH)        //receive the start of Xmodem  
    {  
         if(TIFR & 0x80)                    //timer2 over flow  
        {  
            if(++timercount > 67)                        //wait about 1 second  
            {  
                uart_putchar(XMODEM_RECIEVING_WAIT_CHAR);    //send a "C"  
                timercount=0;  
            }  
            TIFR=TIFR | 0x80;  
        }  
    }  
    //开始接收数据块  
    do  
    {  
        if ((packNO == uart_waitchar()) && (packNO ==(~uart_waitchar())))  
        {    //核对数据块编号正确  
      //SPM_PAGESIZEW 
            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)  
          //  while(bufferPoint >= 64) //(m8每页64字节) 
                {    //正确接受128个字节的数据  
                                       //收到128字节写入2页Flash中  
               write_two_page(); 

                address += SPM_PAGESIZE; 
                    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机全部收到  
   i=0; 
    while(loadString[i]!='\0')  
    {  
        uart_putchar(loadString[i]);  
        i++;  
    }  

    quit();                      //退出Bootloader程序,从0x0000处执行应用程序  
    
}  



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
AVR单片机语音识别电路模块设计