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

📄 bootloader_main.c

📁 AVR单片机BOOTLOADER应用范例
💻 C
📖 第 1 页 / 共 2 页
字号:
/***********************************************
****      AVR BootLoader应用范例              ***
****  	                                     ***
**** 作者:  HJJourAVR                        ***
**** 编译器:WINAVR20050214                   ***
****                                         ***
****  	www.OurAVR.com	 2005.10.17          ***
***********************************************/
//程序参考 马潮老师的M128 Boot_load应用的实例,ICCAVR版本

/*
本程序简单的示范了AVR ATMEGA16的IAP应用,实现智能升级
		Boot Loader
		XMODEM-CRC传输协议
		CRC16校验
		
出于简化程序考虑,各种数据没有对外输出,学习时建议使用JTAG ICE硬件仿真器。
熔丝位设置
 BOOTSZ1=0
 BOOTSZ0=0  Boot区为1K字(2K字节)大小。
 BOOTRST=0  复位向量位于Boot区。
 
makefile中的程序基地址偏移
 LDFLAGS += -Wl,--section-start=.text=0x3800   //0x3800字节=0x1C00字
 
移植程序时,可根据实际大小设定Boot区,但要注意更改makefile和更改BootAdd常数,以及页写的大小分配;

采用115200bps的通讯速率,升级14KB程序需要耗时约5秒[上位机是WINDOWS 2000的超级终端]

疑问:
  1 用HEX文件烧录工作正常,但elf仿真有问题。
    用AVRstudio仿真elf(熔丝设定BOOTRST=0,程序基地址偏移=0x3800)时,所有SRAM变量丢失初始化,
  	表现为put_s()的都是乱码或不可见字符。
    但如果改成应用程序(熔丝设定BOOTRST=1,没有程序基地址偏移),则put_s()可以正常显示
  
  2 XMODEM的结束应答(EOT/CAN)后需加 delay_ms(500)的延时(程序优化,统一写在跳转到用户程序前),
    否则在下面的情况将会无法正常结束XMODEM的传输,但其实程序已经升级成功
    特殊情况:用户程序里面使用了串口,而且波特率较低(如9600bps)且开机即发送大量数据
 
*/

#include <avr/io.h>
#include <avr/delay.h>
//时钟定为外部晶体7.3728MHz,F_CPU=7372800 使用USART,115200bps
#include <avr/boot.h>
/*
boot_page_erase ( address )
	擦除FLASH 指定页,其中address 是以字节为单位的FLASH 地址
boot_page_fill ( address, data )
	填充BootLoader 缓冲页,address 为以字节为单位的缓冲页地址(对mega16 :0~128),
	而data 是长度为两个字节的字数据,因此调用前address 的增量应为2。 
	此时data 的高字节写入到高地址,低字节写入到低地址。
boot_page_write ( address )
	boot_page_write 执行一次的SPM 指令,将缓冲页数据写入到FLASH 指定页。
boot_rww_enable ( )
	RWW 区读使能
	
	根据自编程的同时是否允许读FLASH 存储器,FLASH 存储器可分为两种类型:
可同时读写区( RWW Read-While-Write ) 和 非同时读写区( NRWW NotRead-While-Write)。
对于MEGA16 RWW 为前14K 字节 NRWW 为后2K 字节。
引导加载程序对RWW 区编程时MCU 仍可以从NRWW 区读取指令并执行,而对NRWW 区编程时MCU 处于挂起暂停状态。
在对RWW 区自编程(页写入或页擦除)时,由硬件锁定RWW 区 , RWW 区的读操作被禁止
在对RWW 区的编程结束后应当调用boot_rww_enable() 使RWW 区开放。
*/
#include <avr/crc16.h>
/*
GCCAVR内置函数,可以不用头痛CRC16了
关于CRC的详细说明,可以查看一下网站: 
http://www.nongnu.org/avr-libc/user-manual/group__avr__crc.html 
函数原形
static __inline__ uint16_t _crc16_update(uint16_t __crc, uint8_t __data);
	多项式Polynomial: x^16 + x^15 + x^2 + 1 (0xa001)
	crc初始值Initial value: 0xffff
    通常用于磁盘控制器(disk-drive controllers)
static __inline__ uint16_t _crc_xmodem_update(uint16_t __crc, uint8_t __data);
	多项式Polynomial: x^16 + x^12 + x^5 + 1 (0x1021)
	crc初始值Initial value: 0x0
 	专用于XMODEM通讯协议,等效于C写的
 	uint16_t crc_xmodem_update (uint16_t crc, uint8_t data)
    {
        int i;
        crc = crc ^ ((uint16_t)data << 8);
        for (i=0; i<8; i++)
        {
            if (crc & 0x8000)
                crc = (crc << 1) ^ 0x1021;
            else
                crc <<= 1;
        }
        return crc;
    }
static __inline__ uint16_t _crc_ccitt_update (uint16_t __crc, uint8_t __data)
	多项式Polynomial: x^16 + x^12 + x^5 + 1 (0x8408)
	crc初始值Initial value: 0xffff
    专用于PPP和IrDA通讯协议
*/

//管脚定义
#define PIN_RXD				0	//PD0
#define PIN_TXD				1	//PD1

//常数定义
#define SPM_PAGESIZE 		128				//M16的一个Flash页为128字节(64字)
#define DATA_BUFFER_SIZE 	SPM_PAGESIZE	//定义接收缓冲区长度
#define BAUDRATE			115200			//波特率采用115200bps
//#define F_CPU				7372800			//系统时钟7.3728MHz

//定义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_WAIT_CHAR 	'C'

//定义全局变量
struct str_XMODEM
{
    unsigned char SOH;						//起始字节
    unsigned char BlockNo;					//数据块编号
    unsigned char nBlockNo;					//数据块编号反码
    unsigned char Xdata[128];				//数据128字节
    unsigned char CRC16hi;					//CRC16校验数据高位
    unsigned char CRC16lo;					//CRC16校验数据低位
}
strXMODEM;									//XMODEM的接收数据结构

unsigned long FlashAddress;					//FLASH地址
#define  BootAdd 			0x3800			//Boot区的首地址(应用区的最高地址)
/*	GCC里面地址使用32位长度,适应所有AVR的容量*/

unsigned char BlockCount;					//数据块累计(仅8位,无须考虑溢出)

unsigned char STATUS;						//运行状态
#define ST_WAIT_START 		0x00			//等待启动
#define ST_BLOCK_OK 		0x01			//接收一个数据块成功
#define ST_BLOCK_FAIL 		0x02			//接收一个数据块失败
#define ST_OK 				0x03			//完成


//长延时 max 65536ms
void delay_ms(unsigned int t)
{
    while(t--)
    {
        _delay_ms(1);
    }
}

//更新一个Flash页的完整处理
void write_one_page(void)
{
    unsigned char i;
    unsigned char *buf;
    unsigned int  w;
    boot_page_erase(FlashAddress);				//擦除一个Flash页
    boot_spm_busy_wait();						//等待页擦除完成
    buf=&strXMODEM.Xdata[0];
    for(i=0;i<SPM_PAGESIZE;i+=2)				//将数据填入Flash缓冲页中
    {
        w =*buf++;
        w+=(*buf++)<<8;
        //boot_page_fill(FlashAddress+i, w);	//原句
        boot_page_fill(i, w);					//只是低7位(128字节/页)有效
    }
    boot_page_write(FlashAddress);				//将缓冲页数据写入一个Flash页
    boot_spm_busy_wait();						//等待页编程完成
}

//发送采用查询方式
void put_c(unsigned char c) //发送采用查询方式
{
    loop_until_bit_is_set(UCSRA,UDRE);
    UDR=c;
}

//发送字符串
void put_s(unsigned char *ptr)
{
    while (*ptr)
    {
        put_c(*ptr++);
    }
    put_c(0x0D);
    put_c(0x0A);  //结尾发送回车换行
}


//接收指定字节数据(带超时控制,Timer0的1ms时基)
//	*ptr		数据缓冲区
//	len			数据长度
//	timeout		超时设定,最长65.536S
//  返回值		已接收字节数目
unsigned char get_data(unsigned char *ptr,unsigned char len,unsigned int timeout)
{
    unsigned count=0;
    do
    {
        if (UCSRA & (1<<RXC))
        {
            *ptr++=UDR;				//如果接收到数据,读出
            count++;
            if (count>=len)
            {
                break;				//够了?退出
            }
        }
        if(TIFR & (1<<OCF0))		//T0溢出 1ms

⌨️ 快捷键说明

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