From 27473588a40604822dcbee1c1950d27fdf248fe9 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 29 Jan 2018 21:12:37 +0100 Subject: [PATCH] tcl/fpga/xilinx-xadc.cfg: add support for XADC 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 throught the JTAG TAP. https://www.xilinx.com/support/documentation/user_guides/ug480_7Series_XADC.pdf Change-Id: I6cef4d0244add71749fa28b58a736302151cc4dd Signed-off-by: Robert Jordens Reviewed-on: http://openocd.zylin.com/4395 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/board/kasli.cfg | 1 + tcl/board/kc705.cfg | 1 + tcl/fpga/xilinx-xadc.cfg | 159 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 tcl/fpga/xilinx-xadc.cfg diff --git a/tcl/board/kasli.cfg b/tcl/board/kasli.cfg index caa294f82e..4d96a8f7c7 100644 --- a/tcl/board/kasli.cfg +++ b/tcl/board/kasli.cfg @@ -11,3 +11,4 @@ adapter_khz 25000 source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] +source [find fpga/xilinx-xadc.cfg] diff --git a/tcl/board/kc705.cfg b/tcl/board/kc705.cfg index 39f7fa39c2..d6b835a5ff 100644 --- a/tcl/board/kc705.cfg +++ b/tcl/board/kc705.cfg @@ -3,6 +3,7 @@ source [find interface/ftdi/digilent-hs1.cfg] source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] +source [find fpga/xilinx-xadc.cfg] adapter_khz 25000 # example command to write bitstream, soft-cpu bios and runtime: diff --git a/tcl/fpga/xilinx-xadc.cfg b/tcl/fpga/xilinx-xadc.cfg new file mode 100644 index 0000000000..38691045c9 --- /dev/null +++ b/tcl/fpga/xilinx-xadc.cfg @@ -0,0 +1,159 @@ +# 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 throught 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" + } +} -- 2.30.2