⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iap32.c

📁 avr 单片机之Mega32系列的BootLoad源码
💻 C
字号:
/**********************************************************************************************************
* Compiler        : ICCAVR VER6.3
* PATH Setting    : Output Directory = .\objs\
* Compiler Setting: Output Format = COFF/HEX
                    Optimizations = default
* Target Setting  : Device Configuration = ATMega32L
                    PRINTF Version = Small
                    Return Stack Size = 40
                    SRAM = Internal SRAM
					Pragram Type = Boot loader
                    Boot Size = 2K
* COM Protocol    : BaudRate=38400 bps; 2 StopBits; N  
* Fuse bits       : 0xC83F(Without JTEG,reset section=boot section) //for debug
  	   		        883f(with JTEG,reset section=boot section)     //for debug 
                    0xC93F(whthout jteg. reset section=0X00)       //for final producet 
* Lock bits       : 0x00EC 
* Edit Tools      : UltraEdit-32 VER8.20
* Edit Tabs       : 4 

* Project Name    : BootLoader for ATMega32L
* File name       : IAP32.C
* Crystal         : 7.3728Mhz
* PCB P/N         : used to any PCB that with ATMega32 PCB
* Comments        : 
* ----------< History >---------------------------------------------------------
* File Version    :1.0             
* Author          :zrfzd 
* E-Mail          :zrfzd@163.com 
* Date            :May.19.2005
* Comments        :fist release        
**********************************************************************************************************/
//*****************************************************************************
// MCU selection
//*****************************************************************************
#define MEGATYPE	32	
//#define MEGATYPE	128

//#define BAUDRATE     9600
#define BAUDRATE     38400
//*****************************************************************************
// Include file
//*****************************************************************************
#if (MEGATYPE == 128) 
	#include <iom128v.h> 
	#define SPM_PAGESIZE 256              //M128的一个Flash页为256字节(128字)
#endif	 

#if (MEGATYPE == 32)
	#include <iom32v.h> 
	#define SPM_PAGESIZE 128             //M32的一个Flash页为128字节(64字)
#endif	 

//*****************************************************************************
//计算和定义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' 
//定义全局变量 
//const char startupString[]="Type 'd' download, Others run app.\n\r\0";
char startupString[]="S\n\r\0"; 
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中

	#if (MEGATYPE == 128)		 
    SPMCSR = code;                //寄存器SPMCSR中为操作码
	#elif (MEGATYPE == 32)
    SPMCR = code;                //寄存器SPMCSR中为操作码
	#endif
			 
    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中为一个指令字
	
	#if (MEGATYPE == 128)		 
    SPMCSR = 0x01;
	#elif (MEGATYPE == 32)
    SPMCR = 0x01;
	#endif		 
    
	asm("spm\n"); 
} 

/*==============================================================================
//等待一个Flash页的写完成 
==============================================================================*/
void wait_page_rw_ok(void) 
{ 
	#if (MEGATYPE == 128)
      while(SPMCSR & 0x40)
      {  while(SPMCSR & 0x01); 
         SPMCSR = 0x11;
 	#elif (MEGATYPE == 32)
      while(SPMCR & 0x40)	   
     { 
         while(SPMCR & 0x01); 
         SPMCR = 0x11;
	#endif		  
		  
         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();                            //等待写入完成 
}         

#if (MEGATYPE == 128)
//从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; 
} 
#endif

#if (MEGATYPE == 32)
//从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; 
} 
#endif
 
/*==============================================================================
//等待从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'); 
	  uart_putchar(0x0d);uart_putchar(0x0a);

	 #if (MEGATYPE == 128)	  
     while(!(UCSR0A & 0x20));            //等待结束提示信息回送完成
     RAMPZ = 0x00;                    //RAMPZ清零初始化
     MCUCR=0X01;           //中断向量表移位允许
     MCUCR=0X00;           //中断向量指向应用程序区

	 #elif (MEGATYPE == 32)
     while(!(UCSRA & 0x20));            //等待结束提示信息回送完成
     GICR=0X01;           //中断向量表移位允许
     GICR=0X00;           //中断向量指向应用程序区
	 #endif
    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;
//    unsigned char high,low,temp;	

	asm ("CLI");          		      // disable all interrupts
	#if (MEGATYPE == 128)	  
 //初始化M128的USART0
    WDTCR = (1<<WDCE)|(1<<WDE);
	WDTCR = 0X00;	

    XDIV  = 0x00; //xtal divider
    XMCRA = 0x00; //external memory

    UCSR0B = 0x00; //disable while setting baud rate
    UCSR0A = 0x00;
    UCSR0C = 0x0E;
    UBRR0L = 0x0B; //set baud rate lo
    UBRR0H = 0x00; //set baud rate hi
    UCSR0B = 0x18;
	
    MCUCR = 0x00;
    EICRA = 0x00; //extended ext ints
    EICRB = 0x00;  //extended ext ints    //int6 for IR receiver. Failling edge trigger.
    EIMSK = 0x00;
    TIMSK = 0x00;  //timer interrupt sources
    ETIMSK = 0x00; //extended timer interrupt sources
	
    //初始化M128的T/C0,15ms自动重载 
    OCR0 = 0x6b; 
    TCCR0 = 0x05;  
   #elif (MEGATYPE == 32)
	WDTCR = (1<<WDTOE)|(1<<WDE);
	WDTCR = 0X00;	
  
    #if (BAUDRATE == 9600)
    UCSRC = 0x86;  ////Set frame format: 8data, 1 stop bit 
    UBRRL = 0x2F; //set baud rate lo
    UBRRH = 0x00; //set baud rate hi	 
	#elif (BAUDRATE == 38400)
    UCSRC = 0x8E;            //Set frame format: 8data, 2stop bit
    UBRRL = 0x0b;            //Set baud rate  38400			
    UBRRH = 00;
	#endif     
    UCSRB = 0x18;            //Enable Receiver and Transmitter 
	
    //初始化M32的T/C0,15ms自动重载  
    OCR0 = 0x6B; 
    TCCR0 = 0x05;
   #endif        
       
       
    //向PC机发送开始提示信息 
    while(startupString[i]!='\0') 
    { 
        uart_putchar(startupString[i]); 
        i++; 
    }
	 
    //3秒种等待PC下发“d”,否则退出Bootloader程序,从0x0000处执行应用程序 
    while(1) 
    { 
        if(uart_getchar()== 'd') break; 
        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 & 0x02)                    //timer0 over flow 
        { 
            if(++timercount > 67)                        //wait about 1 second 
            { 
                uart_putchar(XMODEM_RECIEVING_WAIT_CHAR);    //send a "C" 
                timercount=0; 
            } 
            TIFR=TIFR | 0x02; 
        } 
    } 
    
	//开始接收数据块 
    do 
    {  /*  high = uart_waitchar();             //for debug
	     low  = uart_waitchar();
         temp = high;		 
        if ((packNO == high) && (packNO ==(~low)))  */
				 
        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个字节的数据 d
                    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处执行应用程序 
} 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -