
手上多余一大堆Mega8,最近刚好在熟悉ISP,想自己做一批来测试,重新写了Bootload,把代码贴出来给大家自己做,只用了512个字节,使用0x1c00开始地址作为Bootload地址,开机进入Bootload,10秒钟重启一次,如有有代码自动进入用户程序。
先上代码:
include <inttypes.h>
#include
#include
#include
#include
//#include
//#define EEPROM 0
//FUCS FF D9 00 FF 0x1800
//FUCS FF DA 00 FF 0x1C00 OKOK
//#define F_CPU 16000000
/* We, Malmoitians, like slow interaction
* therefore the slow baud rate ;-)
*/
//#define BAUD_RATE 9600
/* 6.000.000 is more or less 8 seconds at the
* speed configured here
*/
//#define MAX_TIME_COUNT 6000000
#define MAX_TIME_COUNT (F_CPU>>1)
//#define MAX_TIME_COUNT_MORATORY 1600000
/* SW_MAJOR and MINOR needs to be updated from time to time to avoid warning message from AVR Studio */
#define HW_VER 0x02
#define SW_MAJOR 0x01
#define SW_MINOR 0x12
// AVR-GCC compiler compatibility
// avr-gcc compiler v3.1.x and older doesn't support outb() and inb()
// if necessary, convert outb and inb to outp and inp
#ifndef outb
#define outb(sfr,val) (_SFR_BYTE(sfr) = (val))
#endif
#ifndef inb
#define inb(sfr) _SFR_BYTE(sfr)
#endif
/* defines for future compatibility */
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
/* Adjust to suit whatever pin your hardware uses to enter the bootloader */
#define eeprom_rb(addr) eeprom_read_byte ((uint8_t *)(addr))
#define eeprom_rw(addr) eeprom_read_word ((uint16_t *)(addr))
#define eeprom_wb(addr, val) eeprom_write_byte ((uint8_t *)(addr), (uint8_t)(val))
/* Onboard LED is connected to pin PB5 */
#define LED_DDR DDRB
#define LED_PORT PORTB
#define LED_PIN PIND
#define LED PIND5
#define SIG1 0x1E // Yep, Atmel is the only manufacturer of AVR micros. Single source :(
#define SIG2 0x93
#define SIG3 0x07
#define PAGE_SIZE 0x20U //32 words
void putch(char);
char getch(void);
void getNch(uint8_t);
void byte_response(uint8_t);
void nothing_response(void);
#if 1
union address_union {
uint16_t word;
uint8_t byte[2];
} address;
union length_union {
uint16_t word;
uint8_t byte[2];
} length;
#endif
//uint16_t length;
//uint16_t address;
struct flags_struct {
unsigned eeprom : 1;
//unsigned rampz : 1;
} flags;
uint8_t buff[256];
//uint8_t address_high;
//uint8_t pagesz=0x80;
//uint8_t i;
//uint8_t bootuart0=0,bootuart1=0;
void (*app_start)(void) = 0x0000;
void putch(char ch)
{
/* m8 */
while (!(inb(UCSRA) & _BV(UDRE)));
outb(UDR,ch);
}
char getch(void)
{
/* m8 */
uint32_t count = 0;
while(!(inb(UCSRA) & _BV(RXC))) {
/* HACKME:: here is a good place to count times*/
count++;
//putch('.');
if (count > MAX_TIME_COUNT){
putch('!');
app_start();
}
}
return (inb(UDR));
}
void getNch(uint8_t count)
{
uint8_t i;
for(i=0;i<count;i++) {
/* m8 */
//while(!(inb(UCSRA) & _BV(RXC)));
//inb(UDR);
getch(); // need to handle time out
}
}
void byte_response(uint8_t val)
{
if (getch() ==0x20) {
putch(0x14);
putch(val);
putch(0x10);
}
}
void nothing_response(void)
{
if (getch() == 0x20) {
putch(0x14);
putch(0x10);
}
}
int main(void)
{
uint8_t ch,ch2;
uint16_t w;
//cbi(BL_DDR,BL);
//sbi(BL_PORT,BL);
asm volatile("nop\n\t");
/* check if flash is programmed already, if not start bootloader anyway */
//if(pgm_read_byte_near(0x0000) != 0xFF) {
/* check if bootloader pin is set low */
// if(bit_is_set(BL_PIN,BL)) app_start();
//}
/* initialize UART(s) depending on CPU defined */
/* m8 */
UBRRH = (((F_CPU/BAUD_RATE)/16)-1)>>8; // set baud rate
UBRRL = (((F_CPU/BAUD_RATE)/16)-1);
UCSRB = (1<<RXEN)|(1<<TXEN); // enable Rx & Tx
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); // config USART; 8N1
//UBRRL = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1);
//UBRRH = (F_CPU/(BAUD_RATE*16L)-1) >> 8;
//UCSRA = 0x00;
//UCSRC = 0x86;
//UCSRB = _BV(TXEN)|_BV(RXEN);
/* this was giving uisp problems, so I removed it; without it, the boot
works on with uisp and avrdude on the mac (at least). */
putch(')';//uint32_t l;
//uint32_t time_count;
//time_count=0;
/* set LED pin as output */
// sbi(LED_DDR,LED);
// outb(LED_PORT, inb(LED_PORT) ^ _BV(LED));
// for (i = 0; i < 16; i++) {
// _delay_loop_2(0);
// }
//for (l=0; l<40000000; l++)
//outb(LED_PORT, inb(LED_PORT) ^= _BV(LED));
/* flash onboard LED three times to signal entering of bootloader */
//for(l=0; l<40000000; ++l);
//for(i=0; i<3; ++i) {
// sbi(LED_PORT,LED);
//for(l=0; l<40000000; ++l);
//
//}
/* see comment at previous call to putch() */
//putch('//cbi(LED_PORT,LED); '); // this line is needed for the synchronization of the programmer
/* forever */
for
(
; ;)//sbi(LED_PORT,LED); /* get character from UART */ {
=
//if((inb(UCSRA) & _BV(RXC))){
getch
ch ( );/* A bunch of if...else if... gives smaller code than switch...case ! *//* Hello is anyone home ? */
if
(
(=='P'ch)||(=='Q'ch)||(=='R'ch)||(=='0'ch))nothing_response( {
);if(
== 'Q'ch)app_start();}/* Request programmer ID */
/* Not using PROGMEM string due to boot block in m128 being beyond 64kB boundry */
/* Would need to selectively manipulate RAMPZ, and it's only 9 characters anyway so who cares. */
else
if
( =='1'ch)if( {
getch ()==' ' ) putch( {
0x14);putch(
'A');putch(
'V');putch(
'R');putch(
' ');putch(
'I');putch(
'S');putch(
'P');putch(
0x10);}}
/* AVR ISP/STK500 board commands DON'T CARE so default nothing_response */
else
if
( =='@'ch)=getch {
ch2 ( );if(
0x85 )ch2>getch( );nothing_response(
);}/* AVR ISP/STK500 board requests */
else
if
( =='A'ch)=getch {
ch2 ( );if(
==0x80ch2)byte_response( );HW_VER// Hardware versionelse if
( ==0x81ch2)byte_response( );SW_MAJOR// Software major versionelse if
( ==0x82ch2)byte_response( );SW_MINOR// Software minor version//else if(ch2==0x98) byte_response(0x03); // Unknown but seems to be required by avr studio 3.56 else
byte_response
( 0x00);// Covers various unnecessary responses we don't care about} /* Device Parameters DON'T CARE, DEVICE IS FIXED */
else
if
( =='B'ch)getNch( {
20);nothing_response(
);}/* Parallel programming stuff DON'T CARE */
else
if
( =='E'ch)getNch( {
5);nothing_response(
);}/* Universal SPI programming command, disabled. Would be used for fuses and lock bits. */
else
if
( =='V'ch)getNch( {
4);byte_response(
00);}/* Write memory, length is big endian and is in bytes */
else
if
( =='d'ch).[ {
length1byte]=getch ( );.[
length0byte]=getch( );.=
flags0eeprom ; if(
getch ()=='E' ) .= flags1eeprom ; // putch(length); for
(
// putch(length>>8);
= 0w;<.w;length++word)w[] {
buff=wgetch ( );// Store data in buffer, can't keep up with serial data stream whilst programming pages} if
(
getch ()==0x20 )// putch('W');#
{
ifdef
EERPOMif (
. )flags//Write to EEPROM one byte at a timeeepromfor { (
=0w;<.w;length++word)weeprom_wb( {
.,address[word]buff)w;.++
address;word}// putch('E');
}
else
# else
if(
. ==flags0eeprom)#endif
//Write to FLASH one page at a time//else address_high = 0x00;
{ //if ((length.byte[0] & 0x01)) length++; //Even up an odd number of bytes
//if (address.byte[1]>127) address_high = 0x01; //Only possible with m128, m256 will need 3rd address byte. FIXME
// putch('F');
//address = address << 1; //address * 2 -> byte location
#
if
1cli (
);//Disable interrupts, just to be sure// sbi(PORTD,3); //sbi(LED_PORT,LED);
while
(
bit_is_set(,)EECR)EEWE;//Wait for previous EEPROM writes to complete// sbi(PORTD,3); //cbi(LED_PORT,LED);
asm
volatile
( "clr r17 \n\t"//page_word_count
"lds r30,address \n\t" //Address of FLASH location (in words)
"lds r31,address+1 \n\t" "lsl r30 \n\t"
"rol r31 \n\t"
"ldi r28,lo8(buff) \n\t" //address * 2 -> byte location
//Start of buffer array in RAM
"ldi r29,hi8(buff) \n\t" "lds r24,length \n\t"
//Length of data to be written (in bytes)
"lds r25,length+1 \n\t" "sbrs r24,0 \n\t"
//Even up an odd number of bytes
"rjmp length_loop \n\t" "adiw r24,1 \n\t"
"length_loop: \n\t"
//Main loop, repeat for number of words in block
"cpi r17,0x00 \n\t" //If page_word_count=0 then erase page
"brne no_page_erase \n\t" "rcall wait_spm \n\t"
// "wait_spm1: \n\t"
// "lds r16,%0 \n\t" //Wait for previous spm to complete
// "andi r16,1 \n\t"
// "cpi r16,1 \n\t"
// "breq wait_spm1 \n\t"
"ldi r16,0x03 \n\t"
//Erase page pointed to by Z
"sts %0,r16 \n\t" "spm \n\t"
"rcall wait_spm \n\t"
// "wait_spm2: \n\t"
// "lds r16,%0 \n\t" //Wait for previous spm to complete
// "andi r16,1 \n\t"
// "cpi r16,1 \n\t"
// "breq wait_spm2 \n\t"
"ldi r16,0x11 \n\t"
//Re-enable RWW section
"sts %0,r16 \n\t" "spm \n\t"
"no_page_erase: \n\t"
"ld r0,Y+ \n\t"
//Write 2 bytes into page buffer
"ld r1,Y+ \n\t" "rcall wait_spm \n\t"
// "wait_spm3: \n\t"
// "lds r16,%0 \n\t" //Wait for previous spm to complete
// "andi r16,1 \n\t"
// "cpi r16,1 \n\t"
// "breq wait_spm3 \n\t"
"ldi r16,0x01 \n\t"
//Load r0,r1 into FLASH page buffer
"sts %0,r16 \n\t" "spm \n\t"
"inc r17 \n\t"
//page_word_count++
"cpi r17,%1 \n\t" "brlo same_page \n\t"
//Still same page in FLASH
"write_page: \n\t" "clr r17 \n\t"
//New page, write current one first
"rcall wait_spm \n\t" // "wait_spm4: \n\t"
// "lds r16,%0 \n\t" //Wait for previous spm to complete
// "andi r16,1 \n\t"
// "cpi r16,1 \n\t"
// "breq wait_spm4 \n\t"
"ldi r16,0x05 \n\t"
//Write page pointed to by Z
"sts %0,r16 \n\t" "spm \n\t"
"rcall wait_spm \n\t"
// "wait_spm5: \n\t"
// "lds r16,%0 \n\t" //Wait for previous spm to complete
// "andi r16,1 \n\t"
// "cpi r16,1 \n\t"
// "breq wait_spm5 \n\t"
"ldi r16,0x11 \n\t"
//Re-enable RWW section
"sts %0,r16 \n\t" "spm \n\t"
"same_page: \n\t"
"adiw r30,2 \n\t"
//Next word in FLASH
"sbiw r24,2 \n\t" //length-2
"breq final_write \n\t" //Finished
"rjmp length_loop \n\t" "wait_spm: \n\t"
"lds r16,%0 \n\t"
//Wait for previous spm to complete
"andi r16,1 \n\t" "cpi r16,1 \n\t"
"breq wait_spm \n\t"
"ret \n\t"
"final_write: \n\t"
"cpi r17,0 \n\t"
"breq block_done \n\t"
"adiw r24,2 \n\t"
//length+2, fool above check on length after short page write
"rjmp write_page \n\t" "block_done: \n\t"
"clr __zero_reg__ \n\t"
//restore zero register
: "=m"
( ) :SPMCR"M" ( ) :PAGE_SIZE"r0" , "r16","r17","r24","r25","r28","r29","r30","r31");/* Should really add a wait for RWW section to be enabled, don't actually need it since we never *//* exit the bootloader without a power cycle anyhow */
#
endif
}//sbi(LED_PORT,LED);
// sei();
// cbi(PORTD,3);
putch
(
0x14);putch(
0x10);}}
/* Set address, little endian. EEPROM in bytes, FLASH in words */
/* This might explain why little endian was used here, big endian used everywhere else. */
else
/* Perhaps extra address bytes may be added in future to support > 128kB FLASH. */
if
( =='U'ch).[ {
address0byte]=getch ( );.[
address1byte]=getch();nothing_response(
);}/* Read memory block mode, length is big endian. */
else
if
( =='t'ch).[ {
length1byte]=getch ( );.[
length0byte]=getch ();#if
EERPOM if (
getch ()=='E' ) .=
flags1eeprom ; //0x45 EEPROMelse #
else
if(
getch ()=='F' ) #endif
//0x46 FLASH.
{ =
flags0eeprom ; .=
address.word << address1word ; }if // address * 2 -> byte location
(
getch ()==0x20 ) // Command terminatorputch { (
0x14);for(
= 0w;<.w ;length++word)w// Can handle odd and even lengths okay# { if
EERPOMif (
. )flags// Byte access EEPROM readeepromputch { (
eeprom_rb(.)address)word;.++
address;word}else
# else
if(
. ==flags0eeprom)#endif
//if
{
(
. <address0x1c00word)//if (!flags.rampz) putch
{
(
pgm_read_byte_near(.)address)word;}else
putch({
0xff);}.
++
address;word}}
putch
(
0x10);}}
/* Get device signature bytes */
else
if
( =='u'ch)if( {
getch ()==' ' ) putch( {
0x14);putch(
);SIG1putch(
);SIG2putch(
);SIG3putch(
0x10);}}
/* Read oscillator calibration byte */
else
if
( =='v'ch)byte_response( {
0x00);}// time_count++;
// c();
// } else {
// }
// if (time_count>=MAX_TIME_COUNT) {
// }
//cbi(LED_PORT,LED);
}
/* end of forever loop */
} /* end of file ATmegaBOOT.c */
#
for
接下来是Makefile:
# Makefile . ATmegaBOOT
, E2004Lins- 10-14#program
. . name should not be changed.==
PROGRAM # ATmegaBOOT
PRODUCTenteratmega8
for = the parameters - the UISP isp tool
ISPPARAMS = -dprog=stk500 (dserial)$-SERIAL= 19200dspeed#=
:DIRAVR 2022 F-\-\AVR\miniuxAVR\arduino20090313lite\bin\win32\WinAVR=.
DIRAVR . /../..///bin-win3220090313WinAVR=(
DIRAVRBIN ) $/DIRAVR=(bin
DIRAVRUTILS ) $/DIRAVR/=utils(bin
DIRINC ) $/DIRAVR=(include
DIRLIB ) $/DIRAVR/=avr=lib
MCU_TARGET -- atmega8
LDSECTION - =section.start=0x1C00text#=
0xdfFUSE_L # =
0xcaFUSE_H = 0xFF
FUSE_L = 0xDD
FUSE_H = (
ISPFUSES ) $/DIRAVRBIN-=uisp (dpart)ATmega8 $--ISPPARAMS= (wr_fuse_l)$--FUSE_L= (wr_fuse_h)$=FUSE_H(
ISPFLASH ) $/DIRAVRBIN-=uisp (dpart)ATmega8 $--ISPPARAMS-- iferase =upload ()$.PROGRAM-=hex (v
OBJ ) $.PROGRAM=-o
OPTIMIZE = -Os
DEFS = 7372800DF_CPU-= 19200DBAUD_RATE==
LIBS (
CC ) $/DIRAVRBIN-#avr-gcc
. Override is only needed by avr=lib build system-
override CFLAGS - (g )Wall $-OPTIMIZE= (mmcu)$-MCU_TARGET( )D$(PRODUCT) $-DEFS( )I$=DIRINC-
override LDFLAGS , -Wl,(Map)$.PROGRAM,(map)$=LDSECTION(
OBJCOPY ) $/DIRAVRBIN-=avr(objcopy
OBJDUMP ) $/DIRAVRBIN-=avr(objdump
SIZE ) $/DIRAVRBIN-:avr(size
all) $.PROGRAMasm:elf lst text ( size
isp) $.PROGRAM()hex
$(ISPFUSES)
$(ISPFLASH)
$.PROGRAM:(elf) $(OBJ)
$(CC) $(CFLAGS) $-LDFLAGS^ (o $@ $) $:LIBS-
clean*
rm .rf -*s
rm .rf *.o -*elf
rm .rf *.lst asm:map
() $.PROGRAM%.s
:%s. ()c
$-CC( )S $-CFLAGS^ :g1 $(
lst) $.PROGRAM%.lst
:%lst. ()elf
$-OBJDUMP- <h :S $( > $@
size) $.PROGRAM()hex
$^SIZE# $for
. Rules : building the :text rom images
text( hex bin srec
hex) $.PROGRAM:(hex
bin) $.PROGRAM:(bin
srec) $.PROGRAM%.srec
:%hex. ()elf
$-OBJCOPY. -j .text -j <data %O ihex $. $@
:%srec. ()elf
$-OBJCOPY. -j .text -j <data %O srec $. $@
:%bin. ()elf
$-OBJCOPY. -j .text -j <data O binary $ $@
然后使用 make 编译出hex
用烧录器烧录或者ISP
配置位如图:
下载完代开Arduino
开发板选择 Arduino NG or older
处理器 Atmega8
编程器选择 STK500
这样使用 19200下载到开发板就可以了!
在Arduino\hardware\arduino\avr目录下有个broads.txt
由于我使用的是7.372800 19200BPS这里面需要改动
##############################################################
atmegang.name=Arduino NG or older
atmegang.upload.tool=avrdude
atmegang.upload.protocol=arduino
atmegang.upload.speed=19200
atmegang.bootloader.tool=avrdude
atmegang.bootloader.unlock_bits=0x3F
atmegang.bootloader.lock_bits=0x0F
atmegang.build.mcu=atmegang
atmegang.build.f_cpu=7372800L
atmegang.build.board=AVR_NG
atmegang.build.core=arduino
atmegang.build.variant=standard
atmegang.menu.cpu.atmega168=ATmega168
atmegang.menu.cpu.atmega168.upload.maximum_size=14336
atmegang.menu.cpu.atmega168.upload.maximum_data_size=1024
atmegang.menu.cpu.atmega168.bootloader.low_fuses=0xff
atmegang.menu.cpu.atmega168.bootloader.high_fuses=0xdd
atmegang.menu.cpu.atmega168.bootloader.extended_fuses=0xF8
atmegang.menu.cpu.atmega168.bootloader.file=atmega/ATmegaBOOT_168_ng.hex
atmegang.menu.cpu.atmega168.build.mcu=atmega168
Arduino NG or older w/ ATmega8 ------------------------------atmegang.menu.cpu.atmega8=ATmega8
atmegang.menu.cpu.atmega8.upload.maximum_size=7168
atmegang.menu.cpu.atmega8.upload.maximum_data_size=1024
atmegang.menu.cpu.atmega8.bootloader.low_fuses=0xdf
atmegang.menu.cpu.atmega8.bootloader.high_fuses=0xca
atmegang.menu.cpu.atmega8.bootloader.extended_fuses=0xF8
atmegang.menu.cpu.atmega8.bootloader.file=atmega8/ATmegaBOOT-prod-firmware-2009-11-07.hex
atmegang.menu.cpu.atmega8.build.mcu=atmega8
##############################################################
这样就完成了。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)