A Few Bits of Code

AVR Programmer

This AVR ISP Programmer is based on Atmel's own avr910.asm source code but is ported from AVR assembly to 8051 assembly.

Summary

Before Arduino clones were dirt cheap I needed a way to program myself an AVR micro. The problem was that all I had on hand was an 8051-based prototyping board. Since you're reading this, I'm guessing you already know what happened... I ported a bit of code over to the 8051 platform and got my AVR programmed.

Hardware/Software

The hardware for this is extremely simple and only requires a few wires. The hookup diagram is listed below and in the source code.

   PC8051
    Tx → Rx
    Rx → Tx
GND → GND

8051AVR
 P1.5 → MOSI
 P1.6 → MISO
 P1.7 → SCK
 P1.4 → RESET
 P1.0 → RED_LED (optional)
 P1.3 → GRN_LED (optional)

As this was ported from AVR's own implementation, you can use any standard AVR software to control the programmer (e.g. AVR Studio). Just choose 'AVR910 ISP' as the programmer type.

Below is the Source. I kept all variable and function names the same so you should be able to easily compare it to the original if need be.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; AVR Programmer                         ;
; An AVR ISP Programmer based on Atmel's ;
;  avr910.asm source code and ported 	 ;
;  to 8051 assembly.                     ;
;                                        ;
; Author: Tim Shaffer                    ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;Include Port/Pin Definitions (uVision does not have the 8052 and later SFR's defined)
$INCLUDE (reg_c51.INC)

;Define Program Constants
RAMSTART EQU 40H	; first RAM address to use for Buffer
BUFSIZE  EQU 40H	; (64 bytes) Size of Buffer
PAGESIZE EQU 10H	; default Page size for Programming
STACKSTART EQU 20H	;Stack start address
;Note: The Stack will need to be small enough to fit between the last 
;Global Register (below) and RAMSTART (above). This program will only 
;be using the Stack to store subroutine return addresses which 
;shouldn't take much space. 

;Define (input/output) pins
;The device ~doing~ the programming is the Master. The target device ~being~ programmed is the Slave.
MOSI  BIT P1.5	;Master Out - Slave In	(output)
MISO  BIT P1.6	;Master In - Slave Out	(input)
SCK   BIT P1.7	;Serial Clock		    (output)
RESET BIT P1.4	;Target AVR MCU Reset	(output)
RED_LED BIT P1.0	;Red Led (active low)
GRN_LED BIT	P1.3	;Green Led (active low)

;Define Global Registers in Internal RAM (0x08 - 0x1F)
; This makes porting easier by not having to change all the register names in the origianl code
cmd1	DATA 08H	; Universal commands params
cmd2	DATA 09H	; 
cmd3	DATA 0AH	; 
pol_al	DATA 0BH	; Polling address low
pol_ah	DATA 0CH	; Polling address high
Bcnt1	DATA 0DH	; Block Mode Counters
Bcnt2	DATA 0EH	;
Bcnt3	DATA 0FH	;
B_Flag	DATA 10H	; Flag for ws_del Routine
B_Mode	DATA 11H	; Marks Block Mode commands (See Note 16)
Memtype	DATA 12H	; Flag for Memorytype for Block Commands (See Note 16)
Pagewords DATA 13H	; Size of Controller page to program in Page Mode (Words!) 
PollcodeF DATA 14H	; Code for Polling Flash

temp1	DATA 15H	; Temporary register 1
temp2	DATA 19H	; Temporary register 2
temp3	DATA 17H	; Temporary register 3
s_data	DATA 18H	; SPI data
u_data	DATA 16H	; UART data
device	DATA 1AH	; Device code
rd_s_data DATA 1BH	; Read data on SPI
pol_cmd	DATA 1CH	; Polling command
p_data	DATA 1DH	; Polling data
addrl	DATA 1EH	; (YL) Low order byte of address
addrh	DATA 1FH	; (YH) High order byte of address


; Interrupt Vectors
ORG 0000H
	LJMP INIT	;Jump Over other Interrupt Vectors (00H - 52H)

;To make porting easier this program is organized in the same way as the original AVR assembly.
;Also, all of the labels and register names have kept the same letter casing.
;All the Functions are listed first.
;The Menu with all its long jumppy routines is second.
;Last is the table of constant data.

ORG 0053H
;Initialize UART
u_init:
	MOV TMOD, #20H 	;Timer1 - 8-bit auto-reload
	MOV TH1, #0FFH	;28800 * 2 = 57600 baud @ 11.0592MHz
	SETB TR1		;Start Timer1 (baud rate generator)
	MOV PCON, #80H	;Double the baud rate
	MOV SCON, #50H	;MODE1(8bit UART set by Timer1), Receive Enable
	RET


;Receive a character on the UART Rx line
getc:
	JNB RI, $			;Wait for a byte to be received on the serial port
	MOV u_data, SBUF	;Store the character from the serial port
	CLR RI
	RET	


;Send a character on the UART Tx line
putc:
	MOV SBUF, u_data	;Send byte
	JNB TI, $			;Wait for Tx to finish
	CLR TI				;Reset Interrupt 
	RET	


;Send (DPTR pointed) null-terminated string to the UART Tx line.
;DPTR loaded with table address before function is called.
put_string:
	CLR A			; Clear A so DPTR has no offset
	MOVC A, @A+DPTR
	JZ ps_ret		; check for end of string (0x00)
	MOV	u_data, A
	LCALL putc		; putc(char)
	INC DPTR		; next char
	SJMP put_string
ps_ret:	RET


;Send (DPTR pointed) table to the UART Tx line.		
;DPTR loaded with table address before function is called.
put_table:
	CLR A			; Clear A so DPTR has no offset
	MOVC A, @A+DPTR
	JZ pt_ret		; check for end of string (0x00)
	MOV	u_data, A
	LCALL putc		; putc(char)
	INC DPTR		; each row has 2 bytes, skip the 2nd
	INC DPTR		; next row
	SJMP put_table
pt_ret:	RET


;Check if device belongs to table. 
;DPTR loaded with table address before function is called.
;Return Value: If device is in table then C=0. If device is not found then C=1
bel_table:
	CLR A			; Clear A so DPTR has no offset
	MOVC A, @A+DPTR	; read table
	JZ c1_ret		; check for end of table
	CJNE A, device, no_match_bel ;Jump if no match
	CLR C			; Clear Carry 
	SJMP c0_ret		; Match! Jump to exit
no_match_bel:
	INC DPTR		; each row has 2 bytes, skip the 2nd
	INC DPTR		; next row
	SJMP bel_table	
c1_ret:	SETB C		; Set Carry
c0_ret:	RET		


;Sets programming Page size for selected Device.
set_pagesize:
	CLR A				; Clear A so DPTR has no offset
	MOVC A, @A+DPTR		; read table
	JZ spa_end			; check for end of table, no Pagesize to set
	CJNE A, device, no_match_page ;Jump if no match
	MOV A, #01H 		; Point to high Byte of Word
	MOVC A, @A+DPTR		; Get Pagesize
	MOV Pagewords, A		; Save Pagesize
	MOV Bcnt3, Pagewords	; initiate Counter
	SJMP spa_end
no_match_page:
	INC DPTR			; each row has 2 bytes, skip the 2nd
	INC DPTR			; next row
	SJMP set_pagesize	
spa_end:
	RET		


;Sets Code for Polling Flash for selected Device.
set_pollcode:
	CLR A				; Clear A so DPTR has no offset
	MOVC A, @A+DPTR		; read table
	JZ spo_end			; check for end of table, no Pollcode to set
	CJNE A, device, no_match_poll ;Jump if no match
	MOV A, #01H			; Point to high Byte of Word
	MOVC A, @A+DPTR		; get Pagesize
	MOV PollcodeF, A	; Set Pollcode for Flash Rom
	SJMP spo_end
no_match_poll:
	INC DPTR 			; each row has 2 bytes, skip the 2nd
	INC DPTR			; next row
	SJMP set_pollcode	
spo_end:
	RET	

	
;Delay ~1ms (x temp1).	(922 machine cycles = 1.000434 ms)
;						(921 machine cycles = 999.3490 ms)
;Machine Cycles calculation = 2+((2+((2+(2*temp2)+2)*temp3)+1+1+2)*temp1)+2
;							= (922 Machine Cycles * temp1) + 4 [for LCALL and RET]
delay:
	MOV temp3, #02H			
d_out:
	MOV temp2, #0E3H	;#227
	DJNZ temp2, $ 			
	DJNZ temp3, d_out
	NOP
	NOP
	DJNZ temp1, delay
	RET						


; Write bytes 1 to 3 on the SPI. Byte 1 must be loadet into s_data
;  Byte 2 is addrh, Byte 3 is addrl
spi123:
	LCALL wrser			; wrser(s_data) SPI write (byte 1)
	MOV s_data, addrh
	LCALL wrser			; wrser(addrh)  SPI write (byte 2)
	MOV s_data, addrl	
	LCALL wrser			; wrser(addrl)  SPI write (byte 3)
	RET


;Write SPI bytes 1 to 4. (for Code simplification)
; Byte 1 must be loadet into cmd1
; Byte 2 must be loadet into cmd2
; Byte 3 must be loadet into cmd3
; Byte 4 must be loadet into u_data
w1234:
	MOV s_data, cmd1
	LCALL wrser
	MOV s_data, cmd2
	LCALL wrser
	MOV s_data, cmd3
	LCALL wrser
	MOV s_data, u_data	; get Byte 4 from serial
	LCALL wrser
	RET


;Write SPI bytes 1 to 3, read Byte 4 to serial. (for Code simplification)
; Byte 1 must be loadet into cmd1
; Byte 2 must be loadet into cmd2
; Byte 3 must be loadet into cmd3
w123r4:
	MOV s_data, cmd1
	LCALL wrser
	MOV s_data, cmd2
	LCALL wrser
	MOV s_data, cmd3
	LCALL wrser
	LCALL rdser			; Read a byte from Serial
	MOV u_data, s_data	; put Byte 4 to serial
	LCALL putc
	RET


; Write and Read bytes on the SPI.
; Return: s_data contains the data that was read on the SPI bus
rdser:	
	MOV	s_data, #00H
wrser:	
	MOV	temp1, #08H		; load bit counter
	MOV	rd_s_data, #00H
wrs0:	;Write MOSI
	MOV A, s_data
	RLC A
	MOV s_data, A
	JNC wrs1	;Set Ouput for this bit 
	SETB MOSI	; MOSI = 1
	SJMP wrs2
wrs1:
	CLR MOSI	; MOSI = 0
wrs2:	;Read MISO
	MOV A, rd_s_data
	RL A
	MOV rd_s_data, A
	;lsl	rd_s_data

	JNB MISO, jmp_miso 	; read MISO
	;sbic	PINB,MISO	; read MISO
	ORL rd_s_data, #01H
	;ori	rd_s_data,1
jmp_miso:
	LCALL pulse_SCK		;pulse SCK

	DJNZ temp1, wrs0 ; advance bit counter and loop
	MOV	s_data, rd_s_data	;Return the data read on MISO
	RET


;Read one address (2 Bytes) from Program Memory and send it through UART
read_send_progmem:
	;tst	device
	MOV A, device
	RLC A
	JC rsp1		; S89 device
	;brmi	rsp1		; S89 device
	MOV s_data, #20H	; read low Byte
	LCALL wrser			; wrser(0x28)  SPI write (byte 1)
	MOV	s_data, addrh
	SJMP rsp2
rsp1:
	MOV	s_data, addrh	; s_data = (addrh << 3) | 0x01;
	LCALL shift_s_data3
	ORL	s_data, #01H
rsp2:
	LCALL wrser			; wrser(addrh) SPI write (byte 2) (S89=byte1)
	MOV	s_data, addrl	
	LCALL wrser			; wrser(addrl) SPI write (byte 3)
	LCALL rdser			;              SPI read  (byte 4)
	MOV	u_data, s_data
	LCALL putc			; send data
	;tst	device
	MOV A, device
	RLC A
	JC rsp3				; S89 device
	MOV	s_data, #28H	; read High Byte
	LCALL wrser			; wrser(0x20)  SPI write (byte 1)
	MOV	s_data, addrh	
	LCALL wrser			; wrser(addrh) SPI write (byte 2)
	MOV	s_data, addrl	
	LCALL wrser			; wrser(addrl) SPI write (byte 3)
	LCALL rdser			;              SPI read  (byte 4)
	MOV	u_data, s_data
	LCALL putc			; send data
rsp3:
	LCALL inc_addr		;Increment addrl/h
	RET


;Read one Byte from Data Memory (eeprom) and send it through UART
;@Args: addrh/addrl hold the address to be read
read_send_datamem:			; Subroutine to read one eeprom Address
	;tst	device
	MOV A, device
	RLC A
	JC rsd1				; S89 device
	MOV	s_data, #0A0H
	LCALL wrser			; wrser(0xa0)   SPI write (byte 1)
	MOV	s_data, addrh
	SJMP rsd2
rsd1:
	;cpi	device,0x87		; if (device == S53)
	MOV A, device
	CJNE A, #87H, rsd11
	SJMP rsd3			; no Support for 89S53 device due to Bug in AVRProg V1.37
rsd11:
	MOV	s_data, addrh
	LCALL shift_s_data3
	ORL	s_data, #05H
rsd2:
	LCALL wrser			; wrser(addrh)  SPI write (byte 2)
	MOV	s_data, addrl	
	LCALL wrser			; wrser(addrl)  SPI write (byte 3)
	LCALL rdser			;               SPI read  (byte 4)
	MOV	u_data, s_data
	LCALL putc			; send data

	LCALL inc_addr		;Increment addrl/h
	RET
rsd3:
	;The original code never returns from this subroutine if you get to this point. Instead the 
	; return address is popped off the Stack and discarded. It then jumps to the same error 
	; routine that the Main waitcmd loop uses. That error routine, in turn, jumps back to the 
	; start of the waitcmd loop. 
	; This is ugly, but to make it easy to port we will just follow along for now 
	; until we have time to come back and fix it.
	POP	temp1		; remove return address from Stack because we are not calling RET
	POP	temp1
	LJMP put_err


;Write u_data to Data Memory (eeprom)
eeprom_write:
	;tst	device
	MOV A, device
	RLC A
	JC eew1			; S89 device

	MOV	s_data, #0C0H
	LCALL wrser			; wrser(0xc0)   SPI write (byte 1)
	MOV	s_data, addrh
	SJMP eew2	
eew1:
	MOV A, device
	CJNE A, #87H, eew11
	SJMP eew3
eew11:
	MOV	s_data, addrh
	LCALL shift_s_data3
	ORL	s_data, #06H
eew2:
	LCALL wrser			; wrser(addrh)  SPI write (byte 2)
	MOV	s_data, addrl
	LCALL wrser			; wrser(addrl)  SPI write (byte 3)
	MOV	s_data, u_data
	LCALL wrser			; wrser(u_data) SPI write (byte 4)
	MOV	temp1, #10		; delay 10mS
	LCALL delay

	LCALL inc_addr		;Increment addrl/h
	RET
eew3:
	POP temp1		; remove return address from Stack. 
	POP temp1		; Look at read_send_datamem routine above for an explanation.
	LJMP put_err


;Shift s_data 3 times left for S89 device.
shift_s_data3:
	;lsl s_data lsl	s_data lsl s_data
	MOV A, s_data
	RLC A
	RLC A
	RLC A
	ANL A, #0F8H
	MOV s_data, A
	;brcc	s3_ret
	JNC s3_ret
	;cpi	device,0x87		
	;brne	s3_ret
	MOV A, device
	CJNE A, #87H, s3_ret	; if (device != S53)	
	;sbr	s_data, 4		; a13 +
	ORL s_data, #04H
s3_ret:	RET


; Shows that the program is working after Powerup (LED test, LEDs flash back and forth a few times)
; LEDs are Active LOW
healthcheck:
	CLR RED_LED			; Red ON
	SETB GRN_LED		; Grn OFF
	MOV temp1, #200		; 200 ms
	LCALL delay		
	MOV temp1, #200		; again 200 ms
	LCALL delay
	MOV s_data, #5		; counter Register, flash back and forth 5 times
LEDloop:				; Pulse for yellow LED
	CLR GRN_LED			; Grn ON
	SETB RED_LED		; Red OFF
	MOV temp1, #200		; 200 ms
	LCALL delay
	CLR RED_LED			; Red ON
	SETB GRN_LED	   	; Grn OFF
	MOV temp1, #200		; 200 ms
	LCALL delay
	DJNZ s_data, LEDloop
	CLR GRN_LED			; Grn ON
	SETB RED_LED		; Red OFF
	RET


; All of the needed macros from the origianl AVR asm have been converted 
;  to subroutines for the 8051. There are also a couple of new routines
;  that were added here to help track of 16-bit values for which the 8051 
;  has no support.

; set RESET passive
pas_RESET:			
	MOV A, device	; Test for S89 device
	RLC A
	JC m2					
	SETB RESET		; Regular device		
	SJMP m3
m2:	CLR RESET		; S89 device
m3:	RET	

; set RESET active
act_RESET:			
	MOV A, device	; Test for S89 device
	RLC A
	JC m4
	CLR RESET		; Regular device
	sJMP m5
m4:	SETB RESET		; S89 device
m5: RET	

;pulse SCK - another macro that is now a subroutine
pulse_SCK:
	SETB SCK
	MOV R1, #20	
	DJNZ R1, $
	CLR SCK		
	MOV R1, #10	
	DJNZ R1, $
	RET

;AVR asm can easily increment a 16-bit address pointer stored in two 8-bit registers using adiw
; This routine mimics that using a fixed set of registers
inc_addr:
	INC	addrl		; Auto increment lower byte of address for S89 device
	MOV A, addrl	;Check if the address rolled over and we need to also increment the high byte
	JNZ exit_inc	;non-zero means addrl DID NOT roll over
	INC addrh		;addrl DID roll over so increment the high byte as well
exit_inc:
	RET

;Another special case subroutine to handle a 16-bit data pointer. 
;This one is composed of R2 as the low byte and R3 as the high byte
;Also sets A=0 if R2 and R3 are both zero otherwise sets A=1
dec_r2r3:
	DEC R2
	MOV A, R2
	CJNE A, #0FFH, dec_cmp	;Check for rollover
	DEC R3					;Only dec the high byte if the lower rolled over from 0x00 -> 0xFF
dec_cmp:
	MOV A, R2
	JNZ dec_end1
	MOV A, R3
	JNZ dec_end1
	MOV A, #00H
	RET
dec_end1:
	MOV A, #01H
	RET



;***************************************************************************
;***************************************************************************
;***************************************************************************
;*
;* INIT
;*
;*
;***************************************************************************
;***************************************************************************
;***************************************************************************
;Main Entry Point of the Program	
INIT:
	MOV SP, #STACKSTART		;Set the Stack Pointer
	MOV	Pagewords, #PAGESIZE	; default Pagesize
	MOV Bcnt3, Pagewords	; set counter for Pagesize
	MOV	device, #20H		; S2313 as default
	MOV B_Mode, #00H		; Flag for Block Modes (see Note 16)
	MOV B_Flag, #00H		; Flag for eNhanced Block write
	MOV P1, #00H			; Initialize ports (output)
	SETB MISO				; Initialize ports (input)
	;release_ports			; Release ports
	LCALL u_init			; Initialize UART
	LCALL healthcheck		; show that Prog is working after Powerup (LED test)
		 	
; Main Program Loop
waitcmd:
	LCALL getc				; while (getc() == ESC) {};
	MOV A, u_data

	CJNE A, #1BH, not_esc	;0x1B == ESC
	SJMP waitcmd

;====== 'T' - Device Type ==================================================
not_esc:
	MOV A, u_data
	CJNE A, #'T', w0		; 'T' Device type

	LCALL getc
	MOV	device, u_data		; get device type
	MOV DPTR, #Dev_M		; prepare to set Pagesize
	LCALL set_pagesize		; If device has Page Mode support, set Pagesize
	MOV	PollcodeF, #0FFH	; preset PollcodeF with 0xFF, will be overwritten if Pollcode known
	MOV DPTR, #Dev_S		; prepare to set Polling Code
	LCALL set_pollcode		; If device has no Page Size support, set code for Polling Flash
	LJMP put_ret

;====== 'S' - Return Software Identifier ===================================
w0:	
	MOV A, u_data
	CJNE A, #'S', w1	; 'S' Return software identifier

	MOV DPTR, #ID_Str
	LCALL put_string	; put string "AVR ISP"
	LJMP waitcmd

;====== 'V' - Return Software Version ======================================
w1:
	MOV A, u_data	
	CJNE A, #'V', w2	; 'V' Return software version

	MOV DPTR, #SW_Ver
	LCALL put_string	; put software version
	LJMP waitcmd

;====== 'v' - Return Hardware Version ======================================
w2:	
	MOV A, u_data
	CJNE A, #'v', w3	; 'v' Return hardware version

	MOV DPTR, #HW_Ver
	LCALL put_string	; put hardware version
	LJMP waitcmd
 
;====== 't' - Show Supported Devices =======================================
w3:	
	MOV A, u_data
	CJNE A, #'t', w4	; 't' Show supported devices

	MOV DPTR, #Dev_S
	LCALL put_table		; put supported devices codes
	MOV DPTR, #Dev_M
	LCALL put_table		; put supported devices codes

	MOV	u_data, #00H	; putc(0x00) - end of device list
	LCALL putc

	LJMP waitcmd 

;====== 'p' - Return Programmer Type =======================================
w4:
	MOV A, u_data	
	CJNE A, #'p', w5	; 'p' Return programmer type

	MOV	u_data, #'S'	; putc('S') - serial programmer
	LCALL putc
	LJMP waitcmd

;====== 'a' - Return autoincrement address support =========================
w5:	
	MOV A, u_data
	CJNE A, #'a', w51	; 'a' Return address auto increment

	MOV	u_data, #'Y'	; putc('Y') - supports autoinc
	LCALL putc
	LJMP waitcmd

;====== 'M' - Return enhanced Mode support (Note 14) ========================
w51:	
;	cpi	u_data,'M'		; 'M' Return enhanced mode Support
;	brne	w52
;	ldi u_data,'Y'		; putc('Y') - supports enhanced Mode
;	rcall putc
;	rjmp	waitcmd

;====== 'i' - Return Chip ID (Note 14) ======================================
w52:
	MOV A, u_data
	CJNE A, #'i', w53	; 'i' Return Chip ID

	MOV DPTR, #ChipID
	LCALL put_string	; put Chip ID string 
	MOV u_data, #0AH	; putc(LF)
	LCALL putc
	LJMP put_ret

;====== 'b' - Return Block write Mode support (Note 17) ========================
w53:
	MOV A, u_data	
	CJNE A, #'b', w6	; 'b' Return enhanced mode Support

	MOV u_data, #'Y'	; putc('Y') - supports enhanced Mode
	LCALL putc

	;BUFSIZE is only one byte so send 00H for the high byte and BUFSIZE for the low byte
	MOV u_data, #00H		;ldi	u_data,high(BUFSIZE); putc((BUFSIZE>>8) & 0xff);
	LCALL putc				;rcall putc
	MOV u_data, #BUFSIZE	;ldi	u_data,low(BUFSIZE)	; putc(BUFSIZE&0xff);
	LCALL putc				;rcall putc
	LJMP waitcmd

;====== 'x' - Set LED ======================================================
w6:	
	MOV A, u_data
	CJNE A, #'x', w61	; 'x' Set LED (LED off or green)

	LCALL getc			; get parameter
	CLR GRN_LED			; Grn ON
	SETB RED_LED		; Red OFF
	LJMP put_ret

;====== 'y' - Clear LED ====================================================
w61:
	MOV A, u_data
	CJNE A, #'y', w7	; 'y' Clear LED (LED on or red)

	LCALL getc			; get parameter
	CLR RED_LED			; Red ON
	SETB GRN_LED		; Grn OFF
	LJMP put_ret

;===========================================================================
; We require that the device code be selected before any of the other commands
w7:
	MOV DPTR, #Dev_S		; load pointer
	LCALL bel_table
	JNC	w71					; device belongs to table
	MOV DPTR, #Dev_M	
	LCALL bel_table
	JNC	w71					; device belongs to table
	LJMP put_err			; not match, goto put_err();

;====== 'P' - Enter Programming Mode =======================================
w71:
	MOV A, u_data	
	CJNE A, #'P', w8	; 'P' Enter programming mode

	CLR RED_LED			; Red ON
	SETB GRN_LED		; Grn OFF	
	;catch_ports			; catch ports
	CLR SCK				; clear SCK
	LCALL pas_RESET		; set RESET passive
	MOV	temp1, #50		; delay 50mS;
	LCALL delay
	LCALL act_RESET		; set RESET active
	MOV	temp1, #50		; delay 50mS;
	LCALL delay	
	MOV	s_data, #0ACH	
	LCALL wrser			; wrser(0xac) SPI write (byte 1)
	MOV	s_data,#53H	
	LCALL wrser			; wrser(0x53) SPI write (byte 2)
						; SPI Synchronization (fix!)
	; if ( (device >= 0x20) && (device <= 0x7F) )
	MOV A, device
	CJNE A, #20H, not20			;cpi	device,0x20 ;brlo s2 
	SJMP is20
not20:
	JNC over20	;CY=0 if device >= 0x20
	SJMP s2
over20:
	RLC A						;tst	device
	JC s2	;device >= 0x80		;brmi	s2
is20:
	;END if
		
	MOV temp3, #32		; count = 32;
s1:	LCALL rdser			; SPI read  (byte 3)		
	MOV A, s_data
	CJNE A, #53H, s11	; if (rdser == 0x53)
	SJMP s3				; break
s11:
	MOV	s_data, #00H				
	LCALL wrser			; wrser(0x00) SPI write (byte 4)
	LCALL pulse_SCK		; pulse SCK
	MOV	s_data, #0ACH		
	LCALL wrser			; wrser(0xac) SPI write (byte 1)
	MOV	s_data, #53H		
	LCALL wrser			; wrser(0x53) SPI write (byte 2)
	;dec	temp3			; count-1
	;brne	s1				; loop
	DJNZ temp3, s1		;loop
	SJMP s3				; else
s2:	MOV	s_data, #00H	
	LCALL wrser			; wrser(0x00) SPI write (byte 3)
s3:	MOV A, device
	RLC A
	JC s4				; S89 device

	MOV s_data, #00H	
	LCALL wrser			; wrser(0x00) SPI write (byte 4)
s4:	MOV temp1, #4		; delay 4mS;
	LCALL delay
	LJMP put_ret

;====== 'c' - Write Program Memory, Low Byte ===============================
w8:
	MOV A, u_data
	CJNE A, #'c', w9	; 'c' Write program memory, low byte

	LCALL getc			; get data byte
w8b:
 	MOV s_data, #40H
	MOV pol_cmd, s_data	; save command for polling	
		
	MOV A, device
	RLC A
	JC w81				; S89 device

	LCALL wrser			; wrser(0x40)   SPI write (byte 1)
	MOV s_data, addrh
	SJMP w82
w81:
	MOV s_data, addrh	; s_data = (addrh << 3) | 0x02;
	LCALL shift_s_data3
	ORL	s_data, #02H
w82:
	LCALL wrser			; wrser(addrh)  SPI write (byte 2)
	MOV s_data, addrl	
	LCALL wrser			; wrser(addrl)  SPI write (byte 3)
	MOV s_data, u_data	
	LCALL wrser			; wrser(u_data) SPI write (byte 4)
	MOV	p_data, u_data	; save data for polling
	MOV	pol_al, addrl	; save address for polling
	MOV	pol_ah, addrh
	
	MOV A, device
	RLC A
	JNC w83				;Branch if NOT an S89 device (device < 0x80)

	LCALL inc_addr		;Increment addrl/h for S89 device
w83:
	LJMP wait_S			; write FLASH delay

;====== 'C' - Write Program Memory, High Byte ==============================
w9:	
	MOV A, u_data
	CJNE A, #'C', w92	; 'C' Write program memory, high byte

	LCALL getc			; get data byte
w9a:
	MOV A, device
	RLC A
	JC w91				; S89 device	

	MOV s_data, #48H	
	MOV pol_cmd, s_data	; save command for polling	
	LCALL wrser			; wrser(0x48)   SPI write (byte 1)
	MOV s_data, addrh	
	LCALL wrser			; wrser(addrh)  SPI write (byte 2)
	MOV s_data, addrl	
	LCALL wrser			; wrser(addrl)  SPI write (byte 3)
	MOV s_data, u_data	; wrser(u_data) SPI write (byte 4)
	LCALL wrser
	MOV p_data, u_data	; save data for polling
	MOV pol_al, addrl	; save address for polling
	MOV pol_ah, addrh
	LCALL inc_addr		; Auto increment address
	LJMP wait_S			; write FLASH delay
w91:
	LJMP put_err		; S89 device have byte wide program memory!	

;====== 'B' Block Write Memory (see Note 17) ======================
w92:
	MOV A, u_data
	; Need a long jump to get to w10 from here	
	CJNE A, #'B', w92_w10	; 'B' Block Write Program Memory
	SJMP w92a
w92_w10:
	LJMP w10

w92a:
	LCALL getc			; get count High Byte
	MOV A, u_data
	JZ w92b				; High byte should be zero because BUFSIZE is only a single byte (the low byte)

	MOV u_data, #01		; Error Code. Only used with put_debug
	LJMP put_err
		
w92b:
	LCALL getc			; get count Low Byte
	;cpi u_data,BUFSIZE+1		; check maximum count 
	;brlo w92c
	MOV A, #BUFSIZE
	CLR C
	SUBB A, u_data		; Check that the buffer is large enough
	JNC w92c			; Positive result means requested size is less than or equal to BUFSIZE

	MOV u_data, #02		; Buffer too small
	LJMP put_err
w92c:
	MOV Bcnt1, u_data	; Counter #1, Store low byte only...ignore BUFSIZE high Byte (must be 0)
	MOV Bcnt2, u_data	; Counter #2
	LCALL getc			; get Memory type to write
	MOV Memtype, u_data	; Flag for Memtype
	;The original AVR code used the 16-bit X variable as a data pointer for SRAM storage and retrieval.
	;We will just use R0 with Indirect Addressing (must use R0 or R1 for the 8051's Indirect Addressing)
	;clr XH
	;ldi XL, RAMSTART		; set X pointer to SRAM begin
	MOV R0, #RAMSTART	; Set to start of SRAM Buffer
w93:
	LCALL getc			; get data until Bcnt1 is reached
	MOV @R0, u_data		; Store data to SRAM Buffer
	INC R0				; Move to next byte in Buffer	
	DJNZ Bcnt1, w93

	MOV R0, #RAMSTART	; Reset to start of SRAM Buffer
	MOV B_Mode, #01		; B_Mode != 0
	
	MOV A, Memtype		; Check Memtype 
	CJNE A, #'F', notF	; Write to Flash Memory
	SJMP w94a
notF:
	CJNE A, #'E', notE 	; Write to EEPROM Memory
	SJMP w94		   	; Entry Point for Data Memory Block write
notE:		
	MOV u_data, #03
	LJMP put_err

w94:					; write Data (EEPROM) Memory
	;ld u_data,X+
	MOV u_data, @R0
	INC R0
	LCALL eeprom_write
	;dec Bcnt2
	;brne w94
	DJNZ Bcnt2, w94
	LJMP put_ret

;Entry Point for Flash Block write
w94a:
	MOV DPTR, #Dev_M	
	LCALL bel_table
	JNC w95				; device belongs to table
	SJMP w96			; not match, goto "non Paged" Mode
w95:					; Entry Point for AVRProg Block Flash write
	MOV s_data, #40H	; write low byte
	LCALL spi123
	;ld	s_data, X+
	MOV s_data, @R0
	INC R0
	LCALL wrser			; wrser(s_data) SPI write (byte 4)
	MOV s_data, #48H	; write high byte
	MOV pol_cmd, s_data	; save command for polling	
	LCALL spi123
	MOV s_data, @R0
	INC R0
	MOV p_data, s_data	; save data for polling
	MOV pol_al, addrl	; save address for polling
	MOV pol_ah, addrh
	LCALL wrser			; wrser(u_data) SPI write (byte 4)
	LCALL inc_addr		; Auto increment address

	DEC Bcnt2
	;breq w95b
	MOV A, Bcnt2
	JZ w95b
	DEC Bcnt2
	;breq w95b
	MOV A, Bcnt2
	JZ w95b

	;tst B_Mode
	MOV A, B_Mode
	;breq w95				
	JZ w95				; Loop for "Block Mode Commands" see Note 16
		
	DJNZ Bcnt3, w95		; count Bytes for Pagesize
w95b:
	;tst B_Mode
	;brne w95c
	MOV A, B_Mode
	JNZ w95c
	LJMP put_ret
w95c:
	DEC Bcnt3			; Bcnt3 will be set correct after write
	MOV s_data, #4CH	; write Memory Page
	LCALL wrser			; wrser(0x4c)  SPI write (byte 1)
	MOV s_data, pol_ah	; last written Adress is in Page to be programmed!
	LCALL wrser			; wrser(addrh) SPI write (byte 2)
	MOV s_data, pol_al	; last written Adress is in Page to be programmed!
	LCALL wrser			; wrser(addrl) SPI write (byte 3)
	MOV s_data, #00H
	LCALL wrser			; wrser(0x00)  SPI write (byte 4)
	MOV Bcnt3, Pagewords	; reload Counter for Pagesize
	LJMP wait_M

;#@KL4 test for 89S8252 Device
w96:					; Non Page Mode Flash write
	;tst	device
	;brmi	w96b			; S89 device
	MOV A, device
	RLC A
	JC w96b				;S89 device

	MOV	p_data, @R0		; load byte to Poll data
	INC R0
	;cpi	p_data,0xFF			; if (p_data == 0xFF)
	MOV A, p_data
	CJNE A, #0FFH, notFF 
	SJMP w961			; skip burning
notFF:
	MOV s_data, #40H	; write low byte
	MOV pol_cmd, s_data	; save command for polling	
	LCALL spi123
	MOV s_data, p_data	; reload data from Poll data
	LCALL wrser			; wrser(s_data) SPI write (byte 4)
	MOV pol_al, addrl	; save address for polling
	MOV pol_ah, addrh
	LCALL Bws_pol
w961:
	DEC Bcnt2
	MOV p_data, @R0		; load byte to Poll data
	INC R0
	;cpi	p_data,0xFF			; if (p_data == 0xFF)
	MOV A, p_data
	CJNE A, #0FFH, notFF2 
	SJMP w962
notFF2:
	MOV s_data, #48H	; write high byte
	MOV pol_cmd, s_data	; save command for polling	
	LCALL spi123
	MOV s_data, p_data	; reload data from Poll data
	LCALL wrser			; wrser(u_data) SPI write (byte 4)
w96a:
	MOV pol_al, addrl	; save address for polling
	MOV pol_ah, addrh
	LCALL Bws_pol
w962:
	LCALL inc_addr		; Auto increment address
	;dec Bcnt2
	;brne w96
	DJNZ Bcnt2, w96
	LJMP put_ret		; reply

w96b:					; Code for 89S8252
;	ldi	s_data,0x40
;	mov	pol_cmd,s_data	; save command for polling	
	MOV s_data, addrh	; s_data = (addrh << 3) | 0x02;
	LCALL shift_s_data3
	ORL s_data, #02H
	LCALL wrser			; wrser(addrh)  SPI write (byte 1)
	MOV s_data, addrl	
	LCALL wrser			; wrser(addrl)  SPI write (byte 2)
	MOV s_data, @R0
	INC R0	
	MOV p_data, s_data	; save data for polling
	LCALL wrser			; wrser(u_data) SPI write (byte 3)
	SJMP w96a

;====== 'R' - Read Program Memory ==========================================
w10:
	MOV A, u_data
	CJNE A, #'R', w10B	; 'R' Read program memory	

	;tst	device
	MOV A, device
	RLC A
	JC rpm1				; S89 device
	MOV s_data, #28H	; read high Byte (order is different from Block Read!)
	LCALL wrser			; wrser(0x28)  SPI write (byte 1)
	MOV s_data, addrh
	SJMP rpm2
rpm1:
	MOV s_data, addrh	; s_data = (addrh << 3) | 0x01;
	LCALL shift_s_data3
	ORL s_data, #01H
rpm2:
	LCALL wrser			; wrser(addrh) SPI write (byte 2)
	MOV s_data, addrl	
	LCALL wrser			; wrser(addrl) SPI write (byte 3)
	LCALL rdser			;              SPI read  (byte 4)
	MOV u_data, s_data
	LCALL putc			; send data

	;tst	device
	MOV A, device
	RLC A
	JC rpm3				; S89 device
	MOV s_data, #20H	; read Low Byte
	LCALL wrser			; wrser(0x20)  SPI write (byte 1)
	MOV s_data, addrh	
	LCALL wrser			; wrser(addrh) SPI write (byte 2)
	MOV s_data, addrl	
	LCALL wrser			; wrser(addrl) SPI write (byte 3)
	LCALL rdser			;              SPI read  (byte 4)
	MOV u_data, s_data
	LCALL putc			; send data
rpm3:
	LCALL inc_addr		; Auto increment address
	LJMP waitcmd		; goto waitcmd();

;====== 'g' - Block Read Memory (See Note 17) ======================
; This is the only command to use a 16-bit data pointer for reading back large
; amounts of data from the target device. R2 and R3 act as that pointer and use
; an (ugly) subroutine to manage them. R2 is the low byte, R3 is the high byte
w10B:
	MOV A, u_data
	CJNE A, #'g', w11	; 'g' Block Read Program Memory
	
	LCALL getc			; XH = getc();
	MOV R3, u_data
	LCALL getc			; XL = getc();
	MOV R2, u_data

	LCALL getc			; getc(Memorytype);
	MOV A, u_data
	CJNE A, #'F', notF2
	SJMP w10B2
notF2:
	CJNE A, #'E', notE2
	SJMP w10B1
notE2:
	LJMP put_err

w10B1:
	LCALL read_send_datamem
	;sbiw XL, 1
	LCALL dec_r2r3		;Also sets A=0 if R2/R3 are both zero
   	JNZ w10B1
	LJMP waitcmd		; goto waitcmd();

w10B2:
 	LCALL read_send_progmem
	MOV A, device
	RLC A
	JC w10B3

	;sbiw XL, 2
	LCALL dec_r2r3		
	LCALL dec_r2r3		;Also sets A=0 if R2/R3 are both zero
	JNZ w10B2
	LJMP waitcmd
w10B3:
	LCALL dec_r2r3		;Also sets A=0 if R2/R3 are both zero
   	JNZ w10B2
	LJMP waitcmd		; goto waitcmd();

;====== 'A' - Load Address =================================================
w11:
	MOV A, u_data
	CJNE A, #'A', w12	; 'A' Load address

	LCALL getc			; addrh = getc();
	MOV addrh, u_data
	LCALL getc			; addrl = getc();
	MOV addrl, u_data
	LJMP put_ret			; goto reply();

;====== 'D' - Write Data Memory ============================================
w12:
	MOV A, u_data
	CJNE A, #'D', w13	; 'D' Write data memory

	LCALL getc			; get data
	LCALL eeprom_write
	LJMP put_ret

;====== 'd' - Read Data Memory =============================================
w13:
	MOV A, u_data
	CJNE A, #'d', w14	; 'd' Read data memory

	LCALL read_send_datamem
	LJMP waitcmd		; goto waitcmd();

;====== 'L' - Leave Programming Mode =======================================
w14:
	MOV A, u_data
	CJNE A, #'L', w142	; 'L' Leave programming mode
w141:
	LCALL pas_RESET		; set RESET passive
	; Ports work differently between AVR and 8051. For now just skip releasing the outputs
	;release_ports		; release ports
	CLR GRN_LED			; Grn ON					
	SETB RED_LED		; Red OFF
	LJMP put_ret

;====== 'E' - Exit , release all Ports, inhibit AVR910 =====================
w142:
	MOV A, u_data
	CJNE A, #'E', w15	; 'E' xit
	SJMP w141			; Exit command for AVR Prog. Also execute "Leave programming mode" routine
	
;====== 'e' - Chip Erase ===================================================
w15:
	MOV A, u_data
	CJNE A, #'e', w16  		; 'e' Chip erase

	MOV s_data, #0ACH
	LCALL wrser			; wrser(0xac) SPI write (byte 1)

	MOV A, device
	RLC A
	JC w151				; S89 device

	MOV s_data, #80H
	LCALL wrser			; wrser(0x80) SPI write (byte 2)
w151:
	MOV s_data, #04H
	LCALL wrser			; wrser(0x04) SPI write (byte 3)
	MOV s_data, #00H
	LCALL wrser			; wrser(0x00) SPI write (byte 4)
	MOV temp1, #40		; delay 40mS
	LCALL delay
	LJMP put_ret

;====== 'l' - Write Lockbits ==============================================
; writes Lockbits in SPI Byte 2 for old "classic" AVR Chips, and in addition
; writes Lockbits in SPI byte 4 for new Mega and Tiny Devices. 
; One Type does not care about the other Byte...

; Some more different Adresses for other devices?
w16:
	MOV A, u_data
	CJNE A, #'l', w161	; 'l' Write Lockbits

	LCALL getc			; get data
	MOV s_data, #0ACH
	LCALL wrser			; wrser(0xac)   SPI write (byte 1)

	MOV A, device
	RLC A
	JC w163				; S89 device

	MOV s_data, u_data 
	ORL s_data, #0E0H
	LCALL wrser			; wrser(u_data) SPI write (byte 2)
	SJMP w162

;====== 'f' - Write Fusebits ==============================================
w161:
	MOV A, u_data
	CJNE A, #'f', w17	; 'f' Write Fusebits

	LCALL getc			; get data
	MOV s_data, #0ACH
	LCALL wrser			; wrser(0xac)   SPI write (byte 1)
	MOV s_data, #0A0H
	LCALL wrser			; wrser(0xa0)   SPI write (byte 2)
w162:
	MOV s_data, #00H
	LCALL wrser			; wrser(0x00)   SPI write (byte 3)
	MOV s_data, u_data 
	LCALL wrser			; wrser(u_data) SPI write (byte 4)
	SJMP w164
w163:
	MOV s_data, u_data 
	ANL s_data, #0E0H	; S89 device
	ORL s_data, #07H
	LCALL wrser			; SPI write (byte3)
	MOV s_data, #00H
	LCALL wrser			; wrser(0x00)   SPI write (byte 4)
w164:
	MOV temp1, #10		; delay 10mS
	LCALL delay
	LJMP put_ret

;====== 's' - Read Signature Bytes =========================================
w17:
	MOV A, u_data
	CJNE A, #'s', w18	; 's' Read signature bytes

	MOV A, device
	RLC A
	JC w171				; S89 device
 
	MOV cmd1, #30H
	MOV cmd2, #00H
	MOV cmd3, #02H
	LCALL w123r4
	DEC cmd3
	LCALL w123r4
	MOV cmd3, #00H
	LCALL w123r4
	LJMP waitcmd
w171:
	LJMP put_err

;====== 'm' - Write Program Memory Page ====================================
w18:
	MOV A, u_data
	CJNE A, #'m', w19	; 'm' Write Program Memory Page

	MOV s_data, #4CH	
	LCALL wrser			; wrser(0x4c)  SPI write (byte 1)
;	mov	s_data,addrh		; original, reload address
	MOV s_data, pol_ah		; for speeding up transfer
	LCALL wrser			; wrser(addrh) SPI write (byte 2)
;	mov	s_data,addrl		; original, reload address
	MOV s_data, pol_al		; for speeding up transfer
	LCALL wrser			; wrser(addrl) SPI write (byte 3)
	MOV s_data, #00H
	LCALL wrser			; wrser(0x00)  SPI write (byte 4)
	LJMP wait_M			; write FLASH delay

;====== ':' - Universal Command ============================================
w19:
	MOV A, u_data
	CJNE A, #':', w20	; ':' Universal Command

	LCALL getc			; get data1
	MOV cmd1, u_data	; cmd1 = data1
	LCALL getc			; get data2
	MOV cmd2, u_data	; cmd2 = data2
	LCALL getc			; get data3
	MOV cmd3, u_data	; cmd3 = data3
	LCALL w123r4
	MOV temp1, #50		; delay 50mS
	LCALL delay
	LJMP put_ret

;====== '.' - New Universal Command ========================================
w20:
	MOV A, u_data
	CJNE A, #'.', w21	; '.' New Universal Command

	LCALL getc			; get data1
	MOV cmd1, u_data	; cmd1 = data1
	LCALL getc			; get data2
	MOV cmd2, u_data	; cmd2 = data2
	LCALL getc			; get data3
	MOV cmd3, u_data	; cmd3 = data3
	LCALL getc			; get data4
	LCALL w1234
	MOV u_data, rd_s_data
	LCALL putc			; send data
	MOV temp1, #50		; delay 50mS
	LCALL delay
	LJMP put_ret
	
;====== 'r' - Read Lock Bits ==============================================
w21:
	MOV A, u_data
	CJNE A, #'r', w22	; 'r' Read Lockbits

	MOV s_data, #58H	; SPI load (byte 1)
	SJMP w22a

;====== 'F' - Read Fusebits (lfuse) =========================================
w22:
	MOV A, u_data
	CJNE A, #'F', w23	; 'F' Read Fusebits

	MOV s_data, #50H	; SPI load (byte 1)
w22a:
	LCALL wrser			; wrser(0x5n)   SPI write (byte 1)
	MOV s_data, #00H	; SPI load (byte 2)
	SJMP w26

;====== 'N' - Read high Fusebits ==========================================
w23:
	MOV A, u_data
	CJNE A, #'N', w24	; 'N' Read high Fusebits
	MOV s_data, #58H
	LCALL wrser			; wrser(0x58)   SPI write (byte 1)
	SJMP w25

;====== 'Q' - Read extendet Fusebits ==============================================
w24:
	MOV A, u_data
	CJNE A, #'Q', w30	; 'Q' Read extendet Fusebits

	MOV s_data, #50H	; SPI load (byte 1)
	LCALL wrser			; wrser(0x50)   SPI write (byte 1)
w25:
	MOV s_data, #08H	; SPI load (byte 2)
w26:
	LCALL wrser			; wrser(0x00)   SPI write (byte 2)
	MOV s_data, #00H
	LCALL wrser			; wrser(0x00)   SPI write (byte 3)
	LCALL rdser			;               SPI read  (byte 4)
	MOV u_data, s_data
	LCALL putc			; send data
	LJMP waitcmd

;====== Unknown Command ====================================================
w30:	LJMP put_err

;====== Wait for FLASH write in avr910 mode ==================================
wait_S:
	MOV DPTR, #Dev_M	
	LCALL bel_table
	JC ws_pol			; No Page Mode, poll last Byte
	LJMP put_ret		; in Byte Mode time is long enougt to get next Byte...
Bws_pol:				; entry adress for Block mode delay
	MOV B_Flag, #01H	; set Flag that ws_poll comes back with ret ...

ws_pol:		
	MOV A, PollcodeF	; if polling not applicable, standard delay
	JZ ws_del			; polling not used
ws_def:
	;cp 	p_data,PollcodeF	; if (data == PollcodeF)
	;breq 	ws_del			; wait default delay
	MOV A, p_data
	CLR C
	SUBB A, PollcodeF	; if (data == PollcodeF)
	JZ ws_del			; wait default delay

	ANL pol_cmd, #0FH	; write command: 0x48, 0x40
	ORL pol_cmd, #20H	; read  command: 0x28, 0x20
	MOV temp3, #00H		; clear polling counter
ws_cy:
	MOV A, device
	RLC A
	JC ws_89			; S89 device

	MOV s_data, pol_cmd	
	LCALL wrser			; wrser(pol_cmd) SPI write (byte 1)
	MOV s_data, pol_ah
	SJMP ws_90
ws_89:
	MOV s_data, pol_ah	; s_data = (pol_ah << 3) | 0x01;
	LCALL shift_s_data3
	ORL s_data, #01H
ws_90:
	LCALL wrser			; wrser(pol_ah) SPI write (byte 2) (S89=byte1)
	MOV s_data, pol_al	
	LCALL wrser			; wrser(pol_al) SPI write (byte 3) (S89=byte2)
	LCALL rdser			;               SPI read  (byte 4) (S89=byte3)
	;tst	device
	;brpl	ws_cb
	MOV A, device
	RLC A
	JNC ws_cb
	
	ANL s_data, #80H	; compare only MSB for S89 device
	ANL p_data, #80H
ws_cb:					
	;cp	s_data,p_data
	;breq	ws_ok			; s_data = p_data
	MOV A, s_data
	CLR C
	SUBB A, p_data		; s_data = p_data
	JZ ws_ok			

	;dec	temp3
	;brne	ws_cy			; loop
	DJNZ temp3, ws_cy	; loop
ws_del:					; 256 polling cycles are over, give additional standard Time
	MOV temp1, #10		; delay 10mS
	LCALL delay
ws_ok:
	;tst B_Flag
	MOV A, B_Flag 
	;breq put_ret
	;JZ put_ret Does not work, needs a long jump
	JNZ ws_ok1
	LJMP put_ret
ws_ok1:
	MOV B_Flag, #00H	; Reset B_Flag for normal operation 
	
	; This is the Only "ret" in the main program loop. Should it be "rjmp put_ret" instead? 
	; For now, stay consistent with the original AVR code until it can be investigated.
	;ret
	RET

;====== Wait for FLASH write in page mode ==================================
wait_M:
	;cpi	device,0x41
	MOV A, device
	CJNE A, #41H, not103
	SJMP wm_del			; polling inapplicable for m103
not103:
	;cpi	device,0x23
	MOV A, device
	CJNE A, #23H, not2313
	SJMP poll_t2313		; polling different for t2313
not2313:
	;cpi	p_data, 0xFF		; if last Byte was 0xFF give standard delay
	MOV A, p_data		; if last Byte was 0xFF give standard delay
	CJNE A, #0FFH, notFF3
	SJMP wm_del
notFF3:
	ANL pol_cmd, #0FH	; write command: 0x48, 0x40
	ORL pol_cmd, #20H	; read  command: 0x28, 0x20
	MOV temp3, #00H		; clear polling counter
wm_cy:
	MOV s_data, pol_cmd	
	LCALL wrser			; wrser(pol_cmd) SPI write (byte 1)
	MOV s_data, pol_ah
	LCALL wrser			; wrser(pol_ah) SPI write (byte 2)
	MOV s_data, pol_al	
	LCALL wrser			; wrser(pol_al) SPI write (byte 3)
	LCALL rdser			;               SPI read  (byte 4)

	;cp	s_data,p_data
	;breq	wm_ok			; s_data = p_data
	MOV A, s_data
	CLR C
	SUBB A, p_data		; s_data = p_data
	JZ wm_ok

	;dec	temp3
	;breq	wm_del			; 256 polling cycles are over, give another 50ms delay...
	;rjmp	wm_cy			; loop
	DJNZ temp3, wm_cy	; Loop
	SJMP wm_del			; 256 polling cycles are over, give another 50ms delay...
wm_del:
	MOV temp1, #50		; delay 50mS
	LCALL delay
wm_ok:
	;tst B_Mode
	MOV A, B_Mode
	;breq wm_end
	JZ wm_end
	;tst Bcnt2
	MOV A, Bcnt2
	;breq wm_end
	JZ wm_end
	LJMP w95
wm_end:
	MOV B_Mode, #00H	; Reset Block Mode Flag
	LJMP put_ret

poll_t2313:				; Polling ATTiny2313 is different
	MOV pol_cmd, #0F0H	; Byte1= 0xF0
	MOV temp3, #00H		; clear polling counter
	MOV pol_ah, temp3	; Byte2= 0x00
p2313_1:
	MOV s_data, pol_cmd	
	LCALL wrser			; wrser(pol_cmd) SPI write (byte 1)
	MOV s_data, pol_ah
	LCALL wrser			; wrser(pol_ah) SPI write (byte 2)
	MOV s_data, pol_al	
	LCALL wrser			; wrser(pol_al) SPI write (byte 3)
	LCALL rdser			;               SPI read  (byte 4)

	;andi	s_data,0x01		; last Bit tells if polling OK
	MOV A, s_data
	ANL A, #01H			; last Bit tells if polling OK
	;breq	wm_ok			; s_data = p_data
	JZ wm_ok			; s_data = p_data
	
	;dec	temp3
	;breq	wm_del			; 256 polling cycles are over, give another 50ms delay...
	;rjmp	p2313_1			; loop
	DJNZ temp3, p2313_1	; Loop
	SJMP wm_del			; 256 polling cycles are over, give another 50ms delay...

;====== Command Error ======================================================
put_debug:				; shows u_data on serial for debug reason				
	LCALL putc
put_err:
	MOV u_data, #'?'	; putc('?')
	LCALL putc			; send '?'
	LJMP waitcmd		
	
;====== Reply Command ======================================================
put_ret:
	MOV u_data, #0DH	; putc(0x0D)
	LCALL putc			; send CR
	LJMP waitcmd	




ORG 1000H
;***************************************************************************
;*
;* TABLE
;*	device codes
;*
;* DESCRIPTION
;*	The following device codes must be used by the host computer. Note
;*	that the device codes are arbitrary selected, they do not have any
;*	thing in common with the signature bytes stored in the device.
;* 	This are the device Codes recognized by the AVRprog Software. Some
;*	Devices may require special hardware or a different, not yet 
;*	implemented Protocol! Use at your own risk.
;*
;***************************************************************************
; 0x20 bytes (0x1000-0x1019)
Dev_S:	; byte write
;      avr910-devcode   ,Code during polling Flash. 0x00: no polling supported, program default time
;	DB	10	,00	;AT90S1200A No support for this type
;	DB	11	,00	;AT90S1200B No support for this type
;	DB	12	,00	;AT90S1200C No support for this type
	DB 35H, 00H
	DB	13H, 00H	;AT90S1200
	DB	20H, 7FH	;AT90S2313A
	DB	28H, 7FH	;AT90S4414A
	DB	30H, 0FFH	;AT90S4433A
	DB	34H, 0FFH	;AT90S2333A
	DB	38H, 7FH	;AT90S8515A
	DB	48H, 0FFH	;AT90S2323A
	DB	4CH, 0FFH	;AT90S2343A
	DB	51H, 0FFH	;tn10
	DB	55H, 0FFH	;tn12
	DB	56H, 0FFH	;tn15
	DB	68H, 0FFH	;AT90S8535
	DB	6CH, 0FFH	;AT90S4434
	DB	86H, 0FFH	;AT89S8252  bug in avrprog in Block write Mode!(See Note 18 for Workaround)
	DB	87H, 0FFH	;AT89S53    bug in avrprog
	DB	0, 0		;End of table

; 0x60 bytes (0x1020-0x1079)	
Dev_M:	; Devices which support Page Programming. Dont forget the Page Size 
		; of different Devices.
		; Maximum is 0x40 due to limitated RAM in 2313 Chip. 
		; (Pages with bigger Pages are programmed multiple times)


; unofficial Device Codes. Match avrdude.conf with tis "avr910-devcode"

; avr910-devcode ,Pagesite in Words
	DB 01H, 40H	;m640 	avr910-Devicecode not official!
;	DB 02H, 40H	;m644 	avr910-Devicecode not official!
;	DB 03H, 40H	;m645 	avr910-Devicecode not official!
	DB 04H, 40H	;m649 	avr910-Devicecode not official!
;	DB 05H, 40H	;m6490 	avr910-Devicecode not official!
	DB 06H, 40H	;90PWM2	avr910-Devicecode not official!
	DB 07H, 40H	;90PWM3	avr910-Devicecode not official!
	DB 08H, 40H	;m1280 	avr910-Devicecode not official!
	DB 09H, 40H	;m1281	avr910-Devicecode not official!
;	DB 0AH, 40H	;m2560 	avr910-Devicecode not official!
;	DB 0BH, 40H	;m2561	avr910-Devicecode not official!
;	DB 0CH, 40H	;m3250 	avr910-Devicecode not official!
;	DB 0DH, 40H	;m6450	avr910-Devicecode not official!
	DB 0EH, 10H	;tn24 	avr910-Devicecode not official!
	DB 1AH, 10H	;tn25 	avr910-Devicecode not official!
	DB 0FH, 20H	;tn44	avr910-Devicecode not official!
	DB 1BH, 20H	;tn45	avr910-Devicecode not official!
	DB 14H, 20H	;tn84	avr910-Devicecode not official!
	DB 1CH, 20H	;tn85	avr910-Devicecode not official!
	DB 1DH, 40H	;CAN128	avr910-Devicecode not official!
	DB 23H, 10H	;tn2313 avr910-Devicecode not official! (STK500 Code used)
	DB 31H, 20H	;m48	avr910-Devicecode not official!
	DB 33H, 20H	;m88 	avr910-Devicecode not official!
	DB 35H, 40H	;m168 	avr910-Devicecode not official!
;	DB 36H, 40H	;m165 	avr910-Devicecode not official!
	DB 37H, 40H	;m164 	avr910-Devicecode not official!
	DB 39H, 40H	;m324 	avr910-Devicecode not official!
;	DB 3CH, 40H	;m325 	avr910-Devicecode not official!
	DB 3DH, 40H	;m329 	avr910-Devicecode not official!
	DB 3EH, 40H	;m3290 	avr910-Devicecode not official!
	DB 57H, 10H	;tn13 	avr910-Devicecode not official! 
		   
;Appearance of this Devicecodes does not mean this Devices are or will be fully supported !

; official Devicecodes as matched in AVRProg V1.40
	DB	3AH, 20H	;m8515, Pagesize 32 words (0x20)
	DB	3BH, 20H	;m8515boot  Bootloader Mode untested!
	DB	41H, 40H	;m103	
	DB	43H, 40H	;m128
	DB	44H, 40H	;m128boot  Bootloader Mode untested!
	DB	45H, 40H	;m64
	DB	46H, 40H	;m64boot   Bootloader Mode untested!
	DB	5EH, 10H	;tn26
	DB	60H, 40H	;m161
	DB	61H, 40H	;m161boot  Bootloader Mode untested!
	DB	62H, 40H	;m162
	DB	63H, 40H	;m162boot  Bootloader Mode untested!
	DB	64H, 40H	;m163
	DB	66H, 40H	;m163boot  Bootloader Mode untested!
	DB	69H, 20H	;m8535
	DB	6AH, 20H	;m8535boot Bootloader Mode untested!
	DB	72H, 40H	;m32
	DB	73H, 40H	;m32boot   Bootloader Mode untested!
	DB	74H, 40H	;m16
	DB	75H, 40H	;m16boot   Bootloader Mode untested!
	DB	76H, 20H	;m8
	DB	77H, 20H	;m8boot    Bootloader Mode untested!
	DB	78H, 40H	;m169
	DB	79H, 40H	;m169boot  Bootloader Mode untested!
	DB 	0, 0		;End of Table

; Devices with known avr910 Devicecodes, but not supported with this Programmer
;	DB	42H	,40H	;m603	obsolete
;	DB	50H			;tn11 Needs additional High Voltage Hardware and uses different Protocoll! No Support!
;	DB	58H			;tn19 Obsolete
;	DB	5cH			;tn28 Only supported in parallel Programming Mode!
;	DB	65H	,20H	;m83	obsolete 
;	DB	67H	,20H	;m83boot  obsolete
;	DB	70H			;AT90C8534  unknown Hardware, untested!
;	DB	71H			;AT90C8544  unknown Hardware, untested!
;	DB	80H			;AT89C1051  unknown Hardware, untested!
;	DB	81H			;AT89C2051  unknown Hardware, untested!


; Revision codes
SW_Ver:
	DB "38",0,0
HW_Ver:
	DB "10",0,0

; ID string "AVR ISP"
ID_Str:
	DB "AVR ISP",0

; Chip ID string to identify the Firmware
ChipID:
	DB "Ver.3.8b (AVR109 Mode, 11.0592Mhz, 57600 baud) for 8051",0	


END				

Download Source (45.79 Kb)