📄 m16_boot.asm
字号:
;********** B O O T L O A D E R F O R A T m e g a 1 6 3 **********
;* File : AVRBoot2.asm (Include chip erase counter)
;* Version : 1.3
;* Compiler : AVR Studio
;* Target : ATmega163
;* Output size : 412 bytes
; code by:
; Mariano Barr髇 Ruiz
; ispbarum@sb.ehu.es
; changes/comments by Martin Thomas, eversmith@heizung-thomas.de
; - works fine with ATmega16 from AVRStudio 4.07 AVRProg,
; thanks Mariano
; - .INCLUDE changed to m16def.inc, added .nolist,.list
; - make start condition configurable, bootloader startes if pin
; is grounded (pulled low) on Device-Reset, enable internal pull-ups
; to avoid external resistor
; - disabled cycle counter
; - baud-rate configureable
; - changed device type to ATmega16
; - fuse-settings:
; BOOTRST - programmed (0, checked in Ponyprog2000)
; BOOTZ1 - unprogrammed (1, unchecked in Ponyprog2000)
; BOOTZ0 - programmed (0, checked in Ponyprog2000)
;.INCLUDE "m163def.inc" ; Include Register/Bit Definitions for the ATmega163
; - mt
.nolist
.INCLUDE "m16def.inc" ; Include Register/Bit Definitions for the ATmega16
.list
.equ clock_boot = 8000000 ; MHz
.equ baud_boot = 19200
; boot code will be enabled if the pin boot_pin on port boot_port
; is pulled low during device-reset - mt
.equ BTDDR = DDRA
.equ BTPORT = PORTA
.equ BTPIN = PINA
.equ BTPINPX = PINA7
;.equ DT = 0x66 ; Device Type = 0x66 (ATmega163)
;.equ SB1 = 0x02 ; Signature byte 1
;.equ SB2 = 0x94 ; Signature byte 2
;.equ SB3 = 0x1e ; Signature byte 3
; mt - for ATMega16
; see souce code and Excel-Workbook to App-Note 109 for Type
; see uC Manual for Signatures
.equ DT = 0x74 ; Device Type = 0x74 (ATmega16) - mt
.equ SB1 = 0x03 ; Signature byte 1 for ATmega16 - mt
.equ SB2 = 0x94 ; Signature byte 2
.equ SB3 = 0x1e ; Signature byte 3
.equ UBRBT = (clock_boot/(16*baud_boot))-1 ; - mt
.org SECONDBOOTSTART ; ($1F00) second boot. Block size is 512B
; sbic PINC,PINC0 ; Skip next instruction if PINC0 cleared
; rjmp FLASHEND+1 ; else normal execution from Reset (FLASHEND+1 = Address 0000)
clr r24
out BTDDR,r24 ; port as input
ser r24
out BTPORT,r24 ; enable internal pull-ups
nop ; sync
nop ; sync more
nop ; sync even more
nop ; ...
sbic BTPIN,BTPINPX
; skip next instruction if the pin is cleared (=pulled down)
rjmp FLASHEND+1 ; else normal execution from Reset (FLASHEND+1 = Address 0000)
; Programming mode
BOOTLSTART:
ldi R24,low(RAMEND)
ldi R25,high(RAMEND)
out SPL,R24
out SPH,R25 ; SP = RAMEND
ldi R24,UBRBT ; Baud rate
out UBRR,R24
ldi R24,(1<<RXEN)|(1<<TXEN)
out UCSRB,R24 ; Enable receiver & transmitter, 8-bit mode
; data -> R22,R23
; address -> R26,R27
L10: rcall uartGet ; repeat (R16 = uartGet)
cpi R16,27 ; while (R16 == ESCAPE)
breq L10
cpi R16,'a' ; if(R16=='a') 'a' = Autoincrement?
brne L12
ldi R16,'Y' ; Autoincrement? Yes, autoincrement is quicker
rjmp L70 ; uartSend(R16)
L12: cpi R16,'A' ; else if(R16=='A') write address
brne L14
rcall uartGet
mov R27,R16 ; R27 <= address high byte
rcall uartGet
mov R26,R16 ; R26 <= address low byte
lsl R26 ; address=address<<1
rol R27 ; convert from word address to byte address
rjmp L68 ; uartSend('\r')
L14: cpi R16,'c' ; else if(R16=='c') write program memory, low byte
brne L16
rcall uartGet
mov R22,R16 ; R22 <= data low byte
rjmp L68 ; uartSend('\r')
L16: cpi R16,'C' ; else if(R16=='C') write program memory, high byte
brne L18
rcall uartGet
mov R23,R16 ; R23 <= data high byte
movw R30,R26 ; Z pointer <= address
movw R0,R22 ; R0&R1 <= data
ldi R24,(1<<SPMEN); page load (fill temporary buffer)
rcall Do_SPM ; do fill temporary buffer
adiw R26,2 ; address=address+2
rjmp L68 ; uartSend('\r')
L18: cpi R16,'e' ; else if(R16=='e') Chip erase
brne L28
; for(address=0; address < (2*SECONDBOOTSTART); address += (2*PAGESIZE))
clr R26 ; page_erase();
clr R27
rjmp L24
L20: movw R30,R26 ; Z pointer <= address
ldi R24,(1<<PGERS)|(1<<SPMEN)
out SPMCR,R24 ; page_erase
rcall Do_SPM ; do page_erase
ldi R24,(1<<ASRE)|(1<<SPMEN) ; Re-Enable the RWW section
rcall Do_SPM ; do Enable RWW section
subi R26,low(-2*PAGESIZE) ; address += (2*PAGESIZE)
sbci R27,high(-2*PAGESIZE)
L24: ldi R24,low(2*SECONDBOOTSTART)
ldi R25,high(2*SECONDBOOTSTART)
cp R26,R24 ; address < Boot Flash address (byte address) 0x3E00 ?
cpc R27,R25
brlo L20
; 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
rjmp L68 ; uartSend('\r')
L28: cpi R16,'m' ; else if(R16== 'm') Write page
brne L34
movw R30,R26 ; Z pointer <- address
ldi R24,(1<<PGWRT)|(1<<SPMEN) ; Write page
rcall Do_SPM ; do Write page
ldi R24,(1<<ASRE)|(1<<SPMEN) ; Re-Enable the RWW section
rcall Do_SPM ; do Enable RWW section
L32: rjmp L68 ; uartSend('\r')
L34: cpi R16,'P' ; else if(R16=='P') Enter programming mode
breq L32 ; uartSend('\r')
cpi R16,'L' ; else if(R16=='L') Leave programming mode
breq L32 ; uartSend('\r')
cpi R16,'p' ; else if (R16=='p') Return programmer type
brne L38
ldi R16,'S' ; uartSend('S') Serial
rjmp L70 ; uartSend(R16)
L38: cpi R16,'R' ; else if(R16=='R') Read program memory
brne L40
movw R30,R26 ; Z pointer <= address
lpm R24,Z+ ; read program memory LSB; store LSB in R24 and Z pointer ++
lpm R16,Z+ ; read program memory MSB; store MSB in R16 and Z pointer ++
rcall uartSend ; uartSend(R16) MSB
movw R26,R30 ; address += 2
mov R16,R24 ; LSB stored in R16
rjmp L70 ; uartSend(R16) LSB
L40: cpi R16,'D' ; else if (R16=='D') Write data to EEPROM
brne L42
rcall uartGet
out EEDR,R16 ; EEDR = uartGet()
ldi R17,6 ; write EEPROM
rcall EepromTalk
rjmp L68 ; uartSend('\r')
L42: cpi R16,'d' ; else if (R16=='d') Read data from EEPROM
brne L44
ldi R17,1 ; read EEPROM
rcall EepromTalk ; R16 = EEPROM data
rjmp L70 ; uartSend(R16)
L44: cpi R16,'F' ; else if(R16=='F') Read fuse bits
brne L46
clr R30 ; Z pointer = 0000
rjmp L50 ; rcall readFuseAndLock
L46: cpi R16,'r' ; else if(R16=='r') Read lock bits
brne L48
ldi R30,1 ; Z pointer = 0001
rjmp L50 ; rcall readFuseAndLock
L48: cpi R16,'N' ; else if(R16=='N') Read high fuse bits
brne L52
ldi R30,3 ; Z pointer = 0003
L50: rcall readFuseAndLock
rjmp L70 ; uartSend(R16)
L52: cpi R16,'t' ; else if(R16=='t') Return supported devices code
brne L54
ldi R16,DT ; Device Type
rcall uartSend ; uartSend(DT) send Device Type
clr R16
rjmp L70 ; uartSend(0)
L54: ; else if ((R16=='l')||(R16=='x')||(R16=='y')||(R16=='T'))
cpi R16,'l' ; 'l' = Write Boot Loader Lockbits
breq L56
cpi R16,'x' ; 'x' = Set LED
breq L56
cpi R16,'y' ; 'y' = Clear LED
breq L56
cpi R16,'T' ; 'T' = Select device type
brne L60
L56: rcall uartGet ; R16 = uartGet()
; YOU CAN INSERT LEDs CODE HERE
rjmp L68 ; uartSend('\r')
L60: cpi R16,'S' ; else if (R16=='S') Return software identifier
brne L62
ldi R30,low(2*Soft_Id)
ldi R31,high(2*Soft_Id)
L61: lpm R16,Z+
tst R16
breq L72 ; branch is end of string ((Z) == 0)
rcall uartSend ; else send char
rjmp L61
L62: cpi R16,'V' ; else if (R16=='V') Return Software Version
brne L64
ldi R16,'1' ; uartSend('1')
rcall uartSend
ldi R16,'3' ; uartSend('3')
rjmp L70 ; uartSend(R16)
L64: cpi R16,'s' ; else if (R16=='s') Return Signature Byte
brne L66
ldi R16,SB1 ; uartSend(SB1) Signature Byte 1
rcall uartSend
ldi R16,SB2 ; uartSend(SB2) Signature Byte 2
rcall uartSend
ldi R16,SB3 ; uartSend(SB3) Signature Byte 3
rjmp L70 ; uartSend(R16)
L66: ldi R16,'?' ; else uartSend('?')
rjmp L70 ; uartSend(R16)
L68: ldi R16,13 ; uartSend('\r')
L70: rcall uartSend ; uartSend(R16)
L72: rjmp L10
readFuseAndLock:
clr R31 ; Z pointer high byte = 0
ldi R24,9 ; SPMCR = 0x09
out SPMCR,R24 ; read fuse and lock
lpm R16,Z ; read program memory
ret
EepromTalk: ; if R17 = 6 write, if R17 = 1 read
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 ; wait until EEWE == 0
rjmp L90
in R16,EEDR ; R16 = EEDR
ret
Do_SPM: ; check for previous SPM complete
Wait_SPM: ; wait until page erase (or page write) is completed
in R20,SPMCR ; SPMEN==0 after page erase or page write completed
sbrc R20,SPMEN ; skip if bit SPMEN in SPMCR is cleared
rjmp Wait_SPM
L92: sbic EECR,EEWE ; wait until EEWE == 0
rjmp L92 ; check that no EEPROM write access is running
out SPMCR,R24
spm ; store program memory
.dw 0xffff ; ensure proper instruction pipelining after
nop ; programming (mega163, mega323, ...)
ret
uartSend: ; send R16
sbis UCSRA,UDRE ; wait for empty transmit buffer (until UDRE==1)
rjmp uartSend
out UDR,R16 ; UDR = R16, start transmission
ret
uartGet:
sbis UCSRA,RXC ; wait for incoming data (until RXC==1)
rjmp uartGet
in R16,UDR ; return received data in R16
ret
;Soft_Id: .DB "AVRB163", 0
; -mt
Soft_Id: .DB "AVRBm16", 0
; END of BOOT LOADER PROGRAM
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -