openocd/tcl/fpga/xilinx-xadc.cfg

162 lines
3.3 KiB
INI

# SPDX-License-Identifier: GPL-2.0-or-later
# 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"
}
}