您的位置:首页 > 其它

avr bootloader 源码

2015-09-11 09:58 591 查看
assembly.s

.text

SPMCR = 0x57 ;RWW区忙标志,读RWW区允许,允许写程序存储区
; void write_page (unsigned int adr, unsigned char function);
; bits 8:15 adr addresses the page...(must setup RAMPZ beforehand!!!)
_write_page::
XCALL __WAIT_SPMEN__
movw r30, r16 ;move address to z pointer (R31 = ZH, R30 = ZL)
STS SPMCR, R18 ;argument 2 decides function
SPM ;perform pagewrite
RET
;-----------------------------------------
; void fill_temp_buffer (unsigned int data, unsigned int adr);
; bits 7:1 in adr addresses the word in the page... (2=first word, 4=second word etc..)
_fill_temp_buffer::
XCALL __WAIT_SPMEN__
movw r30, r18 ;move adress to z pointer (R31=ZH R30=ZL)
movw r0, r16 ;move data to reg 0 and 1
LDI R19, 0x01
STS SPMCR, R19
SPM ;Store program memory
RET

;-----------------------------------------
;unsigned char read_flash(unsigned int add);
_read_flash::
mov r31,r17
mov r30,r16
lpm r16,z
clr r17
ret

;unsigned int read_program_memory (unsigned int adr ,unsigned char cmd);
_read_program_memory::
movw r30, r16 ;move adress to z pointer
SBRC R18, 0 ;read lockbits? (second argument = 0x09)
STS SPMCR, R18 ;if so, place second argument in SPMEN register
LPM r16, Z+
LPM r17, Z
RET

;-----------------------------------------

_enableRWW::
XCALL __WAIT_SPMEN__
LDI R27,0x11
STS SPMCR,R27
SPM
RET

;-----------------------------------------
__WAIT_SPMEN__:
LDS R27,SPMCR ; load SPMCR to R27
SBRC R27,0 ; check SPMEN flag
RJMP __WAIT_SPMEN__ ; wait for SPMEN flag cleared
RET

;-----------------------------------------

assembly.h

void write_page (unsigned int adr, unsigned char function);
void fill_temp_buffer (unsigned int data,unsigned int adr);
unsigned int read_program_memory (unsigned int adr,unsigned char cmd);
//void write_lock_bits (unsigned char val);
void enableRWW(void);
unsigned char read_flash(unsigned int add);

main.c

/******************************************************************************
Atmega16 BootLoad程序
日 期:2004年的最后一天
/*****************************************************************************/
#include <string.h>
#include <macros.h>
#include "assembly.h"//包含汇编代码头文件
//×××××××××××××××××××××××××××××××××××××××××××××××××××××××××
//请根据目标板选择芯片型号
//#define ChipType Atmega8
#define ChipType Atmega16
//#define ChipType Atmega32
//#define ChipType Atmega64
//#define ChipType Atmega128
//#define ChipType Atmega8535
//*********************************************************
//选择BOOT区大小
//#define BootSize 'a' //128
//#define BootSize 'b' //256
//#define BootSize 'c' //512
//#define BootSize 'd' //1024
//#define BootSize 'e' //2048(不知道是否有2048字BOOT空间的芯片)
//选择BootLoad版本号
//#define BootVer 'f' //1.0版本
//#define BootVer 'g' //1.1版本
//#define BootVer 'h' //1.2版本
//#define BootVer 'i' //1.3版本
//#define BootVer 'j' //1.4版本
//#define BootVer 'k' //1.5版本
//#define BootVer 'l' //1.6版本
//#define BootVer 'm' //1.7版本
//#define BootVer 'n' //1.8版本
//#define BootVer 'o' //1.9版本
//#define BootVer 'p' //2.0版本(应该是最终版本了)
//**********************************************************
#define Atmega16 0x31
//*****************************************************************************
//#define InteClk //是否使用内部时钟
//#define OscAddress 0x1fff //时钟校准值存储地址
//#define OscAddress 0x3fff //时钟校准值存储地址
//*****************************************************************************
//8时钟下的波特率设置
//#define BAU 103 //4800
//#define BAU 51 //9600
//#define BAU 34 //14400
//#define BAU 25 //19200
//16M时钟下的波特率设置
#define BAU 103 //9600
//使用的EEPROM
#define EEPROM_UPDATE_0X00_0X06 7
#define EEPROM_REPEAT_ENTER_BOOT_TIMES 0x07
#define EEPROM_DEBUG0 0x08
#define EEPROM_DEBUG1 0x09
#define ERASE_FLASH_PAGE_NUM 112//擦除页数

const unsigned char ucEepromWriteSuccess[EEPROM_UPDATE_0X00_0X06]={"success"};
const unsigned char ucEepromWriteUpdates[EEPROM_UPDATE_0X00_0X06]={"updates"};

//*****************************************************************************
#if (ChipType == Atmega16)
#include "iom16v.h"
#define PageByte 128
#define AddressShift 7
#endif
void FlashLoad(void);
unsigned char GetPageNumber(void);
void ExecCode(void);
char GetOnePageData(void);
unsigned char WriteFlash(void);
char CheckFlash(void);
void SendChar(unsigned char c);
void delay(void); //1ms延时函数
//unsigned char RecChar(void);
static unsigned int GetCRC16Code(unsigned char* pCalcBuf, unsigned char ucSize);

//unsigned char PageBuffer[PageByte+2];
unsigned int PageAddress=0;
#define BUFLEN 200
char uRxData;
char ucRecvBuf[BUFLEN];
unsigned int uiBufLen=0;
unsigned int uiStartBufDateLen=0;

//读EEPROM函数
static void EEPROM_Write(unsigned int Add,unsigned char Data)
{
if(Add<512) //如果地址大于512,无效
{
while(EECR&BIT(EEWE)); //查询上一次EEPROM写操作是否完成
EEAR=Add; //写入地址
EEDR=Data; //写入数据
EECR|=BIT(EEMWE); //EEPROM写主机使能:准备
EECR|=BIT(EEWE); //EEPROM写使能:写入
}
}
//读EEPROM函数
static unsigned char EEPROM_Read(unsigned int Add)
{
unsigned char Temp=0;
if(Add<512) //如果地址大于512,读取0值
{
while(EECR&BIT(EEWE)); //查询上一次EEPROM写操作是否完成
EEAR=Add; //写入地址
EECR|=BIT(EERE); //EEPROM读使能:读出
Temp=EEDR; //读取数据
}
return Temp; //返回数据
}
#if 0
void PrintfStringToArm(char * str)
{
int i=0;
for(i=0;i<strlen(str);i++)
{
SendChar(*(str+i));
}
}
#endif

/*****************************************************************************/
//Flash编程
/*****************************************************************************/
void FlashLoad(void)
{
unsigned int i;
unsigned char ucPageDateSuccessFlag=0;
SendChar('!');
while (1)
{
if(!GetPageNumber())//获取页地址
{
return;
}
else
{
if (PageAddress == 0xff80)//写结束
{
SendChar('$');
CLI();

for(i=0;i<EEPROM_UPDATE_0X00_0X06;i++)
{
EEPROM_Write(i,ucEepromWriteSuccess[i]);
}
SEI();
return;
}

ucPageDateSuccessFlag=GetOnePageData();
if (ucPageDateSuccessFlag==1)//获取一页正确的数据
{
if(WriteFlash())
{
if (CheckFlash())
SendChar('!');
else
SendChar('@');
}
else
{
return;
}
}
else if(ucPageDateSuccessFlag==2)//获取一页错误的数据
{
SendChar('@');
}
else//超时
{
return;
}
}
}
//SendChar('%');
}
/*****************************************************************************/
unsigned char GetPageNumber(void)
{
unsigned int i;
unsigned char j;
unsigned int uiAddress;
for(j=0;j<100;j++)
{
for(i=0; (i+4)<=uiBufLen; i++)
{
if(memcmp(ucRecvBuf+i,"##",2)==0)//"##"后紧跟页地址
{
memcpy(&uiAddress,ucRecvBuf+i+2,2);

PageAddress=(uiAddress<<AddressShift);//验证了Z7~Z13(见中文版Datesheet P245)
uiStartBufDateLen=i+4;//页数据的偏移位

return 1;
}
}
delay();
}
return 0;
}
static unsigned int GetCRC16Code(unsigned char* pCalcBuf, unsigned char ucSize)
{
unsigned char i = 0;
unsigned char j = 0;
unsigned int usReturnValue = 0xFFFF;
unsigned int usNew = 0xA001;

for (i=0; i<ucSize; ++i)
{
usReturnValue ^= pCalcBuf[i];
for(j=0; j<8; ++j)
{
if(usReturnValue & 0x0001)
{
usReturnValue >>= 1;
usReturnValue ^= usNew;
}
else
{
usReturnValue >>= 1;
}
}
}
return usReturnValue;
}

/*****************************************************************************/
char GetOnePageData(void)
{
unsigned char i;
unsigned int LocalCheckSum = 0;
unsigned int CheckSum = 0;
for(i=0;i<200;i++)
{
if(uiBufLen>=(uiStartBufDateLen+PageByte+2))
{
//for(i=0;i<(PageByte+2);i++)
//{
// PageBuffer[i]=ucRecvBuf[i+uiStartBufDateLen];
//}
//LocalCheckSum=GetCRC16Code(PageBuffer, PageByte);
LocalCheckSum=GetCRC16Code(&ucRecvBuf[uiStartBufDateLen-2], PageByte+2);//将页地址也一起校验,共校验PageByte+2个字节

//memcpy(&CheckSum,&PageBuffer[PageByte],2);
memcpy(&CheckSum,&ucRecvBuf[uiStartBufDateLen+PageByte],2);

if (LocalCheckSum == CheckSum)
{
return 1;
}
else
{
CLI();

memset(ucRecvBuf,0,BUFLEN);

uiBufLen=0;
SEI();
return 2;
}
}
delay();
}
return 0;
}
/*****************************************************************************/
unsigned char WriteFlash(void)
{
unsigned int i;
unsigned int TempInt;

for (i=0;i<PageByte;i+=2)
{
//TempInt=PageBuffer[i]+(PageBuffer[i+1]<<8);//写程序是按‘字‘写的,一页128字节,64个字
TempInt=ucRecvBuf[uiStartBufDateLen+i]+(ucRecvBuf[uiStartBufDateLen+i+1]<<8);
fill_temp_buffer(TempInt,i); //call asm routine.见汇编代码,将一页的数据存储好
}

if(PageAddress==0x0000)
{
if(ucRecvBuf[uiStartBufDateLen]==0xFF)
{
//CLI();

//EEPROM_Write(EEPROM_DEBUG1,0xD1);
//SEI();
return 0;

}
else//擦除数据,当为首页时,一致性擦除0-103页所有数据
{
for(;PageAddress<ERASE_FLASH_PAGE_NUM*128;PageAddress+=128)
{
write_page(PageAddress,0x03); //0x03,Bit1=1,页擦除,Bit0=1,存储程序存储器使能(SPMEN)
}
PageAddress=0x0000;
}
}
else if(PageAddress==0x3700)//当为110页首地址时,一致性擦除110-111页的数据
{
for(;PageAddress<0x3800;PageAddress+=128)
{
write_page(PageAddress,0x03); //0x03,Bit1=1,页擦除,Bit0=1,存储程序存储器使能(SPMEN)
}
PageAddress=0x3700;
}
//write_page(PageAddress,0x03); //0x03,Bit1=1,页擦除,Bit0=1,存储程序存储器使能(SPMEN)
i=0;
if((PageAddress < 0x3800)&&(PageAddress>=i))//从112页开始,为Bootloader程序,不允许写
{
write_page(PageAddress,0x05); //0x05,Bit2=1,页写入,Bit0=1,存储程序存储器使能(SPMEN)

enableRWW();
return 1;
}
else
{
return 0;
}
}
/*****************************************************************************/
char CheckFlash(void)
{
unsigned char i;
unsigned int TempInt;
unsigned int TempInt2;
for (i=0;i<PageByte;i+=2)
{
TempInt = read_program_memory(PageAddress + i,0x00);
//TempInt2 = PageBuffer[i] +(PageBuffer[i+1]<<8);
TempInt2=ucRecvBuf[uiStartBufDateLen+i]+(ucRecvBuf[uiStartBufDateLen+i+1]<<8);
if (TempInt != TempInt2)//烧写校验错误
{
CLI();

memset(ucRecvBuf,0,BUFLEN);

uiBufLen=0;

SEI();

return 0;
}
}
CLI();

memset(ucRecvBuf,0,BUFLEN);

uiBufLen=0;

SEI();

return 1;
}
//串口接收完毕中断函数
//串口接收完毕中断触发声明
#pragma interrupt_handler Usart0RecvdIsr:iv_USART_RX
void Usart0RecvdIsr(void)
{
UCSRB&=~ BIT(RXCIE); //接收完毕中断不使能

uRxData=UDR; //读取UDR的数据
if(uiBufLen<BUFLEN)
{
ucRecvBuf[uiBufLen]=uRxData;
uiBufLen++;
}
else
{
uiBufLen=0;
}

UCSRB|=BIT(RXCIE); //接收完毕中断使能
}

/*****************************************************************************/
void SendChar(unsigned char c)
{
while (!(UCSRA&(1<<UDRE)));
UDR=c;
}

void delay(void) //45-50ms左右
{
unsigned int i,j;
for(i=0;i<100;i++)
for(j=0;j<1000;j++);
}

/*****************************************************************************/
void ExecCode(void)
{
WDTCR=0x0F;//跳出前开看门狗2014-02-18添加
GICR=0X01; //中断向量表移位允许
GICR=0X00; //中断向量指向应用程序区

asm("jmp 0x0000");
}
void main()
{
unsigned char i;
unsigned char j;
unsigned char ucEepromRepeatEnterBootTimes;
unsigned char ucEepromRead[EEPROM_UPDATE_0X00_0X06];//={0};
unsigned char bAppErrFlag=0;

CLI();

#if 0//2014-02-18屏蔽
for(i=0; i<30;i++)//延时2s左右,等MCU电源稳定
{
delay();
}
#endif
for(i=0;i<EEPROM_UPDATE_0X00_0X06;i++)
{
ucEepromRead[i]=EEPROM_Read(i);
}

if(memcmp(ucEepromRead,"updates",EEPROM_UPDATE_0X00_0X06)==0)
{

AppErr:

TIMSK=0x00;//必须复位,否则从应用区跳转时会出问题
WDTCR=0x00;

GICR=(1<<IVCE); //中断向量表移位允许
GICR=(1<<IVSEL); //中断向量指向Boot区

UCSRC=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); //8位数据+1位停止
//UCSRB = (1<<RXEN)|(1<<TXEN); //允许串口发送和接收
UCSRB=(1<<RXEN)|(1<<TXEN)|(1<<RXCIE);//允许收发,打开接收中断
UBRR = BAU;

SEI();
for(i=0;i<100;i++)//大约4-5s钟
{
SendChar('['); //通知PC机,BOOT下载准备就绪
for(j=0;j<uiBufLen;j++)
{
if(ucRecvBuf[j]==']')
{
goto UpDateMcu;
}
}
delay(); //延时等待PC机响应

if(bAppErrFlag)//应用程序异常
{
i=0;
}
}

//CLI();
//EEPROM_Write(EEPROM_DEBUG0,0xD0);//入口超时
//SEI();
goto EXIT;

}
#if 1
else
{
if(read_program_memory (0x0000,0x00)==0xFFFF)//判断应用程序首页是否异常
{
#if 0
for(i=0; i<EEPROM_UPDATE_0X00_0X06;i++)
{
EEPROM_Write(i,ucEepromWriteUpdates[i]);
}
#endif

delay();
if(read_program_memory (0x0000,0x00)==0xFFFF)//判断应用程序首页是否异常
{

bAppErrFlag = 1;

goto AppErr;
}
}
ucEepromRepeatEnterBootTimes=EEPROM_Read(EEPROM_REPEAT_ENTER_BOOT_TIMES);

if(ucEepromRepeatEnterBootTimes<0xFD)
{
for(i=0; i<EEPROM_UPDATE_0X00_0X06;i++)
{
EEPROM_Write(i,ucEepromWriteUpdates[i]);
}
}
else
{
#if 1
ucEepromRepeatEnterBootTimes--;

EEPROM_Write(EEPROM_REPEAT_ENTER_BOOT_TIMES,ucEepromRepeatEnterBootTimes);
#endif
}

goto EXIT;
}
#endif

UpDateMcu:
FlashLoad();
EXIT:
ExecCode();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  avr bootloader