共2条
1/1 1 跳转至页
ATMEGA8 ATMEGA8的疑惑?
问
我正在使用ATMEGA8,写程序时,通过对bootrst,ivsel的编程可以确定对复位和中断向量表的位置。看了好久,弄不明白改变这位置有什么用的啊。请同仁能否解释一下。
还有一个问题是,ATMEGA8书上说,加载程序区大小最大为1K,而我刚在网上看到说可以到2K,这是怎么回事啊? 答 1: 写bootrst后,写bootrst后,程序就从boot区开始运行,执行你的boot代码。否则,跳过bot区,直接从app区运行。应该是这样吧? 答 2: 谢谢你说的没错啊,我想知道这两种程序执行方式有什么特点,也就是说各自有什么优缺点吗?我就不知道什么时候该用哪种方式呢, 答 3: 参考下面的代码,实现一个Boot Loder;***************************************************************************************
;*说明:
;* 1、本程序修改自AVRfreaks的Design Note #032,你可以到 http://www.AVRfreaks.com 下载
;* 2、本程序支持 atmega-8 和 AVRProg (版本一定要1.37及以上)。
;* 3、Design Note #032上的程序,是为写的,在上不能正常运行。主要问题是在页写和
;* 擦除以后,不能再重新访问RWW。现在改正了这个bug!
;* 4、请确定你的 AVRProg 的版本在1.37及以上,1.37以下的是不支持 Mega8 的。
;* 5、请用等PonyProg等编程器把编译好的代码(Boot2.hex),写入到Mega8中。
;* 同时编程熔断位:BOOTSZ0 BOOTRST
;* 6、若有问题,请发邮件给我: Zhang_Lei@cnnb.net 。
;* 7、我的主页在 http://AVRmcu.topcities.com 。
;***************************************************************************************
;******************** BOOT LOADER FOR ATmega8 *****************************************
;*
;* File : Boot2.asm (Include chip erase counter)
;* Version : 1.3
;* Compiler : AVR Studio
;* Target : ATmega8
;* Output size : 207 words (414 bytes)
;* Author : 张磊 ;Email-to: Zhang_Lei@cnnb.net; or zlei@21ic
;* website: http://AVRmcu.topcities.com
;***************************************************************************************
;****************************************************
; 定义Mega8识别代码、电子标签字节和其它
;****************************************************
.equ DT = 0x77 ; Mega8识别代码(Mega8 bootloader)
.equ SB1 = 0x07 ; 电子标签字节 1
.equ SB2 = 0x93 ; 电子标签字节 2
.equ SB3 = 0x1e ; 电子标签字节 3
.equ E2END = $1FF ; EEEPROM尾
.equ UBR = 12 ; 波特率 = 19.200 bps ,晶振 = 4 MHz。
;AVRProg 能接受的波特率是 19200 和 115200
.nolist
.include "m8def.inc" ; 包含 mega8 器件配置文件
.list
.CSEG
.org SECONDBOOTSTART ;($0F00) 2'nd boot block size is 512
;****************************************************
; 复位并等待AVRProg发送ESC
;****************************************************
sbic PIND,PIND4 ; if (PIND4为0) then 跳到 Boot_Reset
rjmp $0000 ; else 运行用户代码(地址:$0000)
Boot_Reset:
;**** 初识化堆栈
ldi R24,low(RAMEND)
ldi R25,high(RAMEND)
out SPL,R24
out SPH,R25 ; SP = RAMEND
;**** 初识化串口
ldi R24,UBR ; 波特率
out UBRRL,R24
ldi R24,(1<<RXEN)|(1<<TXEN) ; 使能 TXEN 和 RXEN, 8位
out UCSRB,R24
L10: rcall uartGet ; repeat (R16 = uartGet)
cpi R16,27 ; while (R16 == ESCAPE)
breq L10
rjmp Boot_ID ; 若收到ESC,先显示ID,再跳到Boot_Main
Boot_Main: rcall uartGet ; repeat (R16 = uartGet)
cpi R16,0x1B ; while (R16 == ESCAPE)
breq Boot_Main
cpi R16,'a' ; if(R16=='a') 'a' = Autoincrement?
brne L12
ldi R16,'Y' ; Yes, autoincrement is quicker
rjmp L70 ; uartSend(R16)
;*********************************************************************
; 得到地址,并把字节地址(byte address)转换成字地址(word address)的形式
;*********************************************************************
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 byte address to word address
rjmp Send_CR ; uartSend('\r')
;****************************************************
; 得到 program data 低字节
;****************************************************
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 Send_CR ; uartSend('\r')
;****************************************************
;得到 program data 高字节,并把它存入临时缓冲区
;****************************************************
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 ; SPMCR = 0x01
out SPMCR,R24 ; page load (fill temporary buffer)
spm ; Store program memory
adiw R26,2 ; address=address+2
rjmp Send_CR ; 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 ; test for end
L20: movw R30,R26 ; Z-pointer = address
ldi R24,3 ; SPMCR = 0x03
out SPMCR,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)
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 at address E2END-1
ldi R27,high(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 Send_CR ; uartSend('\r')
;****************************************************
; 页写( page write)
;****************************************************
L28: cpi R16,'m' ; else if(R16== 'm') Write page
brne L34
movw R30,R26 ; Z-pointer = address
ldi R24,5 ; SPMCR = 0x05 Write page
out SPMCR,R24
spm ; Store program memory
rcall wait_spm
L32: rjmp Send_CR ; 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')
;********************************************************
;返回所使用编程接口方式类型,对于串行接口的返回'S',并口的'P'.
;********************************************************
cpi R16,'p' ; else if (R16=='p') Return programmer type
brne L38
ldi R16,'S' ; uartSend('S') Serial
rjmp L70 ; uartSend(R16)
;****************************************************
; 读program memory
;****************************************************
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
;****************************************************
; 写EEPROM
;****************************************************
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 Send_CR ; uartSend('\r')
;****************************************************
; 读EEPROM
;****************************************************
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)
;--- grab another char and ignore
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 Send_CR ; uartSend('\r')
;********************************************************
;* 返回一个7字节ASCII字符串说明编程器类型,我的为"AVRZLM8" :)
;********************************************************
L60: cpi R16,'S' ; else if (R16=='S') Return software identifier
brne L62
Boot_ID: 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('2')
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)
;****************************************************
;* 发送一个“回车”字符(CR)
;****************************************************
Send_CR: ldi R16,13 ; uartSend('\r')
;****************************************************
;* 发送一个Ascii字符
;****************************************************
L70: rcall uartSend ; uartSend(R16)
L72: rjmp Boot_Main
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 then Write, if R17 == 1 then 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
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
;****************************************************
;* 关键是这个子程序!!
;* Design Note #032上的程序,是为写的,在上不能正常运行。
;* 主要问题是在页写和擦除以后,不能再重新访问RWW。
;* 现在以改正这个bug!
;****************************************************
wait_spm: in R16,SPMCR
sbrc R16,SPMEN
rjmp wait_spm
ldi R16,(1<<RWWSRE) | (1<<SPMEN)
out SPMCR,R16
spm
ret
Soft_ID: .DB "AVRZLM8", 0 答 4: 其实Design Note #032没有BUG因为RWW区(应用程序区)通过写RWWSRE位和复位后都会重新开放(可以读),如果在BOOTLOAD程序中没有去读RWW(校验)就无需开放RWW区,上面的程序与Design Note #032 几乎一模一样,就是在最后加入了wait_spm,可以参考原文资料第216页,里面有很详细的介绍,只有数页,还是自己把bootload看明白更好,这样才能不被束缚手脚,举一反三
答 5: to cxiang20012K指的是字节(byte),1k是字(word),即程序字,由于AVR程序是16位字长,所以1个字就是2个字节,AVR这点在资料或宣传上做得很不好,为了表现自己程序大就用字节,很容易给人误导 答 6: 同感,如mega8程序空间为8k,实际上为4kX16bit,你只能放4k程序我用义隆的em78p156,1k空间,1kX13bit,真正能放1k程序,货真价实。
另外上面的Boot Loder程序很好用,我调试程序就用它,方便。
提醒大家的是AVRProg 能接受的波特率决不仅仅只是19200和115200,可以尝试,用高的波特率会大大加快下载速度,有切身体会。
答 7: 呵呵,这个bootloder本来就是改自Design Note #032
还有一个问题是,ATMEGA8书上说,加载程序区大小最大为1K,而我刚在网上看到说可以到2K,这是怎么回事啊? 答 1: 写bootrst后,写bootrst后,程序就从boot区开始运行,执行你的boot代码。否则,跳过bot区,直接从app区运行。应该是这样吧? 答 2: 谢谢你说的没错啊,我想知道这两种程序执行方式有什么特点,也就是说各自有什么优缺点吗?我就不知道什么时候该用哪种方式呢, 答 3: 参考下面的代码,实现一个Boot Loder;***************************************************************************************
;*说明:
;* 1、本程序修改自AVRfreaks的Design Note #032,你可以到 http://www.AVRfreaks.com 下载
;* 2、本程序支持 atmega-8 和 AVRProg (版本一定要1.37及以上)。
;* 3、Design Note #032上的程序,是为写的,在上不能正常运行。主要问题是在页写和
;* 擦除以后,不能再重新访问RWW。现在改正了这个bug!
;* 4、请确定你的 AVRProg 的版本在1.37及以上,1.37以下的是不支持 Mega8 的。
;* 5、请用等PonyProg等编程器把编译好的代码(Boot2.hex),写入到Mega8中。
;* 同时编程熔断位:BOOTSZ0 BOOTRST
;* 6、若有问题,请发邮件给我: Zhang_Lei@cnnb.net 。
;* 7、我的主页在 http://AVRmcu.topcities.com 。
;***************************************************************************************
;******************** BOOT LOADER FOR ATmega8 *****************************************
;*
;* File : Boot2.asm (Include chip erase counter)
;* Version : 1.3
;* Compiler : AVR Studio
;* Target : ATmega8
;* Output size : 207 words (414 bytes)
;* Author : 张磊 ;Email-to: Zhang_Lei@cnnb.net; or zlei@21ic
;* website: http://AVRmcu.topcities.com
;***************************************************************************************
;****************************************************
; 定义Mega8识别代码、电子标签字节和其它
;****************************************************
.equ DT = 0x77 ; Mega8识别代码(Mega8 bootloader)
.equ SB1 = 0x07 ; 电子标签字节 1
.equ SB2 = 0x93 ; 电子标签字节 2
.equ SB3 = 0x1e ; 电子标签字节 3
.equ E2END = $1FF ; EEEPROM尾
.equ UBR = 12 ; 波特率 = 19.200 bps ,晶振 = 4 MHz。
;AVRProg 能接受的波特率是 19200 和 115200
.nolist
.include "m8def.inc" ; 包含 mega8 器件配置文件
.list
.CSEG
.org SECONDBOOTSTART ;($0F00) 2'nd boot block size is 512
;****************************************************
; 复位并等待AVRProg发送ESC
;****************************************************
sbic PIND,PIND4 ; if (PIND4为0) then 跳到 Boot_Reset
rjmp $0000 ; else 运行用户代码(地址:$0000)
Boot_Reset:
;**** 初识化堆栈
ldi R24,low(RAMEND)
ldi R25,high(RAMEND)
out SPL,R24
out SPH,R25 ; SP = RAMEND
;**** 初识化串口
ldi R24,UBR ; 波特率
out UBRRL,R24
ldi R24,(1<<RXEN)|(1<<TXEN) ; 使能 TXEN 和 RXEN, 8位
out UCSRB,R24
L10: rcall uartGet ; repeat (R16 = uartGet)
cpi R16,27 ; while (R16 == ESCAPE)
breq L10
rjmp Boot_ID ; 若收到ESC,先显示ID,再跳到Boot_Main
Boot_Main: rcall uartGet ; repeat (R16 = uartGet)
cpi R16,0x1B ; while (R16 == ESCAPE)
breq Boot_Main
cpi R16,'a' ; if(R16=='a') 'a' = Autoincrement?
brne L12
ldi R16,'Y' ; Yes, autoincrement is quicker
rjmp L70 ; uartSend(R16)
;*********************************************************************
; 得到地址,并把字节地址(byte address)转换成字地址(word address)的形式
;*********************************************************************
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 byte address to word address
rjmp Send_CR ; uartSend('\r')
;****************************************************
; 得到 program data 低字节
;****************************************************
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 Send_CR ; uartSend('\r')
;****************************************************
;得到 program data 高字节,并把它存入临时缓冲区
;****************************************************
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 ; SPMCR = 0x01
out SPMCR,R24 ; page load (fill temporary buffer)
spm ; Store program memory
adiw R26,2 ; address=address+2
rjmp Send_CR ; 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 ; test for end
L20: movw R30,R26 ; Z-pointer = address
ldi R24,3 ; SPMCR = 0x03
out SPMCR,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)
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 at address E2END-1
ldi R27,high(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 Send_CR ; uartSend('\r')
;****************************************************
; 页写( page write)
;****************************************************
L28: cpi R16,'m' ; else if(R16== 'm') Write page
brne L34
movw R30,R26 ; Z-pointer = address
ldi R24,5 ; SPMCR = 0x05 Write page
out SPMCR,R24
spm ; Store program memory
rcall wait_spm
L32: rjmp Send_CR ; 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')
;********************************************************
;返回所使用编程接口方式类型,对于串行接口的返回'S',并口的'P'.
;********************************************************
cpi R16,'p' ; else if (R16=='p') Return programmer type
brne L38
ldi R16,'S' ; uartSend('S') Serial
rjmp L70 ; uartSend(R16)
;****************************************************
; 读program memory
;****************************************************
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
;****************************************************
; 写EEPROM
;****************************************************
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 Send_CR ; uartSend('\r')
;****************************************************
; 读EEPROM
;****************************************************
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)
;--- grab another char and ignore
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 Send_CR ; uartSend('\r')
;********************************************************
;* 返回一个7字节ASCII字符串说明编程器类型,我的为"AVRZLM8" :)
;********************************************************
L60: cpi R16,'S' ; else if (R16=='S') Return software identifier
brne L62
Boot_ID: 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('2')
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)
;****************************************************
;* 发送一个“回车”字符(CR)
;****************************************************
Send_CR: ldi R16,13 ; uartSend('\r')
;****************************************************
;* 发送一个Ascii字符
;****************************************************
L70: rcall uartSend ; uartSend(R16)
L72: rjmp Boot_Main
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 then Write, if R17 == 1 then 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
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
;****************************************************
;* 关键是这个子程序!!
;* Design Note #032上的程序,是为写的,在上不能正常运行。
;* 主要问题是在页写和擦除以后,不能再重新访问RWW。
;* 现在以改正这个bug!
;****************************************************
wait_spm: in R16,SPMCR
sbrc R16,SPMEN
rjmp wait_spm
ldi R16,(1<<RWWSRE) | (1<<SPMEN)
out SPMCR,R16
spm
ret
Soft_ID: .DB "AVRZLM8", 0 答 4: 其实Design Note #032没有BUG因为RWW区(应用程序区)通过写RWWSRE位和复位后都会重新开放(可以读),如果在BOOTLOAD程序中没有去读RWW(校验)就无需开放RWW区,上面的程序与Design Note #032 几乎一模一样,就是在最后加入了wait_spm,可以参考原文资料第216页,里面有很详细的介绍,只有数页,还是自己把bootload看明白更好,这样才能不被束缚手脚,举一反三
答 5: to cxiang20012K指的是字节(byte),1k是字(word),即程序字,由于AVR程序是16位字长,所以1个字就是2个字节,AVR这点在资料或宣传上做得很不好,为了表现自己程序大就用字节,很容易给人误导 答 6: 同感,如mega8程序空间为8k,实际上为4kX16bit,你只能放4k程序我用义隆的em78p156,1k空间,1kX13bit,真正能放1k程序,货真价实。
另外上面的Boot Loder程序很好用,我调试程序就用它,方便。
提醒大家的是AVRProg 能接受的波特率决不仅仅只是19200和115200,可以尝试,用高的波特率会大大加快下载速度,有切身体会。
答 7: 呵呵,这个bootloder本来就是改自Design Note #032
共2条
1/1 1 跳转至页
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
与电子爱好者谈读图四被打赏50分 | |
与电子爱好者谈读图二被打赏50分 | |
【FRDM-MCXN947评测】Core1适配运行FreeRtos被打赏50分 | |
【FRDM-MCXN947评测】双核调试被打赏50分 | |
【CPKCORRA8D1B评测】---移植CoreMark被打赏50分 | |
【CPKCORRA8D1B评测】---打开硬件定时器被打赏50分 | |
【FRDM-MCXA156评测】4、CAN loopback模式测试被打赏50分 | |
【CPKcorRA8D1评测】--搭建初始环境被打赏50分 | |
【FRDM-MCXA156评测】3、使用FlexIO模拟UART被打赏50分 | |
【FRDM-MCXA156评测】2、rt-thread MCXA156 BSP制作被打赏50分 |