;**** 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 ****