📄 megabootloaderblips.asm
字号:
.endif
; AVR chip dependent {in/lds} versus {out/sts} automatic selection macros
; The device include file must be used to define SRAM_START
; usage: InReg reg, addr
.macro INREG
.if @1 < 0x40
in @0, @1
.elif ((@1 >= 0x60) && (@1 < SRAM_START))
lds @0,@1
.else
.error "InReg: Invalid I/O register address"
.endif
.endmacro
; usage: OutReg addr, reg
.macro OUTREG
.if @0 < 0x40
out @0, @1
.elif ((@0 >= 0x60) && (@0 < SRAM_START))
sts @0,@1
.else
.error "OutReg: Invalid I/O register address"
.endif
.endmacro
.LISTMAC ; expand macros in assembler output listing
.CSEG
.org MYORG ; defined in one of the processor-dependent blocks, above
boot_reset:
;--- init stack
ldi R24,low(RAMEND) ; constant is in the include file
ldi R25,high(RAMEND)
out SPL,R24
out SPH,R25 ; SP = RAMEND
;--- init uart
;ldi R24,(1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0) ; 8 bits, 1 stop, async mode
;out UCSRC,R24
; UBRRH is zero after a reset so no code here
ldi R24,UBRRLval ; R24,(clock - 8 * bootldr_baud) / (16 * bootldr_baud) ; Baud rate
OUTREG BAUDL,R24
; enable tx and rx
ldi R24,UARTENA
OUTREG UARTC,R24 ; Enable receiver & transmitter, 8-bit mode
.ifdef LED_DDR
ldi R24,(1 << LED_BITNO)
OUTREG LED_PORT,R24 ; LED port and bit, LED will illuminate now
.endif
;--- following waits for esc char, if not received within a given period, jump to application code
;--- about 1.5 seconds @ 7.3728 clock
;--- delete or chose your own way of entering bootstrap code
clr R23 ; used for PC timeout counters
clr R24 ; R23:24 are a 16 bit counter incrementing R25 each roll-over (65536 iterations)
ldi R25,PCTIMEOUT ; R25 is increments up to PCTIMEOUT
; LOOP until a character other than <escape> is received or until too much time has elapsed.
; Then go to user program at location 0.
boot_esc_lp:
;;rcall nada ; kill some time
dec R23
brne boot_r_1
dec R24
brne boot_r_1 ; 16 bit counter loop
.ifdef LED_DDR
OUTREG LED_PORT,R25 ; this makes LED blink visibly
.endif
dec R25
brne boot_r_1
; --- TIMED OUT, STARTUP USER PROGRAM
boot_r_0:
clr R30 ; ensure 0 if jump here from elsewhere
clr R31
OUTREG UARTC,R30 ; disable UART
ijmp ; timeout, jump to address zero
boot_r_1:
INREG R16,USTAT
sbrs R16,URXC ; Skip if UART byte has arrived
rjmp boot_esc_lp ; not yet, loop
INREG R16,UDATA ; get received data in R16
cpi R16,0x1b ; ESC?
breq boot_esc_lp ;
rjmp L10 ; decode 1st received char that's not an ESCAPE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
b_main: rcall uartGet ; repeat (R16 = uartGet)
cpi R16,0x1B ; while (R16 == ESCAPE)
breq b_main
L10: cpi R16,'a' ; if(R16=='a') 'a' = inquiry: Autoincrement supported?
brne L12
ldi R16,'Y' ; Reply with Yes, autoincrement is quicker
rjmp L70 ; uartSend(R16)
L12: cpi R16,'A' ; else if(R16=='A') set write address
brne L12x1
;--- get word address from UART, convert to byte address
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 byte to word address; save bit 15 to carry
.ifdef RAMPZ
; added this bst instruction for large flash support (stevech)
clr R16 ; Carry unchanged by clr
rol R16 ; get carry from previous ROL R27 into bit 0
out RAMPZ,R16 ; bit 0 is word address bit 15
.endif
rjmp send_cr ; uartSend('\r')
; --- Block write command inquiry added June 2006 Steve Childress
L12x1: cpi R16,'b' ; block mode suport inquiry by host
brne L13
ldi R16,'Y'
rcall uartSend
ldi R16,high(PAGESIZE*2); this chip's flash buffer size in bytes
rcall uartSend
ldi R16,low(PAGESIZE*2)
rjmp L70 ; send and continue
L13: cpi R16,'B' ; 'B' is write block of EEPROM or FLASH data
brne L14
; --- Block write command added June 2006 Steve Childress
rcall L13x4 ; get block size then E or F command
cpi R16,'F'
brne L13x5
; R26:27 have byte address from assumed previous 'A' command
; R28:29 have block size in bytes
L13x2: rcall uartGet ; get upper byte of flash word
mov R0,R16
rcall uartGet
mov R1,R16 ; word is now in R1:R0
movw R30,R26 ; Z register must hold byte addr from the 'A' command
ldi R19,(1<< SPMEN) ; setup for write to flash buffer
OUTREG SPMCSR,R19 ; must set this bit
spm ; store r0:r1 to chip's special flash buffer
adiw r26,2 ; byte address
sbiw r28,2 ; block size counter
brne L13x2 ; loop for all bytes in the block
; Write block - R30:31 have last used addr within block
rjmp L30 ; do the page write and reply to PC
; subroutine common to 'B' and 'g' commands.
; get block size from uart, but in R28:29. Get next uart byte in R16 and return
L13x4:
rcall uartGet ; block size high order byte
mov R29,R16
rcall uartGet ; block size low order byte
mov R28,R16 ; have block size
rjmp uartGet ; next is 'F' for Flash data or 'E'
L13x5:
;;; Block mode EEPROM not supported (makes bootloader smaller)
;;; cpi R16,'E' ; 'E' for block mode EEPROM data
;;; brne L14 ;
;;; rjmp cmdUnknown ; NOT IMPLEMENTED - will wind up at cmdUnknown
L14: cpi R16,'c' ; else if(R16=='c') write program memory, low byte
brne L16
;--- get program memory low byte from UART
rcall uartGet
mov R22,R16 ; R22 = data low byte, keep for use for the next "C" command
rjmp send_cr ; uartSend('\r')
;--- get program data high byte from UART and store in on-chip buffer
L16: cpi R16,'C' ;else if(R16=='C') write program memory,high byte
brne L17
rcall uartGet
mov R23,R16 ; R23 = data high byte. R22 has low byte from the "c" command
movw R30,R26 ; Z pointer = byte address
movw R0,R22 ; R0&R1 = data
ldi R24,1 ; SPMCR = 0x01
OUTREG SPMCSR,R24 ; page load (fill temporary buffer)
spm ; Store program memory
adiw R26,2 ; address+=2 A new "A" command should come after addr rollover to 0
rjmp send_cr ; uartSend('\r')
L17:
cpi R16,'g' ; read block?
brne L18
; --- 'g' comamnd read flash block added. Steve Childress June 2006
rcall L13x4 ; get block size
cpi R16,'F' ; flash?
brne L17x6
movw R30,R26 ; get address in R30:31 (Z)
L17x2:
.ifdef RAMPZ ; chips with more than 64K Bytes of
elpm R16,Z+ ; read program memory MSB; store MSB in R16 and Z pointer ++
; this reads just one block so if Z rolls over to 0 it doesn't matter as there's a "A" command every block
rcall uartSend ; uartSend(R16) MSB
elpm R16,Z+ ; read program memory LSB
.else
lpm R16,Z+ ; read program memory MSB; store MSB in R16 and Z pointer ++
rcall uartSend ; uartSend(R16) MSB
lpm R16,Z+ ; read program memory LSB
.endif
rcall uartSend ; uartSend(R16) LSB+
sbiw R28,2 ; R28:29 is counter based on block size
brne L17x2 ; loop while using Z register
movw R26,R30 ; update for auto-incrm
rjmp b_main ; wait for another command like 'g'
L17x6:
;;; cpi R16,'E' ; 'E' for block mode EEPROM data ;
;;; rjmp cmdUnknown ; NOT IMPLEMENTED - will wind up at cmdUnknown
;--- chip erase?
L18: cpi R16,'e' ; else if(R16=='e') Chip erase
brne L28
; erase all flash, page at a time
clr zl ; word address 0
clr zh
L19:
lsl zl ; get byte address within 64KByte space of flash
rol zh
.ifdef RAMPZ
clr R16 ; doesn't affect carry
rol R16 ; get 16th bit of word addr from carry to bit 0
out RAMPZ,R16 ; and to bit 0 of RAMPZ
ror R16 ; put it back into carry
.endif
ldi R17,( (1<<PGERS) | (1<<SPMEN) ) ; page_erase
OUTREG SPMCSR,R17
spm
rcall wait_spm ; wait for done; preserving C bit
ror zh ; back to word addr, C held 16th word addr bit
ror zl
subi zl,low(-(PAGESIZE)) ; address += ; PAGESIZE is in words
sbci zh,high(-(PAGESIZE)) ; subtract negative PAGESIZE in words = add
ldi R24,low(MYORG) ; is a word addr
ldi R25,high(MYORG)
cp zl,R24 ; compare 16 bit word addr in Z, spans 128KByte Flash
cpc zh,R25
brlo L19
rjmp send_cr ; uartSend('\r')
;===========================================
#ifdef NONESUCH ; old version not right for 128KB flash
clr R26 ; start at addr 0
clr R27
rjmp L24 ; test for end
L20: movw R30,R26 ; Z-pointer = byte address
ldi R24,3 ; SPMCR = 0x03
WRITEPMCR R24 ; page_erase
spm ; Store program memory
; do the page erase
rcall wait_spm ; wait for done
subi R26,low(-2*PAGESIZE) ; address += (2*PAGESIZE)
sbci R27,high(-2*PAGESIZE) ; subtract negative PAGESIZE = add
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -