⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lpc_isp_8k_v02.a51

📁 LPC9XX单片机ISP引导程序,实现在线烧写程序及网络更新
💻 A51
字号:

;89LPC935 boot flash program for IN-SYSTEM PROGRAMMING
;copyright Philips Semiconductors 2003

;FILENAME: 		LPC2_ISP_8K_V02.TXT
;CODE TYPE: 		ISP
;VERSION: 		02
;RELEASE DATE: 		14 JUN 03
;CODE MEMORY SIZE: 	8KB
;CODE ADDRESS RANGE: 	1E00h - 1FFFh
;BOOT VECTOR: 		1F00h
;USES IAP VERSION: 	02
;USES IAP ENTRY: 	FF03h
;Author:		Bill Houghton
;
;Features:
;
;Version 2:
;- Modifieds WDL and WDCON to select longest WDT timeout & provides periodic feeding.
;- Program user code page has option to use either IDATA or XDATA (if available on chip).
;- Software code corruption protection - valid key needed for write operations 
;- Code traps (software reset) added to start of ISP & IAP sections
;
;Version 1:
;- Includes standard features originally released with LPC932.

;code memory space for LPC2
;
;block 0, 1KB, 0000h - 03FFh
;block 1, 1KB, 0400h - 07FFh
;block 2, 1KB, 0800h - 0BFFh
;block 3, 1KB, 0C00h - 0FFFh
;block 4, 1KB, 1000h - 13FFh
;block 5, 1KB, 1400h - 17FFh
;block 6, 1KB, 1800h - 1BFFh
;block 7, 1KB, 1C00h - 1FFFh

;Bootrom, 240 bytes , FF00h - FFEF


PGMU	EQU	00
VRD	EQU	01               
MWR	EQU	02               
MRD	EQU	03               
ERS	EQU	04               
SCRC	EQU	05               
GCRC	EQU	06               
RUSR	EQU	07
F1	EQU	0D1H
WDL	EQU	0C1H
WDCON	EQU	0A7H
WFEED1	EQU	0C2H
WFEED2	EQU	0C3H
               
PGM_MTP	EQU	0FF03H		


;byte variables definition

DSEG	AT	30H

ADR0:		DS	1		;low byte of address
ADR1:		DS	1		;high byte of address
CHKSUM:	DS	1		;record checksum
NBYTES:	DS	1		;number of bytes in record
RTYPE:	DS	1		;record type
TMP3:		DS	1		;temporary storage

UCFG1:	DS	1	;User configuration register 1
UCFG2:	DS	1	;User configuration register 2
BOOTV:	DS	1	;Boot Vector
STATBY:	DS	1	;Status Byte
FCFG1:	DS	1	;Factory config 1, read only
FCFG2:	DS	1	;Factory config 2, read only 
DERIV:	DS	1	;Derivative
TMEB_v:	DS	1	;TMEB
SEC0:		DS	1	;Security byte 0
SEC1:		DS	1	;Security byte 1
SEC2:		DS	1	;Security byte 2
SEC3:		DS	1	;Security byte 3
SEC4:		DS	1	;Security byte 4
SEC5:		DS	1	;Security byte 5
SEC6:		DS	1	;Security byte 6
SEC7:		DS	1	;Security byte 7
MF_ID:		DS	1	;Signature byte 0 (mfg id)
ID_1:		DS	1	;Signature byte 1 (device id)
ID_2:		DS	1	;Signature byte 2 (derivative id)

CRC0:		DS	1	;CRC data
CRC1:		DS	1	;CRC data
CRC2:		DS	1	;CRC data
CRC3:		DS	1	;CRC data

;ISEG	AT	0FFH

;KEY:		DS	1	;IAP request key
KEY data 0xFF

;*************** equates list       ************************

CONFB		EQU	UCFG1		;start of CONF register space
RXDn		EQU	P1.1		;RxD pin
ISP_VER		EQU	02H		;ISP version id = 2
AUXR		EQU	08EH		;auxr register
AUXR1		EQU	0A2H		;auxr 1 register
SRST		EQU	8H		;OR mask for software reset bit
TAMOD		EQU	8FH		;timer aux mode register
P1M1		EQU	91H
P1M2		EQU	92H

OI		EQU	ACC.0		;operation aborted by interrupt 
SV		EQU	ACC.1		;security violation
HVE		EQU	ACC.2		;high voltage error 

SBVAL		EQU	0FFH		;status byte default value
BVVAL		EQU	0FCH		;boot vector default value
DBYTES		EQU	80H		;start of RAM buffer for hex string
KEYVAL		EQU	96H		;IAP request key value

CSEG	AT	2000H-512		;Should be 1E00h

RESET:
	ORL	AUXR1,#SRST	;set the software reset bit
;*********************************************************
;
;	START OF PROGRAM
;
;*********************************************************

;	First, we need to measure the baud rate of
;the host in terms of our own clock speed. This
;measurement can be made on a start bit provided
;the first data bit is a logical one. A capital "U"
;is a good choice since it has alternating 1s and 0s . 
;	Our measurement uses T1 which is clocked at
;fosc/2, which is the same as when T1 is used as 
;a baud rate generator. The UART uses 16x sampling
;so we need to divide the T1 count by 16. Even
;though the timer will be used in the 8-bit
;auto-reload mode for baud rate generation, non-reload
;16-bit mode is used for the measurement to give
;more clock counts for slower baud rates. This number
;will be divided by 16. This method allows the timer
;to count up to 4096 counts (16 x 256). The timer
;counts up towards zero thus counts loaded into the
;timer counter need to be negative numbers. A two's
;complement of the adjusted count produces this result.


INIT:

	ACALL	I_WDT		;
	MOV	P1M1,#00H
	MOV	P1M2,#00H
	MOV	P1,#0FFH
	MOV	TMOD,#10H	;16-bit non-reload 
	ANL	TAMOD,#0EFH	;not pwm mode 
	MOV	PCON,#80H	;SMOD = 1 = baud rate = T1/16
	CLR	A		;
	MOV	TH1,A		;set T1 to zero since we will
	MOV	TL1,A		;use this to count the start bit
MEAS:	
M1:	ACALL	FD_WDT		;feed the WDT
	JNB	RXDn,M1		;wait for RXD to be high
M2:	ACALL	FD_WDT		;feed the WDT
	JB	RXDn,M2		;wait until RXD goes low
	SETB	TR1		;start measuring the bit time
M3:	JNB	RXDn,M3		;wait until RXD goes high
	CLR	TR1		;stop measuring
	ACALL	FD_WDT		;feed the WDT
	MOV	RTYPE,TH1	;copy timer to RAM
	MOV	R1,#RTYPE	;for indirect addressing
	MOV	A,TL1		;get timer low byte
	XCHD	A,@R1		;acc= TL upper nibble & TH lower nibble
	SWAP	A		;acc= TH lower nibble & TL upper nibble
	CPL	A		;complement lower byte of count
	INC	A		;two's complement  = - count/16
	MOV	TL1,A		;
	MOV	TH1,A		;load counts & switch to
	MOV	TMOD,#20H	;8-bit auto-reload mode
	SETB	TR1		;start T1
	MOV	SCON,#52H	;init UART 8-bit variable, TI=1 RI=0
QRZ:	ACALL	ECHO		;wait until character is rcv'd & get it
	CJNE	A,#'U',QRZ	;check to see if uppercase "U"

;***** Intel Hex File Load routine *****
;
;This routine loads an Intel Hex formatted file into 
;the buffer memory. The hex file is received as a series
;of ASCII characters on the serial input line of the
;serial port. A record type of 00H is considered to be
;a data field. Any other type of record is considered
;to be an End-of-File marker. This routine also calculates
;the checksum on the field as it is received and compares
;this calculated checksum with the checksum field received
;in the record.

LCMD:
	MOV	R5,#0	;begin record... zero checksum
	ACALL	ECHO		;get first char and echo
	CJNE	A,#':',LCMD	;record starts with ':' char
	ACALL	GET2		;get the number of bytes in record
	MOV	NBYTES,TMP3	;and save
	ACALL	GET2		;get MSB of load address
	MOV	ADR1,TMP3	;and save
	ACALL	GET2		;get LSB of load address
	MOV	ADR0,TMP3	;and save it
	ACALL	GET2		;get record type
	MOV	RTYPE,TMP3	;and save it
	MOV	A,NBYTES	;else, more than
	MOV	R2,A	
	JZ	EOR		;zero data bytes ?
	MOV	R1,#DBYTES	;pointer for data bytes
LDATA:	ACALL	GET2		;get data byte
	MOV	@R1,TMP3	;store it
	INC	R1		;and bump up the pointer	
	DJNZ	R2,LDATA	;repeat if more bytes in record
EOR:
	MOV	A,R5		;
	MOV	R4,A		;save calculated checksum
	ACALL	GET2		;get the checksum byte
	MOV	A,R4		;and compare with calculated checksum byte
	CJNE	A,TMP3,CHKERR	;recv'd & calc'd chksums match ?
	AJMP	PROCESS		;YES, process command

CHKERR:	MOV	A,#'X'
	AJMP	RSPND1

GET2:	ACALL	ECHO		;get first char of length
	ACALL	A2HEX		;convert to hex
	SWAP	A		;set in high nibble
	MOV	TMP3,A		;store in NBYTES
	ACALL	ECHO		;get second char of length
	ACALL	A2HEX		;convert to hex
	ORL	TMP3,A		;add into NBYTES
	MOV	A,R5		;get checksum
	CLR	C		;subtract NBYTES
	SUBB	A,TMP3		;from checksum and
	MOV	R5,A		;store as new checksum
	RET

;***** console output routine *****
;
;Outputs character in the ACC to 
;the serial output line.

CO:	ACALL	FD_WDT		;feed the WDT
	JNB	TI,CO		;wait till xmtr ready
	CLR	TI		;reset xmtr flag
	MOV	SBUF,A	;output char to SIO
	RET			;and done

;***** console input routine *****
;
;Waits until character has been received
;and then returns char in ACC.

CI:	ACALL	FD_WDT		;feed the WDT
	JNB	RI,CI		;wait till char
	CLR	RI		;reset rcvr flag
	MOV	A,SBUF	;read the char
	RET			;and done

;***** character echo routine *****
;
;waits until a character is received from
;the console input and echos this character
;to the console output. The received char
;is also passed to the caller in the ACC.

ECHO:	ACALL	CI			;get char from console 
	ACALL	CO			;print the character
	JNB	ACC.6,EXECHO	;exit if not 4x,5x, or 6x Hex
	CLR	ACC.5			;convert to upper case
EXECHO:
RET				;and done

;***** ASCII to HEX routine *****
;
;This routine accepts an ASCII char in the ACC
;and converts it into the corresponding hex digit.
;The routine checks to see if the char is in the
;range of '0' through '9' or in the range of 'A'
;through 'F'. If not in either range then the ASCII
;char is not a valid hex entry from the operator
;and an error flag is returned true along with the
;original ASCII char returned in the ACC.

A2HEX:
	JNB	ACC.6,HEX1
	ADD	A,#09H
HEX1:	ANL	A,#0FH
	RET

;***** HEX to ASCII routine *****
;
;This routine receives a single hex digit
;(a four bit nibble) in the ACC and returns
;the equivilent ASCII char in the ACC.

HEX2A:
	ANL	A,#0FH
	CLR	C		;carry affects the testing
	SUBB	A,#0AH	;test for range of 0-9, A-F
	JNC	HAHIGH	;no carry then A-F range
	ADD	A,#3AH	;add offset for 0-9 range
	RET
HAHIGH:
	ADD	A,#41H	;add in offset for A-F range
	RET

PROCESS:
	MOV	A,RTYPE		;get record type
	RL	A			;double ACC for two byte jumps
	MOV	DPTR,#RECTBL	;pointer = start of table
	JMP	@A+DPTR		;branch on record type

RECTBL:
	AJMP	PROGRAM		;0 = program data bytes
	AJMP	RDVER		;1 = read code versions
	AJMP	AUXWR		;2 = misc 'write' functions
	AJMP	AUXRD		;3 = misc 'read' functions
	AJMP	ERASE		;4 = erase block or page
	AJMP	CRCS		;5 = sector CRC
	AJMP	CRCG		;6 = global CRC
	AJMP	SETBR		;7 = set baud rate
	AJMP	RESET		;8 = reset MCU
	AJMP	DCMD		;9 = display device data
	

	
I_WDT:
	MOV	WDL,#0FFH	;set to max count
	ORL	WDCON,#0E0H	;set pre= max
FD_WDT:	MOV	WFEED1,#0A5H	;
	MOV	WFEED2,#5AH		;	
	RET
	

RDVER:
	MOV	A,#ISP_VER	;get ISP version id
	ACALL	OUTBYT		;and print it
	MOV	A,#VRD		;function code 
	CALL	PGM_MTP		;and perform the function
	MOV	A,R7		;get the response 
	ACALL	OUTBYT		;and print it
	AJMP	EOF		;and we're done	
	

	
CSEG	AT	2000H-256		;Should be 1F00h

	AJMP	INIT			;Boot vector entry point

ERROR:
	MOV	A,#'R'		;print a verify error
	ACALL	CO		;send an okay message
	MOV	A,R7		;get status
	ACALL	OUTBYT		;and print
	AJMP	DEXIT		;and done
	
	
PROGRAM:
	MOV	R3,NBYTES	;get the number of bytes in record
	MOV	A,R3		;get the number of bytes in record
	JZ	EOF		;exit if no bytes in record
	MOV	R5,ADR0		;get the load address
	MOV	R4,ADR1		;of the first byte in record
	MOV	R7,#DBYTES	;pointer to data
	MOV	A,#PGMU		;program user code
EXEC:	MOV	R0,#KEY		;address for the key
	MOV	@R0,#KEYVAL	;setup a valid key
	CLR	F1		;specify IRAM
	CALL	PGM_MTP		;write the entire record & verify
	JB	F0,ERROR	;check if an error occured

EOF:	MOV	A,#'.'		;no error
RSPND1:
	ACALL	CO		;send an okay message
	AJMP	DEXIT		;and done


;***** display buffer contents routine *****
;
;This routine displays the contents of the buffer memory
;over a user specified range. The displayed output is formatted
;into a series of lines on the console. A line begins with the
;address of the first byte in the line. Line length is limited
;to a maximum of 16 bytes per line. Once this limit is reached,
;new formatted lines are used.

DCMD:
	MOV	R0,#DBYTES	;
	MOV	DPH,@R0		;get high byte of starting address
	INC	R0		;point to low byte of starting address
	MOV	DPL,@R0		;get low byte of starting address
	INC	R0		;point to high byte of ending address
	MOV	ADR1,@R0	;get high byte of ending address
	INC	R0		;point to low byte of ending address
	MOV	ADR0,@R0	;get low byte of ending address
	INC	R0		;point to function either display or blankcheck
	JNB	RI,$		;wait till host ready to receive
	CLR	RI

DLINE:
	CJNE	@R0,#00H,DAGN	;ignore this if its not a display command
	ACALL	CRLF
	MOV	R2,#10H		;R2 = 16 bytes per line
	MOV	A,DPH
	ACALL	OUTBYT
	MOV	A,DPL
	ACALL	OUTBYT		;print the address
	MOV	A,#'='		;of first byte of
	ACALL	CO		;the line along with

DAGN:

	MOV	R4,DPH
	MOV	R5,DPL
	MOV	A,#RUSR		;READ_USER
	CALL	PGM_MTP		;read the byte
	MOV	A,R7		;get result
DPRN:
	CJNE	@R0,#00H,BLKCHK ;ignore this if its not a display command
	ACALL	OUTBYT		;and print it
	SJMP	CKDEND		;and then check if we've reached the end
BLKCHK:
	CJNE	A,#00H,BLANKERR
CKDEND:
	MOV	A,ADR1		;
	CJNE	A,DPH,DNEXT	;check if DPH = stop high
	MOV	A,ADR0		;
	CJNE	A,DPL,DNEXT	;check if DPL = stop low
	CJNE	@R0,#01H,DEXIT 	;if display command use display exit 
	AJMP	EOF		;blankcheck exit (print a period)

DEXIT:
	ACALL	CRLF		;print a CRLF
	JNB	TI,$
	SETB	REN		;TURN ON UART RECEIVER
	AJMP	LCMD		;branch to main loop
DNEXT:
	INC	DPTR		;more bytes so point to next byte
DNXT1:
	DJNZ	R2,DAGN
	AJMP	DLINE		;we start a new line or not

BLANKERR:
	MOV	A,DPH
	ACALL	OUTBYT		;print DPH
	MOV	A,DPL
	ACALL	OUTBYT		;print DPL
	AJMP	DEXIT		;and exit


AUXWR:
	MOV	R1,#DBYTES	;pointer for data
	MOV	A,@R1		;
	MOV	R7,A		;get the subfunction code 
	INC	R1		;
	MOV	A,@R1		;
	MOV	R5,A		;get the data to write 
	MOV	A,#MWR		;function code 
	AJMP	EXEC		;perform the function & check for errors

ERR:	AJMP	ERROR		;error vector

AUXRD:
	MOV	R1,#DBYTES	;pointer for data
	MOV	A,@R1		;
	MOV	R7,A		;get the subfunction code 
	MOV	A,#MRD		;function code 
	CALL	PGM_MTP		;and perform the function
	JB	F0,ERR		;exit if an error occured
	MOV	A,R7		;get the response 
	ACALL	OUTBYT		;and print it
	AJMP	EOF		;and we're done
	
ERASE:
	MOV	R1,#DBYTES	;pointer for data
	MOV	A,@R1		;
	MOV	R7,A		;get the block or page erase command 
	INC	R1		;
	MOV	A,@R1		;
	MOV	R4,A		;get the high address 
	INC	R1		;
	MOV	A,@R1		;
	MOV	R5,A		;get the low address 
	MOV	A,#ERS		;function code 
	AJMP	EXEC		;perform the function & check for errors

CRCG:
	MOV	A,#GCRC		;function code 
	AJMP	DO_CRC		;and do the CRC
CRCS:
	MOV	R1,#DBYTES	;pointer for data
	MOV	A,@R1		;
	MOV	R7,A		;get the sector number
	MOV	A,#SCRC		;function code 
DO_CRC:
	CALL	PGM_MTP		;and perform the function
	JB	F0,ERR		;exit if an error occured
	MOV	A,R4		;get CRC bits 31:24 
	ACALL	OUTBYT		;and print
	MOV	A,R5		;get CRC bits 23:16 
	ACALL	OUTBYT		;and print
	MOV	A,R6		;get CRC bits 15:8 
	ACALL	OUTBYT		;and print
	MOV	A,R7		;get CRC bits 7:0 
	ACALL	OUTBYT		;and print
	AJMP	EOF		;and we're done

CRLF:	MOV	A,#0DH
	ACALL	CO
	MOV	A,#0AH
	ACALL	CO
	RET



SETBR:
	MOV	A,#'.'		;respond with okay status before
	ACALL	CO		;changing the baud rate (i.e.- at the old baud rate)
	MOV	R1,#0FFH	;
	DJNZ	R1,$		;wait before proceeding	
	DJNZ	R1,$		;wait before proceeding	
	CLR	TR1		;stop the timer
	MOV	R1,#DBYTES	;pointer for data
	MOV	TH1,@R1		;get baud rate
	MOV	TL1,@R1		;get baud rate
	SETB	TR1		;start the timer
	AJMP	EOF		;and we're done

OUTBYT:	MOV	R4,A		;"push acc"
	SWAP	A
	ACALL	HEX2A
	ACALL	CO
	MOV	A,R4		;"pop acc"
	ACALL	HEX2A
	ACALL	CO
	RET



END

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -