📄 yampp7_boot.asm
字号:
/*
Copyright (C) 2002 Jesper Hansen <jesperh@telia.com>.
This file is part of the yampp system.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
yampp-7 USB Bootloader
Jesper Hansen 2002-06-20
Romuald Bialy 2003-04-05
AVR-GCC 3.3
Enables the yampp-7 to download new code via USB.
Rev. Date Name Comment
------ ---------- ----- -------------------------------
1.0 2002-06-20 jesper Initial version
2.1 2003-04-05 MIS added exit from bootloader after STOP keypress
3.0 2004-01-18 MIS added compatibility with Mega162 CPU (enabling RWW section)
5.0 2004-02-13 MIS special version for M162 and load at address 0x3F00.
this make additionally 768 bytes of free space for main code
6.0 2005-03-21 MIS added LED (backlight) blinking during bootloader active
*/
#define __ASSEMBLER__ 1
#define __SFR_OFFSET 0
#include "avr/io.h"
.org 0 ; actually this will be at 0x1F80 (word address)
; SPM Control/Status Register bits
#define BLBSET 3
#define PGWRT 2
#define PGERS 1
#define SPMEN 0
#define USB_PORT PORTD
#define USB_TXRDY PD3
#define USB_RXRDY PD2
#define USB_ADDR 0x8000
;
; version number to report to USB loader program or to YL
;
#define VERSION '6'
;
; start of code
;
boot:
;
; init I/O pins
;
sbi PORTD,PD4 ; needed for compatibility with main firmware
; and detection of bootloader version
ser r25
out PORTB,r25 ; enable all pullups
out PORTD,r25 ; enable all pullups
cbi USB_PORT-1,USB_RXRDY ; set pins as inputs
cbi USB_PORT-1,USB_TXRDY
; check for boot enable
; run the application if PD4 or PD5 (two top buttons)
; is high (not pressed)
sbic PIND,PD4 ; skip if bit is low
rjmp jump_app ; pin was high
; test next pin
sbic PIND,PD5 ; skip if bit is high
rjmp jump_app ; pin was high, go to main app
rjmp do_boot ; pin was low, goto boot loader
;
; send an ACK to the USB host - moved here for code size decrease
;
usb_ack:
ldi r24,'A'
;fall trought
;
; send the byte in r24 over the USB link
;
usb_putbyte:
sbic PIND,USB_TXRDY ; while flag is set
rjmp usb_putbyte ; wait for bit to be cleared
st Y,r24
ret
;
; bootloader code
;
.org 0x20 ; fixed offset so we can jump here from application
do_boot:
cli ; no interrupts, thank you
;
; setup the stack
;
ldi r16, 0x04 ; stack at 0x0404 (anywhere high address in internal RAM)
out SPL, r16
out SPH, r16
;
; enable external memory
;
ldi r25,(1<<SRE) | (1<<SRW10)
out MCUCR,r25
;
; init rest of I/O pins
;
sbi DDRB,PB0 ; LED (backlight) pin as output
sbi DDRB,PB1 ; set RST as output and high
ldi r29,hi8(USB_ADDR)
ldi r28,lo8(USB_ADDR) ; USB adress in Y (for whole bootloader code)
;
; wait for USB start tag
;
do_boot_2:
clr r30 ; clear LED blink counter
clr r31
do_boot_3:
sbiw r30,1 ; decrament blink counter
brne do_boot_4
rcall led_blink
do_boot_4:
sbis PIND,PD1 ; skip if STOP key not pressed
rjmp jump_app ; exit from bootloader
;
; check RXF pin to see if the USB chip
; have some data to send us
;
sbic PIND,USB_RXRDY ; if flag is clear, the usb have an y data, skip next
rjmp do_boot_3 ; no, loop until something
rcall usb_getbyte1 ; get the byte
cpi r24,'?' ; check for status command
breq tell_version
cpi r24,'!' ; check for download command
breq do_download
cpi r24,'E'
brne do_boot_3 ; check if "ESC" sequence
rcall usb_getbyte
cpi r24,'S'
brne do_boot_2
rcall usb_getbyte
cpi r24,'C'
brne do_boot_2
;
; jump to application
;
jump_app:
jmp 0x0000 ; Jump to Application start.
tell_version:
;
; send version info over USB
;
ldi r24,'y'
rcall usb_putbyte
ldi r24,'b'
rcall usb_putbyte
ldi r24,'o'
rcall usb_putbyte
; ldi r24,'o' ; not needed second load of 'o'...
rcall usb_putbyte
ldi r24,'t'
rcall usb_putbyte
ldi r24,VERSION
rcall usb_putbyte ; send the version number
rjmp do_boot_2
do_download:
;
; check for "AB" tag
;
rcall usb_getbyte
cpi r24,'A'
brne do_download
rcall usb_getbyte
cpi r24,'B'
brne do_download
;
; tag received, get data length (in 128 byte blocks)
;
rcall usb_getbyte
mov r10,r24 ; save length in r10
clr r8 ; block counter
boot_loop:
;
; read a USB 128 byte block of data to internal SRAM
; starting at address 0x100
;
rcall usb_ack ; start transmission
ldi r31,hi8(0x100)
ldi r30,lo8(0x100) ; pointer in Z
ldi r26,lo8(128) ; count in X
usb_gb2:
rcall usb_getbyte ; read byte from USB
st Z+,r24 ; store in ram
dec r26 ; dec count
brne usb_gb2 ; loop
;
; program the block
;
rcall program_block
inc r8 ; inc block number
dec r10 ; dec number of blocks
brne boot_loop ; keep going if not 0
; send the last ack
rcall usb_ack
; back to loop
rjmp do_boot_2
;
; read an USB byte to r25/r24
;
usb_getbyte:
sbic PIND,USB_RXRDY ; while flag is set
rjmp usb_getbyte ; wait for bit to be cleared
usb_getbyte1: ld r24,Y
ret
;*******************************************
;
; program the block in r8 from SRAM at 0x100
;
program_block:
mov r31,r8
clr r30
lsr r31 ; shift page number down one bit
ror r30
movw r4,r30 ; save page pointer
; erase the page
ldi r18,(1<<PGERS) | (1<<SPMEN)
rcall do_spm
; fill buffer with data
; page number is already set as the address
; that the temp buffer need
ldi r27,hi8(0x100) ; X is pointer to RAM
ldi r26,lo8(0x100)
ldi r17,64 ; number of words
prog_1:
ld r0,X+
ld r1,X+
ldi r18,(1<<SPMEN)
rcall do_spm
adiw r30,2
dec r17 ; dec word count
brne prog_1
movw r30,r4 ; restore page pointer
; write the page
ldi r18,(1<<PGWRT) | (1<<SPMEN)
rcall do_spm
; re-enable the RWW section
rww_ena:
ldi r18,(1<<RWWSRE) | (1<<SPMEN)
rcall do_spm
in r18, SPMCR
sbrc r18, RWWSB ; If RWWSB is set, the RWW section is not ready yet
rjmp rww_ena ; continue trying enable RWW section
;fall trought to blinking proc
led_blink: ldi r25,1
in r24,PORTB
eor r24,r25 ; change LED output state
out PORTB,r24
ret
;
; perform a SPM operation
;
do_spm: ; check for previous SPM complete
in r16, SPMCR ; get status register
sbrc r16, SPMEN ; skip next if SPM ready
rjmp do_spm ; else loop and wait for it
wait_ee: ; check that no EEPROM write access is present
sbic EECR, EEWE ; skip next if EEPROM ready
rjmp wait_ee ; else loop and wait for it
out SPMCR, r18 ; set the SPM mode
spm ; do the magic boogie
ret ; done
;
; end of file
;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -