AN105

AN105
P R O G R A M M I N G FLASH T H R O U G H T H E J TA G I N T E R F A C E
Relevant Devices
This application note applies to the following
devices:
C8051F000, C8051F001, C8051F002,
C8051F005, C8051F006, C8051F010, C8051F011,
C8051F012, C8051F015, C8051F016,
C8051F017, C8051F206, C8051F220,
C8051F221, C8051F226, C8051F230,
C8051F231, C8051F236, C8051F020,
C8051F021, C8051F022, and C8051F023.
c. Polling the Busy bit to see when the
read or write operation has completed
3. FLASH Programming operations:
a.
b.
c.
d.
Read a FLASH byte
Write a FLASH byte
Erase a FLASH page
Erase the entire FLASH
Figure 1 shows the programming hierarchy for
accessing the FLASH through the JTAG port.
JTAG Interface
Introduction
This note provides enough information about the
This document describes how to program the JTAG interface to enable FLASH programming.
FLASH memory on C8051 devices through the For more information, the JTAG standard, IEEE
JTAG port. Example software is included at the end
of this note.
NOTE: All Silicon Labs devices can be programmed through the JTAG interface. However, the
C8051F2xx family of devices does not support the
IEEE 1149.1 boundary scan function.
The information required to perform FLASH programming through the JTAG interface can be
divided into three categories:
1. JTAG interface information:
a. The 4-pin physical layer interface
(TCK, TMS, TDI, and TDO)
b. The Test Access Port (TAP) state
machine
c. TAP Reset, Instruction Register Scan,
and Data Register Scan primitives
2. JTAG Indirect Register operations:
a. Reading an indirect register
b. Writing to an indirect register
Rev. 1.4 12/03
FLASH Operations:
Byte Read, Byte Write, Page Erase, and
Full Erase
FLASH Interface Registers:
FLASHCON, FLASHDAT, FLASHADR, and
FLASHSCL
Indirect Register Operations:
Indirect Read
Indirect Write
Polling Busy
JTAG Interface Primitives:
TAP Reset
Instruction Register Scan
Data Register Scan
JTAG Physical Layer:
TCK, TMS, TDI, TDO, and
TAP State Machine
Figure 1. JTAG FLASH Programming
Hierarchy
Copyright © 2003 by Silicon Laboratories
AN105-DS14
AN105
1149.1-1990, can be obtained from the Institute of
Electrical and Electronics Engineers (for information, see http://standards.ieee.org). The JTAG interface on C8051 devices is fully compliant with the
IEEE 1149.1 specification. Those already familiar
with JTAG can skip to the section titled "Instruction Register on C8051 Devices‚" on page 7.
Test Access Port (TAP) Interface
The hardware interface to the JTAG port consists of
four signals, as shown in Figure 2:
C8051Fxxx
TCK
TMS
TDI
TDO
Figure 2. TAP Interface
1. TCK input shift clock. Data is sampled at TMS
and TDI on the rising edge of TCK. Data is output on TDO on the falling edge of TCK.
2. TMS input mode select. TMS is used to navigate through the TAP state machine.
3. TDI input. Input data to the Instruction Register (IR) or the Data Register (DR) is presented
to the TDI input, and sampled on the rising
edge of TCK.
4. TDO output. Output data from the Instruction
Register or the Data Register is shifted out
TDO on the falling edge of TCK.
2
Rev. 1.4
AN105
TAP State Machine
The primary purpose of the Test Access Port state
machine, which is shown in Figure 3, is to select
which of two shift registers, the Instruction Register or the Data Register, to connect between TDI
and TDO. In general, the Instruction Register is
used to select which Data Register to scan. The
numbers next to the arrows in the diagram refer to
the logic state of TMS at the time TCK is brought
high.
1
Test Logic
Reset
0
0
1
Select
DR_Scan
Run_Test/Idle
Select
IR_Scan
1
0
0
Capture_DR
1
1
Capture_IR
0
0
0
0
Shift_DR
Shift_IR
1
1
1
1
1
Exit1_DR
Exit1_IR
0
0
0
0
Pause_DR
Pause_IR
1
1
0
Exit2_DR
1
1
Update DR
1
0
Exit2_IR
Update IR
0
1
0
Figure 3. TAP State Machine
Rev. 1.4
3
AN105
TAP Reset
The TAP logic is reset by holding TMS high (logic
'1') and strobing (bringing high and then back low)
TCK at least five times, as shown in Figure 4.
TCK
TMS
TDI
TDO
Run-Test/Idle
Test Logic Reset
???
???
???
???
???
Figure 4. TAP Reset Timing
This advances the state machine to the Test Logic
Reset state from any state in the TAP state
machine, which resets the JTAG port and test logic.
It does not reset the CPU or peripherals.
TAP Notes:
1. Data is valid on TDO beginning with
the falling edge of TCK on entry into
the Shift_DR or Shift_IR states.
TDO goes “push-pull” on this TCK
falling edge and remains “pushpull” until the TCK rising edge.
2. Data is not shifted on entry into
Shift_DR or Shift_IR.
3. Data is shifted on exit of Shift_IR
and Shift_DR.
4
Rev. 1.4
AN105
IR and DR Scan
Register is transferred in the Shift_IR state. During
a Data Register Scan operation, the Data Register is
In addition to test logic reset, there are two primi- transferred in the Shift_DR state. Data is always
tive operations that the state machine controls: shifted LSB-first.
Instruction Register (IR) Scan, and Data Register
(DR) Scan. In a scan operation, data is sampled at In C8051 devices, the Instruction Register is
TDI on the rising edge of TCK, and is output on always 16 bits in length. The length of the Data
TDO on the falling edge of TCK. During an Register varies, depending on the register selected.
Instruction Register Scan operation, the Instruction
TCK
TMS
TDI
IR0
IR1
IR2
IR3
IR4
IR5
IR6
IR7
IR8
IR9
IR10 IR11 IR12 IR13 IR14 IR15
TDO
Update-IR
Update-DR
Run-Test/Idle
Run-Test/Idle
Exit1-IR
Shift-IR
Capture-IR
Select-IR-Scan
Select-DR-Scan
Run-Test/Idle
Figure 5. Instruction Register Scan Timing
Figure 5 shows a timing diagram for an Instruction
Register access.
TCK
TMS
TDI
DI0
TDO
DI1
DI2
DI3
DI4
DIn
DO0 DO1 DO2 DO3 DO4
DOn
Exit1-DR
Shift-DR
Capture-DR
Select-DR-Scan
Run-Test/Idle
Figure 6. Data Register Scan Timing
Figure 6 shows timing for a Data Register access.
Rev. 1.4
5
AN105
IDCODE Example
To better illustrate how a typical JTAG operation
works, we present an example access, in this case,
reading the IDCODE register.
Reading the IDCODE is a two-step process. First,
an Instruction Register Scan operation is initiated,
and the Instruction Register is loaded with the
IDCODE address, 16-bits shifted on TDI, as shown
in Figure 7. Once the Instruction Register has been
loaded, a Data Register Scan operation is initiated,
and the 32-bit IDCODE is read from the device, on
TDO, as shown in Figure 8.
Instruction Register = 0x1004 for IDCODE scan
TCK
TMS
TDI
IR0
IR1
IR2
IR3
IR4
IR5
IR6
IR7
IR8
IR9
IR10 IR11 IR12 IR13 IR14 IR15
TDO
Run-Test/Idle
Update-IR
Exit1-IR
Shift-IR
Capture-IR
Select-IR-Scan
Select-DR-Scan
Run-Test/Idle
Figure 7. Instruction Register Scan Timing for IDCODE Read
Data Register reads '0x10000243' for IDCODE scan on C8051F000 rev D
TCK
TMS
TDI
TDO
DR0
DR1
DR2
DR3
DR4
DR5
DR6
DR7
DR8
DR9 DR10 DR11 DR12 DR13 DR14 DR15 DR16 DR17 DR18 DR19 DR20 DR21 DR22 DR23 DR24 DR25 DR26 DR27 DR28 DR29 DR30 DR31
Rev. 1.4
Run-Test/Idle
Exit1-DR
6
Update-DR
Shift-DR
Capture-DR
Select-DR-Scan
Run-Test/Idle
Figure 8. Data Register Scan Timing for IDCODE Read
AN105
Instruction Register on C8051
Devices
Table 3. DRAddress Decoding
Register
The Instruction Register (IR) on C8051 devices is
always 16-bits in length, and is decoded as follows:
Table 1. Instruction Register Decoding
15:12
11:0
StateCntl
DRAddress
The StateCntl field controls the state of the debug
hardware. In a FLASH programming operation,
the system is first Halted, and then the CPU core is
held in Suspend mode to bypass the Watchdog
timer.
Table 2. StateCntl Decoding
StateCntl*
Device State
0000
Normal
0001
Halt
0010
System Reset
0100
CPU Core Suspend
1111
Normal
*unlisted states are reserved
Table 3. DRAddress Decoding
Register
DRAddress*
*unlisted states are reserved
Indirect Registers
The four FLASH registers (FLASHCON,
FLASHADR, FLASHDAT, and FLASHSCL) are
accessed using a common indirect method. This
indirect scheme handles the information transfer
between the JTAG clock domain, controlled by
TCK, and the CPU clock domain, controlled by
SYSCLK. These FLASH indirect registers are not
to be confused with the standard 8051 indirect registers R0 and R1.
Overview of Indirect Register
Accesses
To read or write to an indirect register, the Instruction Register is first loaded with the proper DRAddress. Reads and writes are then initiated by
writing the appropriate Indirect Operation Code
(IndOpCode) to the selected data register. On a
write, the Write opcode is followed by the data to
be written.
The format for the data register for the incoming
commands is as follows:
Table 4. Indirect Write DR Format
DRAddress*
EXTEST
0x000
SAMPLE/PRELOAD
0x002
IDCODE
0x004
BYPASS
0xFFF
FLASHCON
0x082
FLASHDAT
0x083
FLASHADR
0x084
FLASHSCL
0x085
19:18
17:0
IndOpCode
WriteData
The Indirect Operation Code (IndOpCode) bits are
decoded as follows:
Table 5. IndOpCode Decoding
IndOpCode
Rev. 1.4
Operation
0x
Poll
10
Read
7
AN105
available for reading. Figure 9 shows a flow chart
that describes how to perform a read operation on
an indirect register.
Table 5. IndOpCode Decoding
IndOpCode
11
Operation
Write
Indirect Write
The format for the data register for outgoing data is
The Write operation initiates a write of WriteData
as follows:
to the register selected by DRAddress. Registers of
any width up to 18 bits can be written. If the regisTable 6. Indirect Read DR Format
ter to be written contains fewer than 18 bits, Write19
18:1
0
Data should be left-justified (MSB occupies bit
17). This allows shorter registers to be written in
0
ReadData
Busy
fewer JTAG clock cycles. For example, a write to
an 8-bit indirect register can be accomplished by
shifting only 10 bits (2-bit Write opcode + 8 data
Indirect Read
The Read operation initiates a read from the register selected by DRAddress. Reads can be initiated
by shifting only two bits into the indirect register
(the Read IndOpCode bits). After the Read operation is initiated, the Busy bit is polled to determine
when the operation has completed and the data is
Indirect Read
Load IR with register to be read
IR <= 4xxxh
xxx = DRAddress
Load DR with 'Read' op code
DR <= 10b (2 bits)
Poll Busy in DR
DR <= 0b (1 bit)
Busy
1
0
Read DR
DR <= 0 (n + 1 bits)
n = size of indirect register
Finish
Figure 9. Indirect Read Flow Chart
8
Rev. 1.4
AN105
bits). After a write is initiated, the Busy bit should
be polled to determine when the operation has
completed. Figure 10 shows a flow chart describing how to perform a write operation on an indirect
register.
Polling Busy
The Busy bit indicates that the current read or write
operation has not completed. It goes high (‘1’)
when an operation is initiated and returns low (‘0’)
on completion. Because the Busy bit occupies the
LSB of the returned data, polling for Busy can be
accomplished in one DR shift cycle (on exit of the
Shift_DR state).
On an Indirect Read, once Busy has gone low, the
ReadData can be shifted out. Note that the ReadData is always right-justified. This allows registers
less than 18-bits to be read in fewer JTAG clock
cycles. For example, an 8-bit Read can be performed in 9 DR shifts (8 data bits + 1 Busy bit).
Figure 11 shows the Data Register Scan timing for
polling the Busy bit.
The contents of the Instruction Register should not
be altered when a Read or a Write operation is in
progress.
Indirect Write
Load IR with register to be
written
IR <= 4xxxh
xxx = DRAddress
Load DR with 'Write' op code
and data to be written
DR <= 11yyyyb (2 + n bits)
yyyy = WriteData
TCK
TMS
TDI
Poll Busy in DR
DR <= 0 (1 bit)
Run-Test/Idle
Update-DR
Exit1-DR
Figure 10. Indirect Write Flow Chart
Shift-DR
Finish
Capture-DR
0
Select-DR-Scan
1
Busy
Run-Test/Idle
Busy
TDO
Figure 11. DR Scan Timing for Polling
the Busy Bit
Rev. 1.4
9
AN105
FLASH Programming
Table 9. WriteMode Decoding
FLASH Register Descriptions
WriteMode*
Operation
0010
Initiate page erase on
current page if FLASHDAT = 0xA5;
Initiate erase of entire
FLASH if FLASHDAT =
0xA5 and FLASHADR is
set to the address of the
FLASH Read Lock Byte
or the FLASH Write/
Erase Lock Byte.
The FLASH is accessed through four indirect registers: FLASHCON, FLASHADR, FLASHDAT,
and FLASHSCL. Each of these registers is
accessed using Indirect Read and Indirect Write
operations as outlined in the previous section.
FLASHCON
FLASHCON is an 8-bit register that controls how
the FLASH logic responds to reads and writes to *unlisted states are reserved
the FLASHDAT register. The FLASHCON register
contains a ReadMode setting and a WriteMode FLASHADR
setting, decoded as follows:
Table 7. FLASHCON Decoding
7:4
3:0
WriteMode
ReadMode
Table 8. ReadMode Decoding
ReadMode*
Operation
0000
FLBusy Polling
0010
Initiate FLASH read;
Increment FLASHADR
FLASHADR is a 16-bit register that contains the
address of the FLASH byte to be read or written.
FLASHADR is automatically incremented on completion of a read or a write operation.
FLASHDAT
FLASHDAT is a 10-bit register containing 8-bits of
data, an FLFail bit, and an FLBusy bit, as shown
below:
Table 10. FLASHDAT Read Decoding
*unlisted states are reserved
Table 9. WriteMode Decoding
WriteMode*
Operation
0000
FLBusy Polling
0001
Initiate FLASH Write;
Increment FLASHADR
9:2
1
0
FLData
FLFail
FLBusy
A write to FLASHDAT need only consist of 8 bits
because the last bit latched assumes the MSB position.
A read of FLASHDAT requires 11 DR_SHIFT
cycles (8 for FLData, 1 for FLFail, 1 for FLBusy,
and 1 for Busy).
Polling for FLBusy requires at least 2 DR_SHIFT
cycles, 1 for FLBusy and 1 for Busy.
10
Rev. 1.4
AN105
FLASHSCL
Disabling the Watchdog Timer (WDT)
FLASHSCL is an 8-bit register that sets the prescale value required for deriving the timing for
FLASH operations. When operating from the internal 2 MHz system clock, this register should be
configured with 0x86 as follows:
A flow chart showing the process for disabling the
Watchdog timer is shown in Figure 12. The procedure is as follows:
Table 11. FLASHSCL Configuration
7:4
3:0
1000
0110
1. The system is reset by loading the Instruction
Register (IR) with 0x2FFF.
2. An IDCODE scan is performed by loading IR
with 0x1004, followed by a 32-bit DR scan
with 0x00000000.
3. All following IR addresses set StateCntl to
'0x4', which keeps the core in SUSPEND mode,
and takes the FLASH off-line.
Before the FLASH can be programmed, the device
needs to be reset and the Watchdog timer taken offline. Otherwise, the Watchdog timer may initiate a
system reset during a FLASH operation, resulting
in undefined behavior.
FLASH Access Procedures
Disable WDT
Execute system RESET
IR <= 2FFFh
Read ID Code
IR <= 1004h
DR <= 0 (32-bits)
Finish
Figure 12. Flow Chart for Bypassing the
Watchdog Timer
Rev. 1.4
11
AN105
Reading a FLASH Byte
1. Load FLASHSCL with 0x86, to set proper
FLASH timing using the internal 2 MHz system clock. This is accomplished by an Indirect
Figure 13 shows a flow chart which illustrates how
Write of 0x86 to FLASHSCL.
to read a FLASH byte. The procedure is as follows:
2. Load FLASHADR with the 16-bit address to be
read. This is accomplished with an Indirect
Write of 16-bits to FLASHADR.
FLASH Read
3. Load FLASHCON with code to initiate a read
(0x01). This is accomplished with an Indirect
Write of 8-bits to FLASHCON.
Load FLASHSCL with 0x86:
Indirect Write (0x4085, 0x86)
4. Initiate the read by reading FLASHDAT. This
is an Indirect Read of 0-bits (the DR scan consists of only the 2-bit read op-code). Note that
this merely starts the FLASH read process.
Load FLASHADR with address
to read:
Indirect Write (0x4084, yyyy)
yyyy = 16-bit address
Load FLASHCON with 'Initiate
Read' code:
Indirect Write (0x4082, 0x02)
5. Load FLASHCON with the code to poll
FLBusy (0x00); This is an Indirect Write of 8bits to FLASHCON.
Initiate READ operation by
reading FLASHDAT:
Indirect Read (0x4083,0 bits)
6. Poll FLBusy until it goes low, indicating that
the read has completed. This is an Indirect Read
of 1-bit. The DR Scan for polling FLBusy is
shown in Figure 14.
Load FLASHCON with 'Poll
FLBusy' code:
Indirect Write (0x4082, 0x00)
7. Read FLASHDAT. This is an Indirect Read of
10-bits (8 data bits, 1 FLFail bit, and 1
Poll for FLBusy:
Indirect Read (0x4083, 1 bit)
TCK
FLBusy
1
TMS
TDI
0
TDO
Busy FLBusy
Read FLASHDAT:
Indirect Read (0x4083, 10 bits)
Run-Test/Idle
Update-DR
Exit1-DR
Shift-DR
no
Capture-DR
yes
Select-DR-Scan
Run-Test/Idle
Read next address?
Finish
Figure 13. Flow Chart for Reading a
FLASH Byte
12
Figure 14. DR Scan Timing for Polling
FLBusy
Rev. 1.4
AN105
FLBusy bit). The DR Scan for reading
FLASHDAT is shown in Figure 15.
If a series of consecutive bytes are to be read, the
process can be restarted again at step (3) above,
since FLASHADR is automatically incremented
following a read or a write operation.
The FLFail bit is set to a ‘1’ if the read operation
attempted to access a Read-locked sector.
TCK
TMS
TDI
TDO
Busy FLBusy FLFail
D0
D1
D2
D3
D4
D5
D6
D7
Run-Test/Idle
Update-DR
Exit1-DR
Shift-DR
Capture-DR
Select-DR-Scan
Run-Test/Idle
Figure 15. DR Scan Timing for FLASHDAT Read
Rev. 1.4
13
AN105
Writing a FLASH Byte
1. Load FLASHSCL with 0x86, to set proper
FLASH timing for using the internal 2 MHz
system clock. This is accomplished by an IndiFigure 16 shows a flow chart describing how to
rect Write of 0x86 to FLASHSCL.
write a FLASH byte. The procedure is as follows:
2. Load FLASHADR with the 16-bit address to be
written.
FLASH Write
3. Load FLASHCON with the 'Initiate Write'
opcode (0x10).
Load FLASHSCL with 0x86:
Indirect Write (0x4085, 0x86)
4. Load FLASHDAT with the data to be written.
This is an 8-bit Indirect Write.
5. Load FLASHCON with the 'Poll FLBusy'
opcode (0x00).
Load FLASHADR with address
to be written:
Indirect Write (0x4084, yyyy)
yyyy = 16-bit address
6. Poll FLBusy. This is accomplished by initiating 1-bit Indirect Reads on the FLASHDAT
register.
Load FLASHCON with 'Initiate
Write' code:
Indirect Write (0x4082, 0x10)
If a series of consecutive bytes is to be written, the
process can repeat, starting at step (3) above.
FLASHADR is automatically incremented at the
end of a read or a write operation.
Load FLASHDAT with the data
to be written:
Indirect Write (0x4083, zz)
zz = 8-bit data to be written
The FLFail bit is set to a ‘1’ if the write operation
attempted to write to a Write-locked sector.
Load FLASHCON with 'Poll
FLBusy' code:
Indirect Write (0x4082, 0x00)
Poll for FLBusy:
Indirect Read (0x4083, 1 bit)
FLBusy?
1
0
yes
Write next address?
no
Finish
Figure 16. Flow Chart for Writing a
FLASH Byte
14
Rev. 1.4
AN105
Figure 17 shows the DR Scan timing for the 8-bit
write to FLASHDAT, step (4) above.
Erasing a FLASH Page
The FLASH memory is organized as a series of
512-byte pages. The procedure for erasing a
FLASH page is similar to writing a FLASH byte,
except that the FLASHCON register needs to be set
to 0x20, and FLASHDAT needs to be set to 0xA5.
FLASHADR can be set to any address within the
page to be erased. If FLASHADR is set to either of
the Lock Byte addresses (0x7dfe or 0x7dff on
‘F0xx devices and 0x1dfe or 0x1dff on the ‘F2xx
devices), then the erase operation initiates an erase
of the entire FLASH memory.
Unlike read and write operations, FLASHADR is
not automatically incremented at the end of an
TCK
TMS
D0
TDI
D1
D2
D3
D4
D5
D6
D7
TDO
Run-Test/Idle
Update-DR
Exit1-DR
Shift-DR
Capture-DR
Select-DR-Scan
Run-Test/Idle
Figure 17. DR Scan Timing for a FLASHDAT Write
Rev. 1.4
15
AN105
erase operation. Figure 18 shows a flow chart for
the FLASH page erase procedure.
FLASH Page
Erase
Load FLASHSCL with 0x86:
Indirect Write (0x4085, 0x86)
Load FLASHADR with address
in page to erase:
Indirect Write (0x4084, yyyy)
yyyy = 16-bit address
Load FLASHCON with 'Initiate
Erase' code:
Indirect Write (0x4082, 0x20)
Initiate ERASE operation by
writing '0xA5' to FLASHDAT:
Indirect Write (0x4083,0xA5)
Load FLASHCON with 'Poll
FLBusy' code:
Indirect Write (0x4082, 0x00)
Poll for FLBusy:
Indirect Read (0x4083, 1 bit)
FLBusy?
1
0
Finish
Figure 18. Flow Chart for Erasing a
FLASH Page
16
Rev. 1.4
AN105
Programming a Device in a
JTAG Chain
ister (DR) scan to collect each device’s identification number. If a device does not support the
IDCODE instruction, then it is assigned an ID of
If the C8051 device participates in a boundary scan 0x00000000.
chain with other devices or the JTAG ports of multiple C8051 devices are connected as shown in The Instruction Register discovery process begins
Figure 19, the device can be isolated and pro- with a JTAG_Reset operation. During the followgrammed using methods discussed in this note. A ing IR_Scan operation, ones are shifted into the
software example of programming the FLASH of a TDI pin on the last device in the chain (Device #2
device in a JTAG chain is included at the end of in Figure 19, for example). The IR discovery process ends when a ‘11’ pattern is received from the
this note.
TDO pin of the first device in the JTAG chain
(Device #2 in Figure 19). An input of ‘10’ signifies
Discovering an Unknown JTAG that a new device has been encountered. Figure 20
shows the state machine used for analyzing the
Chain
The purpose of the discovery process is to collect inputs in a discovery IR scan.
information about the devices connected in the
chain. The discovery process assumes that all
TDO = 0
S0
1
Reset
instruction registers have a ‘1’ in the LSB and ‘0’s
in all other bit positions. This is true for all Silicon
Labs devices, but may not be true for all JTAG
Error
S1
devices. Also, upon reset, the optional 32-bit
1
IDCODE register is selected by default. If the
0
device does not have an IDCODE register, the 1-bit
1
BYPASS register is selected instead. In the softS2
New Device/
End of
ware example, the discovery process uses these
Counting
Chain
Zeros
assumptions to record information about the
0
devices connected in the chain.
Figure 20. IR Discovery State Machine
The discovery process is divided into two parts, an
Instruction Register (IR) scan to determine the After the IR scan is complete and the JTAG state
number of devices in the chain and the length of machine is reset, the discovery process issues a DR
each device’s Instruction Register, and a Data Reg- scan to read and store the IDs of the devices for
TCK
TMS
TDO
TDI
JTAG Controller
TCK
TDO
TMS
TDI
JTAG Device #0
TCK
TDO
TMS
TDI
JTAG Device #1
TCK
TDO
TMS
TDI
JTAG Device #2
Figure 19. Typical JTAG Chain Connection
Rev. 1.4
17
AN105
future reference. From the JTAG specification, the IR and DR Scans in JTAG
LSB returned on a DR scan will be a ‘1’ if the
Chains
device supports the IDCODE instruction and a ‘0’
if the device is instead in BYPASS mode. Figure 21 Each Instruction Register scan operation is configshows how the DR scan determines each device’s ured to place all devices other than the device to be
programmed in BYPASS mode. This is accomidentification number.
plished by shifting ‘1’s into the Instruction Registers of all devices before and after the isolated
Discovery
DR Scan
device, as shown in Figure 22.
Reset the JTAG Logic.
(The IDCODE or the BYPASS
register is automatically selected.
Data Register scan operations pad one bit for each
device before the device to be programmed and one
bit for each device after the device to be programmed to account for the BYPASS registers of
these devices.
Initiate DR_SCAN.
Get an Input from the TDO pin
1. IR Scan operations are prefixed with m ‘1’s and
post-fixed with n ‘1’s, where m is the number of
instruction register bits before the device to be
programmed and n is the number of instruction
register bits after the device to be programmed,
as shown in Figure 22.
Input?
1
0
Device does not have an ID.
Assign ID = 0x00L.
Device has an ID.
Shift in the next 31bits.
Last Device?
2. DR Scan operations are prefixed with x ‘0’s and
post-fixed with y ‘0’s where x is the number of
JTAG devices before the device to be programmed and y is the number of JTAG devices
in the chain after the device to be programmed.
no
yes
Done
Isolating a Device
Figure 21. Flow Chart for Discovering
the Device IDs
TDO
To be able to program a device in a chain, the
device must be isolated. An isolated device is the
only one not in BYPASS mode. This allows only
one device to be accessed at a time. There are four
variables that the IR scan and DR scan operations
Instruction Register
Instruction Register
Instruction Register
11...1
0x4yyy
11...1
Data Register
Data Register
Data Register
0
xxxx
0
Device in BYPASS mode
Device being programmed
Device in BYPASS mode
Figure 22. Isolating a C8051 Device to be Programmed
18
Rev. 1.4
TDI
AN105
use to determine how many ‘1’s or ‘0’s to pad with
when issuing a scan, as follows:
Table 12. Variables Required when
Isolating a Device in a JTAG Chain.
For the IR_Scan operations:
number of IR bits before the isolated device
number of IR bits after the isolated device
For the DR_Scan operations:
number of devices before the isolated device
number of devices after the isolated device
In the software example, the JTAG_Isolate() procedure accepts the index of the device to be isolated
and sets these variables accordingly. After the procedure is called, all the following IR and DR scans
are performed on the device specified by the index.
To execute a scan operation on another device, the
JTAG_Isolate() procedure must be called with a
new index prior to issuing the scan. If there is only
one device in the chain, then neither the
JTAG_Isolate() nor the JTAG_Discover() procedures need to be called prior to issuing a scan.
FLASH Operations
FLASH operations for a JTAG chain are the same
as for a single device except that the device under
test must be isolated before calling the FLASH
Operations.
Rev. 1.4
19
AN105
Software Examples For the ‘F00x, ‘F01x, and ‘F2xx Series
Programming a Single JTAG Device
//-----------------------------------------------------------------------------------// JTAG_FLASH.c
//-----------------------------------------------------------------------------------// This program contains some primitive routines which read, write, and erase the FLASH
// through the JTAG port on a C8051Fxxx device under test (DUT). The JTAG pins on the
// DUT are connected to port pins on the C8051F000 master device.
//
// Target device: C8051F000, C8051F010
//
// Tool chain: KEIL Eval ‘c’
//
//-----------------------------------------------------------------------------------// Includes
//-----------------------------------------------------------------------------------#include <c8051f000.h>
// SFR declarations
//-----------------------------------------------------------------------------------// Global CONSTANTS
//-----------------------------------------------------------------------------------sbit
LED = P1^6;
// green LED: ‘1’ = ON; ‘0’ = OFF
// GPIO pins
sbit
TCK =
sbit
TMS =
sbit
TDI =
sbit
TDO =
#define
#define
connecting to JTAG pins on device to be
P3^7;
// JTAG
P3^6;
// JTAG
P3^5;
// JTAG
P3^4;
// JTAG
programmed (DUT)
Test Clock
Mode Select
Data Input
Data Output
TRUE 1
FALSE 0
// JTAG Instruction Register Addresses
#define
INST_LENGTH 16
// number of bits in the
// Instruction Register
#define
#define
#define
BYPASS
EXTEST
SAMPLE
0xffff
0x0000
0x0002
#define
RESET
0x2fff
// System RESET Instruction
#define
#define
IDCODE
IDCODE_LEN
0x1004
32
// IDCODE Instruction address/HALT
// number of bits in the ID code
#define
#define
FLASHCON
FLCN_LEN
0x4082
8
// FLASH Control Instruction address
// number of bits in FLASHCON
#define
#define
#define
FLASHDAT
FLD_RDLEN
FLD_WRLEN
0x4083
10
8
// FLASH Data Instruction address
// number of bits in an FLASHDAT read
// number of bits in an FLASHDAT write
#define
#define
FLASHADR
FLA_LEN
0x4084
16
// FLASH Address Instruction address
// number of bits in FLASHADR
20
Rev. 1.4
AN105
#define
#define
FLASHSCL
FLSC_LEN
0x4085
8
// FLASH Scale Instruction address
// number of bits in FLASHSCL
//-----------------------------------------------------------------------------------// Function PROTOTYPES
//-----------------------------------------------------------------------------------void init (void);
void JTAG_StrobeTCK (void);
void JTAG_Reset (void);
unsigned int JTAG_IR_Scan (unsigned int instruction, int num_bits);
unsigned long JTAG_DR_Scan (unsigned long dat, int num_bits);
void JTAG_IWrite (unsigned int ireg, unsigned long dat, int num_bits);
unsigned long JTAG_IRead (unsigned int ireg, int num_bits);
int FLASH_ByteRead (unsigned int addr, unsigned char *pdat);
int FLASH_ByteWrite (unsigned int addr, unsigned char dat);
int FLASH_PageErase (unsigned int addr);
//-----------------------------------------------------------------------------------// MAIN Routine
void main (void) {
unsigned long id;
unsigned char dest;
int pass;
id = 0x12345678L;
init ();
// initialize ports
JTAG_Reset ();
// Reset the JTAG state machine on DUT
JTAG_IR_Scan (RESET, INST_LENGTH);
// Reset the DUT
JTAG_IR_Scan (IDCODE, INST_LENGTH);
id = JTAG_DR_Scan (0x0L, IDCODE_LEN);
//
//
//
//
load IDCODE into IR and HALT the DUT
read the IDCODE
IDCODE should = 0x10000243 for
C8051F000 rev D device
// here we erase the FLASH page 0x1000 - 0x11ff, read 0x1000 (it’s an 0xff),
// write a 0x66 to 0x1000, and read 0x1000 again (it’s changed to an 0x66).
while (1) {
pass = FLASH_PageErase (0x7c00);
// erase page prior to writing...
while (!pass);
// handle Write Lock condition
dest = 0x5a;
// set test variable to non-0xff value
pass = FLASH_ByteRead (0x7c00, &dest);
while (!pass);
// dest should return 0xff
// handle Read Lock condition
dest = 0x66;
pass = FLASH_ByteWrite (0x7c00, dest);
while (!pass);
// store 0x66 at 0x1000
// handle Read Lock condition
pass = FLASH_ByteRead (0x7c00, &dest);
while (!pass);
// dest should return 0x66
// handle Read Lock condition
pass = FLASH_PageErase (0x7c00);
Rev. 1.4
21
AN105
while (!pass);
pass = FLASH_ByteRead (0x7c00, &dest);
while (!pass);
}
}
//-----------------------------------------------------------------------------------// Functions and Procedures
//-----------------------------------------------------------------------------------//-----------------------------------------------------------------------------------// init
//-----------------------------------------------------------------------------------// This routine disables the watchdog timer and initializes the GPIO pins
//
void init (void) {
WDTCN = 0xde;
WDTCN = 0xad;
// disable watchdog timer
XBR2 |= 0x40;
PRT1CF |= 0x40;
PRT3CF |= 0xe0;
P3 &= 0x1f;
//
//
//
//
enable crossbar
enable P1.6 (LED) as a push-pull output
make P3.7-5 push-pull outputs
TCK, TMS, and TDI all low
}
//-----------------------------------------------------------------------------------// JTAG_StrobeTCK
//-----------------------------------------------------------------------------------// This routine strobes the TCK pin (brings high then back low again)
// on the target system.
//
void JTAG_StrobeTCK (void) {
TCK = 1;
TCK = 0;
}
//-----------------------------------------------------------------------------------// JTAG_Reset
//-----------------------------------------------------------------------------------// This routine places the JTAG state machine on the target system in
// the Test Logic Reset state by strobing TCK 5 times while leaving
// TMS high. Leaves the JTAG state machine in the Run_Test/Idle state.
//
void JTAG_Reset (void) {
TMS = 1;
JTAG_StrobeTCK
JTAG_StrobeTCK
JTAG_StrobeTCK
JTAG_StrobeTCK
JTAG_StrobeTCK
();
();
();
();
();
// move to Test Logic Reset state
TMS = 0;
22
Rev. 1.4
AN105
JTAG_StrobeTCK ();
// move to Run_Test/Idle state
}
//-----------------------------------------------------------------------------------// JTAG_IR_Scan
//-----------------------------------------------------------------------------------// This routine loads the supplied <instruction> of <num_bits> length into the JTAG
// Instruction Register on the target system. Leaves in the Run_Test/Idle state.
// The return value is the n-bit value read from the IR.
// Assumes the JTAG state machine starts in the Run_Test/Idle state.
//
unsigned int JTAG_IR_Scan (unsigned int instruction, int num_bits) {
unsigned int retval;
int
i;
// JTAG instruction read
// JTAG IR bit counter
retval = 0x0;
TMS = 1;
JTAG_StrobeTCK
TMS = 1;
JTAG_StrobeTCK
TMS = 0;
JTAG_StrobeTCK
TMS = 0;
JTAG_StrobeTCK
();
// move to SelectDR
();
// move to SelectIR
();
// move to Capture_IR
();
// move to Shift_IR state
for (i=0; i < num_bits; i++) {
TDI = (instruction & 0x01);
instruction = instruction >> 1;
// shift IR, LSB-first
retval = retval >> 1;
if (TDO) {
retval |= (0x01 << (num_bits - 1));
}
if (i == (num_bits - 1)) {
TMS = 1;
}
// move to Exit1_IR state
JTAG_StrobeTCK();
}
TMS = 1;
JTAG_StrobeTCK ();
TMS = 0;
JTAG_StrobeTCK ();
// move to Update_IR
// move to RTI state
return retval;
}
//-----------------------------------------------------------------------------------// JTAG_DR_Scan
//-----------------------------------------------------------------------------------// This routine shifts <num_bits> of <data> into the Data Register, and returns
// up to 32-bits of data read from the Data Register.
// Leaves in the Run_Test/Idle state.
// Assumes the JTAG state machine starts in the Run_Test/Idle state.
Rev. 1.4
23
AN105
//
unsigned long JTAG_DR_Scan (unsigned long dat, int num_bits) {
unsigned long
int
i;
retval;
// JTAG return value
// JTAG DR bit counter
retval = 0x0L;
TMS = 1;
JTAG_StrobeTCK ();
TMS = 0;
JTAG_StrobeTCK ();
TMS = 0;
JTAG_StrobeTCK ();
// move to SelectDR
// move to Capture_DR
// move to Shift_DR state
for (i=0; i < num_bits; i++) {
TDI = (dat & 0x01);
dat = dat >> 1;
// shift DR, LSB-first
retval = retval >> 1;
if (TDO) {
retval |= (0x01L << (num_bits - 1));
}
if ( i == (num_bits - 1)) {
TMS = 1;
}
JTAG_StrobeTCK();
}
TMS = 1;
JTAG_StrobeTCK ();
TMS = 0;
JTAG_StrobeTCK ();
// move to Exit1_DR state
// move to Update_DR
// move to RTI state
return retval;
}
//-----------------------------------------------------------------------------------// JTAG_IWrite
//-----------------------------------------------------------------------------------// This routine performs an indirect write to register <ireg>, containing <dat>, of
// <num_bits> in length. It follows the write operation with a polling operation, and
// returns when the operation is completed. Note: the polling implemented here refers
// to the JTAG register write operation being completed, NOT the FLASH write operation.
// Polling for the FLASH write operation is handled at a higher level
// Examples of valid indirect registers are:
// FLCN - FLASH Control
// FLSC - FLASH Scale
// FLA - FLASH Address
// FLD - FLASH Data
// Leaves in the Run_Test/Idle state.
//
void JTAG_IWrite (unsigned int ireg, unsigned long dat, int num_bits) {
24
int done;
// TRUE = write complete; FALSE otherwise
JTAG_IR_Scan (ireg, INST_LENGTH);
// load IR with <ireg>
Rev. 1.4
AN105
dat |= (0x03L << num_bits);
// append ‘WRITE’ opcode to data
// load DR with <dat>
JTAG_DR_Scan (dat, num_bits + 2);
// initiate the JTAG write
// load DR with ‘0’, and check for BUSY bit to go to ‘0’.
do {
done = !(JTAG_DR_Scan (0x0L, 1));
// poll for JTAG_BUSY bit
} while (!done);
}
//-----------------------------------------------------------------------------------// JTAG_IRead
//-----------------------------------------------------------------------------------// This routine performs an indirect read of register <ireg>, of <num_bits> in length.
// It follows the read operation with a polling operation, and returns when the
// operation is completed. Note: the polling implemented here refers to the JTAG
// register read operation being completed, NOT the FLASH read operation.
// Polling for the FLASH read operation is handled at a higher level.
// Examples of valid indirect registers are:
// FLCN - FLASH Control
// FLSC - FLASH Scale
// FLA - FLASH Address
// FLD - FLASH Data
// Leaves in the Run_Test/Idle state.
//
unsigned long JTAG_IRead (unsigned int ireg, int num_bits) {
unsigned long retval;
int done;
// value returned from READ operation
// TRUE = write complete; FALSE otherwise
JTAG_IR_Scan (ireg, INST_LENGTH);
// load IR with <ireg>
// load DR with read opcode (0x02)
JTAG_DR_Scan (0x02L, 2);
// initiate the JTAG read
do {
done = !(JTAG_DR_Scan (0x0L, 1));
} while (!done);
// poll for JTAG_BUSY bit
retval = JTAG_DR_Scan (0x0L, num_bits + 1);
retval = retval >> 1;
// allow poll operation to
// read remainder of the bits
// shift JTAG_BUSY bit off the end
return retval;
}
//-----------------------------------------------------------------------------------// FLASH_ByteRead
//-----------------------------------------------------------------------------------// This routine reads the byte at <addr> and stores it at the address pointed to by
// <pdat>.
// Returns TRUE if the operation was successful; FALSE otherwise (page read-protected).
//
int FLASH_ByteRead (unsigned int addr, unsigned char *pdat)
{
unsigned long testval;
// holds result of FLASHDAT read
Rev. 1.4
25
AN105
int done;
int retval;
// TRUE/FALSE flag
// TRUE if operation successful
JTAG_IWrite (FLASHSCL, 0x86L, FLSC_LEN);
// set FLASHSCL based on SYSCLK
// frequency (2MHz = 0x86)
// set FLASHADR to address to read from
JTAG_IWrite (FLASHADR, (unsigned long) addr, FLA_LEN);
JTAG_IWrite (FLASHCON, 0x02L, FLCN_LEN);
// set FLASHCON for FLASH Read
// operation (0x02)
JTAG_IRead (FLASHDAT, FLD_RDLEN);
// initiate the read operation
JTAG_IWrite (FLASHCON, 0x0L, FLCN_LEN);
// set FLASHCON for ‘poll’ operation
do {
done = !(JTAG_IRead (FLASHDAT, 1));
} while (!done);
// poll for FLBUSY to de-assert
testval = JTAG_IRead (FLASHDAT, FLD_RDLEN); // read the resulting data
retval = (testval & 0x02) ? FALSE: TRUE;
// FLFail is next to LSB
testval = testval >> 2;
// shift data.0 into LSB position
*pdat = (unsigned char) testval;
// place data in return location
return retval;
// return FLASH Pass/Fail
}
//-----------------------------------------------------------------------------------// FLASH_ByteWrite
//-----------------------------------------------------------------------------------// This routine writes the data <dat> to FLASH at the address <addr>.
// Returns TRUE if the operation was successful; FALSE otherwise (page
// write-protected).
//
int FLASH_ByteWrite (unsigned int addr, unsigned char dat)
{
unsigned long testval;
// holds result of FLASHDAT read
int done;
// TRUE/FALSE flag
int retval;
// TRUE if operation successful
JTAG_IWrite (FLASHSCL, 0x86L, FLSC_LEN);
// set FLASHSCL based on SYSCLK
// frequency (2MHz = 0x86)
// set FLASHADR to address to write to
JTAG_IWrite (FLASHADR, (unsigned long) addr, FLA_LEN);
JTAG_IWrite (FLASHCON, 0x10L, FLCN_LEN);
// set FLASHCON for FLASH Write
// operation (0x10)
// initiate the write operation
JTAG_IWrite (FLASHDAT, (unsigned long) dat, FLD_WRLEN);
JTAG_IWrite (FLASHCON, 0x0L, FLCN_LEN);
// set FLASHCON for ‘poll’ operation
do {
26
Rev. 1.4
AN105
done = !(JTAG_IRead (FLASHDAT, 1));
} while (!done);
// poll for FLBusy to de-assert
testval = JTAG_IRead (FLASHDAT, 2);
// read FLBusy and FLFail
retval = (testval & 0x02) ? FALSE: TRUE;
// FLFail is next to LSB
return retval;
// return FLASH Pass/Fail
}
//-----------------------------------------------------------------------------------// FLASH_PageErase
//-----------------------------------------------------------------------------------// This routine performs an erase of the page in which <addr> is contained.
// This routine assumes that no FLASH operations are currently in progress.
// This routine exits with no FLASH operations currently in progress.
// Returns TRUE if the operation was successful; FALSE otherwise (page protected).
//
int FLASH_PageErase (unsigned int addr)
{
unsigned long testval;
// holds result of FLASHDAT read
int done;
// TRUE/FALSE flag
int retval;
// TRUE if operation successful
JTAG_IWrite (FLASHSCL, 0x86L, FLSC_LEN);
// set FLASHSCL based on SYSCLK
// frequency (2MHz = 0x86)
// set FLASHADR to address within page to erase
JTAG_IWrite (FLASHADR, (unsigned long) addr, FLA_LEN);
JTAG_IWrite (FLASHCON, 0x20L, FLCN_LEN);
// set FLASHCON for FLASH Erase
// operation (0x20)
JTAG_IWrite (FLASHDAT, 0xa5L, FLD_WRLEN);
// set FLASHDAT to 0xa5 to initiate
// erase procedure
JTAG_IWrite (FLASHCON, 0x0L, FLCN_LEN);
// set FLASHCON for ‘poll’ operation
do {
done = !(JTAG_IRead (FLASHDAT, 1));
} while (!done);
// poll for FLBusy to de-assert
testval = JTAG_IRead (FLASHDAT, 2);
// read FLBusy and FLFail
retval = (testval & 0x02) ? FALSE: TRUE;
// FLFail is next to LSB
// set return value based on FLFail bit
return retval;
// return FLASH Pass/Fail
}
Rev. 1.4
27
AN105
Programming Multiple JTAG Devices in a Chain
//************************************************************************************
// JTAG_Chain.c
//-----------------------------------------------------------------------------------// This program contains some primitive routines which gather information through the
// JTAG port on multiple JTAG compatible devices under test (DUT) connected in a
// chain. The TCK & TMS JTAG pins on the DUT are connected in parallel to port pins on
// the C8051F00x, C8051F01x master device and the TDI & TDO pins are connected in
// series.
//
// **NOTE: The first device in the chain (device 0) is the one whose TDO pin is
//
connected to the TDO pin of the master device.
//
// Target device: C8051F00x,C8051F01x
//
// Tool chain: KEIL Eval ‘c’
//************************************************************************************
//-----------------------------------------------------------------------------------// Includes
//-----------------------------------------------------------------------------------#include <c8051f000.h>
// SFR declarations
//-----------------------------------------------------------------------------------// Global CONSTANTS
//-----------------------------------------------------------------------------------#define MAX_NUM_DEVICES_IN_CHAIN 10
#define SYSCLK 2000000
// SYSCLK frequency in Hz
sbit
LED = P1^6;
// green LED: ‘1’ = ON; ‘0’ = OFF
sbit
sbit
sbit
TCK = P3^7;
TMS = P3^6;
TDI = P3^5;
sbit
TDO = P3^4;
#define
#define
//
//
//
//
//
//
JTAG Test Clock -- Connected to TCK pin on all devices.
JTAG Mode Select -- Connected to TMS pin on all devices.
JTAG Data Input(output of master) -- Connected to the
TDI pin of device n.
JTAG Data Output (input to master)-- Connected to the
TDO pin of device 0.
TRUE 1
FALSE 0
// JTAG Instruction Register Addresses
#define
INST_LENGTH 16
#define
BYPASS
0xffff
#define
EXTEST
0x0000
#define
SAMPLE
0x0002
// number of bits in the C8051Fxxx
// Instruction Register
#define
RESET
0x2fff
// System RESET Instruction
#define
#define
IDCODE
IDCODE_LEN
0x1004
32
// IDCODE Instruction address/HALT
// number of bits in the ID code
#define
#define
FLASHCON
FLCN_LEN
0x4082
8
// FLASH Control Instruction address
// number of bits in FLASHCON
28
Rev. 1.4
AN105
#define
#define
#define
FLASHDAT
FLD_RDLEN
FLD_WRLEN
0x4083
10
8
// FLASH Data Instruction address
// number of bits in an FLASHDAT read
// number of bits in an FLASHDAT write
#define
#define
FLASHADR
FLA_LEN
0x4084
16
// FLASH Address Instruction address
// number of bits in FLASHADR
#define
FLASHSCL
0x4085
// FLASH Scale Instruction address
#define
FLSC_LEN
8
// number of bits in FLASHSCL
//-----------------------------------------------------------------------------------// Global Variable DECLARATIONS
//-----------------------------------------------------------------------------------// The addresses of the following variables are explicitly defined for viewing
// purposes. If the width of the external memory window is 5 bytes, then each
// device will take up exactly one row starting from the second row.
char xdata num_devices _at_ 0x0000;
char
char
char
char
xdata
xdata
xdata
xdata
num_devices_before
num_devices_after
num_IR_bits_before
num_IR_bits_after
_at_
_at_
_at_
_at_
typedef struct JTAG_Information {
unsigned char IR_length;
unsigned long id;
} JTAG_Information;
0x0001;
0x0002;
0x0003;
0x0004;
//
//
//
//
#devices before and after the isolated
device
#instruction register bits before and
after the isolated device
// Discovery information
// Instruction register length
// Identification code for each device
// Array: one entry per device in the
// JTAG chain
JTAG_Information xdata JTAG_info[MAX_NUM_DEVICES_IN_CHAIN];
//-----------------------------------------------------------------------------------// Function PROTOTYPES
//-----------------------------------------------------------------------------------void init (void);
void JTAG_StrobeTCK (void);
void JTAG_Reset (void);
void Blink_Led(void);
void
void
void
void
JTAG_Discover(void);
JTAG_Discover_IR(void);
JTAG_Discover_DR(void);
JTAG_Isolate(char index);
unsigned long JTAG_IR_Scan (unsigned long instruction, char num_bits) ;
unsigned long JTAG_DR_Scan (unsigned long dat, char num_bits);
void JTAG_IWrite (unsigned int ireg, unsigned long dat, int num_bits);
unsigned long JTAG_IRead (unsigned int ireg, int num_bits);
int FLASH_ByteRead (unsigned int addr, unsigned char *pdat);
int FLASH_ByteWrite (unsigned int addr, unsigned char dat);
int FLASH_PageErase (unsigned int addr);
//-----------------------------------------------------------------------------------// MAIN Routine
//------------------------------------------------------------------------------------
Rev. 1.4
29
AN105
void main (void)
{
long xdata id;
unsigned char dest;
int pass;
int address;
char device = 0;
init ();
// initialize ports
LED = 1;
// turn on the LED
JTAG_Discover();
JTAG_Isolate(0);
JTAG_IR_Scan (IDCODE, INST_LENGTH);
id = JTAG_DR_Scan (0x0L, IDCODE_LEN);
//
//
//
//
//
JTAG_Isolate(1);
JTAG_IR_Scan (IDCODE, INST_LENGTH);
id = JTAG_DR_Scan (0x0L, IDCODE_LEN);
// load IDCODE into IR and HALT the DUT
// get the ID Code of the isolated device
JTAG_Isolate(2);
JTAG_IR_Scan (IDCODE, INST_LENGTH);
id = JTAG_DR_Scan (0x0L, IDCODE_LEN);
// load IDCODE into IR and HALT the DUT
// get the ID Code of the isolated device
IDCODE should = 0x10000243 for
C8051F000 rev D device
isolate device 0
load IDCODE into IR and HALT the DUT
get the ID Code of the isolated device
// Here we perform 2 tests on each device. These 2 tests take approximately
// 43 seconds for each device with SYSCLK at 2 Mhz and approximatly 6 seconds
// running at 16 Mhz.
for(device = 0; device < num_devices; device++) {
JTAG_Isolate(device);
//TEST 1 -- ERASE A FLASH PAGE
pass = FLASH_PageErase (0x1000);
while (!pass);
// erase page prior to writing
// handle Write Lock condition
//Verify that locations 0x1000 - 0x11FF are 0xFF
for(address = 0x1000; address < 0x1200; address++){
pass = FLASH_ByteRead (address, &dest);
// dest should return 0xff
if(!pass || dest != 0xFF) Blink_Led();
}
//TEST 2 -- WRITE A PATTERN TO FLASH PAGE
for(address = 0x1000; address < 0x1200; address++){
dest = address & 0x00FF;
// strip away upper 8 bits
pass = FLASH_ByteWrite (address, dest);// store LSByte of address at address
while (!pass);
// handle Read Lock condition
}
dest = 0x12;
// set test variable to non-0xff value
//Verify that locations 0x1000 - 0x11FF are following the pattern
30
Rev. 1.4
AN105
for(address = 0x1000; address < 0x1200; address++){
pass = FLASH_ByteRead (address, &dest);
if(!pass || dest != (address & 0x00FF)) Blink_Led();
}
}
LED = 0;
// turn off the led,
// program executed correctly
while(1);
}
//************************************************************************************
// Function and Procedure DEFINITIONS
//************************************************************************************
//-----------------------------------------------------------------------------------// Blink_Led
//-----------------------------------------------------------------------------------// This routine blinks the Green LED forever to indicate an error.
//
void Blink_Led(void)
{
int i;
// millisecond counter
int ms = 200;
// stay in each state for ms milliseconds
TCON
TMOD
TMOD
CKCON
&= ~0x30;
&= ~0x0F;
|= 0x01;
|= 0x08;
// STOP Timer0 and clear overflow flag
// configure Timer0 to 16-bit mode
// Timer0 counts SYSCLKs
while (1){
LED = ~LED;
for (i
TR0
TH0
TL0
TR0
=
=
=
=
=
0; i < ms; i++) {
0;
(-SYSCLK/1000) >> 8;
-SYSCLK/1000;
1;
// count milliseconds
// STOP Timer0
// SET Timer0 to overflow in 1ms
// START Timer0
while(TF0 == 0);
// wait for overflow
TF0 = 0;
// clear overflow indicator
}
}
}
//-----------------------------------------------------------------------------------// init
//-----------------------------------------------------------------------------------// This routine disables the watchdog timer and initializes the GPIO pins
//
void init (void)
{
WDTCN = 0xde;
WDTCN = 0xad;
// disable watchdog timer
Rev. 1.4
31
AN105
XBR2
PRT1CF
PRT3CF
P3
|= 0x40;
|= 0x40;
|= 0xe0;
&= ~0xE0;
//
//
//
//
enable crossbar
enable P1.6 (LED) as a push-pull output
make P3.7-5 push-pull outputs
set TCK, TMS, and TDI all low
num_devices = 1;
// The default number of devices is one.
// JTAG_Discover() does not have to be
// called if only one device is connected.
num_devices_before = 0;
num_devices_after = 0;
num_IR_bits_before = 0;
num_IR_bits_after = 0;
//
//
//
//
//
Initializing these variables to zero
allows calling the JTAG_IR_Scan() and
the JTAG_DR_Scan() without first
calling JTAG_Isolate() when there is
only one device in the chain.
}
//-----------------------------------------------------------------------------------// JTAG_StrobeTCK
//-----------------------------------------------------------------------------------// This routine strobes the TCK pin (brings high then back low again)
// on the target system.
//
void JTAG_StrobeTCK (void)
{
TCK = 1;
TCK = 0;
}
//-----------------------------------------------------------------------------------// JTAG_Reset
//-----------------------------------------------------------------------------------// This routine places the JTAG state machine on the target system in
// the Test Logic Reset state by strobing TCK 5 times while leaving
// TMS high. Leaves the JTAG state machine in the Run_Test/Idle state.
//
void JTAG_Reset (void)
{
TMS = 1;
JTAG_StrobeTCK
JTAG_StrobeTCK
JTAG_StrobeTCK
JTAG_StrobeTCK
JTAG_StrobeTCK
();
();
();
();
();
// move to Test Logic Reset state
TMS = 0;
JTAG_StrobeTCK ();
// move to Run_Test/Idle state
}
//-----------------------------------------------------------------------------------// JTAG_Discover
//-----------------------------------------------------------------------------------// This routine sequentially queries a chain of JTAG devices and accomplishes the
// following three tasks.
//
For the global struct array <JTAG_info>
32
Rev. 1.4
AN105
//
-- fills in the length of each device’s instruction register
//
-- fills in each device’s IDCODE.
//
For the global variable <num_devices>
//
-- updates it with the number of JTAG devices connected in the chain.
//
void JTAG_Discover(void)
{
JTAG_Discover_IR();
// At this point we know num_devices(a global variable) and we know the
// length of each device’s IR given in the variable JTAG_info[].IR_length
JTAG_Discover_DR();
// Read and assign the ID for each
// device
} //end discover
//-----------------------------------------------------------------------------------// JTAG_Discover_IR
//-----------------------------------------------------------------------------------// This routine fills a structure with the length of each device’s instruction
// register. It also updates the global variable <num_devices> with the number of
// JTAG devices connected in the chain.
//
// BACKGROUND: When an IRSCAN is issued, a JTAG device must return a 1 as the LSB
//
and zeros in all the other bits. We shift in all ones so when we
//
encounter two ones in a row, we know we are past the end of the chain.
//
A state machine is implemented in this routine to keep track of
//
inputs received.
//
// STATE DEFINITONS:
//
0 - NO INPUTS -- at beginning of chain
//
1 - INPUT SEQUENCE: 1 -- could be at a new device or at chain end
//
2 - INPUT SEQUENCE: 100..0 -- counting zeros
//
//
void JTAG_Discover_IR(void)
{
char state = 0;
// beginning of chain
char num_zeros = 0;
// number of zeros following a one in
// an IR_SCAN. num_zeros + 1 = IR_length
char current_device_index = -1;
bit done = FALSE;
// current_device_index + 1 = num_devices
// (on the last iteration)
// TRUE when end of chain is reached
JTAG_Reset();
// RESET and move to Run_Test/Idle
// advance to Shift_IR State
TMS = 1;
JTAG_StrobeTCK ();
TMS = 1;
JTAG_StrobeTCK ();
TMS = 0;
JTAG_StrobeTCK ();
TMS = 0;
// move to SelectDR
// move to SelectIR
// move to Capture_IR
Rev. 1.4
33
AN105
JTAG_StrobeTCK ();
// move to Shift_IR state and get the
// the first input
TDI = 1;
// STATE is initially 0
// shift in all ones
// for each device
do{
if(TDO != 1){
Blink_Led();
}
// Error if the first input is not one.
// Could mean bad connections or
// non-compliant devices.
state = 1;
// received a 1, could be at a new
// device or at the end of the chain
num_zeros = 0;
// initialize for the zero counting loop
// for the number of zeros in each device’s IR
do {
JTAG_StrobeTCK();
// get the next bit.
switch(state){
case 1: if(TDO == 0){
// found new device(10)
current_device_index++;
num_zeros++;
state = 2;
} else {
done = TRUE;
// at end of chain (11)
}
break;
case 2: if(TDO == 0){
num_zeros++;
} else {
state = 1;
}
break;
default: Blink_Led();
// counting zeros (10..0)
// past end of current device (10..01)
// an error has occurred
} // end switch
} while ((state != 1) && (!done));
// while the input is not one,
// count zeros until we get a one.
if (!done) {
// if we are not past the last device
JTAG_info[current_device_index].IR_length = num_zeros + 1;
}
} while (!done);
//while we are not past the last device
num_devices = current_device_index + 1;
34
Rev. 1.4
AN105
// navigate the JTAG State Machine back to RTI state.
TMS = 1;
JTAG_StrobeTCK ();
// move to Exit1_IR state
TMS = 1;
JTAG_StrobeTCK ();
// move to Update_IR state
TMS = 0;
JTAG_StrobeTCK ();
// move to Run_Test/Idle state
}
//-----------------------------------------------------------------------------------// JTAG_Discover_DR
//-----------------------------------------------------------------------------------//GOAL: Obtain the ID code of each device(If it supports IDCODE), and fill in
//
the field JTAG_info[].id (32-bit).
//
Assign all zeros if device does not have an IDCODE.
//
//BACKGROUND: After JTAG State Machine Reset, the IDCODE is automatically selected
//
If a device does not have an IDCODE register, the BYPASS
//
register is selected instead.
//
On a DR_SCAN, each IDCODE register returns a 32-bit ID with LSB = 1
//
and each BYPASS register returns 1-bit = 0.
void JTAG_Discover_DR(void)
{
char current_device_index = 0;
unsigned char i;
// loop counter
JTAG_Reset ();
// Reset the JTAG state machine on DUT
// move to Run_Test/Idle
// The IDCODE or the BYPASS Register is automatically selected.
// Navigate to the Shift_DR state
TMS = 1;
JTAG_StrobeTCK ();
TMS = 0;
JTAG_StrobeTCK ();
TMS = 0;
TDI = 1;
// move to SelectDR
// move to Capture_DR
// shift in all ones
current_device_index = 0;
while (current_device_index < num_devices) {
JTAG_StrobeTCK ();
// move to Shift_DR state and get input
if (TDO == 0) {
// Device does not have an IDCODE register
JTAG_info[current_device_index].id = 0x00000000L;
} else { // TDO == 1
JTAG_info[current_device_index].id = 0x80000000L;
Rev. 1.4
35
AN105
for (i = 0; i < 31; i++){
// Get the next 31-bits of the device ID
JTAG_StrobeTCK ();
JTAG_info[current_device_index].id =
JTAG_info[current_device_index].id >> 1;
if (TDO) {
JTAG_info[current_device_index].id |= 0x80000000L;
}
} // end for
} // end if-else
current_device_index++;
} // end while
//fill the rest of the entries with zeros
for (; current_device_index < MAX_NUM_DEVICES_IN_CHAIN; current_device_index++) {
JTAG_info[current_device_index].IR_length = 0;
JTAG_info[current_device_index].id = 0x00000000L;
}
// Navigate JTAG State Machine back to RTI state
TMS = 1;
JTAG_StrobeTCK ();
// move to Exit1_DR
TMS = 1;
JTAG_StrobeTCK ();
// move to Update DR
TMS = 0;
JTAG_StrobeTCK ();
// move to RTI
}
//-----------------------------------------------------------------------------------// JTAG_Isolate
//-----------------------------------------------------------------------------------// This routine updates 4 global variables. JTAG_Discover() must be called prior to
// calling this routine in order to set up the data structure.
//
// VARIABLE DEFINITIONS
//
num_IR_bits_before -- number of instruction register bits before the isolated
//
device
//
num_IR_bits_after -- number of instruction register bits after the isolated
//
device
//
num_devices_before -- number of devices before the isolated device
//
num_devices_after -- number of device after the isolated device
//
void JTAG_Isolate(char index)
{
unsigned char i;
if ((index > (num_devices - 1)) || (index < 0) ) {
// check if index is out of range
Blink_Led();
}
36
Rev. 1.4
AN105
num_devices_before = index;
num_devices_after = num_devices - index - 1;
num_IR_bits_before = 0;
num_IR_bits_after = 0;
// initializing for loop
for (i = 0; i < num_devices; i++) {
if (i < index) {
num_IR_bits_before += JTAG_info[i].IR_length;
} else if (i > index) {
num_IR_bits_after += JTAG_info[i].IR_length;
}
// last case -- equal, do nothing
} // end for
} //end isolate
//-----------------------------------------------------------------------------------// JTAG_IR_Scan
//-----------------------------------------------------------------------------------// This routine loads the supplied <instruction> of <num_bits> length into the JTAG
// Instruction Register on the isolated device. It shifts the BYPASS opcode (all ones)
// into the Instruction Registers of the other devices in the chain.
//
// NOTE: JTAG_Discover() must be called before this function is called.
//
// NOTE: If more than one device is connected in the chain, JTAG_Isolate() must also
//
be called prior to calling this function.
//
// The return value is the n-bit value read from the IR.
// Assumes the JTAG state machine starts in the Run_Test/Idle state.
// Leaves JTAG in the Run_Test/Idle state.
//
unsigned long JTAG_IR_Scan (unsigned long instruction, char num_bits)
{
unsigned long retval;
char i;
// JTAG instruction read
// JTAG IR bit counter
retval = 0x0L;
// navigate the JTAG State Machine in all devices to the Shift_IR state
TMS = 1;
JTAG_StrobeTCK ();
// move to SelectDR
TMS = 1;
JTAG_StrobeTCK ();
// move to SelectIR
TMS = 0;
JTAG_StrobeTCK ();
// move to Capture_IR
TMS = 0;
JTAG_StrobeTCK ();
// move to Shift_IR state
TDI=1;
for (i=0; i < num_IR_bits_before; i++) {
Rev. 1.4
37
AN105
JTAG_StrobeTCK();
// fill the IR of the devices
// before the isolated device
// with all ones, the BYPASS opcode
}
for (i=0; i < num_bits; i++) {
TDI = (instruction & 0x01);
instruction = instruction >> 1;
// determine output
retval = retval >> 1;
if (TDO) {
retval |= (0x01 << (num_bits - 1));
}
if ((i == (num_bits - 1)) && (num_IR_bits_after == 0)) {
TMS = 1;
// move to Exit1_IR state
}
JTAG_StrobeTCK();
// move to Shift_IR state
// advance
}
TDI = 1;
for (i=0; i < num_IR_bits_after; i++) {
// now process IR bits after the
// isolated device
if (i == (num_IR_bits_after - 1)) {
TMS = 1;
}
// move to Exit1_IR state
JTAG_StrobeTCK();
// fill the IR of the devices
// after the isolated device
// with all ones, the BYPASS opcode.
}
// navigate back to the RTI state
TMS = 1;
JTAG_StrobeTCK ();
TMS = 0;
JTAG_StrobeTCK ();
// move to Update_IR
// move to RTI state
return retval;
}
//-----------------------------------------------------------------------------------// JTAG_DR_Scan
//-----------------------------------------------------------------------------------// This routine shifts <num_bits> of <data> into the Data Register of the isolated
// device in the chain, and returns up to 32-bits of data read from its Data Register.
//
// Assumes the JTAG state machine starts in the Run_Test/Idle state.
// Leaves in the Run_Test/Idle state.
//
unsigned long JTAG_DR_Scan (unsigned long dat, char num_bits)
{
unsigned long retval;
38
// JTAG return value
Rev. 1.4
AN105
char i;
// JTAG DR bit counter
retval = 0x0L;
// navigate the JTAG State Machine in all devices to
TMS = 1;
JTAG_StrobeTCK ();
// move
TMS = 0;
JTAG_StrobeTCK ();
// move
TMS = 0;
JTAG_StrobeTCK ();
// move
the Shift_DR state
to SelectDR
to Capture_DR
to Shift_DR state
TDI = 0;
for (i=0; i < num_devices_before; i++) {
JTAG_StrobeTCK();
// fill the BYPASS Register
// of the devices before the
// isolated device with zeros.
}
for (i=0; i < num_bits; i++) {
TDI = (dat & 0x01);
dat = dat >> 1;
// determine the output
retval = retval >> 1;
if (TDO) {
retval |= (0x01L << (num_bits - 1));
}
if ((i == (num_bits - 1)) && (num_devices_after == 0)) {
TMS = 1;
// move to Exit1_IR state
}
JTAG_StrobeTCK();
//output and get input
}
TDI = 0;
for (i=0; i < num_devices_after; i++) {
if (i == (num_devices_after - 1)) {
TMS = 1;
}
JTAG_StrobeTCK();
}
// move to Exit1_IR state
//
//
//
//
move to Shift_DR state,
fill the BYPASS Register
of the devices after the
isolated device with zeros.
// navigate the JTAG State Machine in all devices to the RTI state
TMS = 1;
JTAG_StrobeTCK ();
// move to Update_DR
TMS = 0;
JTAG_StrobeTCK ();
// move to RTI state
return retval;
// retval is MSB aligned
Rev. 1.4
39
AN105
}
//-----------------------------------------------------------------------------------// JTAG_IWrite
//-----------------------------------------------------------------------------------// This routine performs an indirect write to register <ireg>, containing <dat>, of
// <num_bits> in length. It follows the write operation with a polling operation, and
// returns when the operation is completed. Note: the polling implemented here refers
// to the JTAG register write operation being completed, NOT the FLASH write operation.
// Polling for the FLASH write operation is handled at a higher level
// Examples of valid indirect registers are:
// FLASHCON - FLASH Control
// FLASHSCL - FLASH Scale
// FLASHADR - FLASH Address
// FLASHDAT - FLASH Data
// Leaves in the Run_Test/Idle state.
//
void JTAG_IWrite (unsigned int ireg, unsigned long dat, int num_bits)
{
bit done;
// TRUE = write complete; FALSE otherwise
JTAG_IR_Scan (ireg, INST_LENGTH);
// load IR with <ireg>
dat |= (0x03L << num_bits);
// append ‘WRITE’ opcode to data
// load DR with <dat>
JTAG_DR_Scan (dat, num_bits + 2);
// initiate the JTAG write
// load DR with ‘0’, and check for BUSY bit to go to ‘0’.
do {
done = !(JTAG_DR_Scan (0x0L, 1));
// poll for JTAG_BUSY bit
} while (!done);
}
//-----------------------------------------------------------------------------------// JTAG_IRead
//-----------------------------------------------------------------------------------// This routine performs an indirect read of register <ireg>, of <num_bits> in length.
// It follows the read operation with a polling operation, and returns when the
// operation is completed. Note: the polling implemented here refers to the JTAG
// register read operation being completed, NOT the FLASH read operation.
// Polling for the FLASH read operation is handled at a higher level.
// Examples of valid indirect registers are:
// FLASHCON - FLASH Control
// FLASHSCL - FLASH Scale
// FLASHADR - FLASH Address
// FLASHDAT - FLASH Data
// Leaves JTAG in the Run_Test/Idle state.
//
unsigned long JTAG_IRead (unsigned int ireg, int num_bits) {
40
unsigned long retval;
bit done;
// value returned from READ operation
// TRUE = write complete; FALSE otherwise
JTAG_IR_Scan (ireg, INST_LENGTH);
// load IR with <ireg>
// load DR with read opcode (0x02)
JTAG_DR_Scan (0x02L, 2);
// initiate the JTAG read
Rev. 1.4
AN105
do {
done = !(JTAG_DR_Scan (0x0L, 1));
} while (!done);
// poll for JTAG_BUSY bit
retval = JTAG_DR_Scan (0x0L, num_bits + 1);
retval = retval >> 1;
// allow poll operation to
// read remainder of the bits
// shift JTAG_BUSY bit off the end
return retval;
}
//-----------------------------------------------------------------------------------// FLASH_ByteRead
//-----------------------------------------------------------------------------------// This routine reads the byte at <addr> and stores it at the address pointed to by
// <pdat>.
// Returns TRUE if the operation was successful; FALSE otherwise (page
// read-protected).
//
int FLASH_ByteRead (unsigned int addr, unsigned char *pdat)
{
unsigned long testval;
// holds result of FLASHDAT read
bit done;
// TRUE/FALSE flag
int retval;
// TRUE if operation successful
JTAG_IWrite (FLASHSCL, 0x86L, FLSC_LEN);
// set FLASHSCL based on SYSCLK
// frequency (2MHz = 0x86)
// set FLASHADR to address to read from
JTAG_IWrite (FLASHADR, (unsigned long) addr, FLA_LEN);
JTAG_IWrite (FLASHCON, 0x02L, FLCN_LEN);
// set FLASHCON for FLASH Read
// operation (0x02)
JTAG_IRead (FLASHDAT, FLD_RDLEN);
// initiate the read operation
JTAG_IWrite (FLASHCON, 0x0L, FLCN_LEN);
// set FLASHCON for ‘poll’ operation
do {
done = !(JTAG_IRead (FLASHDAT, 1));
} while (!done);
// poll for FLBUSY to de-assert
testval = JTAG_IRead (FLASHDAT, FLD_RDLEN);
// read the resulting data
retval = (testval & 0x02) ? FALSE: TRUE;
// FLFail is next to LSB
testval = testval >> 2;
// shift data.0 into LSB position
*pdat = (unsigned char) testval;
// place data in return location
return retval;
// return FLASH Pass/Fail
}
//-----------------------------------------------------------------------------------// FLASH_ByteWrite
//-----------------------------------------------------------------------------------// This routine writes the data <dat> to FLASH at the address <addr>.
// Returns TRUE if the operation was successful; FALSE otherwise (page
Rev. 1.4
41
AN105
// write-protected).
//
int FLASH_ByteWrite (unsigned int addr, unsigned char dat)
{
unsigned long testval;
// holds result of FLASHDAT read
int done;
// TRUE/FALSE flag
int retval;
// TRUE if operation successful
JTAG_IWrite (FLASHSCL, 0x86L, FLSC_LEN);
// set FLASHSCL based on SYSCLK
// frequency (2MHz = 0x86)
// set FLASHADR to address to write to
JTAG_IWrite (FLASHADR, (unsigned long) addr, FLA_LEN);
JTAG_IWrite (FLASHCON, 0x10L, FLCN_LEN);
// set FLASHCON for FLASH Write
// operation (0x10)
// initiate the write operation
JTAG_IWrite (FLASHDAT, (unsigned long) dat, FLD_WRLEN);
JTAG_IWrite (FLASHCON, 0x0L, FLCN_LEN);
// set FLASHCON for ‘poll’ operation
do {
done = !(JTAG_IRead (FLASHDAT, 1));
} while (!done);
// poll for FLBusy to de-assert
testval = JTAG_IRead (FLASHDAT, 2);
// read FLBusy and FLFail
retval = (testval & 0x02) ? FALSE: TRUE;
// FLFail is next to LSB
return retval;
// return FLASH Pass/Fail
}
//-----------------------------------------------------------------------------------// FLASH_PageErase
//-----------------------------------------------------------------------------------// This routine performs an erase of the page in which <addr> is contained.
// This routine assumes that no FLASH operations are currently in progress.
// This routine exits with no FLASH operations currently in progress.
// Returns TRUE if the operation was successful; FALSE otherwise (page protected).
//
int FLASH_PageErase (unsigned int addr)
{
unsigned long testval;
// holds result of FLASHDAT read
bit done;
// TRUE/FALSE flag
int retval;
// TRUE if operation successful
JTAG_IWrite (FLASHSCL, 0x86L, FLSC_LEN);
// set FLASHSCL based on SYSCLK
// frequency (2MHz = 0x86)
// set FLASHADR to address within page to erase
JTAG_IWrite (FLASHADR, (unsigned long) addr, FLA_LEN);
42
JTAG_IWrite (FLASHCON, 0x20L, FLCN_LEN);
// set FLASHCON for FLASH Erase
// operation (0x20)
JTAG_IWrite (FLASHDAT, 0xa5L, FLD_WRLEN);
// set FLASHDAT to 0xa5 to initiate
// erase procedure
Rev. 1.4
AN105
JTAG_IWrite (FLASHCON, 0x0L, FLCN_LEN);
// set FLASHCON for ‘poll’ operation
do {
done = !(JTAG_IRead (FLASHDAT, 1));
} while (!done);
// poll for FLBusy to de-assert
testval = JTAG_IRead (FLASHDAT, 2);
// read FLBusy and FLFail
retval = (testval & 0x02) ? FALSE: TRUE;
// FLFail is next to LSB
// set return value based on FLFail bit
return retval;
// return FLASH Pass/Fail
}
Rev. 1.4
43
AN105
Software Examples For the ‘F02x Series
Programming a Single JTAG Device
//-----------------------------------------------------------------------------------// JTAG_Flash_F02x.c
//-----------------------------------------------------------------------------------// This program contains some primitive routines which read, write, and erase the FLASH
// through the JTAG port on a C8051Fxxx device under test (DUT). The JTAG pins on the
// DUT are connected to port pins on the C8051F02x master device.
//
// Target device: C8051F02x
//
// Tool chain: KEIL Eval ‘c’
//
//-----------------------------------------------------------------------------------// Includes
//-----------------------------------------------------------------------------------#include <c8051f020.h>
// SFR declarations
//-----------------------------------------------------------------------------------// 16-bit SFR Definitions for ‘F02x
//-----------------------------------------------------------------------------------sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
DP
TMR3RL
TMR3
ADC0
ADC0GT
ADC0LT
RCAP2
T2
RCAP4
T4
DAC0
DAC1
=
=
=
=
=
=
=
=
=
=
=
=
0x82;
0x92;
0x94;
0xbe;
0xc4;
0xc6;
0xca;
0xcc;
0xe4;
0xf4;
0xd2;
0xd5;
//
//
//
//
//
//
//
//
//
//
//
//
data pointer
Timer3 reload value
Timer3 counter
ADC0 data
ADC0 greater than window
ADC0 less than window
Timer2 capture/reload
Timer2
Timer4 capture/reload
Timer4
DAC0 data
DAC1 data
//-----------------------------------------------------------------------------------// Global CONSTANTS
//-----------------------------------------------------------------------------------sbit LED = P1^6;
// green LED: ‘1’ = ON; ‘0’ = OFF
sbit SW2 = P3^7;
// SW2=’0’ means switch pressed
#define SYSCLK
// GPIO pins
sbit
TCK =
sbit
TMS =
sbit
TDI =
sbit
TDO =
#define
#define
22118400
connecting to JTAG pins on device to
P3^7;
// JTAG
P3^6;
// JTAG
P3^5;
// JTAG
P3^4;
// JTAG
be programmed (DUT)
Test Clock
Mode Select
Data Input
Data Output
TRUE 1
FALSE 0
// JTAG Instruction Register Addresses
#define
INST_LENGTH 16
44
// SYSCLK frequency in Hz
// number of bits in the Instruction Register
Rev. 1.4
AN105
#define
#define
#define
BYPASS
EXTEST
SAMPLE
0xffff
0x0000
0x0002
#define
RESET
0x2fff
// System RESET Instruction
#define
#define
IDCODE
IDCODE_LEN
0x1004
32
// IDCODE Instruction address/HALT
// number of bits in the ID code
#define
#define
FLASHCON
FLCN_LEN
0x4082
8
// FLASH Control Instruction address
// number of bits in FLASHCON
#define
#define
#define
FLASHDAT
FLD_RDLEN
FLD_WRLEN
0x4083
10
8
// FLASH Data Instruction address
// number of bits in an FLASHDAT read
// number of bits in an FLASHDAT write
#define
#define
FLASHADR
FLA_LEN
0x4084
16
// FLASH Address Instruction address
// number of bits in FLASHADR
#define
#define
FLASHSCL
FLSC_LEN
0x4085
8
// FLASH Scale Instruction address
// number of bits in FLASHSCL
//-----------------------------------------------------------------------------------// Function PROTOTYPES
//-----------------------------------------------------------------------------------void SYSCLK_Init (void);
void PORT_Init (void);
void JTAG_StrobeTCK (void);
void JTAG_Reset (void);
unsigned int JTAG_IR_Scan (unsigned int instruction, int num_bits);
unsigned long JTAG_DR_Scan (unsigned long dat, int num_bits);
void JTAG_IWrite (unsigned int ireg, unsigned long dat, int num_bits);
unsigned long JTAG_IRead (unsigned int ireg, int num_bits);
int FLASH_ByteRead (unsigned int addr, unsigned char *pdat);
int FLASH_ByteWrite (unsigned int addr, unsigned char dat);
int FLASH_PageErase (unsigned int addr);
//-----------------------------------------------------------------------------------// MAIN Routine
void main (void) {
unsigned long id;
unsigned char dest;
int pass;
id = 0x12345678L;
WDTCN = 0xde;
WDTCN = 0xad;
// disable watchdog timer
PORT_Init ();
SYSCLK_Init ();
// initialize crossbar and GPIO
// initialize oscillator
JTAG_Reset ();
// Reset the JTAG state machine on DUT
Rev. 1.4
45
AN105
JTAG_IR_Scan (RESET, INST_LENGTH);
// Reset the DUT
JTAG_IR_Scan (IDCODE, INST_LENGTH);
id = JTAG_DR_Scan (0x0L, IDCODE_LEN);
//
//
//
//
load IDCODE into IR and HALT the DUT
read the IDCODE
IDCODE should = 0x10000243 for
C8051F000 rev D device
// here we erase the FLASH page 0x1000 - 0x11ff, read 0x1000 (it’s an 0xff),
// write a 0x66 to 0x1000, and read 0x1000 again (it’s changed to an 0x66).
while (1) {
pass = FLASH_PageErase (0x7c00);
// erase page prior to writing...
while (!pass);
// handle Write Lock condition
dest = 0x5a;
// set test variable to non-0xff value
pass = FLASH_ByteRead (0x7c00, &dest);
while (!pass);
// dest should return 0xff
// handle Read Lock condition
dest = 0x66;
pass = FLASH_ByteWrite (0x7c00, dest);
while (!pass);
// store 0x66 at 0x1000
// handle Read Lock condition
pass = FLASH_ByteRead (0x7c00, &dest);
while (!pass);
// dest should return 0x66
// handle Read Lock condition
pass = FLASH_PageErase (0x7c00);
while (!pass);
pass = FLASH_ByteRead (0x7c00, &dest);
while (!pass);
}
}
//-----------------------------------------------------------------------------------// Functions and Procedures
//-----------------------------------------------------------------------------------//----------------------------------------------------------------------------// SYSCLK_Init
//----------------------------------------------------------------------------//
// This routine initializes the system clock to use an 22.1184MHz crystal
// as its clock source.
//
void SYSCLK_Init (void)
{
int i;
// delay counter
46
OSCXCN = 0x67;
// start external oscillator with
// 22.1184MHz crystal
for (i=0; i < 256; i++) ;
// XTLVLD blanking interval (>1ms)
while (!(OSCXCN & 0x80)) ;
// Wait for crystal osc. to settle
OSCICN = 0x88;
// select external oscillator as SYSCLK
// source and enable missing clock
// detector
Rev. 1.4
AN105
}
//----------------------------------------------------------------------------// PORT_Init
//----------------------------------------------------------------------------//
// Configure the Crossbar and GPIO ports
//
void PORT_Init (void)
{
XBR0
= 0x04;
// Enable UART0
XBR1
= 0x00;
XBR2
= 0x40;
// Enable crossbar and weak pull-ups
P0MDOUT |= 0x01;
// enable TX0 as a push-pull output
P1MDOUT |= 0x40;
// enable P1.6 (LED) as push-pull output
P3MDOUT |= 0xe0;
P3 &= ~0xe0;
// make P3.7-5 push-pull outputs
// TCK, TMS, and TDI all low
}
//-----------------------------------------------------------------------------------// JTAG_StrobeTCK
//-----------------------------------------------------------------------------------// This routine strobes the TCK pin (brings high then back low again)
// on the target system.
//
void JTAG_StrobeTCK (void) {
TCK = 1;
TCK = 0;
}
//-----------------------------------------------------------------------------------// JTAG_Reset
//-----------------------------------------------------------------------------------// This routine places the JTAG state machine on the target system in
// the Test Logic Reset state by strobing TCK 5 times while leaving
// TMS high. Leaves the JTAG state machine in the Run_Test/Idle state.
//
void JTAG_Reset (void) {
TMS = 1;
JTAG_StrobeTCK
JTAG_StrobeTCK
JTAG_StrobeTCK
JTAG_StrobeTCK
JTAG_StrobeTCK
();
();
();
();
();
// move to Test Logic Reset state
TMS = 0;
JTAG_StrobeTCK ();
// move to Run_Test/Idle state
}
//-----------------------------------------------------------------------------------// JTAG_IR_Scan
//-----------------------------------------------------------------------------------// This routine loads the supplied <instruction> of <num_bits> length into the JTAG
// Instruction Register on the target system. Leaves in the Run_Test/Idle state.
Rev. 1.4
47
AN105
// The return value is the n-bit value read from the IR.
// Assumes the JTAG state machine starts in the Run_Test/Idle state.
//
unsigned int JTAG_IR_Scan (unsigned int instruction, int num_bits) {
unsigned int retval;
int
i;
// JTAG instruction read
// JTAG IR bit counter
retval = 0x0;
TMS = 1;
JTAG_StrobeTCK
TMS = 1;
JTAG_StrobeTCK
TMS = 0;
JTAG_StrobeTCK
TMS = 0;
JTAG_StrobeTCK
();
// move to SelectDR
();
// move to SelectIR
();
// move to Capture_IR
();
// move to Shift_IR state
for (i=0; i < num_bits; i++) {
TDI = (instruction & 0x01);
instruction = instruction >> 1;
// shift IR, LSB-first
retval = retval >> 1;
if (TDO) {
retval |= (0x01 << (num_bits - 1));
}
if (i == (num_bits - 1)) {
TMS = 1;
}
// move to Exit1_IR state
JTAG_StrobeTCK();
}
TMS = 1;
JTAG_StrobeTCK ();
TMS = 0;
JTAG_StrobeTCK ();
// move to Update_IR
// move to RTI state
return retval;
}
//-----------------------------------------------------------------------------------// JTAG_DR_Scan
//-----------------------------------------------------------------------------------// This routine shifts <num_bits> of <data> into the Data Register, and returns
// up to 32-bits of data read from the Data Register.
// Leaves in the Run_Test/Idle state.
// Assumes the JTAG state machine starts in the Run_Test/Idle state.
//
unsigned long JTAG_DR_Scan (unsigned long dat, int num_bits) {
unsigned long
int
i;
retval;
// JTAG return value
// JTAG DR bit counter
retval = 0x0L;
48
Rev. 1.4
AN105
TMS = 1;
JTAG_StrobeTCK ();
TMS = 0;
JTAG_StrobeTCK ();
TMS = 0;
JTAG_StrobeTCK ();
// move to SelectDR
// move to Capture_DR
// move to Shift_DR state
for (i=0; i < num_bits; i++) {
TDI = (dat & 0x01);
dat = dat >> 1;
// shift DR, LSB-first
retval = retval >> 1;
if (TDO) {
retval |= (0x01L << (num_bits - 1));
}
if ( i == (num_bits - 1)) {
TMS = 1;
}
JTAG_StrobeTCK();
}
TMS = 1;
JTAG_StrobeTCK ();
TMS = 0;
JTAG_StrobeTCK ();
// move to Exit1_DR state
// move to Update_DR
// move to RTI state
return retval;
}
//-----------------------------------------------------------------------------------// JTAG_IWrite
//-----------------------------------------------------------------------------------// This routine performs an indirect write to register <ireg>, containing <dat>, of
// <num_bits> in length. It follows the write operation with a polling operation, and
// returns when the operation is completed. Note: the polling implemented here refers
// to the JTAG register write operation being completed, NOT the FLASH write operation.
// Polling for the FLASH write operation is handled at a higher level
// Examples of valid indirect registers are:
// FLCN - FLASH Control
// FLSC - FLASH Scale
// FLA - FLASH Address
// FLD - FLASH Data
// Leaves in the Run_Test/Idle state.
//
void JTAG_IWrite (unsigned int ireg, unsigned long dat, int num_bits) {
int done;
// TRUE = write complete; FALSE otherwise
JTAG_IR_Scan (ireg, INST_LENGTH);
// load IR with <ireg>
dat |= (0x03L << num_bits);
// append ‘WRITE’ opcode to data
// load DR with <dat>
JTAG_DR_Scan (dat, num_bits + 2);
// initiate the JTAG write
// load DR with ‘0’, and check for BUSY bit to go to ‘0’.
do {
Rev. 1.4
49
AN105
done = !(JTAG_DR_Scan (0x0L, 1));
} while (!done);
// poll for JTAG_BUSY bit
}
//-----------------------------------------------------------------------------------// JTAG_IRead
//-----------------------------------------------------------------------------------// This routine performs an indirect read of register <ireg>, of <num_bits> in length.
// It follows the read operation with a polling operation, and returns when the
// operation is completed. Note: the polling implemented here refers to the JTAG
// register read operation being completed, NOT the FLASH read operation.
// Polling for the FLASH read operation is handled at a higher level.
// Examples of valid indirect registers are:
// FLCN - FLASH Control
// FLSC - FLASH Scale
// FLA - FLASH Address
// FLD - FLASH Data
// Leaves in the Run_Test/Idle state.
//
unsigned long JTAG_IRead (unsigned int ireg, int num_bits) {
unsigned long retval;
int done;
// value returned from READ operation
// TRUE = write complete; FALSE otherwise
JTAG_IR_Scan (ireg, INST_LENGTH);
// load IR with <ireg>
// load DR with read opcode (0x02)
JTAG_DR_Scan (0x02L, 2);
// initiate the JTAG read
do {
done = !(JTAG_DR_Scan (0x0L, 1));
} while (!done);
// poll for JTAG_BUSY bit
retval = JTAG_DR_Scan (0x0L, num_bits + 1);
retval = retval >> 1;
// allow poll operation to
// read remainder of the bits
// shift JTAG_BUSY bit off the end
return retval;
}
//-----------------------------------------------------------------------------------// FLASH_ByteRead
//-----------------------------------------------------------------------------------// This routine reads the byte at <addr> and stores it at the address pointed to by
// <pdat>.
// Returns TRUE if the operation was successful; FALSE otherwise (page read-protected).
//
int FLASH_ByteRead (unsigned int addr, unsigned char *pdat)
{
unsigned long testval;
// holds result of FLASHDAT read
int done;
// TRUE/FALSE flag
int retval;
// TRUE if operation successful
JTAG_IWrite (FLASHSCL, 0x86L, FLSC_LEN);
// set FLASHSCL based on SYSCLK
// frequency (2MHz = 0x86)
// set FLASHADR to address to read from
JTAG_IWrite (FLASHADR, (unsigned long) addr, FLA_LEN);
50
Rev. 1.4
AN105
JTAG_IWrite (FLASHCON, 0x02L, FLCN_LEN);
// set FLASHCON for FLASH Read
// operation (0x02)
JTAG_IRead (FLASHDAT, FLD_RDLEN);
// initiate the read operation
JTAG_IWrite (FLASHCON, 0x0L, FLCN_LEN);
// set FLASHCON for ‘poll’ operation
do {
done = !(JTAG_IRead (FLASHDAT, 1));
} while (!done);
// poll for FLBUSY to de-assert
testval = JTAG_IRead (FLASHDAT, FLD_RDLEN);
// read the resulting data
retval = (testval & 0x02) ? FALSE: TRUE;
// FLFail is next to LSB
testval = testval >> 2;
// shift data.0 into LSB position
*pdat = (unsigned char) testval;
// place data in return location
return retval;
// return FLASH Pass/Fail
}
//-----------------------------------------------------------------------------------// FLASH_ByteWrite
//-----------------------------------------------------------------------------------// This routine writes the data <dat> to FLASH at the address <addr>.
// Returns TRUE if the operation was successful; FALSE otherwise (page
// write-protected).
//
int FLASH_ByteWrite (unsigned int addr, unsigned char dat)
{
unsigned long testval;
// holds result of FLASHDAT read
int done;
// TRUE/FALSE flag
int retval;
// TRUE if operation successful
JTAG_IWrite (FLASHSCL, 0x86L, FLSC_LEN);
// set FLASHSCL based on SYSCLK
// frequency (2MHz = 0x86)
// set FLASHADR to address to write to
JTAG_IWrite (FLASHADR, (unsigned long) addr, FLA_LEN);
JTAG_IWrite (FLASHCON, 0x10L, FLCN_LEN);
// set FLASHCON for FLASH Write
// operation (0x10)
// initiate the write operation
JTAG_IWrite (FLASHDAT, (unsigned long) dat, FLD_WRLEN);
JTAG_IWrite (FLASHCON, 0x0L, FLCN_LEN);
// set FLASHCON for ‘poll’ operation
do {
done = !(JTAG_IRead (FLASHDAT, 1));
} while (!done);
// poll for FLBusy to de-assert
testval = JTAG_IRead (FLASHDAT, 2);
// read FLBusy and FLFail
retval = (testval & 0x02) ? FALSE: TRUE;
// FLFail is next to LSB
return retval;
// return FLASH Pass/Fail
Rev. 1.4
51
AN105
}
//-----------------------------------------------------------------------------------// FLASH_PageErase
//-----------------------------------------------------------------------------------// This routine performs an erase of the page in which <addr> is contained.
// This routine assumes that no FLASH operations are currently in progress.
// This routine exits with no FLASH operations currently in progress.
// Returns TRUE if the operation was successful; FALSE otherwise (page protected).
//
int FLASH_PageErase (unsigned int addr)
{
unsigned long testval;
// holds result of FLASHDAT read
int done;
// TRUE/FALSE flag
int retval;
// TRUE if operation successful
JTAG_IWrite (FLASHSCL, 0x86L, FLSC_LEN);
// set FLASHSCL based on SYSCLK
// frequency (2MHz = 0x86)
// set FLASHADR to address within page to erase
JTAG_IWrite (FLASHADR, (unsigned long) addr, FLA_LEN);
JTAG_IWrite (FLASHCON, 0x20L, FLCN_LEN);
// set FLASHCON for FLASH Erase
// operation (0x20)
JTAG_IWrite (FLASHDAT, 0xa5L, FLD_WRLEN);
// set FLASHDAT to 0xa5 to initiate
// erase procedure
JTAG_IWrite (FLASHCON, 0x0L, FLCN_LEN);
// set FLASHCON for ‘poll’ operation
do {
done = !(JTAG_IRead (FLASHDAT, 1));
} while (!done);
// poll for FLBusy to de-assert
testval = JTAG_IRead (FLASHDAT, 2);
// read FLBusy and FLFail
retval = (testval & 0x02) ? FALSE: TRUE;
// FLFail is next to LSB
// set return value based on FLFail bit
return retval;
// return FLASH Pass/Fail
}
52
Rev. 1.4
AN105
Programming Multiple JTAG Devices in a Chain
//************************************************************************************
// JTAG_Chain_F02x.c
//-----------------------------------------------------------------------------------// This program contains some primitive routines which gather information through the
// JTAG port on multiple JTAG compatible devices under test (DUT) connected in a
// chain. The TCK & TMS JTAG pins on the DUT are connected in parallel to port pins on
// the C8051F02x master device and the TDI & TDO pins are connected in
// series.
//
// **NOTE: The first device in the chain (device 0) is the one whose TDO pin is
//
connected to the TDO pin of the master device.
//
// Target device: C8051F02x
//
// Tool chain: KEIL Eval ‘c’
//************************************************************************************
//-----------------------------------------------------------------------------------// Includes
//-----------------------------------------------------------------------------------#include <c8051f020.h>
// SFR declarations
//-----------------------------------------------------------------------------------// 16-bit SFR Definitions for ‘F02x
//-----------------------------------------------------------------------------------sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
DP
TMR3RL
TMR3
ADC0
ADC0GT
ADC0LT
RCAP2
T2
RCAP4
T4
DAC0
DAC1
=
=
=
=
=
=
=
=
=
=
=
=
0x82;
0x92;
0x94;
0xbe;
0xc4;
0xc6;
0xca;
0xcc;
0xe4;
0xf4;
0xd2;
0xd5;
//
//
//
//
//
//
//
//
//
//
//
//
data pointer
Timer3 reload value
Timer3 counter
ADC0 data
ADC0 greater than window
ADC0 less than window
Timer2 capture/reload
Timer2
Timer4 capture/reload
Timer4
DAC0 data
DAC1 data
//-----------------------------------------------------------------------------------// Global CONSTANTS
//-----------------------------------------------------------------------------------#define MAX_NUM_DEVICES_IN_CHAIN 10
sbit
sbit
LED = P1^6;
SW2 = P3^7;
#define SYSCLK
sbit
sbit
sbit
TCK = P3^7;
TMS = P3^6;
TDI = P3^5;
sbit
TDO = P3^4;
// green LED: ‘1’ = ON; ‘0’ = OFF
// SW2=’0’ means switch pressed
22118400
//
//
//
//
//
//
// SYSCLK frequency in Hz
JTAG Test Clock -- Connected to TCK pin on all devices.
JTAG Mode Select -- Connected to TMS pin on all devices.
JTAG Data Input(output of master) -- Connected to the
TDI pin of device n.
JTAG Data Output (input to master)-- Connected to the
TDO pin of device 0.
Rev. 1.4
53
AN105
#define
#define
TRUE 1
FALSE 0
// JTAG Instruction Register Addresses
#define
INST_LENGTH 16
#define
BYPASS
0xffff
#define
EXTEST
0x0000
#define
SAMPLE
0x0002
// number of bits in the C8051Fxxx
// Instruction Register
#define
RESET
0x2fff
// System RESET Instruction
#define
#define
IDCODE
IDCODE_LEN
0x1004
32
// IDCODE Instruction address/HALT
// number of bits in the ID code
#define
#define
FLASHCON
FLCN_LEN
0x4082
8
// FLASH Control Instruction address
// number of bits in FLASHCON
#define
#define
#define
FLASHDAT
FLD_RDLEN
FLD_WRLEN
0x4083
10
8
// FLASH Data Instruction address
// number of bits in an FLASHDAT read
// number of bits in an FLASHDAT write
#define
#define
FLASHADR
FLA_LEN
0x4084
16
// FLASH Address Instruction address
// number of bits in FLASHADR
#define
#define
FLASHSCL
FLSC_LEN
0x4085
8
// FLASH Scale Instruction address
// number of bits in FLASHSCL
//-----------------------------------------------------------------------------------// Global Variable DECLARATIONS
//-----------------------------------------------------------------------------------// The addresses of the following variables are explicitly defined for viewing
// purposes. If the width of the external memory window is 5 bytes, then each
// device will take up exactly one row starting from the second row.
char xdata num_devices _at_ 0x0000;
char
char
char
char
xdata
xdata
xdata
xdata
num_devices_before
num_devices_after
num_IR_bits_before
num_IR_bits_after
_at_
_at_
_at_
_at_
typedef struct JTAG_Information {
unsigned char IR_length;
unsigned long id;
} JTAG_Information;
0x0001;
0x0002;
0x0003;
0x0004;
//
//
//
//
#devices before and after the isolated
device
#instruction register bits before and
after the isolated device
// Discovery information
// Instruction register length
// Identification code for each device
// Array: one entry per device in the
// JTAG chain
JTAG_Information xdata JTAG_info[MAX_NUM_DEVICES_IN_CHAIN];
//-----------------------------------------------------------------------------------// Function PROTOTYPES
//-----------------------------------------------------------------------------------void SYSCLK_Init (void);
void PORT_Init (void);
void JTAG_StrobeTCK (void);
54
Rev. 1.4
AN105
void JTAG_Reset (void);
void Blink_Led(void);
void
void
void
void
void
init(void);
JTAG_Discover(void);
JTAG_Discover_IR(void);
JTAG_Discover_DR(void);
JTAG_Isolate(char index);
unsigned long JTAG_IR_Scan (unsigned long instruction, char num_bits) ;
unsigned long JTAG_DR_Scan (unsigned long dat, char num_bits);
void JTAG_IWrite (unsigned int ireg, unsigned long dat, int num_bits);
unsigned long JTAG_IRead (unsigned int ireg, int num_bits);
int FLASH_ByteRead (unsigned int addr, unsigned char *pdat);
int FLASH_ByteWrite (unsigned int addr, unsigned char dat);
int FLASH_PageErase (unsigned int addr);
//-----------------------------------------------------------------------------------// MAIN Routine
//-----------------------------------------------------------------------------------void main (void)
{
long xdata id;
unsigned char dest;
int pass;
int address;
char device = 0;
WDTCN = 0xde;
WDTCN = 0xad;
// disable watchdog timer
PORT_Init ();
SYSCLK_Init ();
// initialize crossbar and GPIO
// initialize oscillator
LED = 1;
// turn on the LED
init();
JTAG_Discover();
// initialize JTAG Chain variables
// IDCODE should = 0x10000243 for
// C8051F000 rev D device
JTAG_Isolate(0);
JTAG_IR_Scan (IDCODE, INST_LENGTH);
id = JTAG_DR_Scan (0x0L, IDCODE_LEN);
// isolate device 0
// load IDCODE into IR and HALT the DUT
// get the ID Code of the isolated device
// comment out this code if you have less than two devices in the chain
JTAG_Isolate(1);
JTAG_IR_Scan (IDCODE, INST_LENGTH);
// load IDCODE into IR and HALT the DUT
id = JTAG_DR_Scan (0x0L, IDCODE_LEN);
// get the ID Code of the isolated device
// comment out this code if you have less than three devices in the chain
JTAG_Isolate(2);
JTAG_IR_Scan (IDCODE, INST_LENGTH);
// load IDCODE into IR and HALT the DUT
id = JTAG_DR_Scan (0x0L, IDCODE_LEN);
// get the ID Code of the isolated device
Rev. 1.4
55
AN105
for(device = 0; device < num_devices; device++) {
JTAG_Isolate(device);
//TEST 1 -- ERASE A FLASH PAGE
pass = FLASH_PageErase (0x1000);
while (!pass);
// erase page prior to writing
// handle Write Lock condition
//Verify that locations 0x1000 - 0x11FF are 0xFF
for(address = 0x1000; address < 0x1200; address++){
pass = FLASH_ByteRead (address, &dest);
// dest should return 0xff
if(!pass || dest != 0xFF) Blink_Led();
}
//TEST 2 -- WRITE A PATTERN TO FLASH PAGE
for(address = 0x1000; address < 0x1200; address++){
dest = address & 0x00FF;
// strip away upper 8 bits
pass = FLASH_ByteWrite (address, dest);// store LSByte of address at address
while (!pass);
// handle Read Lock condition
}
dest = 0x12;
// set test variable to non-0xff value
//Verify that locations 0x1000 - 0x11FF are following the pattern
for(address = 0x1000; address < 0x1200; address++){
pass = FLASH_ByteRead (address, &dest);
if(!pass || dest != (address & 0x00FF)) Blink_Led();
}
}
LED = 0;
// turn off the led,
// program executed correctly
while(1);
}
//************************************************************************************
// Function and Procedure DEFINITIONS
//************************************************************************************
//----------------------------------------------------------------------------// SYSCLK_Init
//----------------------------------------------------------------------------//
// This routine initializes the system clock to use an 22.1184MHz crystal
// as its clock source.
//
void SYSCLK_Init (void)
{
int i;
// delay counter
56
OSCXCN = 0x67;
// start external oscillator with
// 22.1184MHz crystal
for (i=0; i < 256; i++) ;
// XTLVLD blanking interval (>1ms)
while (!(OSCXCN & 0x80)) ;
// Wait for crystal osc. to settle
Rev. 1.4
AN105
OSCICN = 0x88;
// select external oscillator as SYSCLK
// source and enable missing clock
// detector
}
//----------------------------------------------------------------------------// PORT_Init
//----------------------------------------------------------------------------//
// Configure the Crossbar and GPIO ports
//
void PORT_Init (void)
{
XBR0
= 0x04;
// Enable UART0
XBR1
= 0x00;
XBR2
= 0x40;
// Enable crossbar and weak pull-ups
P0MDOUT |= 0x01;
// enable TX0 as a push-pull output
P1MDOUT |= 0x40;
// enable P1.6 (LED) as push-pull output
P3MDOUT |= 0xe0;
P3 &= ~0xe0;
// make P3.7-5 push-pull outputs
// TCK, TMS, and TDI all low
}
//-----------------------------------------------------------------------------------// Blink_Led
//-----------------------------------------------------------------------------------// This routine blinks the Green LED forever to indicate an error.
//
void Blink_Led(void)
{
int i;
// millisecond counter
int ms = 200;
// stay in each state for ms milliseconds
TCON
TMOD
TMOD
CKCON
&= ~0x30;
&= ~0x0F;
|= 0x01;
|= 0x08;
// STOP Timer0 and clear overflow flag
// configure Timer0 to 16-bit mode
// Timer0 counts SYSCLKs
while (1){
LED = ~LED;
for (i
TR0
TH0
TL0
TR0
=
=
=
=
=
0; i < ms; i++) {
0;
(-SYSCLK/1000) >> 8;
-SYSCLK/1000;
1;
// count milliseconds
// STOP Timer0
// SET Timer0 to overflow in 1ms
// START Timer0
while(TF0 == 0);
// wait for overflow
TF0 = 0;
// clear overflow indicator
}
}
}
//-----------------------------------------------------------------------------------// init
//------------------------------------------------------------------------------------
Rev. 1.4
57
AN105
// This routine initializes the variables used in a JTAG chain.
//
void init (void)
{
num_devices = 1;
// The default number of devices is one.
// JTAG_Discover() does not have to be
// called if only one device is connected.
num_devices_before = 0;
num_devices_after = 0;
num_IR_bits_before = 0;
num_IR_bits_after = 0;
//
//
//
//
//
Initializing these variables to zero
allows calling the JTAG_IR_Scan() and
the JTAG_DR_Scan() without first
calling JTAG_Isolate() when there is
only one device in the chain.
}
//-----------------------------------------------------------------------------------// JTAG_StrobeTCK
//-----------------------------------------------------------------------------------// This routine strobes the TCK pin (brings high then back low again)
// on the target system.
//
void JTAG_StrobeTCK (void)
{
TCK = 1;
TCK = 0;
}
//-----------------------------------------------------------------------------------// JTAG_Reset
//-----------------------------------------------------------------------------------// This routine places the JTAG state machine on the target system in
// the Test Logic Reset state by strobing TCK 5 times while leaving
// TMS high. Leaves the JTAG state machine in the Run_Test/Idle state.
//
void JTAG_Reset (void)
{
TMS = 1;
JTAG_StrobeTCK
JTAG_StrobeTCK
JTAG_StrobeTCK
JTAG_StrobeTCK
JTAG_StrobeTCK
();
();
();
();
();
// move to Test Logic Reset state
TMS = 0;
JTAG_StrobeTCK ();
// move to Run_Test/Idle state
}
//-----------------------------------------------------------------------------------// JTAG_Discover
//-----------------------------------------------------------------------------------// This routine sequentially queries a chain of JTAG devices and accomplishes the
// following three tasks.
//
For the global struct array <JTAG_info>
//
-- fills in the length of each device’s instruction register
58
Rev. 1.4
AN105
//
-- fills in each device’s IDCODE.
//
For the global variable <num_devices>
//
-- updates it with the number of JTAG devices connected in the chain.
//
void JTAG_Discover(void)
{
JTAG_Discover_IR();
// At this point we know num_devices(a global variable) and we know the
// length of each device’s IR given in the variable JTAG_info[].IR_length
JTAG_Discover_DR();
// Read and assign the ID for each
// device
} //end discover
//-----------------------------------------------------------------------------------// JTAG_Discover_IR
//-----------------------------------------------------------------------------------// This routine fills a structure with the length of each device’s instruction
// register. It also updates the global variable <num_devices> with the number of
// JTAG devices connected in the chain.
//
// BACKGROUND: When an IRSCAN is issued, a JTAG device must return a 1 as the LSB
//
and zeros in all the other bits. We shift in all ones so when we
//
encounter two ones in a row, we know we are past the end of the chain.
//
A state machine is implemented in this routine to keep track of
//
inputs received.
//
// STATE DEFINITONS:
//
0 - NO INPUTS -- at beginning of chain
//
1 - INPUT SEQUENCE: 1 -- could be at a new device or at chain end
//
2 - INPUT SEQUENCE: 100..0 -- counting zeros
//
//
void JTAG_Discover_IR(void)
{
char state = 0;
// beginning of chain
char num_zeros = 0;
// number of zeros following a one in
// an IR_SCAN. num_zeros + 1 = IR_length
char current_device_index = -1;
bit done = FALSE;
// current_device_index + 1 = num_devices
// (on the last iteration)
// TRUE when end of chain is reached
JTAG_Reset();
// RESET and move to Run_Test/Idle
// advance to Shift_IR State
TMS = 1;
JTAG_StrobeTCK ();
TMS = 1;
JTAG_StrobeTCK ();
TMS = 0;
JTAG_StrobeTCK ();
TMS = 0;
JTAG_StrobeTCK ();
// move to SelectDR
// move to SelectIR
// move to Capture_IR
// move to Shift_IR state and get the
Rev. 1.4
59
AN105
// the first input
TDI = 1;
// STATE is initially 0
// shift in all ones
// for each device
do{
if(TDO != 1){
Blink_Led();
}
// Error if the first input is not one.
// Could mean bad connections or
// non-compliant devices.
state = 1;
// received a 1, could be at a new
// device or at the end of the chain
num_zeros = 0;
// initialize for the zero counting loop
// for the number of zeros in each device’s IR
do {
JTAG_StrobeTCK();
// get the next bit.
switch(state){
case 1: if(TDO == 0){
// found new device(10)
current_device_index++;
num_zeros++;
state = 2;
} else {
done = TRUE;
// at end of chain (11)
}
break;
case 2: if(TDO == 0){
num_zeros++;
} else {
state = 1;
}
break;
default: Blink_Led();
// counting zeros (10..0)
// past end of current device (10..01)
// an error has occurred
} // end switch
} while ((state != 1) && (!done));
// while the input is not one,
// count zeros until we get a one.
if (!done) {
// if we are not past the last device
JTAG_info[current_device_index].IR_length = num_zeros + 1;
}
} while (!done);
//while we are not past the last device
num_devices = current_device_index + 1;
// navigate the JTAG State Machine back to RTI state.
60
Rev. 1.4
AN105
TMS = 1;
JTAG_StrobeTCK ();
TMS = 1;
JTAG_StrobeTCK ();
TMS = 0;
JTAG_StrobeTCK ();
// move to Exit1_IR state
// move to Update_IR state
// move to Run_Test/Idle state
}
//-----------------------------------------------------------------------------------// JTAG_Discover_DR
//-----------------------------------------------------------------------------------//GOAL: Obtain the ID code of each device(If it supports IDCODE), and fill in
//
the field JTAG_info[].id (32-bit).
//
Assign all zeros if device does not have an IDCODE.
//
//BACKGROUND: After JTAG State Machine Reset, the IDCODE is automatically selected
//
If a device does not have an IDCODE register, the BYPASS
//
register is selected instead.
//
On a DR_SCAN, each IDCODE register returns a 32-bit ID with LSB = 1
//
and each BYPASS register returns 1-bit = 0.
void JTAG_Discover_DR(void)
{
char current_device_index = 0;
unsigned char i;
// loop counter
JTAG_Reset ();
// Reset the JTAG state machine on DUT
// move to Run_Test/Idle
// The IDCODE or the BYPASS Register is automatically selected.
// Navigate to the Shift_DR state
TMS = 1;
JTAG_StrobeTCK ();
TMS = 0;
JTAG_StrobeTCK ();
TMS = 0;
TDI = 1;
// move to SelectDR
// move to Capture_DR
// shift in all ones
current_device_index = 0;
while (current_device_index < num_devices) {
JTAG_StrobeTCK ();
// move to Shift_DR state and get input
if (TDO == 0) {
// Device does not have an IDCODE register
JTAG_info[current_device_index].id = 0x00000000L;
} else { // TDO == 1
JTAG_info[current_device_index].id = 0x80000000L;
for (i = 0; i < 31; i++){
// Get the next 31-bits of the device ID
Rev. 1.4
61
AN105
JTAG_StrobeTCK ();
JTAG_info[current_device_index].id =
JTAG_info[current_device_index].id >> 1;
if (TDO) {
JTAG_info[current_device_index].id |= 0x80000000L;
}
} // end for
} // end if-else
current_device_index++;
} // end while
//fill the rest of the entries with zeros
for (; current_device_index < MAX_NUM_DEVICES_IN_CHAIN; current_device_index++) {
JTAG_info[current_device_index].IR_length = 0;
JTAG_info[current_device_index].id = 0x00000000L;
}
// Navigate JTAG State Machine back to RTI state
TMS = 1;
JTAG_StrobeTCK ();
// move to Exit1_DR
TMS = 1;
JTAG_StrobeTCK ();
// move to Update DR
TMS = 0;
JTAG_StrobeTCK ();
// move to RTI
}
//-----------------------------------------------------------------------------------// JTAG_Isolate
//-----------------------------------------------------------------------------------// This routine updates 4 global variables. JTAG_Discover() must be called prior to
// calling this routine in order to set up the data structure.
//
// VARIABLE DEFINITIONS
//
num_IR_bits_before -- number of instruction register bits before the isolated
//
device
//
num_IR_bits_after -- number of instruction register bits after the isolated
//
device
//
num_devices_before -- number of devices before the isolated device
//
num_devices_after -- number of device after the isolated device
//
void JTAG_Isolate(char index)
{
unsigned char i;
if ((index > (num_devices - 1)) || (index < 0) ) {
// check if index is out of range
Blink_Led();
}
num_devices_before = index;
62
Rev. 1.4
AN105
num_devices_after = num_devices - index - 1;
num_IR_bits_before = 0;
num_IR_bits_after = 0;
// initializing for loop
for (i = 0; i < num_devices; i++) {
if (i < index) {
num_IR_bits_before += JTAG_info[i].IR_length;
} else if (i > index) {
num_IR_bits_after += JTAG_info[i].IR_length;
}
// last case -- equal, do nothing
} // end for
} //end isolate
//-----------------------------------------------------------------------------------// JTAG_IR_Scan
//-----------------------------------------------------------------------------------// This routine loads the supplied <instruction> of <num_bits> length into the JTAG
// Instruction Register on the isolated device. It shifts the BYPASS opcode (all ones)
// into the Instruction Registers of the other devices in the chain.
//
// NOTE: JTAG_Discover() must be called before this function is called.
//
// NOTE: If more than one device is connected in the chain, JTAG_Isolate() must also
//
be called prior to calling this function.
//
// The return value is the n-bit value read from the IR.
// Assumes the JTAG state machine starts in the Run_Test/Idle state.
// Leaves JTAG in the Run_Test/Idle state.
//
unsigned long JTAG_IR_Scan (unsigned long instruction, char num_bits)
{
unsigned long retval;
char i;
// JTAG instruction read
// JTAG IR bit counter
retval = 0x0L;
// navigate the JTAG State Machine in all devices to the Shift_IR state
TMS = 1;
JTAG_StrobeTCK ();
// move to SelectDR
TMS = 1;
JTAG_StrobeTCK ();
// move to SelectIR
TMS = 0;
JTAG_StrobeTCK ();
// move to Capture_IR
TMS = 0;
JTAG_StrobeTCK ();
// move to Shift_IR state
TDI=1;
for (i=0; i < num_IR_bits_before; i++) {
Rev. 1.4
63
AN105
JTAG_StrobeTCK();
// fill the IR of the devices
// before the isolated device
// with all ones, the BYPASS opcode
}
for (i=0; i < num_bits; i++) {
TDI = (instruction & 0x01);
instruction = instruction >> 1;
// determine output
retval = retval >> 1;
if (TDO) {
retval |= (0x01 << (num_bits - 1));
}
if ((i == (num_bits - 1)) && (num_IR_bits_after == 0)) {
TMS = 1;
// move to Exit1_IR state
}
JTAG_StrobeTCK();
// move to Shift_IR state
// advance
}
TDI = 1;
for (i=0; i < num_IR_bits_after; i++) {
// now process IR bits after the
// isolated device
if (i == (num_IR_bits_after - 1)) {
TMS = 1;
}
// move to Exit1_IR state
JTAG_StrobeTCK();
// fill the IR of the devices
// after the isolated device
// with all ones, the BYPASS opcode.
}
// navigate back to the RTI state
TMS = 1;
JTAG_StrobeTCK ();
TMS = 0;
JTAG_StrobeTCK ();
// move to Update_IR
// move to RTI state
return retval;
}
//-----------------------------------------------------------------------------------// JTAG_DR_Scan
//-----------------------------------------------------------------------------------// This routine shifts <num_bits> of <data> into the Data Register of the isolated
// device in the chain, and returns up to 32-bits of data read from its Data Register.
//
// Assumes the JTAG state machine starts in the Run_Test/Idle state.
// Leaves in the Run_Test/Idle state.
//
unsigned long JTAG_DR_Scan (unsigned long dat, char num_bits)
{
unsigned long retval;
char i;
64
// JTAG return value
// JTAG DR bit counter
Rev. 1.4
AN105
retval = 0x0L;
// navigate the JTAG State Machine in all devices to
TMS = 1;
JTAG_StrobeTCK ();
// move
TMS = 0;
JTAG_StrobeTCK ();
// move
TMS = 0;
JTAG_StrobeTCK ();
// move
the Shift_DR state
to SelectDR
to Capture_DR
to Shift_DR state
TDI = 0;
for (i=0; i < num_devices_before; i++) {
JTAG_StrobeTCK();
// fill the BYPASS Register
// of the devices before the
// isolated device with zeros.
}
for (i=0; i < num_bits; i++) {
TDI = (dat & 0x01);
dat = dat >> 1;
// determine the output
retval = retval >> 1;
if (TDO) {
retval |= (0x01L << (num_bits - 1));
}
if ((i == (num_bits - 1)) && (num_devices_after == 0)) {
TMS = 1;
// move to Exit1_IR state
}
JTAG_StrobeTCK();
//output and get input
}
TDI = 0;
for (i=0; i < num_devices_after; i++) {
if (i == (num_devices_after - 1)) {
TMS = 1;
}
JTAG_StrobeTCK();
}
// move to Exit1_IR state
//
//
//
//
move to Shift_DR state,
fill the BYPASS Register
of the devices after the
isolated device with zeros.
// navigate the JTAG State Machine in all devices to the RTI state
TMS = 1;
JTAG_StrobeTCK ();
// move to Update_DR
TMS = 0;
JTAG_StrobeTCK ();
// move to RTI state
return retval;
// retval is MSB aligned
}
Rev. 1.4
65
AN105
//-----------------------------------------------------------------------------------// JTAG_IWrite
//-----------------------------------------------------------------------------------// This routine performs an indirect write to register <ireg>, containing <dat>, of
// <num_bits> in length. It follows the write operation with a polling operation, and
// returns when the operation is completed. Note: the polling implemented here refers
// to the JTAG register write operation being completed, NOT the FLASH write operation.
// Polling for the FLASH write operation is handled at a higher level
// Examples of valid indirect registers are:
// FLASHCON - FLASH Control
// FLASHSCL - FLASH Scale
// FLASHADR - FLASH Address
// FLASHDAT - FLASH Data
// Leaves in the Run_Test/Idle state.
//
void JTAG_IWrite (unsigned int ireg, unsigned long dat, int num_bits)
{
bit done;
// TRUE = write complete; FALSE otherwise
JTAG_IR_Scan (ireg, INST_LENGTH);
// load IR with <ireg>
dat |= (0x03L << num_bits);
// append ‘WRITE’ opcode to data
// load DR with <dat>
JTAG_DR_Scan (dat, num_bits + 2);
// initiate the JTAG write
// load DR with ‘0’, and check for BUSY bit to go to ‘0’.
do {
done = !(JTAG_DR_Scan (0x0L, 1));
// poll for JTAG_BUSY bit
} while (!done);
}
//-----------------------------------------------------------------------------------// JTAG_IRead
//-----------------------------------------------------------------------------------// This routine performs an indirect read of register <ireg>, of <num_bits> in length.
// It follows the read operation with a polling operation, and returns when the
// operation is completed. Note: the polling implemented here refers to the JTAG
// register read operation being completed, NOT the FLASH read operation.
// Polling for the FLASH read operation is handled at a higher level.
// Examples of valid indirect registers are:
// FLASHCON - FLASH Control
// FLASHSCL - FLASH Scale
// FLASHADR - FLASH Address
// FLASHDAT - FLASH Data
// Leaves JTAG in the Run_Test/Idle state.
//
unsigned long JTAG_IRead (unsigned int ireg, int num_bits) {
66
unsigned long retval;
bit done;
// value returned from READ operation
// TRUE = write complete; FALSE otherwise
JTAG_IR_Scan (ireg, INST_LENGTH);
// load IR with <ireg>
// load DR with read opcode (0x02)
JTAG_DR_Scan (0x02L, 2);
// initiate the JTAG read
Rev. 1.4
AN105
do {
done = !(JTAG_DR_Scan (0x0L, 1));
} while (!done);
// poll for JTAG_BUSY bit
retval = JTAG_DR_Scan (0x0L, num_bits + 1);
retval = retval >> 1;
// allow poll operation to
// read remainder of the bits
// shift JTAG_BUSY bit off the end
return retval;
}
//-----------------------------------------------------------------------------------// FLASH_ByteRead
//-----------------------------------------------------------------------------------// This routine reads the byte at <addr> and stores it at the address pointed to by
// <pdat>.
// Returns TRUE if the operation was successful; FALSE otherwise (page
// read-protected).
//
int FLASH_ByteRead (unsigned int addr, unsigned char *pdat)
{
unsigned long testval;
// holds result of FLASHDAT read
bit done;
// TRUE/FALSE flag
int retval;
// TRUE if operation successful
JTAG_IWrite (FLASHSCL, 0x86L, FLSC_LEN);
// set FLASHSCL based on SYSCLK
// frequency (2MHz = 0x86)
// set FLASHADR to address to read from
JTAG_IWrite (FLASHADR, (unsigned long) addr, FLA_LEN);
JTAG_IWrite (FLASHCON, 0x02L, FLCN_LEN);
// set FLASHCON for FLASH Read
// operation (0x02)
JTAG_IRead (FLASHDAT, FLD_RDLEN);
// initiate the read operation
JTAG_IWrite (FLASHCON, 0x0L, FLCN_LEN);
// set FLASHCON for ‘poll’ operation
do {
done = !(JTAG_IRead (FLASHDAT, 1));
} while (!done);
// poll for FLBUSY to de-assert
testval = JTAG_IRead (FLASHDAT, FLD_RDLEN);
// read the resulting data
retval = (testval & 0x02) ? FALSE: TRUE;
// FLFail is next to LSB
testval = testval >> 2;
// shift data.0 into LSB position
*pdat = (unsigned char) testval;
// place data in return location
return retval;
// return FLASH Pass/Fail
}
//-----------------------------------------------------------------------------------// FLASH_ByteWrite
//-----------------------------------------------------------------------------------// This routine writes the data <dat> to FLASH at the address <addr>.
// Returns TRUE if the operation was successful; FALSE otherwise (page
// write-protected).
Rev. 1.4
67
AN105
//
int FLASH_ByteWrite (unsigned int addr, unsigned char dat)
{
unsigned long testval;
// holds result of FLASHDAT read
int done;
// TRUE/FALSE flag
int retval;
// TRUE if operation successful
JTAG_IWrite (FLASHSCL, 0x86L, FLSC_LEN);
// set FLASHSCL based on SYSCLK
// frequency (2MHz = 0x86)
// set FLASHADR to address to write to
JTAG_IWrite (FLASHADR, (unsigned long) addr, FLA_LEN);
JTAG_IWrite (FLASHCON, 0x10L, FLCN_LEN);
// set FLASHCON for FLASH Write
// operation (0x10)
// initiate the write operation
JTAG_IWrite (FLASHDAT, (unsigned long) dat, FLD_WRLEN);
JTAG_IWrite (FLASHCON, 0x0L, FLCN_LEN);
// set FLASHCON for ‘poll’ operation
do {
done = !(JTAG_IRead (FLASHDAT, 1));
} while (!done);
// poll for FLBusy to de-assert
testval = JTAG_IRead (FLASHDAT, 2);
// read FLBusy and FLFail
retval = (testval & 0x02) ? FALSE: TRUE;
// FLFail is next to LSB
return retval;
// return FLASH Pass/Fail
}
//-----------------------------------------------------------------------------------// FLASH_PageErase
//-----------------------------------------------------------------------------------// This routine performs an erase of the page in which <addr> is contained.
// This routine assumes that no FLASH operations are currently in progress.
// This routine exits with no FLASH operations currently in progress.
// Returns TRUE if the operation was successful; FALSE otherwise (page protected).
//
int FLASH_PageErase (unsigned int addr)
{
unsigned long testval;
// holds result of FLASHDAT read
bit done;
// TRUE/FALSE flag
int retval;
// TRUE if operation successful
JTAG_IWrite (FLASHSCL, 0x86L, FLSC_LEN);
// set FLASHSCL based on SYSCLK
// frequency (2MHz = 0x86)
// set FLASHADR to address within page to erase
JTAG_IWrite (FLASHADR, (unsigned long) addr, FLA_LEN);
68
JTAG_IWrite (FLASHCON, 0x20L, FLCN_LEN);
// set FLASHCON for FLASH Erase
// operation (0x20)
JTAG_IWrite (FLASHDAT, 0xa5L, FLD_WRLEN);
// set FLASHDAT to 0xa5 to initiate
// erase procedure
JTAG_IWrite (FLASHCON, 0x0L, FLCN_LEN);
// set FLASHCON for ‘poll’ operation
Rev. 1.4
AN105
do {
done = !(JTAG_IRead (FLASHDAT, 1));
} while (!done);
// poll for FLBusy to de-assert
testval = JTAG_IRead (FLASHDAT, 2);
// read FLBusy and FLFail
retval = (testval & 0x02) ? FALSE: TRUE;
// FLFail is next to LSB
// set return value based on FLFail bit
return retval;
// return FLASH Pass/Fail
}
Rev. 1.4
69
AN105
Contact Information
Silicon Laboratories Inc.
4635 Boston Lane
Austin, TX 78735
Tel: 1+(512) 416-8500
Fax: 1+(512) 416-9669
Toll Free: 1+(877) 444-3032
Email: [email protected]
Internet: www.silabs.com
The information in this document is believed to be accurate in all respects at the time of publication but is subject to change without notice.
Silicon Laboratories assumes no responsibility for errors and omissions, and disclaims responsibility for any consequences resulting from
the use of information included herein. Additionally, Silicon Laboratories assumes no responsibility for the functioning of undescribed features
or parameters. Silicon Laboratories reserves the right to make changes without further notice. Silicon Laboratories makes no warranty, representation or guarantee regarding the suitability of its products for any particular purpose, nor does Silicon Laboratories assume any liability
arising out of the application or use of any product or circuit, and specifically disclaims any and all liability, including without limitation consequential or incidental damages. Silicon Laboratories products are not designed, intended, or authorized for use in applications intended to
support or sustain life, or for any other application in which the failure of the Silicon Laboratories product could create a situation where personal injury or death may occur. Should Buyer purchase or use Silicon Laboratories products for any such unintended or unauthorized application, Buyer shall indemnify and hold Silicon Laboratories harmless against all claims and damages.
Silicon Laboratories and Silicon Labs are trademarks of Silicon Laboratories Inc.
Other products or brandnames mentioned herein are trademarks or registered trademarks of their respective holders.
70
Rev. 1.4