You are on page 1of 23

Program boot loader atmega 8

Hardware
Basically AVRUSBBoot can be used with all circuits which are supported by the AVR USB driver. To switch between the bootloader and the application, an aditional jumper is necessary. Here is an example (Here the levels on the data lines are 5V which doesn't meet the USB specification! The supply voltage should be regulated to 3,3V - 3,6V):

;--------------------------------------------------------------------------------------; ; Program: Bootloader_Mega8.asm ; ; Writer: Herbert Dingfelder, DL5NEG ; for contact information visit WWW.DL5NEG.DE ; ; Based on: AVR-Freaks Design Note #32 ; ; Function: Bootloader for ATmega8, Works via the UART with the normal ; AVRProg PC-Software ; ; Hardware: ATmega8 with a 7.3728MHz crystal ; ; History: ; ; 13.07.2004 - Source code adapted for Mega8, assembles without errors ;

; 15.07.2004 - Used crystal is not 7.3 but 3.686 MHz -> UART setting adapted ; - LED on LEDport/LEDbit is switched on within the boot section, ; tested in Hardware and works -> processor starts correctly ; within the boot section ; 18.07.2004 - Problem how to download the bootloader is solved: Simply use ; the AVRProg in the "mega8" mode, not in "mega8boot" mode. ; Since the Intel-Hex Format contains the address for the code ; in each line, the programmers recognizes that the code has to ; go to the bootrom part of the flash (provide that the ; ".org MY_BOOTSTART" is put at the beginning of the source code) ; - UART communication between bootloader and host PC works ; (echo mode and character recognition tested and works) ; - Crystal changed to 7.3728MHz in an attempt to fight "flushing" ; problems in AVRProg (without success), UART setting adapted ; - AVRProg is able to read the flash correctly (tested, works) ; - Reading and writing to EEPROM on host commands 'D' and 'd' works. ; - Flash erase did not work in the NRWR section (the last 1024 ; words of the flash) The original version from DesignNote #32 ; was for ATmega163 which does not have RWR/NRWR sections. ; Problem solved by implementing the wait_for_spm function that ; makes sure that a new SPM does only start when the previous one ; is completed. (tested, works now) ; - function to reenable the RWW section implemented -> ; loading data into the application section tested and works fine ; (Still some problems with sync on the interface between AVRProg ; and the boot loader, messagebox "flushing" appears, fuse bits are ; read differently many times and software download needs to be ; started twice sometimes. As it is known that AVRProg is very sensible ; command/answer sync, this does not point towards real bootloader problems. ; It has to be tracked on the interface.) ; -> Good enough to work with temporarily, Version 1.0 released. ; - Startup-function implemented for 10 second wait after power-on. If

; no ASCII(27) is received via UART within that time, the application starts. ; If the application section is empty (all cells are $FF) e.g. directly ; after uploading the bootloader itself, then software will wait forever ; for a ESC via the UART to start the bootloader software ; (while waiting for the ESC the LED blinks) ; - Function pause implemented for delays in steps of 10ms (tested works) ; - Command 'E' implemented for leaving the bootloader mode and start the ; application ; - With that entry end exit function the bootloader is fully usable, starting ; the downloaded application is tested and works perfectly ; -> Version 1.1 released ; - Still known problem: the above mentioned sync problem in combination ; with AVRProg have to be identified and solved. ; - Only 2 Words are left in the bootloader memory. If Bugfixing needs more, ; the erease counter within the EEPROM can be skipped ; 24.07.2004 - Debug Session with Andy, DG9NDZ to find why AVRProg 1.37 still has some ; problems with the bootloader, especially in the "Advanced" Window. ; * Command 'v' for Hardware Version was not implemented -> fixed ; * Command ':' for tranparent command setting was not implemented ; -> is now implemented in simple version, always returning \0 ; By monitoring the PC/AVR interface it was found that AVRProg1.37 does ; not use the defined commands r/F/N for reading the lock and fuse bits, ; but uses the universal command ':' to send the programming instructions ; directly. Additionally the calibration byte is read by the ':' command. ; * Command 'b' is send by AVRProg1.37 but is not implemented. It was found that ; it is fatal for the programming mode to implement 'b' to return 'Y', 'Y'. ; To simply leave it out (returns ? for unknow command) works perfectly. ; 25.07.2004 - To implement all improvements found on 24.07.2004 without skipping lots of ; of other code made it necessary to increase the boot loader size to 512words ; (=1kByte). Code adapted. ; - Command ':' enlarged to map r/F/N functionality ; - Tested, current status: Works well in AVRProg both for flash reading and writing

; and also in the Advance window the lock and fuse bits are display correctly. ; Only week point remaining to press "write" in advance window, that causes a ; loose of sync between host and bootloader. No harm is done to the target device. ; -> Version 1.2 released. ; 26.07.2004 - Monitoring of interface from host reveals the root cause of the sync problem when ; writing the the lock and fuse bits. AVRProg1.37 uses the "new universal command" ; which is "." + 4 data bytes. This command was not implemented. As changing the ; fuse bits is dangerous when the device is remote (one could lock himself out ; forever), the command is now implemented simply to ignore the inputs but correctly ; serve the interface to the host to avoid sync problems. Tested and works perfectly. ; -> Version 1.3 release ; ; ; ; Before or after programming a new ATmega8 with this Boot Loader you must program Fuse ; bits as follows: ; ; The ATmega8 Fuse High bits must be programmed to 0x04 in order to configure ; the Boot size to 256 words and to move the Reset Vector to word address 0x1f00. ; ; I.e. set the check box for BOOTRST in AVR-Prog-Advanced and set the ; selector to 256words, then press "write". It is important that this selected ; size of the bootrom fits to the .org command within this source code, otherwise ; the processor will not correctly start at the first line of this code after reset. ; (Settings can be checked now or later with "read"). ; ; Optional: ; ; The Lock bits can be programmed to 0xEF to protect the Boot Flash Section from ; unintentional changes and to allow accessing the Application Flash Section. ; ; I.e. the setting for BLB0 and BLB1 in AVR-Prog-Advance: ; ; BLB0 (sets the protection for the application section) must be set to ; Mode 1 (no protection) to allow full access of LPM and SPM commands within ; the application section. ; ; BLB1 (sets the protection for the boot loader section) can be set to Mode 2 ; (SPM cannot write to boot section) or can be left to Mode 1 (no protection).

; ; The Fuse bits must be programmed before programming the Lock bits. ; ; ; AVRProg Commands as defined by Atmel ; ; ; ; Enter Programming Mode 'P' ; Auto Increment Address 'a' ; Set Address 'A' ah al ; Write Program Memory, Low Byte 'c' dd ; Write Program Memory, High Byte 'C' dd ; Issue Page Write 'm' ; Read Lock Bits 'r' ; Read Program Memory 'R' ; Read EEPROM Memory 'd' ; Write EEPROM Memory 'D' dd ; Chip Erase 'e' ; Write Lock Bits 'l' dd ; Read Fuse Bits 'F' ; Read High Fuse Bits 'N' ; Read Extended Fuse Bits 'Q' ; Leave Programming Mode 'L' ; Select Device Type 'T' dd ; Read Signature Bytes 's' ; Return Supported Device Codes 't' n*dd ; Return Software Identifier 'S' ; Return Software Version 'V' ; Return Hardware Version 'v' ; Return Programmer Type 'p' ; Set LED 'x' ; Clear LED 'y' ; Exit Bootloader 'E' ; Check Block Support 'b' ; Start Block Flash Load 'B' 2*dd 'F' 13d (not implemented) ; ; Start Block EEPROM Load 'B' 2*dd 'E' ; ; Start Block Flash Read 'g' 2*dd 'F' n*dd (not implemented) ; Start Block EEPROM Read 'g' 2*dd 'E' n*dd ; Universal Command (3 data bytes) ':' 3*dd dd ; New Universal Command (4 data bytes)'.' 4*dd dd ; ;-------------------------definition and includes -------------------------------------.INCLUDE "m8def.inc" Definitions for the mega8 .def tmp_r = r18 temporary stuff .def pa_10ms = r19 the pause time in steps of 10ms .def uni_cmd1 = r20 ':' send three bytes. These ; Include Register/Bit ; Use Reg. R18 for ; used for selecting ; Universal command

Host Writes ID dd 13d dd 2*dd dd

dd dd dd 3*dd 00d s[7] dd dd dd dd dd 'Y' 2*dd

13d

13d 13d

.def uni_cmd2 = r21 futher usage in r20, r21, r28 .def uni_cmd3 = r10 .equ VER_H = '1' version higher number .equ VER_L = '3' version lower number .equ VERH_H = '1' version higher number .equ VERH_L = '0' version lower number .equ DT = 0x76 (ATmega8) .equ SB1 = 0x07 .equ SB2 = 0x93 .equ SB3 = 0x1e .equ ESC = 27 ; Ascii 27 = Escape

; are stored for

; bootloader software ; bootloader software ; bootloader hardware ; bootloader hardware ; Device Type = 0x76 ; Signature byte 1 ; Signature byte 2 ; Signature byte 3

;LR***************************************************** .equ fCK = 7372800 ;X-tal frequency * .equ BaudR=19200 ;Baud rate * .equ Tr_Sp=0 ;Transmission speed (U2X) * .equ UBR=-1+(5+10*fCK/(16*BaudR-8*BaudR*Tr_Sp))/10 ; * .equ presc=1024 ; * .equ fTmr=100 ;freq. of Timer 0 (1/10ms=100) * .equ TmrLoad=256-(fCK/(presc*fTmr)) ; * .equ CR = 13 ; * ; * ;Pin for LED and Boot escape definition: * .equ LEDport =PORTc ; * .equ LEDdir =DDRc ; * .equ LEDbit =1 ; * ; * .equ TestPort =PINC ; * .equ TestBit =1 ; * ; * .equ ActiveStatLED=0 ;0=low, 1=high active stat * .if ActiveStatLED ; * .macro set_led ; * sbi LEDport,LEDbit ; * .endm ; * ; * .macro clr_led ; * cbi LEDport,LEDbit ; * .endm ; * .else ; * .macro set_led ; * cbi LEDport,LEDbit ; * .endm ; * ; * .macro clr_led ; * sbi LEDport,LEDbit ; * .endm ; * .endif ; * ; *

;LR***************************************************** .equ MY_BOOTSTART = THIRDBOOTSTART starts in the flash ; here we define where the bootloader

;----------------------------- here we go ---------------------------------------------.org MY_BOOTSTART ; bootstart address according to .equ above

; ---------------------------------- Boot Escape ----------------------------------------;LR*********************************** in tmp_r,TestPort ; * sbrc tmp_r,TestBit ; * rjmp FLASHEND+1 ; * ;LR*********************************** ; ----------------------------------- init stackpointer -------------------------------ldi R24, low(RAMEND) ; SP = RAMEND ldi R25, high(RAMEND) out SPL, R24 out SPH, R25 ldi tmp_r, 0b00000101 ; set prescaler to 1024 out TCCR0, tmp_r ; ---------------------------------- init UART ----------------------------------------;LR*********************************** .if Tr_Sp ; * sbi UCSRA,U2x ; * .else ; * cbi UCSRA,U2x ; * .endif ; * ;LR*********************************** ldi tmp_r, LOW(UBR) out UBRRL, tmp_r .if HIGH(UBR) ldi tmp_r, HIGH(UBR) out UBRRH, tmp_r .endif ldi tmp_r,(1<<RXEN)|(1<<TXEN) transmitter, 8-bit mode out UCSRB,tmp_r

; Enable receiver &

; -------------------------- check for action on UART ---------------------------------; After power-on, the processor starts with the bootloader section. Ususally the user ; want the application to start automatically. Only in special cases, a software update ; is required. So if no ESC (ASCII(27)) is received within 8 seconds after power-on, ; the application starts. sbi LEDdir, LEDbit LEDport to output to drive an LED ldi R17, 20 number of LED-flashes for the waiting periode ; Switch ; Preset the

start_wait: clr_led rcall pause200 sbic UCSRA,RXC rjmp Char_Rec0 data (if RXC==1) st_wait2: set_led rcall pause200 sbic UCSRA,RXC data (if RXC==1) rjmp Char_Rec1 data (if RXC==1) dec R17 counter brne start_wait counter has reached zero clr_led rjmp FLASHEND+1 application program

; switch off the LED ; wait a moment ; check for incoming

; switch on the LED ; wait a moment ; check for incoming ; check for incoming ; decremente the loop ; and leave loop if ; switch off the LED ; Start the

;--- some character was received --Char_Rec0: set_led ; switch on the LED Char_Rec1: in R16,UDR ; fetch received character and put it into R16 cpi R16, ESC ; if the received character was ESC brne No_ESC ; start the bootloader main loop ;--------------------------------- start of main loop ---------------------------------;-------------------- wait for a character from UART other than ESC -------------------L10: rcall uartGet ; repeat (R16 = uartGet) cpi R16, ESC ; while (R16 == ESCAPE) breq L10 No_ESC: ;--------- Command 'E' leaves the bootloader mode and starts the application -----------cpi R16, 'E' ; if(R16=='E') 'E' = Exit bootloader brne L11 ;LR******************************** ldi R16,CR rcall uartSend TstUDRE: sbis UCSRA,UDRE ; wait for empty transmit buffer (until UDRE==1) rjmp TstUDRE TstTXC: sbis UCSRA,TXC ; wait for USART Transmit Complete (until TXC==1) rjmp TstTXC ;LR******************************** rcall pause200

clr_led rjmp FLASHEND+1 application program

; switch off the LED ; Start the

; (flashend+1) = Address 0 ;--------- Command 'a' is question from host for autoimcrement capability--------------; simple anser is 'Y' for yes, autoincrement is done L11: cpi R16, 'a' ; if(R16=='a') 'a' = Autoincrement? brne L12 ldi R16,'Y' ; Yes, autoincrement is quicker rjmp L70 ; uartSend(R16) Send the 'Y' and go up for next command ;--------- Command 'A' is setting the address for the next operation ------------------; two bytes (in total) for high and low address are sent from the host L12: cpi R16,'A' ; else if(R16=='A') write address brne L14 rcall uartGet mov R27,R16 is stored in R27 rcall uartGet mov R26,R16 stored in R26 lsl R26 address=address<<1 rol R27 byte address to word address rjmp L68 uartSend('\r') send CR and go up for next command ; address high byte

; address low byte is ; ; convert from ;

;--------- Command 'c' is write low byte to program memory ----------------------------; the low byte is simply stored in a register, the actual writing to the flashes ; page-buffer is done later, after the high byte was received L14: cpi R16,'c' ; else if(R16=='c') write program memory, low byte brne L16 rcall uartGet written from host mov R22,R16 in R22 ; read the byte to be ; store data low byte

rjmp L68 uartSend('\r') send CR and go up for next command

;--------- Command 'C' is write high byte to program memory ---------------------------; together with the (already received) low byte, the highbyte is writen to the flashes ; page buffer. When the page buffer is completely written, it can be transfered into ; the real flash by the "page write" command. ; ; If only SPMEN is written, the following SPM instruction will store the value in R1:R0 ; in the temporary page buffer addressed by the Z pointer. L16: cpi R16,'C' write program memory,high byte brne L18 rcall uartGet from the host mov R23,R16 byte in R23 movw ZL,R26 with the current address movw R0,R22 word (data high and low byte) registers R0 and R1 rcall wait_for_spm ready to accept a new task ldi R24, (1<<SPMEN) out SPMCR,R24 temporary buffer) spm program memory adiw R26,2 address=address+2 rjmp L68 uartSend('\r') send CR and go up for next command ; make sure SPM is ; set SPMEN in SPMCR ; page load (fill ; Store ; ; ; else if(R16=='C')

; read the high byte ; store the data high ; load the Z pointer ; transfer the data ; into

;-------------------------- Command 'e' is chip erase ---------------------------------; "chip erase" for the boot loader means to erase all flash pages othen than the ; boot loader sector itself L18: cpi R16,'e' Chip erase brne L28 ; else if(R16=='e')

; the loop that has to be performed to clear the application section is: ; for(address=0; address < (2*MY_BOOTSTART); address += (2*PAGESIZE)) ; the "address" variable to be used are the registers R26 and R27 clr R26 address 0 clr R27 rjmp L24 loop at the check for "end-criteria reached" ;......... beginning of erase loop ............ L20: ; If the PGERS bit is written to one at the same time as SPMEN, the next SPM ; instruction within four clock cycles executes page erase. The page address ; is taken from the high part of the Z pointer. rcall wait_for_spm ready to accept a new task movw ZL,R26 with the address of the to be erased ldi R24, (1<<PGERS) | (1<<SPMEN); simultaniously set PGERS and SPMEN in SPMCR out SPMCR,R24 ; to prepare for the page_erase spm program memory nop subi R26,low(-2*PAGESIZE) the size of a page sbci R27,high(-2*PAGESIZE) already ; reached the beginning of the boot-loader section L24: ldi R24,low( 2*MY_BOOTSTART) where the boot-loader ldi R25,high(2*MY_BOOTSTART) ; load R24, R25 with the address ; section starts ; do a word; smaller than ; if that is ; Store ; make sure SPM is ; load the Z-pointer ; page ; start with

; continue the ;

; increment the address by

; this is the check for end-criteria reached, i.e. has the address

cp R26,R24 compare to check if the address is still cpc R27,R25 the address where the bootloader starts brlo L20 the case, go to the beginning of the erase loop

; ..... remember the number of flash-erases in the EEPROM ..... ldi R26,low( E2END -1) ; increment Chip Erase Counter located ldi R27,high(E2END -1) ; at address E2END-1 movw R22,R26 ; Save Chip Erase Counter Address in R22 ldi R17,1 ; read EEPROM rcall EepromTalk mov R24,R16 ; R24 = Chip Erase Counter low byte rcall EepromTalk mov R25,R16 ; R25 = Chip Erase Counter high byte adiw R24,1 ; counter ++ out EEDR,R24 ; EEDR = R24 Chip Erase Counter low byte movw R26,R22 ; R26 = Chip Erase Counter Address ldi R17,6 ; write EEPROM rcall EepromTalk out EEDR,R25 ; EEDR = R25 Chip Erase Counter high byte rcall EepromTalk ; .......................................................... rcall wait_for_spm ready to accept a new task rcall enable_rww RWW section so it can be accessed again rjmp L68 uartSend('\r') send CR and go up for next command ; make sure SPM is ; reenable the ;

;---------------------------- Command 'm' is write page -------------------------------; To execute page write, set up the address in the Z pointer, write 'X0000101' to SPMCR ; and execute SPM within four clock cycles after writing SPMCR. The data in R1 and R0 ; is ignored. The page address must be written to PCPAGE. Other bits in the Z pointer will ; be ignored during this operation. L28: cpi R16,'m' ; else if(R16== 'm') Write page brne L34 rcall wait_for_spm ready to accept a new task movw ZL,R26 address ldi R24, (1<<PGWRT) | (1<<SPMEN); set PGWRT and SPMEN in SPMCR to prepare for Write page out SPMCR,R24 spm program memory ; Store ; make sure SPM is ; load Z-pointer with

nop rcall enable_rww RWW section so it can be accessed again L32: rjmp L68 uartSend('\r') send CR and go up for next command ; ; reenable the

;--------------------- Command 'P' is enter programming mode --------------------------; nothing is done here, only the command is confirmed to host by sending CR L34: cpi R16,'P' ; else if(R16=='P') Enter programming mode breq L32 ; uartSend('\r') Send CR to host and go up for next command ;--------------------- Command 'L' is leave programming mode --------------------------; nothing is done here, only the command is confirmed to host by sending CR cpi R16,'L' ; else if(R16=='L') Leave programming mode breq L32 ; uartSend('\r') Send CR to host and go up for next command ;--------------------- Command 'p' is Return programmer type --------------------------; simply return an 'S' to indicate to host that this is a serial programmer cpi R16,'p' Return programmer type brne L38 ldi R16,'S' Serial rjmp L70 ; uartSend(R16) and go up for next command ;--------------------- Command 'R' is "Read one word from program memory" -------------; reads one word from the 'current' address that is stored in R26 and increments R26 L38: cpi R16,'R' ; else if(R16=='R') Read program memory brne L40 movw ZL,R26 address of memory to be read lpm memory LSB; lpm memory MSB; R24,Z+ store LSB in R24 and Z pointer ++ R16,Z+ store MSB in R16 and Z pointer ++ ; load Z-pointer with ; read program ; read program ; uartSend(R16) write ; else if (R16=='p')

; uartSend('S')

rcall uartSend back MSB to host

movw R26,ZL 'current' address += 2 mov R16,R24 rjmp L70 uartSend(R16) write back the LSB to host and go ;--------------------- Command 'D' is "write data to -------------L40: cpi R16,'D' Write data to EEPROM brne L41 rcall uartGet write from the UART out EEDR,R16 ldi R17,6 rcall EepromTalk rjmp L68 uartSend('\r') Confirm the command to host with CR

; increment the ; LSB stored in R16 ; ; up for next command EEPROM" -------------; else if (R16=='D') ; fetch the data to ; EEDR = uartGet() ; write EEPROM ;

;--------- Command 'b' is question from host for block mode capability--------------; simple anser is 'N' 'N', no bootloader does not support blockmode L41: cpi R16, 'b' Blockmode? brne L42 ldi R16,'N' rcall uartSend ; if(R16=='b') 'b' =

; send 'N'

ldi R16,'N' ; send 'N' rjmp L70 ; uartSend(R16) Send the 'N' and go up for next command ;--------------------- Command 'd' is "read data from EEPROM ---------------------------L42: cpi R16,'d' ; else if (R16=='d') Read data from EEPROM brne L43 ldi R17,1 ; read EEPROM rcall EepromTalk ; R16 = EEPROM data rjmp L70 ; uartSend(R16) ;-------------------------- Command ':' is universal command --------------------------; Host sends 3 more bytes which must be used to determine the required action. AVRProg ; uses the ':' with parameters to do things that could simply be done by r/F/N. ; We have to map recognized parameters to the refering action.

L43: cpi R16,':' Universal Command brne L44 ;.............. read in the parameters ............................... rcall uartGet mov uni_cmd1, r16 rcall uartGet mov uni_cmd2, r16 rcall uartGet mov uni_cmd3, r16 ... clr r16 with zero, if parameters are not recognized, zero will be returned to host ;.................................................................. ... cpi uni_cmd1, 0x58 paramter is 0x58 brne cmd1_not_0x58 cpi uni_cmd2, 0x00 paramter is 0x00 brne cmd2_not_0x00_1 ; -> 58 00 is read lock bits, ldi ZL,1 0001 (-> readFuseAndLock will read lock) rcall readFuseAndLock cmd2_not_0x00_1: cpi uni_cmd2, 0x08 paramter is 0x08 brne cmd2_not_0x08 ; check if 2nd ; check if 1st ; preset r16 ; ; R16 = uartGet() ; store the read byte ; R16 = uartGet() ; store the read byte ; R16 = uartGet() ; store the read byte ; else if(R16==':')

;..................................................................

; check if 2nd

; Z pointer = ; go get the requested bits

; -> 58 08 is read fuse high bits, ldi ZL,3 ; Z pointer = 0003 (-> readFuseAndLock will read high fuse) rcall readFuseAndLock ; go get the requested bits cmd2_not_0x08: cmd1_not_0x58: cpi uni_cmd1, 0x50 paramter is 0x50 brne cmd1_not_0x50 ; check if 1st

cpi uni_cmd2, 0x00 paramter is 0x00 brne cmd2_not_0x00_2 ; -> 50 00 is read fuse bits, clr ZL 0000 (-> readFuseAndLock will read fuse) rcall readFuseAndLock cmd2_not_0x00_2: cmd1_not_0x50: rcall uartSend the read lock/fuse bits rjmp L68 uartSend('\r') and go up for next command

; check if 2nd

; Z-pointer = ; go get the requested bits

; uartSend(bits) send ;

;--------------------- Command 'F' is "read fuse bits" --------------------------------L44: cpi R16,'F' ; else if(R16=='F') Read fuse bits brne L46 clr ZL ; Z-pointer = 0000 (-> readFuseAndLock will read fuse) rjmp L50 ; rcall readFuseAndLock ;--------------------- Command 'r' is "read lock bits" --------------------------------L46: cpi R16,'r' ; else if(R16=='r') Read lock bits brne L48 ldi ZL,1 ; Z pointer = 0001 (-> readFuseAndLock will read lock) rjmp L50 ; rcall readFuseAndLock ;--------------------- Command 'N' is "read fuse high bits" ---------------------------L48: cpi R16,'N' ; else if(R16=='N') Read high fuse bits brne L52 ldi ZL,3 ; Z-pointer = 0003 (-> readFuseAndLock will read high fuse) ;-------- for all previous commands F,r,N hear we call the readFuseAndLock -------------; function that will read the bits that are indicated by the Z-register L50:

rcall readFuseAndLock rjmp L70 uartSend(R16)

;--------------------- Command 't' is Return supported devices code -------------------; obviously we return only the device code of the mega8 here L52: cpi R16,'t' ; else if(R16=='t') Return supported devices code brne L54 ldi R16,DT rcall uartSend Device Type of Mega8 clr R16 of AVRProg requires the termination of t-command with a \0 not with a CR as other commands rjmp L70 and go up for next command ; Device Type ; uartSend(DT) send ; command set ; the ; uartSend(0)

; ---------------- ignored commands that are not sensible for boot loader -------------; The following 4 commands only make sense for a general programmer, not for a bootloader. ; As theres commands come with an additional byte as parameter, with have to fetch that ; byte from the UART to avoid messing up the UART reading. L54: cpi R16,'l' Loader lockbits breq L56 cpi R16,'x' breq L56 cpi R16,'y' breq L56 cpi R16,'T' type brne L60 L56: rcall uartGet rjmp L68 uartSend('\r') and go up for next command ; R16 = uartGet() ; ; 'l' = Write Boot

; 'x' = Set LED ; 'y' = Clear LED ; 'T' = Select device

;--------------------- Command 'S' is Return software identifier ----------------------L60: cpi R16,'S' ; else if(R16=='S') Return software identifier brne L62

ldi ZL,low(2*Soft_Id) Z-Register ldi ZH,high(2*Soft_Id) L61:

; load address of String into

lpm R16,Z+ character of the string and increment string pointer tst R16 breq L72 character output loop charcter was '\0' rcall uartSend character via the UART rjmp L61 of loop for next character

; read one

; exit the ; send the read ; go to start

;--------------------- Command 'V' is Return software Version -------------------------L62: cpi R16,'V' ; else if (R16=='V') Return Software Version brne L63 ldi R16, VER_H software version higher number rcall uartSend ldi R16, VER_L software version lower number rjmp L70 go up for next command ; send bootloader

; send bootloader ; uartSend and

;--------------------- Command 'v' is Return hardware Version -------------------------L63: cpi R16,'v' ; else if (R16=='v') Return hardware Version brne L64 ldi R16, VERH_H software version higher number rcall uartSend ldi R16, VERH_L software version lower number rjmp L70 go up for next command ; send bootloader

; send bootloader ; uartSend and

;--------------------- Command 's' is Return Signature Byte ---------------------------L64: cpi R16,'s' ; else if (R16=='s') Return Signature Byte brne L65 ldi R16,SB1 Signature Byte 1 ; uartSend(SB1)

rcall uartSend ldi R16,SB2 Signature Byte 2 rcall uartSend ldi R16,SB3 Signature Byte 3 rjmp L70 go up for next command ; uartSend(SB2)

; uartSend(SB3) ; uartSend and

;--------------------- Command '.' is new universal command ---------------------------; this command will be ignored, only the inteface will be handled correctly L65: cpi R16,'.' ; else if (R16=='.') New Universal Command brne L66 ;.............. read in the 4 parameters ............................... rcall rcall rcall rcall uartGet uartGet uartGet uartGet ; ; ; ; R16 R16 R16 R16 = = = = uartGet() uartGet() uartGet() uartGet()

; ...................................................................... clr R16 rcall uartSend rjmp L68 uartSend('\r') and go up for next command ; uartSend(/0) ;

;++++++++++++++ handling the different command till here ++++++++++++++++++++++++++++++++ ; only general completion for all commands below ;---------------------- failed commands can end up here -------------------------------; an '?' is send via the UART to indicate fail host, then main loop starts again L66: ldi R16,'?' rjmp L70 uartSend(R16) ; else uartSend('?') ;

;--------- successfully completed commands without return value can end up here --------; an CR is sent via the UART to confirm execution to host, then main loop starts again L68: ldi R16,13 uartSend('\r') ;

;------------ successfully completed commands with return value can end up here --------; the return value is sent via the UART to confirm execution to host ; then main loop starts again L70: rcall uartSend ; uartSend(R16) L72: rjmp L10 beginning of main loop ; jump up to

;-------------------------- end of main loop -------------------------------------------

;================= end of main program, only subroutines from here on ===================

;------------------ reads fuse or lock bits (depending on Z-Reg.) -----------readFuseAndLock: ; An LPM instruction within three cycles after BLBSET and SPMEN are set in the SPMCR ; Register, will read either the Lock bits or the Fuse bits ; (depending on Z0 in the Z pointer) into the destination register. rcall wait_for_spm ready to accept a new task clr ZH high byte = 0 ; make sure SPM is ; Z pointer

ldi R24,(1<<BLBSET)|(1<<SPMEN) ; set BLBSET and SPMEN in SPMCR out SPMCR,R24 ; read fuse and lock lpm R16,Z ; read program memory ret ;------------- does an read or write on the EEPROM (depending on R17) -------; if R17 == 6 then Write, if R17 == 1 then Read EepromTalk: out EEARL,R26 ; EEARL = address low out EEARH,R27 ; EEARH = address high adiw R26,1 ; address++ sbrc R17,1 ; skip if R17 == 1 (read Eeprom) sbi EECR,EEMWE ; EEMWE = 1 (write Eeprom) out EECR,R17 ; EECR = R17 (6 write, 1 read)

L90: sbic EECR,EEWE 0 rjmp L90 in R16,EEDR ret ;---------------- send one character via UART (parameter is r16) ------------uartSend: sbis UCSRA,UDRE ; wait for empty transmit buffer (until UDRE==1) rjmp uartSend out UDR,R16 ; UDR = R16, start transmission ret ;---------------- read one character from UART (returned in r16) ------------uartGet: sbis UCSRA,RXC data (until RXC==1) rjmp uartGet in R16,UDR received data in R16 ret ;-------------------- wait for SPM to be ready for new tasks ----------------; while( SPMCR_REG & (1<<SPMEN) ) wait_for_spm: in r16, SPMCR SPMCR into register andi r16, (1<<SPMEN) brne wait_for_spm if bit not yet cleared Wait_ee: sbic EECR, EEWE EEPROM write access is present rjmp Wait_ee ret ; ---------------------------- re-enable the RWW section --------------------; When programming (page erase or page write) to the RWW section, the RWW section ; is blocked for reading (the RWWSB will be set by hardware). To re-enable the RWW ; section, the user software must wait until the programming is completed (SPMEN will be ; cleared). Then, if the RWWSRE bit is written to one at the same time as SPMEN, the ; next SPM instruction within four clock cycles re-enables the RWW section. ; read the content of ; check if bit SPMEN is set ; and do more loops ; wait for incoming ; return ; R16 = EEDR ; wait until EEWE ==

; check that no

; If this is not done, all addresses will read $FF even if they contain other values. enable_rww: rcall wait_for_spm ready to accept a new task ldi r16, (1<<RWWSRE) | (1<<SPMEN) SPMCR to prepare out SPMCR, r16 reenabling the rww section spm initiate the reenabling ret pause200: ldi pa_10ms, 20 ;---------------------------------- Pause -----------------------------------; Delays the CPU the selected periode, parameter pa_10ms is in 10ms steps pause: ldi tmp_r, TmrLoad (10ms) out TCNT0, tmp_r in tmp_r, TIFR sbr tmp_r, (1<<TOV0) out TIFR, tmp_r ; cycles till overflow ; reset the overflow flag ; preset the counter for 100 Hz ; make sure SPM is ; set rwwsre and spmen in ; for ;

pw: ;LR**************************** sbic UCSRA,RXC ; check for incoming data (if RXC==1) rjmp PauseEnd ;LR**************************** in tmp_r, TIFR ; check if overflow flag is set sbrs tmp_r, TOV0 rjmp pw ; if not, wait more ;--- do this 10ms as often as requested in parameter pa_10ms dec pa_10ms ; decrement the counter brne pause ; and do the loop again if not zero yet PauseEnd: ret

;---------------- data for identifier string --------------------------------Soft_Id: .DB "AVRB_M8", 0

:020000020000FC :101E0000F8940FE50DBF04E00EBF22243324909A0E :101E1000919A899A41E050EA06E0F101EF01F1015F :101E2000019700408099E1F781F12197349668F19C

:101E3000809BFBCF0F2EC5950694E9F72397269636 :101E400068F7EA35F20550F3F797F695E7952F0115 :101E5000CAE0E6EBFFE10590002031F078D00016F3 :101E6000D1F3CA9591F0F5CF06EA8AD070D0E1F7A8 :101E70000AEA86D06CD0F1F76AD0F1F3F101E89468 :101E80000430F0F059F1063018F422BA21BAB8C083 :101E900031F45DD05CD0672859F331010FC00730B1 :101EA00059F455D019F453D0005821F00590001280 :101EB0006894F7CF1EF0DCCF07EADBCF0BEAD9CF6F :101EC000ECEBFFE1C0E0EC0FF21DC4910150D8F73C :101ED00008EA56D00591C150E0F7CACFA0E6B0E0BD :101EE000ED0135D021F433D00058689431F0E894F6 :101EF0000D93A03204E0B007A1F7AC17BD0731F194 :101F0000A0E2B4E0E054FC4F10E232971E900E9035 :101F100001E015D01A95C9F7E0301EE1F107A8F4E9 :101F200003E00DD005E009D0AC17BD0769F776F0E6 :101F3000E054FC4F09EA24D0D4CF01D001E107BF1F :101F4000E89507B700FDFDCF0895B8CF91CF809BEE :101F5000FECF8099FECF18E0C2019695879523D0D9 :101F600021D006958099006807FD642676946794D1 :101F700008F4642608F475261A9591F7053A089531 :101F800011D09198149119E0009500C000C00AD0BA :101F9000069518F40000919802C0919A00C01A9515 :101FA000A1F70895C2010497F0F78D3F18F011F0E2 :101FB0008F3F01F00895506564610000030107033D :0A1FC00003C0041E930704001E0076 :00000001FF

You might also like