|
- # Xilinx XADC support for 7 Series FPGAs
- #
- # The 7 Series FPGAs contain an on-chip 12 bit ADC that can probe die
- # temperature, internal power supply rail voltages as well as external
- # voltages. The XADC is available both from fabric as well as through the
- # JTAG TAP.
- #
- # This code implements access through the JTAG TAP.
- #
- # https://www.xilinx.com/support/documentation/user_guides/ug480_7Series_XADC.pdf
-
- # build a 32 bit DRP command for the XADC DR
- proc xadc_cmd {cmd addr data} {
- array set cmds {
- NOP 0x00
- READ 0x01
- WRITE 0x02
- }
- return [expr {($cmds($cmd) << 26) | ($addr << 16) | ($data << 0)}]
- }
-
- # XADC register addresses
- # Some addresses (status registers 0-3) have special function when written to.
- proc XADC {key} {
- array set addrs {
- TEMP 0x00
- LOCK 0x00
- VCCINT 0x01
- VCCAUX 0x02
- VAUXEN 0x02
- VPVN 0x03
- RESET 0x03
- VREFP 0x04
- VREFN 0x05
- VCCBRAM 0x06
- SUPAOFFS 0x08
- ADCAOFFS 0x09
- ADCAGAIN 0x0a
- VCCPINT 0x0d
- VCCPAUX 0x0e
- VCCODDR 0x0f
- VAUX0 0x10
- VAUX1 0x11
- VAUX2 0x12
- VAUX3 0x13
- VAUX4 0x14
- VAUX5 0x15
- VAUX6 0x16
- VAUX7 0x17
- VAUX8 0x18
- VAUX9 0x19
- VAUX10 0x1a
- VAUX11 0x1b
- VAUX12 0x1c
- VAUX13 0x1d
- VAUX14 0x1e
- VAUX15 0x1f
- SUPBOFFS 0x30
- ADCBOFFS 0x31
- ADCBGAIN 0x32
- FLAG 0x3f
- CFG0 0x40
- CFG1 0x41
- CFG2 0x42
- SEQ0 0x48
- SEQ1 0x49
- SEQ2 0x4a
- SEQ3 0x4b
- SEQ4 0x4c
- SEQ5 0x4d
- SEQ6 0x4e
- SEQ7 0x4f
- ALARM0 0x50
- ALARM1 0x51
- ALARM2 0x52
- ALARM3 0x53
- ALARM4 0x54
- ALARM5 0x55
- ALARM6 0x56
- ALARM7 0x57
- ALARM8 0x58
- ALARM9 0x59
- ALARM10 0x5a
- ALARM11 0x5b
- ALARM12 0x5c
- ALARM13 0x5d
- ALARM14 0x5e
- ALARM15 0x5f
- }
- return $addrs($key)
- }
-
- # Select the XADC DR
- proc xadc_select {tap} {
- set XADC_IR 0x37
- irscan $tap $XADC_IR
- runtest 10
- }
-
- # XADC transfer
- proc xadc_xfer {tap cmd addr data} {
- set ret [drscan $tap 32 [xadc_cmd $cmd $addr $data]]
- runtest 10
- return [expr "0x$ret"]
- }
-
- # XADC register write
- proc xadc_write {tap addr data} {
- xadc_xfer $tap WRITE $addr $data
- }
-
- # XADC register read, non-pipelined
- proc xadc_read {tap addr} {
- xadc_xfer $tap READ $addr 0
- return [xadc_xfer $tap NOP 0 0]
- }
-
- # convert 16 bit register code from ADC measurement on
- # external voltages (VAUX) to Volt
- proc xadc_volt {code} {
- return [expr {$code * 1./(1 << 16)}]
- }
-
- # convert 16 bit temperature measurement to Celsius
- proc xadc_temp {code} {
- return [expr {$code * 503.975/(1 << 16) - 273.15}]
- }
-
- # convert 16 bit suppply voltage measurement to Volt
- proc xadc_sup {code} {
- return [expr {$code * 3./(1 << 16)}]
- }
-
- # perform a single channel measurement using default settings
- proc xadc_single {tap ch} {
- set cfg0 [xadc_read $tap [XADC CFG0]]
- set cfg1 [xadc_read $tap [XADC CFG1]]
- # set channel
- xadc_write $tap [XADC CFG0] $cfg0
- # single channel, disable the sequencer
- xadc_write $tap [XADC CFG1] 0x3000
- # leave some time for the conversion
- runtest 100
- set ret [xadc_read $tap [XADC $ch]]
- # restore CFG0/1
- xadc_write $tap [XADC CFG0] $cfg0
- xadc_write $tap [XADC CFG1] $cfg1
- return $ret
- }
-
- # measure all internal voltages
- proc xadc_report {tap} {
- xadc_select $tap
- echo "TEMP [format %.2f [xadc_temp [xadc_single $tap TEMP]]] C"
- foreach ch [list VCCINT VCCAUX VCCBRAM VPVN VREFP VREFN \
- VCCPINT VCCPAUX VCCODDR] {
- echo "$ch [format %.3f [xadc_sup [xadc_single $tap $ch]]] V"
- }
- }
|