手上多余一大堆Mega8,最近刚好在熟悉ISP,想自己做一批来测试,重新写了Bootload,把代码贴出来给大家自己做,只用了512个字节,使用0x1c00开始地址作为Bootload地址,开机进入Bootload,10秒钟重启一次,如有有代码自动进入用户程序。
先上代码:
include#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 //#define BAUD_RATE 9600 //#define MAX_TIME_COUNT 6000000 #define MAX_TIME_COUNT (F_CPU>>1) //#define MAX_TIME_COUNT_MORATORY 1600000 #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 #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif #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)) #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) { while (!(inb(UCSRA) & _BV(UDRE))); outb(UDR,ch); } char getch(void) { uint32_t count = 0; while(!(inb(UCSRA) & _BV(RXC))) { 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 //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("nopnt"); //if(pgm_read_byte_near(0x0000) != 0xFF) { // if(bit_is_set(BL_PIN,BL)) app_start(); //} UBRRH = (((F_CPU/BAUD_RATE)/16)-1)>>8; // set baud rate UBRRL = (((F_CPU/BAUD_RATE)/16)-1); UCSRB = (1< > 8; //UCSRA = 0x00; //UCSRC = 0x86; //UCSRB = _BV(TXEN)|_BV(RXEN); putch(' '); //uint32_t l; //uint32_t time_count; //time_count=0; // sbi(LED_DDR,LED); // for (i = 0; i < 16; i++) { // outb(LED_PORT, inb(LED_PORT) ^ _BV(LED)); // _delay_loop_2(0); // } //for (l=0; l<40000000; l++) //outb(LED_PORT, inb(LED_PORT) ^= _BV(LED)); //for(i=0; i<3; ++i) { //for(l=0; l<40000000; ++l); // sbi(LED_PORT,LED); //for(l=0; l<40000000; ++l); // //} //putch(' '); // this line is needed for the synchronization of the programmer //cbi(LED_PORT,LED); for (;;) { //sbi(LED_PORT,LED); //if((inb(UCSRA) & _BV(RXC))){ ch = getch(); if((ch=='P')||(ch=='Q')||(ch=='R')||(ch=='0')) { nothing_response(); if (ch=='Q')app_start(); } else if(ch=='1') { if (getch() == ' ') { putch(0x14); putch('A'); putch('V'); putch('R'); putch(' '); putch('I'); putch('S'); putch('P'); putch(0x10); } } else if(ch=='@') { ch2 = getch(); if (ch2>0x85) getch(); nothing_response(); } else if(ch=='A') { ch2 = getch(); if(ch2==0x80) byte_response(HW_VER); // Hardware version else if(ch2==0x81) byte_response(SW_MAJOR); // Software major version else if(ch2==0x82) 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 } else if(ch=='B') { getNch(20); nothing_response(); } else if(ch=='E') { getNch(5); nothing_response(); } else if(ch=='V') { getNch(4); byte_response(00); } else if(ch=='d') { length.byte[1] = getch(); length.byte[0]= getch(); flags.eeprom = 0; if (getch() == 'E') flags.eeprom = 1; // putch(length); // putch(length>>8); for (w=0;w buff[w] = getch(); // Store data in buffer, can't keep up with serial data stream whilst programming pages } if (getch() ==0x20) { // putch('W'); #ifdef EERPOM if (flags.eeprom) { //Write to EEPROM one byte at a time for(w=0;w eeprom_wb(address.word,buff[w]); address.word++; } // putch('E'); } else #else if (flags.eeprom==0) #endif { //Write to FLASH one page at a time //if (address.byte[1]>127) address_high = 0x01; //Only possible with m128, m256 will need 3rd address byte. FIXME //else address_high = 0x00; //address = address << 1; //address * 2 -> byte location //if ((length.byte[0] & 0x01)) length++; //Even up an odd number of bytes // putch('F'); #if 1 cli(); //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 nt" //page_word_count "lds r30,address nt" //Address of FLASH location (in words) "lds r31,address+1 nt" "lsl r30 nt" //address * 2 -> byte location "rol r31 nt" "ldi r28,lo8(buff) nt" //Start of buffer array in RAM "ldi r29,hi8(buff) nt" "lds r24,length nt" //Length of data to be written (in bytes) "lds r25,length+1 nt" "sbrs r24,0 nt" //Even up an odd number of bytes "rjmp length_loop nt" "adiw r24,1 nt" "length_loop: nt" //Main loop, repeat for number of words in block "cpi r17,0x00 nt" //If page_word_count=0 then erase page "brne no_page_erase nt" "rcall wait_spm nt" // "wait_spm1: nt" // "lds r16,%0 nt" //Wait for previous spm to complete // "andi r16,1 nt" // "cpi r16,1 nt" // "breq wait_spm1 nt" "ldi r16,0x03 nt" //Erase page pointed to by Z "sts %0,r16 nt" "spm nt" "rcall wait_spm nt" // "wait_spm2: nt" // "lds r16,%0 nt" //Wait for previous spm to complete // "andi r16,1 nt" // "cpi r16,1 nt" // "breq wait_spm2 nt" "ldi r16,0x11 nt" //Re-enable RWW section "sts %0,r16 nt" "spm nt" "no_page_erase: nt" "ld r0,Y+ nt" //Write 2 bytes into page buffer "ld r1,Y+ nt" "rcall wait_spm nt" // "wait_spm3: nt" // "lds r16,%0 nt" //Wait for previous spm to complete // "andi r16,1 nt" // "cpi r16,1 nt" // "breq wait_spm3 nt" "ldi r16,0x01 nt" //Load r0,r1 into FLASH page buffer "sts %0,r16 nt" "spm nt" "inc r17 nt" //page_word_count++ "cpi r17,%1 nt" "brlo same_page nt" //Still same page in FLASH "write_page: nt" "clr r17 nt" //New page, write current one first "rcall wait_spm nt" // "wait_spm4: nt" // "lds r16,%0 nt" //Wait for previous spm to complete // "andi r16,1 nt" // "cpi r16,1 nt" // "breq wait_spm4 nt" "ldi r16,0x05 nt" //Write page pointed to by Z "sts %0,r16 nt" "spm nt" "rcall wait_spm nt" // "wait_spm5: nt" // "lds r16,%0 nt" //Wait for previous spm to complete // "andi r16,1 nt" // "cpi r16,1 nt" // "breq wait_spm5 nt" "ldi r16,0x11 nt" //Re-enable RWW section "sts %0,r16 nt" "spm nt" "same_page: nt" "adiw r30,2 nt" //Next word in FLASH "sbiw r24,2 nt" //length-2 "breq final_write nt" //Finished "rjmp length_loop nt" "wait_spm: nt" "lds r16,%0 nt" //Wait for previous spm to complete "andi r16,1 nt" "cpi r16,1 nt" "breq wait_spm nt" "ret nt" "final_write: nt" "cpi r17,0 nt" "breq block_done nt" "adiw r24,2 nt" //length+2, fool above check on length after short page write "rjmp write_page nt" "block_done: nt" "clr __zero_reg__ nt" //restore zero register : "=m" (SPMCR) : "M" (PAGE_SIZE) : "r0","r16","r17","r24","r25","r28","r29","r30","r31"); #endif } //sbi(LED_PORT,LED); // sei(); // cbi(PORTD,3); putch(0x14); putch(0x10); } } else if(ch=='U') { address.byte[0] = getch(); address.byte[1]=getch(); nothing_response(); } else if(ch=='t') { length.byte[1] = getch(); length.byte[0] =getch(); #if EERPOM if (getch() == 'E') flags.eeprom = 1; //0x45 EEPROM else #else if (getch() == 'F') #endif { //0x46 FLASH flags.eeprom = 0; address.word = address.word << 1; // address * 2 -> byte location } if (getch() == 0x20) { // Command terminator putch(0x14); for (w=0;w // Can handle odd and even lengths okay #if EERPOM if (flags.eeprom) { // Byte access EEPROM read putch(eeprom_rb(address.word)); address.word++; } else #else if (flags.eeprom==0) #endif { // if (address.word<0x1c00) { //if (!flags.rampz) putch(pgm_read_byte_near(address.word)); }else{ putch(0xff); } address.word++; } } putch(0x10); } } else if(ch=='u') { if (getch() == ' ') { putch(0x14); putch(SIG1); putch(SIG2); putch(SIG3); putch(0x10); } } else if(ch=='v') { byte_response(0x00); } // } else { // time_count++; // if (time_count>=MAX_TIME_COUNT) { // c(); // } // } //cbi(LED_PORT,LED); } }
接下来是Makefile:
# Makefile for ATmegaBOOT # E.Lins, 2004-10-14 # program name should not be changed... PROGRAM = ATmegaBOOT PRODUCT=atmega8 # enter the parameters for the UISP isp tool ISPPARAMS = -dprog=stk500 -dserial=$(SERIAL) -dspeed=19200 #DIRAVR = F:2022AVRminiuxAVRarduino-litebinwin32WinAVR-20090313 DIRAVR = ../../../bin/win32/WinAVR-20090313 DIRAVRBIN = $(DIRAVR)/bin DIRAVRUTILS = $(DIRAVR)/utils/bin DIRINC = $(DIRAVR)/include DIRLIB = $(DIRAVR)/avr/lib MCU_TARGET = atmega8 LDSECTION = --section-start=.text=0x1C00 #FUSE_L = 0xdf #FUSE_H = 0xca FUSE_L = 0xFF FUSE_H = 0xDD ISPFUSES = $(DIRAVRBIN)/uisp -dpart=ATmega8 $(ISPPARAMS) --wr_fuse_l=$(FUSE_L) --wr_fuse_h=$(FUSE_H) ISPFLASH = $(DIRAVRBIN)/uisp -dpart=ATmega8 $(ISPPARAMS) --erase --upload if=$(PROGRAM).hex -v OBJ = $(PROGRAM).o OPTIMIZE = -Os DEFS = -DF_CPU=7372800 -DBAUD_RATE=19200 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: $(PROGRAM).elf lst text asm 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 *.map asm: $(PROGRAM).s %.s: %.c $(CC) -S $(CFLAGS) -g1 $^ lst: $(PROGRAM).lst %.lst: %.elf $(OBJDUMP) -h -S $< > $@ size: $(PROGRAM).hex $(SIZE) $^ # Rules for 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下载到开发板就可以了!
在Arduinohardwarearduinoavr目录下有个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
##############################################################
这样就完成了。



