2018-01-29 14:12:37 -06:00
|
|
|
# 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.
|
|
|
|
#
|
2020-04-25 18:25:32 -05:00
|
|
|
# This code implements access through the JTAG TAP.
|
2018-01-29 14:12:37 -06:00
|
|
|
#
|
|
|
|
# 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} {
|
2021-04-09 18:23:57 -05:00
|
|
|
return [expr {$code * 1./(1 << 16)}]
|
2018-01-29 14:12:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
# convert 16 bit temperature measurement to Celsius
|
|
|
|
proc xadc_temp {code} {
|
2021-04-09 18:23:57 -05:00
|
|
|
return [expr {$code * 503.975/(1 << 16) - 273.15}]
|
2018-01-29 14:12:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
# convert 16 bit suppply voltage measurement to Volt
|
|
|
|
proc xadc_sup {code} {
|
2021-04-09 18:23:57 -05:00
|
|
|
return [expr {$code * 3./(1 << 16)}]
|
2018-01-29 14:12:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
# 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"
|
|
|
|
}
|
|
|
|
}
|