AVR OCD (On Chip Debug) Documentation Note: this information is retrieved from public domain information. It is partially guessed only, and also not complete. Described here are only AVR OCD "Private" Commands (JTAG Instructions 8,9,A,B). Only commands and status bits are described that are actually verified on real silicon.
AVR Flash Programming using JTAG
Copyleft 2003 Nugis Foundation.
Document Date 05 April 2003
JTAG Instruction 0x08 - Force Break
JTAG Instruction 0x09 - Run
JTAG Instruction 0x0A - Execute AVR Instruction (2 Words!)
use 0x0A, SDR 0xFFFF0000 to read PC (actually returns PC+2 or PC+4)
JTAG Instruction 0x0B - Access OCD Registers
there are total 16 Addressable Registers after IR next DRSHIFT is RW Flag (1=Write) + 4 Bits Address those Data in Instruction is 21 (5 + 16) bits note for read operation OCD Address need to be pre latched!
Register 0 PSB0
Register 1 PSB1
Register 2 PDMSB
Register 3 PDSB
Register 8 Break Control Register (BCR)
Bit | rw | Description |
D15 | rw | 1=Enable Timers to Run during Break |
D14 | rw | 1=PC is read as +4 not +2 after break ? |
D13 | rw | 1=Break on change Flow ?! |
D12 | rw | 1=Enable PSB0 |
D11 | rw | 1=Enable PSB1 |
D10 | rw | 1=Enable PDMSB as single break |
D9 | rw | 1=Enable Mask in Break Comparison |
D8 | rw | 1= |
D7 | rw | 1=* |
D6 | rw | 1= |
D5 | rw | 1= |
D4 | rw | 1=* |
D3 | rw | 1=* |
D2 | rw | 1= |
D1-0 | r | (read as 0) |
* note when D7, D4, D3 are all set then PDSB is enabled s Program Break
Register 9 - Break Status Register (BSR)
Bit | rw | Description |
D15-D8 | r | |
D7 | r | 1=Break on change flow |
D6 | r | 1=Break on PSB0 (Reg0) |
D5 | r | 1=Break on PSB1 (Reg1) |
D4 | r | 1=Break on PDMSB (Reg2 as single break) |
D3 | r | 1=Break on PDSB (Reg3) |
D2 | r | 1=Break on ? (has been seen) |
D1 | r | 1=Break forced by OCD (Instr 8) |
D0 | r | 1=Break by AVR Break Instruction (0x9598) |
Register C - OCDR Readback
Bit | rw | Description |
D15-8 | rw | OCDR 7..0 |
D7-0 | r | unused (read as 0) |
Register D - Control and Status Register
Bit | rw | Description |
D15 | rw | 1=Enable OCDR |
D14 | rw | 1=? |
D13-D5 | r | |
D4 | r | 1=OCDR written by AVR and not read by OCD |
D3 | r | 1=Reset not active |
D2 | r | 1=Reset not active |
D1-0 | r |
it enables access to OCDR, and then writes a constant to OCDR (using 0xA exec-avr-insts) and then reads and displays OCDR contents
NOTE "MAX_FREQ" "100000";
IRSTOP IDLE; DRSTOP IDLE;
ACTION read_idcode = header RECOMMENDED, check_chain RECOMMENDED, exiting;
DATA data_chain; BOOLEAN idval[32];
'********************************** INTEGER ilen = 4; ' IR length is 4 INTEGER scanlen = 141; ' Boundary Scan lenght is 141 for ATmega16
'**************************************************** ' AVR JTAG Commands '**************************************************** ' ' JTAG Mandatory commands ' BOOLEAN extest[ilen] = $0; ' ' JTAG IDCODE command (see IEEE 1149.1) ' BOOLEAN idcode[ilen] = $1; BOOLEAN sample_preload[ilen] = $2; ' ' AVR JTAG Programming Commands (fully documented in Atmel Docs!) ' BOOLEAN prog_enable[ilen] = $4; ' BOOLEAN prog_commands[ilen] = $5; ' BOOLEAN prog_preload[ilen] = $6; ' BOOLEAN prog_pageread[ilen] = $7; ' ' ' AVR JTAG OCD "Private" commands (need NDA and Atmel Approval!) ' ' ' Command 0x8: ' BOOLEAN avr_08[ilen] = $8; ' 08 Private ' ' Command 0x9: Release from Break? ' BOOLEAN avr_09[ilen] = $9; ' 09 Private ' ' Command 0xA: Execute AVR Instruction ' ' IRSCAN 4, $A; ' DRSCAN 16, instr_1 ' .. ' DRSCAN 16, instr_n ' BOOLEAN avr_instr[ilen] = $A; ' 0A Private ' ' Command 0xB: Read/Write internal Addres Space ' ' ' IRSCAN 4, $B; ' DRSCAN n?, ADDR_SPACE_SELECTOR+RW_FLAG ' DRSCAN 16,addr? ' DRSCAN 16,data?
' B:C - Read OCDR ' IRSCAN 4, $B; ' DRSCAN n, $0C; ' DRSCAN 16, $0000, CAPTURE OCDR[15..0];
BOOLEAN avr_comm[ilen] = $B; ' 0B Private ' ' JTAG OCD "Public" Command: RESET_AVR ' DR is 1 bit wide, "1" is hold in Reset, "0" means Run normal ' notice execution of ' IRSCAN 3, $C; ' DRSCAN 1, $1; ' Clears the sysclk counter always, Clears the AVR Core always ' Notice while JTAG_AVR_RESET is active, core is not executing ' but the peripherals are not hold in reset, that is command ' 0xA will write to peripherals ' BOOLEAN avr_reset[ilen] = $C; ' 0C Reset, one bit, 1=RESET
' Commands 0x3, 0xD, 0xE are not implemented.
' ' JTAG Mandatory command, place TAP controller in "Bypass" ' BOOLEAN bypass[ilen] = $F;
BOOLEAN comm [32]; BOOLEAN b16 [16]; BOOLEAN b24 [24]; BOOLEAN b32 [32];
BOOLEAN ocd [40];
BOOLEAN scanr [scanlen]; ' Boundary Scan Register BOOLEAN instr [16]; ' Instruction BOOLEAN tick [16]; ' Clock Ticks
ENDDATA;
PROCEDURE header; PRINT "******************************************************************************"; PRINT " AVR JTAG OCD sniffer! "; ENDPROC;
PROCEDURE print16 USES data_chain; PRINT "B16= ", b16[15],b16[14],b16[13],b16[12],b16[11],b16[10],b16[9],b16[8], b16[7],b16[6],b16[5],b16[4],b16[3],b16[2],b16[1],b16[0]; ENDPROC;
PROCEDURE print_ocd USES data_chain; PRINT "OCD= ", ocd[39],ocd[38],ocd[37],ocd[36],ocd[35],ocd[34],ocd[33],ocd[32], " ", ocd[31],ocd[30],ocd[29],ocd[28],ocd[27],ocd[26],ocd[25],ocd[24], " ", ocd[23],ocd[22],ocd[21],ocd[20],ocd[19],ocd[18],ocd[17],ocd[16], " ", ocd[15],ocd[14],ocd[13],ocd[12],ocd[11],ocd[10],ocd[9],ocd[8], " ", ocd[7],ocd[6],ocd[5],ocd[4],ocd[3],ocd[2],ocd[1],ocd[0]; ENDPROC;
PROCEDURE print_port USES data_chain; ' INTEGER i_32; ' FOR i_32 = 0 to scanlen-1; ' scanr[0] = 0; ' NEXT i_32;
scanr[135] = 0; scanr[132] = 0;
IRSCAN ilen, sample_preload[3..0]; ' Boundary Scan DRSCAN scanlen, scanr[(scanlen-1)..0], CAPTURE scanr[(scanlen-1)..0];
' Print PORTA PRINT "PORTA ", scanr[23],scanr[20],scanr[17],scanr[14],scanr[11],scanr[8],scanr[5],scanr[2]; PRINT "DDRA ", scanr[22],scanr[19],scanr[16],scanr[13],scanr[10],scanr[7],scanr[4],scanr[1];
IF (scanr[72] == 1) THEN PRINT "RESET HIGH"; IF (scanr[72] == 0) THEN PRINT "RESET LOW";
' PRINT "OSC: ", scanr[66],scanr[65],scanr[64],scanr[63]; ENDPROC;
PROCEDURE reset_avr USES data_chain; IRSCAN ilen, avr_reset[3..0]; DRSCAN 1, $1; ENDPROC;
PROCEDURE exec_avr USES data_chain; IRSCAN ilen, avr_instr[3..0]; DRSCAN 16, instr[15..0]; ENDPROC;
PROCEDURE check_chain USES data_chain, print16, print_ocd, exec_avr, reset_avr, print_port; PRINT "******************************************************************************";
IRSCAN ilen, avr_reset[3..0]; DRSCAN 1, $1;
IRSCAN ilen, avr_reset[3..0]; DRSCAN 1, $0;
WAIT IDLE, 7000 USEC, IDLE;
PRINT "TEST OCDR"; PRINT "******************************************************************************";
IRSCAN ilen,avr_comm[3..0]; ocd[4..0] = $0D; DRSCAN 5, ocd[4..0]; ocd[39..0] = $1D8000; DRSCAN 21, ocd[20..0];
WAIT IDLE, 7000 USEC, IDLE;
instr[15..0] = $EF05; CALL exec_avr; instr[15..0] = $BF01; CALL exec_avr;
IRSCAN ilen,avr_comm[3..0]; ocd[4..0] = $0C; DRSCAN 5, ocd[4..0]; ocd[39..0] = $0000000000; DRSCAN 16, ocd[15..0], CAPTURE ocd[15..0]; CALL print_ocd;
instr[15..0] = $EA06; CALL exec_avr; instr[15..0] = $BF01; CALL exec_avr;
IRSCAN ilen,avr_comm[3..0]; ocd[4..0] = $0C; DRSCAN 5, ocd[4..0]; ocd[39..0] = $0000000000; DRSCAN 16, ocd[15..0], CAPTURE ocd[15..0]; CALL print_ocd;
ENDPROC;
PROCEDURE exiting; PRINT "******************************************************************************"; EXIT (0); ENDPROC;