Full Version : Simple Serial Programmer for AVRs
avr >>TECHNICAL & HARDWARE >>Simple Serial Programmer for AVRs


AVR_Admin- 04-28-2006
BUILD A SIMPLE SERIAL PROGRAMMER FOR AVR DEVICES by Dick Cappel

Note that the AVR910 programmer does not support all AVR processors, especially the newest chips. Be sure to check the documentation to see if it supports the version(s) of the processor you are interested in.

Atmel described a simple programmer based on the AT90S1200 (NOT the AT90S1200A) controller in their application note, AVR910 (a modification to use the AT90S2313 is also given below).

The circuit is so small and simple, I was able to put two of them together without using a printed circuit board, taking only about an hour to assemble each one. Both worked fine without any hitches.

These programmers are compatible with RS-232 ports, cost well under $10 US to build, and program AVR chips in the serial mode (and thus is not able to access programming options only available in parallel mode -read those data sheets!). It connects to a target controller via a 6 pin cable. The target controller needs to have its own clock and power supply. The target also supplies power to the programmer.

The 6 pin cable as well as the rest of the system is clearly explained in the AVR910 application note. The programmer works seamlessly with the programmer application that comes with the AVR Studio package and also seamlessly with MacAVRpa, an assembler/programmer application for the Macintosh.

Though several web sites mentioned the programmer, even after finding the application note, I still had questions, so I decided to put the bulk of the information here for anyone who might be starting down the same road. In addition to the electronic components, you need these things to build and use the programmer based on the AVR910 application note.

Link to Site: http://cappels.org/dproj/910page/avr910.htm

AVR_Admin- 04-28-2006
ASSEMBLLY CODE for AT90S1200

CODE

;***************************************************************************
;*
;* Title : AVR ISP (Auto adr inc, 19200bps)
;* Version : 2.2
;* Last updated : May 31 2000 (pkastnes)
;* Target : AT90S1200
;* File  : avr910.asm
;* Author(s) : Ole Saether, Terje Frostad,
;*    Ingar Fredriksen, Morten W. Lund
;*                Haakon Skar, Paal Kastnes
;*
;* 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  |
;* | Report autoincrement address      | 'a' |       |      | 'Y' |      |
;* | 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  |
;* | Issue Page Write                  | 'm' |       |      | 13d |      |
;* | 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  |
;* | Universial command                | ':' |  3*dd |   dd | 13d |      |
;* | New universal command         | '.' |  4*dd |   dd | 13d |      |
;* | Special test command          | 'Z' |  2*dd |   dd |     |      |
;* +-----------------------------------+-----+-------+------+-----+------+
;*
;* 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.
;*
;* NOTE 13
;*      Devices using Page Mode Programming write one page of flash memory
;*      before issuing a Page Mode Write Pulse.
;*
;* HISTORY
;*      V2.2    00.03.10 (pkastnes)     Added support for multiple new devices
;* V2.1 98.10.26 (mlund) New date marking.
;*     Removed support for AT90S1200C.
;*     Added support for AT90S4433A.
;* V2.0 98.01.06 (mlund) ATmega103 support
;* V1.7 97.11.06 (mlund) Universial command (':') implemented.
;*     Releases all pins when not in
;*     programming mode.
;* V1.6e 97.11.04 (mlund) mega103 rev D support
;* V1.6c 97.10.30 (mlund) Auto incrementing / SPI sync
;*     also works for mega103.
;*      V1.6 97.09.09 (hskar) Created Page Mode Version (mega103)
;* V1.5 97.08.21 (mlund) Modified / Bugfix / Major cleanup
;* ... ...   (no records)
;* V?.? 97.03.15 (OS)  Created
;*
;*
;*  
;* Device Support List    
;* -------------------
;*
;* +-------+----------+------+-------+------+------+------+-------+
;* |Device |Signature | Code | Flash |EEProm| Lock | Fuse | PMode |
;* +-------+----------+------+-------+------+------+------+-------+
;* |tiny12 | 1E 90 05 | 0x55 |  R/W  | R/W  | R/W  | R/W  | Byte  |
;* |tiny15 | 1E 90 06 | 0x56 |  R/W  | R/W  | R/W  | R/W  | Byte  |
;* |       |          |      |       |      |      |      |       |
;* | S1200 | 1E 90 01 | 0x13 |  R/W  | R/W  |  W   | NA   | Byte  |
;* |       |          |      |       |      |      |      |       |
;* | S2313 | 1E 91 01 | 0x20 |  R/W  | R/W  |  W   | NA   | Byte  |
;* | S2323 | 1E 91 02 | 0x48 |  R/W  | R/W  | R/W  | R/W  | Byte  |    
;* | S2333 | 1E 91 05 | 0x34 |  R/W  | R/W  | R/W  | R/W  | Byte  |    
;* | S2343 | 1E 91 03 | 0x4C |  R/W  | R/W  | R/W  | R/W  | Byte  |    
;* |       |          |      |       |      |      |      |       |
;* | S4414 | 1E 92 01 | 0x28 |  R/W  | R/W  |  W   | NA   | Byte  |    
;* | S4433 | 1E 92 03 | 0x30 |  R/W  | R/W  | R/W  | R/W  | Byte  |    
;* | S4434 | 1E 92 02 | 0x6C |  R/W  | R/W  | R/W  | R/W  | Byte  |    
;* |       |          |      |       |      |      |      |       |
;* | S8515 | 1E 93 01 | 0x38 |  R/W  | R/W  |  W   | NA   | Byte  |    
;* | S8535 | 1E 93 03 | 0x68 |  R/W  | R/W  | R/W  | R/W  | Byte  |    
;* |       |          |      |       |      |      |      |       |
;* |mega83 | 1E 93 05 | 0x65 |  R/W  | R/W  | R/W  | R/W  | Page  |    
;* |mega103| 1E 97 01 | 0x41 |  R/W  | R/W  | R/W  | R/W  | Page  |    
;* |mega161| 1E 94 01 | 0x60 |  R/W  | R/W  | R/W  | R/W  | Page  |    
;* |mega163| 1E 94 02 | 0x64 |  R/W  | R/W  | R/W  | R/W  | Page  |    
;* +-------+----------+------+-------+------+------+------+-------+
;*
;* LEGEND:
;* -------
;* Signature - Device Signature Byte
;* Code      - Unique device code used by AVRProg to identify device
;* Flash     - Flash size in bytes
;* EEProm    - EEProm size in bytes
;* Lock      - Lockbits
;* Fuse      - Fusebits
;* PMode     - Indicates if device uses byte or page programming mode
;*
;* R/W - Read and Write Access
;* R   - Read Access Only
;* W   - Write Access Only
;* NA  - Not Accessible
;*
;***************************************************************************

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

.equ tn12 = 0x55
.equ tn15 = 0x56
.equ S1200D = 0x13
.equ S2313A = 0x20
.equ S4414A = 0x28
.equ S8515A = 0x38
.equ S2323A = 0x48
.equ S2343A = 0x4C
.equ S2333A = 0x34
.equ S4433A = 0x30
.equ S4434 = 0x6C
.equ S8535 = 0x68
.equ m83 = 0x65
.equ m161 = 0x60
.equ m163 = 0x64
.equ m603 = 0x42
.equ m103 = 0x41

;**** Revision Codes ****

.equ SW_MAJOR = '2' ; Major SW revision number
.equ SW_MINOR = '2' ; 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.
;*
;***************************************************************************

.equ resetpin = 4

.macro set_reset
sbi portb,resetpin
.endm

.macro clr_reset
cbi portb,resetpin
.endm

.macro ddrd_init
nop
; sbi ddrd,3
.endm

.macro ddrb_init
ldi temp1,(0xFF ^ (1<<MISO))
out ddrb,temp1; PB5 is input, the rest is output
.endm

.macro ddrb_release
ldi temp1,(1<<resetpin)
out ddrb,temp1; PB4 (RESET) is output, the rest is input
.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 ; Receive pin must be external interrupt !!

;**** 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 param1  = r27
.def cmd1  = r28
.def cmd2  = r29
.def cmd3  = r30
.def rd_s_data = R31

;*********************
;* Interrupt Vectors *
;*********************

.CSEG
rjmp RESET ; Reset Handle
.org OVF0addr
rjmp TIM0_OVF; Timer0 Overflow Handle


;***************************************************************************
;*
;* INTERRUPT
;* TIM0_OVF - Software UART Service Routine
;*
;***************************************************************************

TIM0_OVF:
in r0,SREG ; store SREG
ldi temp1,(256-N+8)
out TCNT0,temp1; reset T/C0 to one bit length
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<<RXC;    set receive complete
to_1:   ; }
out SREG,r0        ; restore SREG
reti  ; exit

transmit:
cpi bit_cnt,1; if (bit_cnt == 1) \\ start bit
brne to_2 ; {
cbi PORTD,TXPIN; generate start bit
rjmp to_1 ; exit
to_2:   ; }
cpi bit_cnt,10; if (bit_cnt == 10) \\ stop bit
brne to_3 ; {
sbi PORTD,TXPIN; generate stop bit
clr temp1 ; disable TC0 overflow interrupt
out TIMSK,temp1
sbr u_stat,1<<TXC; set transmit complete bit
rjmp to_1 ; exit
to_3:   ; }
sbrc u_data,0; if (LSB set)
sbi PORTD,TXPIN; PD3 = HIGH
sbrs u_data,0; if (LSB clear)
cbi PORTD,TXPIN; PD3 = LOW
lsr u_data ; shift left u_data
rjmp to_1 ; exit


;***************************************************************************
;*
;* FUNCTION
;* u_init
;*
;* DESCRIPTION
;* Initialize UART.
;*
;***************************************************************************

u_init:
ldi u_stat,1<<TXC; set TXC
ldi temp1,R ; set clock rate
out TCCR0,temp1
sbi DDRD,TXPIN; initialize UART pins
cbi DDRD,RXPIN
ret


;***************************************************************************
;*
;* FUNCTION
;* putc
;*
;* DESCRIPTION
;* Send a character on the UART Tx line.
;*
;***************************************************************************

putc:
clr u_stat ; clear UART status flags
clr bit_cnt ; clear bit counter
ldi temp1,1<<TOV0; enable T/C0 overflow interrupt
out TIMSK,temp1
putc0:
sbrs u_stat,TXC; while (!(u_stat & TXC)); // Wait for TXC
rjmp putc0
ret


;***************************************************************************
;*
;* FUNCTION
;* getc
;*
;* DESCRIPTION
;* Wait for start bit and receive a character on the UART Rx line.
;*
;***************************************************************************

getc:
sbis PIND,RXPIN
rjmp getc
getc0:
sbic PIND,RXPIN
rjmp getc0
ldi temp1,(256-(N+N/2)+8+12);
out TCNT0,temp1 ; preset T/C0 to 1.5 bit lengths
ldi temp1,1<<TOIE0
out TIFR,temp1; clear T/C0 overflow flag
out TIMSK,temp1; enable T/C0 overflow Interrupt
clr bit_cnt ; clear bit counter
getc1:
sbrs u_stat,RXC; wait for Receive Complete
rjmp getc1
cbr u_stat,1<<RXC; clear RXC
ret


;***************************************************************************
;*
;* FUNCTION
;* delay
;*
;* DESCRIPTION
;*  Make a small delay.
;*
;***************************************************************************

delay:
ldi temp2,0xff
dl:
dec temp2
brne dl
dec temp1
brne delay
ret


;***************************************************************************
;*
;* FUNCTION
;* wrser
;*
;* DESCRIPTION
;*  Write and read bytes on the SPI.
;*
;***************************************************************************
rdser:
clr s_data

wrser:
ldi temp1,8
ldi rd_s_data,0
wrs0:
rol s_data
brcc wrs1
sbi portb,MOSI
rjmp wrs2
wrs1:
cbi portb,MOSI
wrs2:
lsl rd_s_data
sbic pinb,MISO
ori rd_s_data,1

pulse_sck
dec temp1
brne wrs0
mov s_data,rd_s_data
ret

;***************************************************************************
;*
;* FUNCTION
;* spiinit (Enter programming mode)
;*
;* DESCRIPTION
;* Initialize SPI interface on AVR or 'AT89 device.
;*
;***************************************************************************

spiinit:
ddrd_init ; initialize port D
ddrb_init ; initialize port B
cbi portb,SCK; clear SCK
set_reset ; set RESET = 1
ldi temp1,0xff; delay(0xff);
rcall delay
clr_reset ; set RESET = 0

ldi temp1,0xff; delay(0xff);
rcall delay

ldi s_data,0xac; wrser(0xac);  // SPI write (byte 1)
rcall wrser
ldi s_data,0x53; wrser(0x53);  // SPI write (byte 2)
rcall wrser

  ; // SPI Synchronization (fix!)
cpi device,0x20; if ( (device >= 0x20) && (device <= 0x7F) )
brlo s2
tst device
brmi s2
s0b:   ; {
ldi count,32; count = 32;
s1:   ; do {
rcall rdser ;  if (rdser == 0x53) // SPI read (byte 3)
cpi s_data,0x53
breq s3 ;   break;
ldi s_data,0x00;  wrser(0x00);  // SPI write (byte 4)
rcall wrser
pulse_sck ;  pulse SCK
ldi s_data,0xac;  wrser(0xac);  // SPI write (byte 1)
rcall wrser
ldi s_data,0x53;  wrser(0x53);  // SPI write (byte 2)
rcall wrser
dec count ; } while(--count);
brne s1
rjmp s3 ; }
  ; else
s2:   ; {
ldi s_data,0x00; wrser(0x00);  // SPI write (byte 3)
rcall wrser
s3:   ; }
ldi s_data,0x00; wrser(0x00); // SPI write (byte 4)
rcall wrser

ldi temp1,0x10; delay(0x10);
rcall delay
ret

;***************************************************************************
;*
;* FUNCTION
;* show_id
;*
;* DESCRIPTION
;* Show our ID ("AVR ISP") on the serial line.
;*
;***************************************************************************

show_id:
ldi u_data,0x41 ; 'A'
rcall putc
ldi u_data,0x56 ; 'V'
rcall putc
ldi u_data,0x52 ; 'R'
rcall putc
ldi u_data,0x20 ; ' '
rcall putc
ldi u_data,0x49 ; 'I'
rcall putc
ldi u_data,0x53 ; 'S'
rcall putc
ldi u_data,0x50 ; 'P'
rcall putc
ret


;***************************************************************************
;*
;* RESET
;*
;* DESCRIPTION
;* Initialization
;*
;***************************************************************************

RESET:
clr temp1
out GIMSK,temp1; disable external interrupt
ser temp1 ; Initialize
out PORTD,temp1
set_reset ; set RESET=1
out PORTB,temp1
ddrb_release
rcall u_init ; Initialize UART
sei  ; Enable interrupts


;***************************************************************************
;*
;* PROGRAM
;* waitcmd -> 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,SW_MAJOR
rcall putc
ldi u_data,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,tn12; putc(tiny12);
rcall putc
ldi u_data,tn15; putc(tiny15);
rcall putc
ldi u_data,S1200D; putc(S1200D);
rcall putc
ldi u_data,S2313A; putc(S2313A);
rcall putc
ldi u_data,S4414A; putc(S4414A);
rcall putc
ldi u_data,S8515A; putc(S8515A);
rcall putc
ldi u_data,S2323A; putc(S2323A);
rcall putc
ldi u_data,S2343A; putc(S2343A);
rcall putc
ldi u_data,S2333A; putc(S2333A);
rcall putc
ldi u_data,S4433A; putc(S4433A);
rcall putc
ldi u_data,S4434; putc(S4434);
rcall putc
ldi u_data,S8535; putc(S8535);
rcall putc
ldi u_data,m83; putc(m83);
rcall putc
ldi u_data,m161; putc(mega161);
rcall putc
ldi u_data,m163; putc(mega163);
rcall putc
ldi u_data,m103; putc(mega103);
rcall putc
ldi u_data,m603; putc(mega603);
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 w51
ldi u_data,0x53    ; putc('S'); // serial programmer
rcall putc
rjmp waitcmd

;**** Return autoincrement address support

w51:
cpi u_data,'a'; 'a' Return address auto increment
brne w5
ldi u_data,'Y'; putc('Y');  // supports autoinc
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,tn12; if ((device != tn12) &&
breq w72
cpi device,tn15; if ((device != tn15) &&
breq w72
cpi device,S1200D; if ((device != S1200D) &&
breq w72
cpi device,S2313A; (device != S2313A) &&
breq w72
cpi device,S4414A; (device != S4414A) &&
breq w72
cpi device,S8515A; (device != S8515A) &&
breq w72
cpi device,S2323A; (device != S2323A))
breq w72
cpi device,S2343A; (device != S2343A))
breq w72
cpi device,S2333A; (device != S2333A) &&
breq w72
cpi device,S4433A; (device != S4433A) &&
breq w72
cpi device,S4434; (device != S4434A) &&
breq w72
cpi device,S8535; (device != S8535) &&
breq w72
cpi device,m83; (device != m83) &&
breq w72
cpi device,m161; (device != m161) &&
breq w72
cpi device,m163; (device != m163) &&
breq w72
cpi device,m603; (device != m603) &&
breq w72
cpi device,m103; (device != m103) &&
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
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,0x01; Auto increment address    !!!!
clr temp2
add addrl,temp1
adc addrh,temp2

rjmp writeFLASHdelay

;**** Write Program Memory, Low Byte ****

w9:
cpi u_data,0x63    ; 'c' Write program memory, low byte
brne w12
rcall getc

ldi s_data,0x40; wrser(0x40); // SPI write (byte 1)
rcall wrser
mov s_data,addrh; s_data = addrh;
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; wrser(u_data); // SPI write (byte 4)
rcall wrser

writeFLASHdelay:
cpi device,m103
breq w92
cpi device,m83
breq w92
cpi device,m603
breq w92
cpi device,m161
breq w92
cpi device,m163
breq w92

ldi temp1,0x20; delay(0x20);  // 24585 cycles delay
rcall delay ;   // Page mode requires no delay!
w92:
rjmp put_ret ; goto reply();

;**** Read Program Memory ****

w12:
cpi u_data,0x52; 'R' Read program memory
brne w10 ;
ldi s_data,0x28; wrser(0x28); // SPI write (byte 1)
rcall wrser
mov s_data,addrh; s_data = addrh;
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

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 readaddrinc
;**** 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 w13
rcall getc

ldi s_data,0xc0
rcall wrser
mov s_data,addrh
rcall wrser
mov s_data,addrl
rcall wrser
mov s_data,u_data
rcall wrser
ldi temp1,0x20
rcall delay

ldi temp1,0x01; Auto increment address    !!!!
clr temp2
add addrl,temp1
adc addrh,temp2

rjmp put_ret

;;**** Read Data Memory ****

w13:
cpi u_data,0x64; 'd' Read data memory
brne w14
ldi s_data,0xa0; wrser(0xA0); // SPI write (byte 1)
rcall wrser
mov s_data,addrh; s_data = addrh;
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

readaddrinc:
ldi temp1,0x01; Auto increment address    !!!!
clr temp2
add addrl,temp1
adc addrh,temp2

rjmp waitcmd ; goto waitcmd();


;**** Leave Programming Mode ****

w14:
cpi u_data,0x4c; 'L' Leave programming mode
brne w15
ddrb_release
set_reset ; set RESET = 1
rjmp    put_ret

;**** Chip Erase ****

w15:
cpi u_data,0x65    ; 'e' Chip erase
       brne w16
ldi s_data,0xac
rcall wrser
ldi s_data,0x80
rcall wrser
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
andi s_data,0x06
ori s_data,0xe0
rcall wrser
ldi s_data,0x00
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 w18
ldi param1,0x02
rcall w17call
ldi param1,0x01
rcall w17call
ldi param1,0x00
rcall w17call
rjmp waitcmd

w17call:
ldi s_data,0x30
rcall wrser
ldi s_data,0x00
rcall wrser
mov s_data,param1
rcall wrser
rcall rdser
mov u_data,s_data
rcall putc
ret


;**** Write Program Memory Page ****

w18:
cpi u_data,0x6D; 'm' Write Program Memory Page
brne w19

ldi s_data,0x4c; wrser(0x4c); // 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

ldi s_data,0x00; wrser(0x00); // SPI write (byte 4)
rcall wrser
ldi temp1,0xff;  delay(0xFF); // 0x20 = 24585 cycles delay
rcall delay
rjmp put_ret

;**** Universal Command ****

w19:
cpi u_data,0x3A; ':' Universal Command
brne w191

rcall getc
mov cmd1,u_data
rcall getc
mov cmd2,u_data
rcall getc
mov cmd3,u_data
clr u_data
rcall NewUniversal
ldi temp1,0xff;  delay(0xFF); // 0x20 = 24585 cycles delay
rcall delay
rjmp put_ret

;**** New Universal Command ****

w191:
cpi u_data,'.'; '.' New Universal Command
brne w99

rcall getc
mov cmd1,u_data
rcall getc
mov cmd2,u_data
rcall getc
mov cmd3,u_data
rcall getc
rcall NewUniversal
ldi temp1,0xff;  delay(0xFF); // 0x20 = 24585 cycles delay
rcall delay
rjmp put_ret

NewUniversal:
mov s_data,cmd1
rcall wrser
mov s_data,cmd2
rcall wrser
mov s_data,cmd3
rcall wrser
mov s_data,u_data
rcall wrser

mov u_data,rd_s_data

rcall putc
ret
w99:

;**** Command Error ****

put_err:
ldi u_data,0x3f; putc('?'); \\ send '?'
rcall putc
rjmp waitcmd

;**** Reply Command ****

put_ret:
ldi u_data,0x0d; putc(0x0D); \\ send CR
rcall putc
rjmp waitcmd

delay1us:  ;    count               R16
       nop                                                      
       cpi     temp1,0x03
       breq    finished
       nop
       nop
loop:  
dec     temp1
       cpi     temp1,0x03
       brne    loop              
finished:
       ret    

;**** End of File ****

AVR_Admin- 04-28-2006
ASSEMBLY CODE for AT90S2313

CODE

; MODIFIED TO RUN ON THE AT90S2313 by Dick Cappel
;
;***************************************************************************
;*
;* Title : AVR ISP (Auto adr inc, 19200bps)
;* Version : 2.2
;* Last updated : May 31 2000 (pkastnes)
;* Target : AT90S1200
;* File  : avr910.asm
;* Author(s) : Ole Saether, Terje Frostad,
;*    Ingar Fredriksen, Morten W. Lund
;*                Haakon Skar, Paal Kastnes
;*
;* 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  |
;* | Report autoincrement address      | 'a' |       |      | 'Y' |      |
;* | 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  |
;* | Issue Page Write                  | 'm' |       |      | 13d |      |
;* | 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  |
;* | Universial command                | ':' |  3*dd |   dd | 13d |      |
;* | New universal command        | '.' |  4*dd |   dd | 13d |      |
;* | Special test command        | 'Z' |  2*dd |   dd |     |      |
;* +-----------------------------------+-----+-------+------+-----+------+
;*
;* 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.
;*
;* NOTE 13
;*      Devices using Page Mode Programming write one page of flash memory
;*      before issuing a Page Mode Write Pulse.
;*
;* HISTORY
;*      V2.2    00.03.10 (pkastnes)     Added support for multiple new devices
;* V2.1 98.10.26 (mlund) New date marking.
;*     Removed support for AT90S1200C.
;*     Added support for AT90S4433A.
;* V2.0 98.01.06 (mlund) ATmega103 support
;* V1.7 97.11.06 (mlund) Universial command (':') implemented.
;*     Releases all pins when not in
;*     programming mode.
;* V1.6e 97.11.04 (mlund) mega103 rev D support
;* V1.6c 97.10.30 (mlund) Auto incrementing / SPI sync
;*     also works for mega103.
;*      V1.6 97.09.09 (hskar) Created Page Mode Version (mega103)
;* V1.5 97.08.21 (mlund) Modified / Bugfix / Major cleanup
;* ... ...   (no records)
;* V?.? 97.03.15 (OS)  Created
;*
;*
;*  
;* Device Support List    
;* -------------------
;*
;* +-------+----------+------+-------+------+------+------+-------+
;* |Device |Signature | Code | Flash |EEProm| Lock | Fuse | PMode |
;* +-------+----------+------+-------+------+------+------+-------+
;* |tiny12 | 1E 90 05 | 0x55 |  R/W  | R/W  | R/W  | R/W  | Byte  |
;* |tiny15 | 1E 90 06 | 0x56 |  R/W  | R/W  | R/W  | R/W  | Byte  |
;* |       |          |      |       |      |      |      |       |
;* | S1200 | 1E 90 01 | 0x13 |  R/W  | R/W  |  W   | NA   | Byte  |
;* |       |          |      |       |      |      |      |       |
;* | S2313 | 1E 91 01 | 0x20 |  R/W  | R/W  |  W   | NA   | Byte  |
;* | S2323 | 1E 91 02 | 0x48 |  R/W  | R/W  | R/W  | R/W  | Byte  |    
;* | S2333 | 1E 91 05 | 0x34 |  R/W  | R/W  | R/W  | R/W  | Byte  |    
;* | S2343 | 1E 91 03 | 0x4C |  R/W  | R/W  | R/W  | R/W  | Byte  |    
;* |       |          |      |       |      |      |      |       |
;* | S4414 | 1E 92 01 | 0x28 |  R/W  | R/W  |  W   | NA   | Byte  |    
;* | S4433 | 1E 92 03 | 0x30 |  R/W  | R/W  | R/W  | R/W  | Byte  |    
;* | S4434 | 1E 92 02 | 0x6C |  R/W  | R/W  | R/W  | R/W  | Byte  |    
;* |       |          |      |       |      |      |      |       |
;* | S8515 | 1E 93 01 | 0x38 |  R/W  | R/W  |  W   | NA   | Byte  |    
;* | S8535 | 1E 93 03 | 0x68 |  R/W  | R/W  | R/W  | R/W  | Byte  |    
;* |       |          |      |       |      |      |      |       |
;* |mega83 | 1E 93 05 | 0x65 |  R/W  | R/W  | R/W  | R/W  | Page  |    
;* |mega103| 1E 97 01 | 0x41 |  R/W  | R/W  | R/W  | R/W  | Page  |    
;* |mega161| 1E 94 01 | 0x60 |  R/W  | R/W  | R/W  | R/W  | Page  |    
;* |mega163| 1E 94 02 | 0x64 |  R/W  | R/W  | R/W  | R/W  | Page  |    
;* +-------+----------+------+-------+------+------+------+-------+
;*
;* LEGEND:
;* -------
;* Signature - Device Signature Byte
;* Code      - Unique device code used by AVRProg to identify device
;* Flash     - Flash size in bytes
;* EEProm    - EEProm size in bytes
;* Lock      - Lockbits
;* Fuse      - Fusebits
;* PMode     - Indicates if device uses byte or page programming mode
;*
;* R/W - Read and Write Access
;* R   - Read Access Only
;* W   - Write Access Only
;* NA  - Not Accessible
;*
;***************************************************************************

;**** includes ****

.include "2313def.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.
;*
;***************************************************************************

.equ tn12 = 0x55
.equ tn15 = 0x56
.equ S1200D = 0x13
.equ S2313A = 0x20
.equ S4414A = 0x28
.equ S8515A = 0x38
.equ S2323A = 0x48
.equ S2343A = 0x4C
.equ S2333A = 0x34
.equ S4433A = 0x30
.equ S4434 = 0x6C
.equ S8535 = 0x68
.equ m83 = 0x65
.equ m161 = 0x60
.equ m163 = 0x64
.equ m603 = 0x42
.equ m103 = 0x41

;**** Revision Codes ****

.equ SW_MAJOR = '2' ; Major SW revision number
.equ SW_MINOR = '2' ; 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.
;*
;***************************************************************************

.equ resetpin = 4

.macro set_reset
sbi portb,resetpin
.endm

.macro clr_reset
cbi portb,resetpin
.endm

.macro ddrd_init
nop
; sbi ddrd,3
.endm

.macro ddrb_init
ldi temp1,(0xFF ^ (1<<MISO))
out ddrb,temp1; PB5 is input, the rest is output
.endm

.macro ddrb_release
ldi temp1,(1<<resetpin)
out ddrb,temp1; PB4 (RESET) is output, the rest is input
.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 ; Receive pin must be external interrupt !!

;**** 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 param1  = r27
.def cmd1  = r28
.def cmd2  = r29
.def cmd3  = r30
.def rd_s_data = R31

;*********************
;* Interrupt Vectors *
;*********************

.CSEG
rjmp RESET ; Reset Handle
.org OVF0addr
rjmp TIM0_OVF; Timer0 Overflow Handle


;***************************************************************************
;*
;* INTERRUPT
;* TIM0_OVF - Software UART Service Routine
;*
;***************************************************************************

TIM0_OVF:
in r0,SREG ; store SREG
ldi temp1,(256-N+8)
out TCNT0,temp1; reset T/C0 to one bit length
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<<RXC;    set receive complete
to_1:   ; }
out SREG,r0        ; restore SREG
reti  ; exit

transmit:
cpi bit_cnt,1; if (bit_cnt == 1) \\ start bit
brne to_2 ; {
cbi PORTD,TXPIN; generate start bit
rjmp to_1 ; exit
to_2:   ; }
cpi bit_cnt,10; if (bit_cnt == 10) \\ stop bit
brne to_3 ; {
sbi PORTD,TXPIN; generate stop bit
clr temp1 ; disable TC0 overflow interrupt
out TIMSK,temp1
sbr u_stat,1<<TXC; set transmit complete bit
rjmp to_1 ; exit
to_3:   ; }
sbrc u_data,0; if (LSB set)
sbi PORTD,TXPIN; PD3 = HIGH
sbrs u_data,0; if (LSB clear)
cbi PORTD,TXPIN; PD3 = LOW
lsr u_data ; shift left u_data
rjmp to_1 ; exit


;***************************************************************************
;*
;* FUNCTION
;* u_init
;*
;* DESCRIPTION
;* Initialize UART.
;*
;***************************************************************************

u_init:
ldi u_stat,1<<TXC; set TXC
ldi temp1,R ; set clock rate
out TCCR0,temp1
sbi DDRD,TXPIN; initialize UART pins
cbi DDRD,RXPIN
ret


;***************************************************************************
;*
;* FUNCTION
;* putc
;*
;* DESCRIPTION
;* Send a character on the UART Tx line.
;*
;***************************************************************************

putc:
clr u_stat ; clear UART status flags
clr bit_cnt ; clear bit counter
ldi temp1,1<<TOV0; enable T/C0 overflow interrupt
out TIMSK,temp1
putc0:
sbrs u_stat,TXC; while (!(u_stat & TXC)); // Wait for TXC
rjmp putc0
ret


;***************************************************************************
;*
;* FUNCTION
;* getc
;*
;* DESCRIPTION
;* Wait for start bit and receive a character on the UART Rx line.
;*
;***************************************************************************

getc:
sbis PIND,RXPIN
rjmp getc
getc0:
sbic PIND,RXPIN
rjmp getc0
ldi temp1,(256-(N+N/2)+8+12);
out TCNT0,temp1 ; preset T/C0 to 1.5 bit lengths
ldi temp1,1<<TOIE0
out TIFR,temp1; clear T/C0 overflow flag
out TIMSK,temp1; enable T/C0 overflow Interrupt
clr bit_cnt ; clear bit counter
getc1:
sbrs u_stat,RXC; wait for Receive Complete
rjmp getc1
cbr u_stat,1<<RXC; clear RXC
ret


;***************************************************************************
;*
;* FUNCTION
;* delay
;*
;* DESCRIPTION
;*  Make a small delay.
;*
;***************************************************************************

delay:
ldi temp2,0xff
dl:
dec temp2
brne dl
dec temp1
brne delay
ret


;***************************************************************************
;*
;* FUNCTION
;* wrser
;*
;* DESCRIPTION
;*  Write and read bytes on the SPI.
;*
;***************************************************************************
rdser:
clr s_data

wrser:
ldi temp1,8
ldi rd_s_data,0
wrs0:
rol s_data
brcc wrs1
sbi portb,MOSI
rjmp wrs2
wrs1:
cbi portb,MOSI
wrs2:
lsl rd_s_data
sbic pinb,MISO
ori rd_s_data,1

pulse_sck
dec temp1
brne wrs0
mov s_data,rd_s_data
ret

;***************************************************************************
;*
;* FUNCTION
;* spiinit (Enter programming mode)
;*
;* DESCRIPTION
;* Initialize SPI interface on AVR or 'AT89 device.
;*
;***************************************************************************

spiinit:
ddrd_init ; initialize port D
ddrb_init ; initialize port B
cbi portb,SCK; clear SCK
set_reset ; set RESET = 1
ldi temp1,0xff; delay(0xff);
rcall delay
clr_reset ; set RESET = 0

ldi temp1,0xff; delay(0xff);
rcall delay

ldi s_data,0xac; wrser(0xac);  // SPI write (byte 1)
rcall wrser
ldi s_data,0x53; wrser(0x53);  // SPI write (byte 2)
rcall wrser

  ; // SPI Synchronization (fix!)
cpi device,0x20; if ( (device >= 0x20) && (device <= 0x7F) )
brlo s2
tst device
brmi s2
s0b:   ; {
ldi count,32; count = 32;
s1:   ; do {
rcall rdser ;  if (rdser == 0x53) // SPI read (byte 3)
cpi s_data,0x53
breq s3 ;   break;
ldi s_data,0x00;  wrser(0x00);  // SPI write (byte 4)
rcall wrser
pulse_sck ;  pulse SCK
ldi s_data,0xac;  wrser(0xac);  // SPI write (byte 1)
rcall wrser
ldi s_data,0x53;  wrser(0x53);  // SPI write (byte 2)
rcall wrser
dec count ; } while(--count);
brne s1
rjmp s3 ; }
  ; else
s2:   ; {
ldi s_data,0x00; wrser(0x00);  // SPI write (byte 3)
rcall wrser
s3:   ; }
ldi s_data,0x00; wrser(0x00); // SPI write (byte 4)
rcall wrser

ldi temp1,0x10; delay(0x10);
rcall delay
ret

;***************************************************************************
;*
;* FUNCTION
;* show_id
;*
;* DESCRIPTION
;* Show our ID ("AVR ISP") on the serial line.
;*
;***************************************************************************

show_id:
ldi u_data,0x41 ; 'A'
rcall putc
ldi u_data,0x56 ; 'V'
rcall putc
ldi u_data,0x52 ; 'R'
rcall putc
ldi u_data,0x20 ; ' '
rcall putc
ldi u_data,0x49 ; 'I'
rcall putc
ldi u_data,0x53 ; 'S'
rcall putc
ldi u_data,0x50 ; 'P'
rcall putc
ret


;***************************************************************************
;*
;* RESET
;*
;* DESCRIPTION
;* Initialization
;*
;***************************************************************************

RESET: ldi r16,RAMEND     ;Init Stack Pointer
out SPL,r16
       
clr temp1
out GIMSK,temp1; disable external interrupt
ser temp1 ; Initialize
out PORTD,temp1
set_reset ; set RESET=1
out PORTB,temp1
ddrb_release
rcall u_init ; Initialize UART
sei  ; Enable interrupts


;***************************************************************************
;*
;* PROGRAM
;* waitcmd -> 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,SW_MAJOR
rcall putc
ldi u_data,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,tn12; putc(tiny12);
rcall putc
ldi u_data,tn15; putc(tiny15);
rcall putc
ldi u_data,S1200D; putc(S1200D);
rcall putc
ldi u_data,S2313A; putc(S2313A);
rcall putc
ldi u_data,S4414A; putc(S4414A);
rcall putc
ldi u_data,S8515A; putc(S8515A);
rcall putc
ldi u_data,S2323A; putc(S2323A);
rcall putc
ldi u_data,S2343A; putc(S2343A);
rcall putc
ldi u_data,S2333A; putc(S2333A);
rcall putc
ldi u_data,S4433A; putc(S4433A);
rcall putc
ldi u_data,S4434; putc(S4434);
rcall putc
ldi u_data,S8535; putc(S8535);
rcall putc
ldi u_data,m83; putc(m83);
rcall putc
ldi u_data,m161; putc(mega161);
rcall putc
ldi u_data,m163; putc(mega163);
rcall putc
ldi u_data,m103; putc(mega103);
rcall putc
ldi u_data,m603; putc(mega603);
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 w51
ldi u_data,0x53    ; putc('S'); // serial programmer
rcall putc
rjmp waitcmd

;**** Return autoincrement address support

w51:
cpi u_data,'a'; 'a' Return address auto increment
brne w5
ldi u_data,'Y'; putc('Y');  // supports autoinc
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,tn12; if ((device != tn12) &&
breq w72
cpi device,tn15; if ((device != tn15) &&
breq w72
cpi device,S1200D; if ((device != S1200D) &&
breq w72
cpi device,S2313A; (device != S2313A) &&
breq w72
cpi device,S4414A; (device != S4414A) &&
breq w72
cpi device,S8515A; (device != S8515A) &&
breq w72
cpi device,S2323A; (device != S2323A))
breq w72
cpi device,S2343A; (device != S2343A))
breq w72
cpi device,S2333A; (device != S2333A) &&
breq w72
cpi device,S4433A; (device != S4433A) &&
breq w72
cpi device,S4434; (device != S4434A) &&
breq w72
cpi device,S8535; (device != S8535) &&
breq w72
cpi device,m83; (device != m83) &&
breq w72
cpi device,m161; (device != m161) &&
breq w72
cpi device,m163; (device != m163) &&
breq w72
cpi device,m603; (device != m603) &&
breq w72
cpi device,m103; (device != m103) &&
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
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,0x01; Auto increment address    !!!!
clr temp2
add addrl,temp1
adc addrh,temp2

rjmp writeFLASHdelay

;**** Write Program Memory, Low Byte ****

w9:
cpi u_data,0x63    ; 'c' Write program memory, low byte
brne w12
rcall getc

ldi s_data,0x40; wrser(0x40); // SPI write (byte 1)
rcall wrser
mov s_data,addrh; s_data = addrh;
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; wrser(u_data); // SPI write (byte 4)
rcall wrser

writeFLASHdelay:
cpi device,m103
breq w92
cpi device,m83
breq w92
cpi device,m603
breq w92
cpi device,m161
breq w92
cpi device,m163
breq w92

ldi temp1,0x20; delay(0x20);  // 24585 cycles delay
rcall delay ;   // Page mode requires no delay!
w92:
rjmp put_ret ; goto reply();

;**** Read Program Memory ****

w12:
cpi u_data,0x52; 'R' Read program memory
brne w10 ;
ldi s_data,0x28; wrser(0x28); // SPI write (byte 1)
rcall wrser
mov s_data,addrh; s_data = addrh;
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

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 readaddrinc
;**** 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 w13
rcall getc

ldi s_data,0xc0
rcall wrser
mov s_data,addrh
rcall wrser
mov s_data,addrl
rcall wrser
mov s_data,u_data
rcall wrser
ldi temp1,0x20
rcall delay

ldi temp1,0x01; Auto increment address    !!!!
clr temp2
add addrl,temp1
adc addrh,temp2

rjmp put_ret

;;**** Read Data Memory ****

w13:
cpi u_data,0x64; 'd' Read data memory
brne w14
ldi s_data,0xa0; wrser(0xA0); // SPI write (byte 1)
rcall wrser
mov s_data,addrh; s_data = addrh;
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

readaddrinc:
ldi temp1,0x01; Auto increment address    !!!!
clr temp2
add addrl,temp1
adc addrh,temp2

rjmp waitcmd ; goto waitcmd();


;**** Leave Programming Mode ****

w14:
cpi u_data,0x4c; 'L' Leave programming mode
brne w15
ddrb_release
set_reset ; set RESET = 1
rjmp    put_ret

;**** Chip Erase ****

w15:
cpi u_data,0x65    ; 'e' Chip erase
       brne w16
ldi s_data,0xac
rcall wrser
ldi s_data,0x80
rcall wrser
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
andi s_data,0x06
ori s_data,0xe0
rcall wrser
ldi s_data,0x00
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 w18
ldi param1,0x02
rcall w17call
ldi param1,0x01
rcall w17call
ldi param1,0x00
rcall w17call
rjmp waitcmd

w17call:
ldi s_data,0x30
rcall wrser
ldi s_data,0x00
rcall wrser
mov s_data,param1
rcall wrser
rcall rdser
mov u_data,s_data
rcall putc
ret


;**** Write Program Memory Page ****

w18:
cpi u_data,0x6D; 'm' Write Program Memory Page
brne w19

ldi s_data,0x4c; wrser(0x4c); // 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

ldi s_data,0x00; wrser(0x00); // SPI write (byte 4)
rcall wrser
ldi temp1,0xff;  delay(0xFF); // 0x20 = 24585 cycles delay
rcall delay
rjmp put_ret

;**** Universal Command ****

w19:
cpi u_data,0x3A; ':' Universal Command
brne w191

rcall getc
mov cmd1,u_data
rcall getc
mov cmd2,u_data
rcall getc
mov cmd3,u_data
clr u_data
rcall NewUniversal
ldi temp1,0xff;  delay(0xFF); // 0x20 = 24585 cycles delay
rcall delay
rjmp put_ret

;**** New Universal Command ****

w191:
cpi u_data,'.'; '.' New Universal Command
brne w99

rcall getc
mov cmd1,u_data
rcall getc
mov cmd2,u_data
rcall getc
mov cmd3,u_data
rcall getc
rcall NewUniversal
ldi temp1,0xff;  delay(0xFF); // 0x20 = 24585 cycles delay
rcall delay
rjmp put_ret

NewUniversal:
mov s_data,cmd1
rcall wrser
mov s_data,cmd2
rcall wrser
mov s_data,cmd3
rcall wrser
mov s_data,u_data
rcall wrser

mov u_data,rd_s_data

rcall putc
ret
w99:

;**** Command Error ****

put_err:
ldi u_data,0x3f; putc('?'); \\ send '?'
rcall putc
rjmp waitcmd

;**** Reply Command ****

put_ret:
ldi u_data,0x0d; putc(0x0D); \\ send CR
rcall putc
rjmp waitcmd

delay1us:  ;    count               R16
       nop                                                      
       cpi     temp1,0x03
       breq    finished
       nop
       nop
loop:  
dec     temp1
       cpi     temp1,0x03
       brne    loop              
finished:
       ret    


Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.