;**** A P P L I C A T I O N N O T E A V R 9 1 0 ************************
;*
;* Title : AVR ISP
;* Version : 1.5
;* Last updated : 97.08.26
;* Target : AT90S1200
;*
;* DESCRIPTION
;* The firmware on all programmers now support a unified protocol for
;* program and data memory programming. The host computer do not need
;* to know if the programmer operates in serial or parallel mode.
;*
;* The following commands are supported. All commands start with a
;* single letter. The programmer returns 13d (carriage return) or the
;* data read after the command is finished.
;*
;* +-------------+------------+------+
;* Commands | Host writes | Host reads | |
;* -------- +-----+-------+------+-----+ |
;* | ID | data | data | | Note |
;* +-----------------------------------+-----+-------+------+-----+------+
;* | Enter programming mode | 'P' | | | 13d | 1 |
;* | Set address | 'A' | ah al | | 13d | 2 |
;* | Write program memory, low byte | 'c' | dd | | 13d | 3 |
;* | Write program memory, high byte | 'C' | dd | | 13d | 3 |
;* | Read program memory | 'R' | |dd(dd)| | 4 |
;* | Write data memory | 'D' | dd | | 13d | |
;* | Read data memory | 'd' | | dd | | |
;* | Chip erase | 'e' | | | 13d | |
;* | Write lock bits | 'l' | dd | | 13d | |
;* | Write fuse bits | 'f' | dd | | 13d | 11 |
;* | Read fuse and lock bits | 'F' | | dd | | 11 |
;* | Leave programming mode | 'L' | | | 13d | 5 |
;* | Select device type | 'T' | dd | | 13d | 6 |
;* | Read signature bytes | 's' | | 3*dd | | |
;* | Return supported device codes | 't' | | n*dd | 00d | 7 |
;* | Return software identifier | 'S' | | s[7] | | 8 |
;* | Return sofware version | 'V' | |dd dd | | 9 |
;* | Return hardware version | 'v' | |dd dd | | 9 |
;* | Return programmer type | 'p' | | dd | | 10 |
;* | Set LED | 'x' | dd | | 13d | 12 |
;* | Clear LED | 'y' | dd | | 13d | 12 |
;* +-----------------------------------+-----+-------+------+-----+------+
;*
;* NOTE 1
;* The Enter programming mode command MUST be sent one time prior to
;* the other commands, with the exception of the 't', 'S', 'V', 'v'
;* and 'T' commands. The 'T' command must be sent before this command
;* (see note 6).
;*
;* For programmers supporting both parallel and serial programming
;* mode this command enters parallel programming mode. For programmers
;* supporting only serial programming mode, this command enters serial
;* programming mode.
;*
;* NOTE 2
;* The ah and al are the high and low order bytes of the address. For
;* parallel programmers this command issues the Load Address Low/High
;* Byte command. For serial programmers the address byte is stored for
;* use by the Read/Write commands.
;*
;* NOTE 3
;* For parallel programmers this command issues the Program Flash
;* command. For serial programmers this command iussues the Write
;* Program Memory Command. For devices with byte-wide program memories
;* only the low byte command should be used.
;*
;* NOTE 4
;* The contents of the program memory at the address given by the 'A'
;* command are written to the serial port in binary form. For byte
;* wide memories one byte is written. For 16 bit memories two bytes
;* are written,MSB first.
;*
;* NOTE 5
;* This command must be executed after the programming is finished.
;*
;* NOTE 6
;* The select device type command must be sent before the enter
;* programming command
;*
;* NOTE 7
;* The supported device codes are returned in binary form terminated
;* by 0x00.
;*
;* NOTE 8
;* This return a 7 character ASCII string identifying the programmer.
;* For the development board it is "AVR DEV", for the parallel
;* programmer it is "AVR PPR" and for the in-curcuit programmer it is
;* "AVR ICP".
;*
;* NOTE 9
;* The software/hardware version are returned as two ASCII numbers.
;*
;* NOTE 10
;* This command should be used to identify the programmer type. The
;* return value is 'S' for serial (or SPI) programmers or 'P' for
;* parallel programmers.
;*
;* NOTE 11
;* The write fuse bits command are available only on parallel
;* programmers and only for AVR devices (device code < 0x80). The host
;* should use the return programmer type command to determine the
;* programmer type, do not use the "AVR PPR" idenifier because other
;* programmers may be available in the future.
;*
;* NOTE 12
;* Currently only the AVR development board has LEDs. The other boards
;* must implement this commands as NOPs.
;*
;* HISTORY
;* V1.5 97.08.21 (MWL) Modified / Bugfix / Major cleanup
;* ... ... (no records)
;* V?.? 97.03.15 (OS) Created
;*
;***************************************************************************
;**** includes ****
.include "1200def.inc"
;***************************************************************************
;*
;* CONSTANTS
;* 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.
;*
;* The following devices are supported (make a new table for each
;* software release):
;*
;* SW_MAJOR=1, SW_MINOR=5
;*
;* AT90S1200 rev. C (abbreviated S1200C)
;* AT90S1200 rev. D (abbreviated S1200D)
;* AT90S8515 rev. A (abbreviated S8515A)
;* AT89S8252 (abbreviated S8252)
;*
;***************************************************************************
.equ S1200C = 0x12
.equ S1200D = 0x13
.equ S8515A = 0x38
.equ S8252 = 0x86
;**** Revision Codes ****
.equ SW_MAJOR = 1 ; Major SW revision number
.equ SW_MINOR = 5 ; Minor SW revision number
.equ HW_MAJOR = 1 ; Major HW revision number
.equ HW_MINOR = 0 ; Minor HW revision number
;***************************************************************************
;*
;* MACROS
;* Program Macros
;*
;* DESCRIPTION
;* Change the following four macros if the RESET pin to the
;* target moves and/or if the SCK/MISO/MOSO moves.
;*
;***************************************************************************
.macro set_reset
sbi portb,4
.endm
.macro clr_reset
cbi portb,4
.endm
.macro ddrd_init
nop
; sbi ddrd,3
.endm
.macro ddrb_init
ldi temp1,0xdf
out ddrb,temp1 ; PB5 is input, the rest is output
.endm
.macro pulse_sck
sbi portb,SCK
ldi temp2,6
m0: dec temp2
brne m0
cbi portb,SCK
ldi temp2,3
m1: dec temp2
brne m1
.endm
;*****************
;* SPI Constants *
;*****************
.equ MOSI = 6 ; Bit number on PORTB
.equ MISO = 5 ; Bit number on PORTB
.equ SCK = 7 ; Bit number on PORTB
;******************
;* UART Constants *
;******************
;**** Constant declarations Data Rate ****
;.equ N = 95 ; 115200 BAUD when R=1 and XTAL=11.059MHz
;.equ N = 31 ; 57600 BAUD when R=2 and XTAL=11.059MHz
;.equ N = 43 ; 38400 BAUD when R=2 and XTAL=11.059MHz
.equ N = 33 ; 19200 BAUD when R=2 and XTAL=4.00MHz
;.equ N = 102 ; 38400 BAUD when R=1 and XTAL=4.00MHz
.equ R = 2
;**** UART transmit pin in PORTD ****
.equ TXPIN = 1
.equ RXPIN = 0
;**** Bit positions in UART Status Register ****
.equ TXC = 0 ; Transmit
.equ RXC = 1 ; Receive
;*****************************
;* Global Register Variables *
;*****************************
.def device = r16 ; Device code
.def temp1 = r17
.def temp2 = r18
.def s_data = r19 ; SPI data
.def u_data = r20 ; UART data
.def addrl = r21 ; Low order byte of address
.def addrh = r22 ; High order byte of address
.def bit_cnt = r23 ; Bit count used by UART routine
.def u_stat = r24 ; Status byte used by UART routine
.def cmd = r25 ; Serial programming command
.def count = r26 ; Time out variable for "enter programming mode"
;.def debug1 = r27
;*********************
;* Interrupt Vectors *
;*********************
.CSEG
rjmp RESET ; Reset Handle
reti ; IRQ0 Handle (not used)
rjmp TIM0_OVF ; Timer0 Overflow Handle
reti ; Analog Comparator Handle (not used)
;***************************************************************************
;*
;* INTERRUPT
;* TIM0_OVF - Timer/Counter0 Overflow Interrupt
;*
;***************************************************************************
TIM0_OVF:
in r0,SREG ; store SREG
ldi temp1,(256-N+8)
out TCNT0,temp1 ; reset T/C0 to one bit lenght
inc bit_cnt ; increment bit counter
sbrs u_stat,TXC ; if (transmit complete flag clear)
rjmp transmit ; goto transmit
to_0: sec ; set carry
sbis PIND,RXPIN ; if (RxD == LOW)
clc ; clear carry
ror u_data ; shift carry into u_data
cpi bit_cnt,8 ; if (bit_cnt == 8)
brne to_1 ; {
clr temp1 ; disable T/C0 Overflow Interrupt
out TIMSK,temp1
sbr u_stat,1< main
;*
;* DESCRIPTION
;* Wait for and execute commands.
;*
;***************************************************************************
waitcmd:rcall getc ; while (getc() == ESC) {};
cpi u_data,0x1b
breq waitcmd
;**** Device Type ****
cpi u_data,0x54 ; 'T' Device type
brne w0
rcall getc ; getc(); // dummy
mov device,u_data ; putc(device);
rjmp put_ret
;**** Return Software Identifier ****
w0: cpi u_data,0x53 ; 'S' Return software identifier
brne w1
rcall show_id ; show_id();
rjmp waitcmd
;**** Return Software Version ****
w1: cpi u_data,0x56 ;'V' Return software version
brne w2
ldi u_data,0x30+SW_MAJOR ; putc(0x30+SW_MAJOR);
rcall putc
ldi u_data,0x30+SW_MINOR ; putc(0x30+SW_MINOR);
rcall putc
rjmp waitcmd
;**** Return Hardware Version ****
w2: cpi u_data,0x76 ;'v' Return hardware version
brne w3
ldi u_data,0x30+HW_MAJOR ; putc(0x30+HW_MAJOR);
rcall putc
ldi u_data,0x30+HW_MINOR ; putc(0x30+HW_MINOR);
rcall putc
rjmp waitcmd
;**** Show Supported Devices ****
w3: cpi u_data,0x74 ; 't' Show supported devices
brne w4
ldi u_data,S1200C ; putc(S1200C);
rcall putc
ldi u_data,S1200D ; putc(S1200D);
rcall putc
ldi u_data,S8515A ; putc(S8515A);
rcall putc
ldi u_data,S8252 ; putc(S8252);
rcall putc
ldi u_data,0x00 ; putc(0x00); // end of device list
rcall putc
rjmp waitcmd
;**** Return Programmer Type ****
w4: cpi u_data,0x70 ; 'p' Return programmer type
brne w5
ldi u_data,0x53 ; putc('S'); // serial programmer
rcall putc
rjmp waitcmd
;**** Set LED ****
w5: cpi u_data,0x78 ; 'x' Set LED (ignored)
brne w6
rjmp put_ret
;**** Clear LED ****
w6: cpi u_data,0x79 ; 'y' Clear LED (ignored)
brne w7
rjmp put_ret
;**** Enter Programming Mode ****
; We require that the device code be selected before any of the other commands
w7: cpi device,S1200C ; if ((device != S1200C) &&
breq w72
cpi device,S1200D ; (device != S1200D) &&
breq w72
cpi device,S8515A ; (device != S8515A) &&
breq w72
cpi device,S8252 ; (device != S8252))
breq w72
rjmp put_err ; goto put_err();
w72: cpi u_data,0x50 ; 'P' Enter programming mode
brne w8
rcall spiinit ; spiinit();
rjmp put_ret
;**** Wait Program Memory ****
;* USAGE
;* wait_pm(byte cmd, byte c_data);
;*
;* cmd : 0x28 - wait for high byte written
;* 0x20 - wait for low byte written
;* u_data : current data written
;wait_pm: ; do
; ; {
; mov s_data,cmd ; wrser(cmd); // SPI write (byte 1)
; rcall wrser
; mov s_data,addrh ; wrser(addrh); // SPI write (byte 2)
; rcall wrser
; mov s_data,addrl ; wrser(addrl); // SPI write (byte 3)
; rcall wrser
; rcall rdser ; s_data = rdser(); // SPI read (byte 4)
; }
; cp s_data,u_data ; while(s_data != u_data);
; brne wait_pm
; ret
;**** Write Program Memory, High Byte ****
w8: cpi u_data,0x43 ; 'C' Write program memory, high byte
brne w9
rcall getc
cpi device,S8252 ; if (device == S8252)
brne w81 ; {
rjmp put_err ; goto err();
; // (AT89 series have byte wide program memory !)
; }
w81: ldi s_data,0x48 ; wrser(0x48); // SPI write (byte 1)
rcall wrser
mov s_data,addrh ; wrser(addrh); // SPI write (byte 2)
rcall wrser
mov s_data,addrl ; wrser(addrl); // SPI write (byte 3)
rcall wrser
mov s_data,u_data ; wrser(u_data); // SPI write (byte 4)
rcall wrser
ldi temp1,0x20 ; delay(0x20); // 24585 cycles delay
rcall delay
; ldi cmd,0x28
; sbi PORTB,PB3 ; DEBUG!!!!!
; rcall wait_pm
; cbi PORTB,PB3 ; DEBUG!!!!!
rjmp put_ret ; goto reply();
;**** Write Program Memory, Low Byte ****
w9: cpi u_data,0x63 ; 'c' Write program memory, low byte
brne w10
rcall getc
cpi device,S8252 ; if (device != S8252)
breq w989 ; {
ldi s_data,0x40 ; wrser(0x40); // SPI write (byte 1)
rcall wrser
mov s_data,addrh ; s_data = addrh;
rjmp w91 ; }
; else
w989: ; {
mov s_data,addrh ; s_data = (addrh << 3) | 0x02;
lsl s_data
lsl s_data
lsl s_data
ori s_data,0x02
w91: ; }
rcall wrser ; wrser(s_data); // SPI write (byte 2)
mov s_data,addrl ; wrser(addrl); // SPI write (byte 3)
rcall wrser
mov s_data,u_data ; wrset(u_data); // SPI write (byte 4)
rcall wrser
ldi temp1,0x20 ; delay(0x20); // 24585 cycles delay
rcall delay
; ldi cmd,0x20
; sbi PORTB,PB3 ; DEBUG!!!!!
; rcall wait_pm
; cbi PORTB,PB3 ; DEBUG!!!!!
rjmp put_ret ; goto reply();
;**** Read Program Memory ****
w12: cpi u_data,0x52 ; 'R' Read program memory
brne w13
cpi device,S8252 ; if (device != S8252)
breq w1289 ; {
ldi s_data,0x28 ; wrser(0x28); // SPI write (byte 1)
rcall wrser
mov s_data,addrh ; s_data = addrh;
rjmp w121 ; }
; else
w1289: ; {
mov s_data,addrh ; s_data = (addrh << 3) | 0x01;
lsl s_data
lsl s_data
lsl s_data
ori s_data,0x01
w121: ; }
rcall wrser ; wrser(s_data); // SPI write (byte 2)
mov s_data,addrl ; wrser(addrl); // SPI write (byte 3)
rcall wrser
rcall rdser ; putc(rdser()); // Send data (byte 4)
mov u_data,s_data
rcall putc
cpi device,S8252 ; if (device == S8252)
brne w122 ; {
rjmp waitcmd ; goto waitcmd();
; }
; else
w122: ; {
ldi s_data,0x20 ; wrser(0x20); // SPI write (byte 1)
rcall wrser
mov s_data,addrh ; wrser(addrh); // SPI write (byte 2)
rcall wrser
mov s_data,addrl ; wrser(addrl); // SPI write (byte 3)
rcall wrser
rcall rdser ; putc(rdser()); // Send data (byte 4)
mov u_data,s_data
rcall putc
rjmp waitcmd ; goto waitcmd();
; }
;**** Load Address ****
w10: cpi u_data,0x41 ; 'A' Load address
brne w11
rcall getc ; addrh = getc();
mov addrh,u_data
rcall getc ; addrl = getc();
mov addrl,u_data
rjmp put_ret ; goto reply();
;**** Write Data Memory ****
w11: cpi u_data,0x44 ; 'D' Write data memory
brne w12
rcall getc
cpi device,S8252
breq w1189
ldi s_data,0xc0
rcall wrser
mov s_data,addrh
rjmp w111
w1189: mov s_data,addrh
lsl s_data
lsl s_data
lsl s_data
ori s_data,0x06
w111: rcall wrser
mov s_data,addrl
rcall wrser
mov s_data,u_data
rcall wrser
ldi temp1,0x20
rcall delay
rjmp put_ret
;;**** Read Data Memory ****
w13: cpi u_data,0x64 ; 'd' Read data memory
brne w14
cpi device,S8252 ; if (device != S8252)
breq w1389 ; {
ldi s_data,0xa0 ; wrser(0xA0); // SPI write (byte 1)
rcall wrser
mov s_data,addrh ; s_data = addrh;
rjmp w131 ; }
; else
w1389: ; {
mov s_data,addrh ; s_data = (addrh << 3) | 0x05;
lsl s_data
lsl s_data
lsl s_data
ori s_data,0x05
w131: ; }
rcall wrser ; wrser(s_data); // SPI write (byte 2)
mov s_data,addrl ; wrser(addrl); // SPI write (byte 3)
rcall wrser
rcall rdser ; putc(rdser()); // Send data (byte 4)
mov u_data,s_data
rcall putc
rjmp waitcmd ; goto waitcmd();
;**** Leave Programming Mode ****
w14: cpi u_data,0x4c ; 'L' Leave programming mode
brne w15
cpi device,S8252
breq w141
set_reset ; set RESET = 1
rjmp put_ret
w141: clr_reset ; set RESET = 0
rjmp put_ret
;**** Chip Erase ****
w15: cpi u_data,0x65 ; 'e' Chip erase
brne w16
ldi s_data,0xac
rcall wrser
cpi device,S8252
breq w1589
ldi s_data,0x80
rcall wrser
w1589: ldi s_data,0x04
rcall wrser
ldi s_data,0x00
rcall wrser
ldi temp1,0x30
rcall delay
rjmp put_ret
;**** Write Lock Bits ****
w16: cpi u_data,0x6c ; 'l' Write lock bits
brne w17
rcall getc
ldi s_data,0xac
rcall wrser
mov s_data,u_data
cpi device,S8252
breq w1689
andi s_data,0x06
ori s_data,0xe0
rcall wrser
ldi s_data,0x00
rcall wrser
rjmp w162
w1689: andi s_data,0xe0
ori s_data,0x07
rcall wrser
w162: ldi s_data,0x00
rcall wrser
ldi temp1,0x30
rcall delay
rjmp put_ret
;**** Read Signature Bytes ****
w17: cpi u_data,0x73 ; 's' Read signature bytes
brne w99
cpi device,S8252
breq put_err
ldi s_data,0x30
rcall wrser
ldi s_data,0x00
rcall wrser
ldi s_data,0x02
rcall wrser
rcall rdser
mov u_data,s_data
rcall putc
ldi s_data,0x30
rcall wrser
ldi s_data,0x00
rcall wrser
ldi s_data,0x01
rcall wrser
rcall rdser
mov u_data,s_data
rcall putc
ldi s_data,0x30
rcall wrser
ldi s_data,0x00
rcall wrser
ldi s_data,0x00
rcall wrser
rcall rdser
mov u_data,s_data
rcall putc
rjmp waitcmd
w99: rjmp put_err
;**** Reply Command ****
put_ret:ldi u_data,0x0d ; putc(0x0D); \\ send CR
rcall putc
rjmp waitcmd
;**** Command Error ****
put_err:ldi u_data,0x3f ; putc('?'); \\ send '?'
rcall putc
rjmp waitcmd
;**** End of File ****