mirror of
https://github.com/pConst/basic_verilog.git
synced 2025-01-28 07:02:55 +08:00
626 lines
48 KiB
Plaintext
626 lines
48 KiB
Plaintext
;
|
||
;------------------------------------------------------------------------------------------
|
||
; Copyright <20> 2012-2013, Xilinx, Inc.
|
||
; This file contains confidential and proprietary information of Xilinx, Inc. and is
|
||
; protected under U.S. and international copyright and other intellectual property laws.
|
||
;------------------------------------------------------------------------------------------
|
||
;
|
||
; Disclaimer:
|
||
; This disclaimer is not a license and does not grant any rights to the materials
|
||
; distributed herewith. Except as otherwise provided in a valid license issued to
|
||
; you by Xilinx, and to the maximum extent permitted by applicable law: (1) THESE
|
||
; MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL FAULTS, AND XILINX HEREBY
|
||
; DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY,
|
||
; INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT,
|
||
; OR FITNESS FOR ANY PARTICULAR PURPOSE; and (2) Xilinx shall not be liable
|
||
; (whether in contract or tort, including negligence, or under any other theory
|
||
; of liability) for any loss or damage of any kind or nature related to, arising
|
||
; under or in connection with these materials, including for any direct, or any
|
||
; indirect, special, incidental, or consequential loss or damage (including loss
|
||
; of data, profits, goodwill, or any type of loss or damage suffered as a result
|
||
; of any action brought by a third party) even if such damage or loss was
|
||
; reasonably foreseeable or Xilinx had been advised of the possibility of the same.
|
||
;
|
||
; CRITICAL APPLICATIONS
|
||
; Xilinx products are not designed or intended to be fail-safe, or for use in any
|
||
; application requiring fail-safe performance, such as life-support or safety
|
||
; devices or systems, Class III medical devices, nuclear facilities, applications
|
||
; related to the deployment of airbags, or any other applications that could lead
|
||
; to death, personal injury, or severe property or environmental damage
|
||
; (individually and collectively, "Critical Applications"). Customer assumes the
|
||
; sole risk and liability of any use of Xilinx products in Critical Applications,
|
||
; subject only to applicable laws and regulations governing limitations on product
|
||
; liability.
|
||
;
|
||
; THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE AT ALL TIMES.
|
||
;
|
||
;------------------------------------------------------------------------------------------
|
||
;
|
||
;
|
||
; _ ______ ____ ____ __ __ __
|
||
; | |/ / ___| _ \/ ___|| \/ |/ /_
|
||
; | ' / | | |_) \___ \| |\/| | '_ \
|
||
; | . \ |___| __/ ___) | | | | (_) )
|
||
; |_|\_\____|_| |____/|_| |_|\___/
|
||
;
|
||
;
|
||
; PicoBlaze Reference Design.
|
||
;
|
||
;
|
||
; Routines for XADC Communication, Control and Monitoring
|
||
;
|
||
; Ken Chapman - Xilinx Ltd
|
||
;
|
||
; 9th January 2013 - Initial Version
|
||
;
|
||
;
|
||
; NOTE - This is not a standalone PSM file. Include this file in a program that
|
||
; then calls these routines and works with the values in scratch pad memory.
|
||
;
|
||
; INCLUDE "xadc_routines.psm"
|
||
;
|
||
;
|
||
; IMPORTANT - These routines interact with input and output ports which must
|
||
; be appropriately defined to interface with XADC. The CONSTANT
|
||
; directives defined below must correspond with the port assignments.
|
||
;
|
||
;
|
||
; INTRODUCTION
|
||
; ------------
|
||
;
|
||
; This file implements two routines that allow the XADC registers to be read or written
|
||
; using the DRP and KCPSM6 interface circuit defined in the hardware. Please see the
|
||
; 'kc705_kcpsm6_xadc.vhd' reference design which contains full descriptions of the
|
||
; interface and various KCPSM6 input and output ports allocated to it.
|
||
;
|
||
; This file also includes routines which help to interpret and convert register values
|
||
; into their corresponding voltage and temperature values.
|
||
;
|
||
;------------------------------------------------------------------------------------------
|
||
; Hardware Constants
|
||
;------------------------------------------------------------------------------------------
|
||
;
|
||
; The following constants define the input and output ports allocated to the XADC DRP
|
||
; interface. These constants reflect the ports used in the 'kc705_kcpsm6_xadc.vhd'
|
||
; reference design file and should be modified if different ports are allocated in your
|
||
; own designs.
|
||
;
|
||
; Prior to initiating a read or write transaction, KCPSM6 must present the 7-bit address of
|
||
; the target XADC register to the DRP interface using the following output port.
|
||
;
|
||
CONSTANT XADC_register_address, 80 ; register address[6:0]
|
||
;
|
||
; If a new value is to be written to an XADC configuration register then the 16-bit value
|
||
; must also be presented to the DRP interface using the following pair of output ports.
|
||
;
|
||
CONSTANT XADC_write_data0, 82 ; new register value[7:0]
|
||
CONSTANT XADC_write_data1, 83 ; new register value[15:8]
|
||
;
|
||
; To initiate a transaction with XADC a value is output to a Constant Optimised Output
|
||
; Port. The value of bit0 defines the state of DWE for read (0) or write (1).
|
||
;
|
||
CONSTANT XADC_start_port, 02 ; 'k_write_strobe' starts transaction
|
||
CONSTANT XADC_read_mode, 00000000'b ; DWE = 0 read - bit0
|
||
CONSTANT XADC_write_mode, 00000001'b ; DWE = 1 write - bit0
|
||
;
|
||
; Once a transaction has been started, the hardware will present a 'transaction in progress'
|
||
; flag 'tip' to KCPSM6 via the 'XADC_status_port' defined below. KCPSM6 must wait for 'tip'
|
||
; to be Low (0) before proceeding to read the register value requested or starting another
|
||
; transaction. The status port also provides KCPSM6 with the ability to check if XADC is
|
||
; being used, or has been modified, by the JTAG interface. Finally, this port is also used
|
||
; to observe the over temperature alarm signal (OT).
|
||
;
|
||
CONSTANT XADC_status_port, 04
|
||
CONSTANT XADC_tip, 00000001'b ; 'transaction in progress' - bit0
|
||
CONSTANT XADC_JTAG_busy, 00000010'b ; JTAG busy - bit1
|
||
CONSTANT XADC_JTAG_locked, 00000100'b ; JTAG locked - bit2
|
||
CONSTANT XADC_JTAG_modified, 00001000'b ; JTAG modified - bit3
|
||
CONSTANT XADC_OT_alarm, 00010000'b ; OT over temperature alarm - bit4
|
||
;
|
||
; Following completion of a read transaction the 16-bit contents of the XADC register can
|
||
; be read from the following pair of input ports.
|
||
;
|
||
CONSTANT XADC_read_data0, 02 ; register value[7:0]
|
||
CONSTANT XADC_read_data1, 03 ; register value[15:8]
|
||
;
|
||
; As well as the 'OT' alarm observed via the 'XADC_status_port', XADC generates up to
|
||
; 7 more alarm signals (plus an 8th alarm which is the logical-OR of the 7 alarms). The
|
||
; following constant define the input port used by KCPSM6 to observe these alarms and the
|
||
; bits to which they have been allocated.
|
||
;
|
||
CONSTANT XADC_alarm_port, 05
|
||
CONSTANT XADC_ALM0_Temperature, 00000001'b ; ALM(0) Temperature - bit0
|
||
CONSTANT XADC_ALM1_VCCINT, 00000010'b ; ALM(1) VCCINT - bit1
|
||
CONSTANT XADC_ALM2_VCCAUX, 00000100'b ; ALM(2) VCCAUX - bit2
|
||
CONSTANT XADC_ALM3_VCCBRAM, 00001000'b ; ALM(3) VCCBRAM - bit3
|
||
CONSTANT XADC_ALM4_VCCPINT, 00010000'b ; ALM(4) VCCPINT (Zynq only) - bit4
|
||
CONSTANT XADC_ALM5_VCCPAUX, 00100000'b ; ALM(5) VCCPAUX (Zynq only) - bit5
|
||
CONSTANT XADC_ALM6_VCCO_DDR, 01000000'b ; ALM(6) VCCO_DDR (Zynq only) - bit6
|
||
CONSTANT XADC_ALM7, 10000000'b ; ALM(7) Any alarm - bit7
|
||
;
|
||
;
|
||
;------------------------------------------------------------------------------------------
|
||
; Routine to read and return the contents of an XADC register.
|
||
;------------------------------------------------------------------------------------------
|
||
;
|
||
; Reads XADC register via DRP.
|
||
; The 7-bit address of the register to be read must be provided in sA.
|
||
; The 16-bit register value will be returned in register pair [s9,s8].
|
||
;
|
||
; Registers used s0, s8, s9 (preserved) and sA.
|
||
;
|
||
;
|
||
read_XADC: OUTPUT sA, XADC_register_address ;set address (DADDR)
|
||
OUTPUTK XADC_read_mode, XADC_start_port ;Start read transaction (DWE = 0)
|
||
CALL wait_for_XADC_DRP ;wait for DRP to complete
|
||
INPUT s8, XADC_read_data0 ;read register value into [s9,s8]
|
||
INPUT s9, XADC_read_data1
|
||
RETURN
|
||
;
|
||
;
|
||
;------------------------------------------------------------------------------------------
|
||
; Routine to write new value to an XADC configuration register.
|
||
;------------------------------------------------------------------------------------------
|
||
;
|
||
; Write XADC register via DRP.
|
||
; The address of the register to be written must be provided in sA.
|
||
;
|
||
; NOTE - There are only 32 writable configuration registers so the
|
||
; register address should be in the range 40 to 5F hex.
|
||
;
|
||
; The 16-bit value to be stored in the configuration register must be provided in
|
||
; register pair [s9,s8].
|
||
;
|
||
; Registers used s0, s8 (preserved), s9 (preserved) and sA (preserved).
|
||
;
|
||
write_XADC: OUTPUT sA, XADC_register_address ;set address (DADDR)
|
||
OUTPUT s8, XADC_write_data0 ;set data (DI[7:0])
|
||
OUTPUT s9, XADC_write_data1 ;set data (DI[15:8])
|
||
OUTPUTK XADC_write_mode, XADC_start_port ;Start write transaction (DWE = 1)
|
||
;
|
||
; Test the 'transaction in progress' until it is observed to be Low.
|
||
; This will complete a write transaction or indicates when a register value
|
||
; is available to be read following a read transaction.
|
||
;
|
||
wait_for_XADC_DRP: INPUT s0, XADC_status_port
|
||
TEST s0, XADC_tip
|
||
JUMP NZ, wait_for_XADC_DRP
|
||
RETURN
|
||
;
|
||
;
|
||
;------------------------------------------------------------------------------------------
|
||
; Routine to read the XADC status and alarm signals.
|
||
;------------------------------------------------------------------------------------------
|
||
;
|
||
; This routine is a simple read of the input ports associated with the XADC status and
|
||
; alarm signals with the bits returned in registers 's8' and 's9'.
|
||
;
|
||
; Hint - Constants have been defined to identify the bit allocations.
|
||
; e.g. TEST s8, XADC_ALM1_VCCINT will test the VCCINT alarm bit.
|
||
;
|
||
;
|
||
; Register Bit XADC Signal CONSTANT defined to isolate bit
|
||
;
|
||
; s8 0 ALM(0) Temperature XADC_ALM0_Temperature
|
||
; s8 1 ALM(1) VCCINT XADC_ALM1_VCCINT
|
||
; s8 2 ALM(2) VCCAUX XADC_ALM2_VCCAUX
|
||
; s8 3 ALM(3) VCCBRAM XADC_ALM3_VCCBRAM
|
||
; s8 4 ALM(4) VCCPINT (Zynq only) XADC_ALM4_VCCPINT
|
||
; s8 5 ALM(5) VCCPAUX (Zynq only) XADC_ALM5_VCCPAUX
|
||
; s8 6 ALM(6) VCCO_DDR (Zynq only) XADC_ALM6_VCCO_DDR
|
||
; s8 7 ALM(7) Any alarm XADC_ALM7
|
||
;
|
||
; s9 1 JTAG busy XADC_JTAG_busy
|
||
; s9 2 JTAG locked XADC_JTAG_locked
|
||
; s9 3 JTAG modified XADC_JTAG_modified
|
||
; s9 4 OT over temperature alarm XADC_OT_alarm
|
||
;
|
||
; Registers s8 and s9.
|
||
;
|
||
read_XADC_status: INPUT s8, XADC_alarm_port
|
||
INPUT s9, XADC_status_port
|
||
AND s9, 00011110'b ;mask unused bits
|
||
RETURN
|
||
;
|
||
;
|
||
;------------------------------------------------------------------------------------------
|
||
; Routine to convert XADC Temperature sample to degrees centigrade
|
||
;------------------------------------------------------------------------------------------
|
||
;
|
||
; Die temperature is obtained by reading the temperature status register (00 hex) from
|
||
; XADC (obviously the die temperature channel must have been sampled for the value to be
|
||
; valid and reasonably current).
|
||
;
|
||
; The temperature sample obtained when reading the status register is 16-bits. Of these,
|
||
; it is the 12 most significant bits which are immediately trustworthy and represent a die
|
||
; temperature with a theoretical range from -273degC to +230.7degC. The transfer function
|
||
; for the 12-bit sample is...
|
||
;
|
||
; Temperature in degC = ((12-bit_ADC_code x 503.975) / 4096) - 273.15
|
||
;
|
||
; However, the use of sample averaging (built-in to XADC when enabled, in the application
|
||
; or a combination of both) can exploit the 4 least significant bits to minimize
|
||
; quantisation effects and/or improve resolution. So in this routine the full 16-bit
|
||
; value will be used and converted using the following modified transfer function.
|
||
;
|
||
; Temperature in degC = ((16-bit_ADC_code x 503.975) / (16 x 4096)) - 273.15
|
||
;
|
||
; Note that only a part of the theoretical temperature range could ever be observed in
|
||
; practice (e.g. -40 to +100 for industrial grade devices) so it is of more value to
|
||
; preserve the potentially useful resolution than the unused range. As such this routine
|
||
; converts the raw status register value into a new 16-bit value which more directly
|
||
; relates to degrees centigrade in a practical range.
|
||
;
|
||
; Hint - Without any form or sample averaging or filtering then the standard 12-bit
|
||
; resolution corresponds with 'steps' of 0.123degC . It is useful to recognise
|
||
; that this means that die temperature can be known and presented to the nearest
|
||
; WHOLE degree using simple rounding. It can also be justified to round
|
||
; temperature to the nearest one half of a degree. Note however that that it
|
||
; would be inappropriate to represent die temperature using greater numerical
|
||
; accuracy than the 0.123degC step size (i.e. a decimal representation using
|
||
; more than one decimal place). So just because the converted value produced
|
||
; by this routine appears to have greater resolution it should be used with
|
||
; due consideration.
|
||
;
|
||
;
|
||
; This routine will take the 16-bit temperature status register value in register pair
|
||
; [s9,s8] and convert it to a 16-bit signed value in register pair [s3,s2] representing
|
||
; die temperature in degrees centigrade.
|
||
;
|
||
; A 16x16 bit multiplication routine generating a 32-bit product is used to maintain a
|
||
; high degree of precision throughout the conversion process. The 16-bit temperature
|
||
; sample is multiplied by a 16-bit constant representing the value 503.975.
|
||
;
|
||
; 503.975 x 128 = 64508.8 --> 64509 ---> FBFD hex
|
||
;
|
||
; Then a 32-bit constant representing 273.15 is subtracted.
|
||
;
|
||
; 273.15 x 128 x 16 x 4096 = 2291348275.2 --> 2291348275 ---> 88933333 hex
|
||
;
|
||
; The most significant 16-bits of the 32-bit result will then represent temperature in
|
||
; degrees centigrade with a signed <9.7> format meaning 9 integer bits and 7 fractional
|
||
; bits providing more than adequate range and precision.
|
||
;
|
||
;
|
||
; Example
|
||
; 16-bit ADC Code = 9A85 hex (Theoretically +31.045 degC)
|
||
;
|
||
; 9A85
|
||
; x FBFD
|
||
; --------
|
||
; 98191C71 --> 98191C71
|
||
; - 88933333
|
||
; --------
|
||
; 0F85E93E --> 0F85
|
||
;
|
||
; 0F85 hex = 3973 --> 3973 / 128 = 31.039 degC
|
||
;
|
||
; 0F85 hex = 0000111110000101 --> 000011111.0000101 <9.7> format
|
||
; 31 and 5/128
|
||
;
|
||
;
|
||
; Operational limits of an industrial grade device
|
||
;
|
||
; Temp 16-bit Converted Meaning of
|
||
; degC ADC Code <9.7> format signed <9.7> value
|
||
;
|
||
; -40 766E hex EBFF hex -5121/128 = -40.0078 (-40 and 1/128)
|
||
; +100 BD8C hex 3200 hex +12800/128 = +100.0 (+100 and 0/128)
|
||
;
|
||
;
|
||
; Registers used s0, s1, s2 ,s3, s4, s5, s6, s7, s8, s9
|
||
;
|
||
; Provide: [s9,s8] - 16-bit temperature status register value.
|
||
; Returns: [s3,s2] - 16-bit signed <9.7> format temperature in degrees centigrade.
|
||
;
|
||
convert_XADC_temperature: LOAD s5, s9 ;copy original 16-bit sample
|
||
LOAD s4, s8
|
||
LOAD s7, FB ;16-bit constant representing 503.975
|
||
LOAD s6, FD
|
||
CALL mult_16x16 ;[s5,s4]x[s7,s6]=[s3,s2,s1,s0]
|
||
SUB s0, 33 ;subtract 32-bit constant representing 273.15
|
||
SUBCY s1, 33
|
||
SUBCY s2, 93
|
||
SUBCY s3, 88
|
||
RETURN ;[s3,s2] holds signed <9.7> format
|
||
;
|
||
;
|
||
;------------------------------------------------------------------------------------------
|
||
; Routine to convert an internal supply sample to a 16-bit milli-Volt integer value
|
||
;------------------------------------------------------------------------------------------
|
||
;
|
||
; Internal supply voltages are associated with the following status registers (obviously
|
||
; a supply must have been sampled for the value stored in a register to be valid).
|
||
;
|
||
; Power Status Registers (Hex addresses)
|
||
; Supply Last sample Minimum Maximum
|
||
;
|
||
; VCCINT 01 25 21
|
||
; VCCAUX 02 26 22
|
||
; VCCBRAM 06 27 23
|
||
;
|
||
; VCCPINT 0D 2C 28 (Zynq Only)
|
||
; VCCPAUX 0E 2D 29 (Zynq Only)
|
||
; VCCO_DDR 0F 2E 2A (Zynq Only)
|
||
;
|
||
;
|
||
; The value obtained when reading a power supply status register is 16-bits. Of these,
|
||
; it is the 12 most significant bits which are immediately trustworthy and represent a
|
||
; voltage with a theoretical range from 0v to 2.999v. The transfer function for the
|
||
; 12-bit sample is...
|
||
;
|
||
; Voltage = (12-bit_ADC_code / 4096) x 3
|
||
;
|
||
; However, the use of sample averaging (built-in to XADC when enabled, in the application
|
||
; or a combination of both) can exploit the 4 least significant bits to minimize
|
||
; quantisation effects and/or improve resolution. So in this routine the full 16-bit
|
||
; value will be used and converted using the following modified transfer function.
|
||
;
|
||
; Voltage = (16-bit_ADC_code / (16 x 4096) ) x 3
|
||
;
|
||
;
|
||
; This routine takes a 16-bit voltage status register value in register pair [s9,s8] and
|
||
; converts it to a 16-bit unsigned integer representing voltage rounded to the nearest
|
||
; milli-volt (mV). The standard 12-bit resolution corresponds with 'steps' of 0.732mV so
|
||
; 1mV resolution is justified and reasonable especially as this routine will maintain
|
||
; higher precision throughout the conversion process.
|
||
;
|
||
; A 16x16 bit multiplication routine generating a 32-bit product is used to scale
|
||
; the status register value into a 'milli-volt' value aligned with the upper 16-bits of
|
||
; the 32-bit product. Following multiplication, bit15 of the product represents 0.5mV and
|
||
; this is used to round the final voltage value before it is returned.
|
||
;
|
||
;
|
||
; Example
|
||
; 16-bit ADC Code = 5555 hex (Theoretically 1.000V = 1000mV)
|
||
;
|
||
; 5555
|
||
; x 0BB8 <-- Scaling factor
|
||
; --------
|
||
; 03E7FC18 --> 03E7 (upper 16-bits of 32-bit product)
|
||
; + 1 (most significant bit of FC18 is High >=0.5mv)
|
||
; ----
|
||
; 03E8 --> 1000mV
|
||
;
|
||
;
|
||
; Registers used s0, s1, s2 ,s3, s4, s5, s6, s7, s8, s9
|
||
;
|
||
; Provide: [s9,s8] - 16-bit supply voltage status register value.
|
||
; Returns: [s3,s2] - 16-bit unsigned voltage in milli-volts (mV).
|
||
;
|
||
convert_XADC_supply_voltage: LOAD s5, s9 ;copy original 16-bit sample
|
||
LOAD s4, s8
|
||
LOAD s7, 0B ;16-bit scaling constant
|
||
LOAD s6, B8
|
||
CALL mult_16x16 ;[s5,s4]x[s7,s6]=[s3,s2,s1,s0]
|
||
TEST s1, 10000000'b ;round up to next mV if fraction
|
||
ADDCY s2, 00 ; is 0.5mV or more
|
||
ADDCY s3, 00
|
||
RETURN ;[s3,s2] holds 16-bit mV value
|
||
;
|
||
;
|
||
;------------------------------------------------------------------------------------------
|
||
; Routines to convert Unipolar and Bipolar samples to a 16-bit milli-Volt integer value
|
||
;------------------------------------------------------------------------------------------
|
||
;
|
||
; The external analogue inputs are associated with the following status registers.
|
||
; Obviously an analogue input must be connected to XADC and that input must have been
|
||
; sampled for the value stored in the corresponding status register to be valid.
|
||
;
|
||
;
|
||
; Analogue Status Register
|
||
; Input (Hex addresses)
|
||
;
|
||
; VP/VN 03
|
||
; VAUXP[0]/VAUXN[0] 10
|
||
; VAUXP[1]/VAUXN[1] 11
|
||
; VAUXP[2]/VAUXN[2] 12
|
||
; VAUXP[3]/VAUXN[3] 13
|
||
; VAUXP[4]/VAUXN[4] 14
|
||
; VAUXP[5]/VAUXN[5] 15
|
||
; VAUXP[6]/VAUXN[6] 16
|
||
; VAUXP[7]/VAUXN[7] 17
|
||
; VAUXP[8]/VAUXN[8] 18
|
||
; VAUXP[9]/VAUXN[9] 19
|
||
; VAUXP[A]/VAUXN[A] 1A
|
||
; VAUXP[B]/VAUXN[B] 1B
|
||
; VAUXP[C]/VAUXN[C] 1C
|
||
; VAUXP[D]/VAUXN[D] 1D
|
||
; VAUXP[E]/VAUXN[E] 1E
|
||
; VAUXP[F]/VAUXN[F] 1F
|
||
;
|
||
;
|
||
; An input can be configured to be Unipolar with an input voltage range of 0.0v to +1.0v or
|
||
; Bipolar with and input range of -0.5v to +0.5v. In each case the total voltage range is
|
||
; 1v and the value read from the status register reflects this range. The only difference
|
||
; being that the Unipolar value is unsigned and the Bipolar value is a signed using twos
|
||
; complement format.
|
||
;
|
||
; The value obtained when reading one of these status registers is 16-bits. Of these bits,
|
||
; it is the 12 most significant bits which are immediately trustworthy and represent a
|
||
; voltage with the following transfer function...
|
||
;
|
||
; Voltage = 12-bit_ADC_code / 4096
|
||
;
|
||
; However, the use of sample averaging (built-in to XADC when enabled, in the application
|
||
; or a combination of both) can exploit the 4 least significant bits to minimize
|
||
; quantisation effects and/or improve resolution. So in this routine the full 16-bit
|
||
; value will be used and converted using the following modified transfer function.
|
||
;
|
||
; Voltage = 16-bit_ADC_code / (16 x 4096)
|
||
;
|
||
; When an input is Unipolar the ADC_code is a 16-bit unsigned value and must be converted
|
||
; to represent a voltage in the range 0.0v to +1.0v. When an input is Bipolar the ADC_code
|
||
; is a 16-bit signed value (twos complement) and must be converted to represent a voltage
|
||
; in the range -0.5v to +0.5v.
|
||
;
|
||
; 16-bit Unipolar Unipolar Bipolar Bipolar
|
||
; ADC_code value voltage value voltage
|
||
;
|
||
; 0000 0 0v 0 0v
|
||
; 7FFF 32767 0.49998v +32767 +0.49998v
|
||
; 8000 32768 0.5v -32768 -0.5v
|
||
; FFFF 65535 0.99998v -1 -0.0153v
|
||
;
|
||
; Both the routines provided below take a 16-bit voltage status register value in register
|
||
; pair [s9,s8] and convert it to a 16-bit signed integer representing voltage rounded to
|
||
; the nearest milli-volt (mV). The standard 12-bit resolution corresponds with 'steps' of
|
||
; 244uV so 1mV resolution is justified and reasonable especially as this routine will
|
||
; maintain higher precision throughout the conversion process. Note that the effect of
|
||
; rounding may result in converted values of 1000mv for Unipolar and +500mV for Bipolar
|
||
; even though the theoretical limit of the transfer function falls slightly short of these
|
||
; maximum positive levels.
|
||
;
|
||
; A Unipolar input should result in converted values in the range 0mV to 1000mv which is
|
||
; 0000 to 03E8 hex. Since all values are positive the 16-bit value could be considered to
|
||
; be an unsigned 16-bit integer. However, it can be useful to think in terms of the
|
||
; returned value being a 16-bit signed integer which only has positive values. In this
|
||
; way the same signed representation applies to both Unipolar and Bipolar values.
|
||
;
|
||
; A Bipolar input should result in values in the range -500mV to +500mv which is FE0C to
|
||
; 01F4 hex in 16-bit twos complement.
|
||
;
|
||
; The conversion process employs a 16x16 bit multiplication routine generating a 32-bit
|
||
; product which is used to scale the status register value into a 'milli-volt' value
|
||
; aligned with the upper 16-bits of the 32-bit product. Following multiplication of a
|
||
; positive value, bit15 of the product represents 0.5mV and this is used to round the
|
||
; final voltage value before it is returned.
|
||
;
|
||
; All Unipolar values are positive so the scaling and rounding is straightforward.
|
||
; Positive Bipolar values can also be handled in exactly the same way as Unipolar values.
|
||
; When a negative Bipolar value needs to be converted it will be complemented to form a
|
||
; positive value which can be scaled and rounded in the same way. The scaled and rounded
|
||
; result is then complemented to restore the negative polarity to the value. This scheme
|
||
; enables most of the code to be reused but also ensures that rounding effects are balanced
|
||
; around zero (something which is easy to get wrong when handling twos complement).
|
||
;
|
||
;
|
||
; Unipolar example
|
||
;
|
||
; 16-bit ADC Code = E666 hex (Theoretically 0.900V = 900mV)
|
||
;
|
||
; E666
|
||
; x 03E8 <-- Scaling factor
|
||
; --------
|
||
; 0383FE70 --> 0383 (upper 16-bits of 32-bit product)
|
||
; + 1 (most significant bit of FE70 High >=0.5mv)
|
||
; ----
|
||
; 0384 --> 900mV
|
||
;
|
||
;
|
||
; Bipolar example - Positive
|
||
;
|
||
; 16-bit ADC Code = 6666 hex (Theoretically +0.39999V = +400mV)
|
||
;
|
||
; Most significant bit of 999A is Low so value is positive and can be converted
|
||
; in the same way as a Unipolar value.
|
||
;
|
||
; 6666
|
||
; x 03E8 <-- Scaling factor
|
||
; --------
|
||
; 018FFE70 --> 018F (upper 16-bits of 32-bit product)
|
||
; + 1 (most significant bit of FE70 high >= +0.5mv)
|
||
; ----
|
||
; 0190 --> +400mV
|
||
;
|
||
;
|
||
; Bipolar example - Negative
|
||
;
|
||
; 16-bit ADC Code = 999A hex (Theoretically -0.39999V = -400mV)
|
||
;
|
||
; Most significant bit of 999A is High so value is negative. In this case the value
|
||
; is first converted to a positive number whilst remembering that the value is negative.
|
||
;
|
||
; 999A --> invert all bits --> 6665 --> +1 --> 6666
|
||
;
|
||
; Convert the positive value in the same way as a Unipolar value.
|
||
;
|
||
; 6666
|
||
; x 03E8 <-- Scaling factor
|
||
; --------
|
||
; 018FFE70 --> 018F (upper 16-bits of 32-bit product)
|
||
; + 1 (most significant bit of FE70 high >= +0.5mv)
|
||
; ----
|
||
; 0190 --> +400mV
|
||
;
|
||
; Restore the negative polarity.
|
||
;
|
||
; 0190 --> invert all bits --> FE6F --> +1 --> FE70
|
||
;
|
||
; FE70 --> -400mV
|
||
;
|
||
;
|
||
; Unipolar Conversion
|
||
; -------------------
|
||
;
|
||
; Provide: [s9,s8] - 16-bit Unipolar external input status register value.
|
||
; Returns: [s3,s2] - 16-bit signed (but only positive) voltage in milli-volts (mV).
|
||
;
|
||
; Registers used s0, s1, s2 ,s3, s4, s5, s6, s7, s8, s9
|
||
;
|
||
convert_XADC_unipolar_voltage: LOAD s5, s9 ;copy original 16-bit sample
|
||
LOAD s4, s8
|
||
LOAD s7, 03 ;16-bit scaling constant
|
||
LOAD s6, E8
|
||
CALL mult_16x16 ;[s5,s4]x[s7,s6]=[s3,s2,s1,s0]
|
||
TEST s1, 10000000'b ;round up to next mV if fraction
|
||
ADDCY s2, 00 ; is 0.5mV or more
|
||
ADDCY s3, 00
|
||
RETURN ;[s3,s2] holds 16-bit mV value
|
||
;
|
||
;
|
||
;
|
||
; Bipolar Conversion
|
||
; -------------------
|
||
;
|
||
; Provide: [s9,s8] - 16-bit Unipolar external input status register value.
|
||
; Returns: [s3,s2] - 16-bit signed (but only positive) voltage in milli-volts (mV).
|
||
;
|
||
; Registers used s0, s1, s2 ,s3, s4, s5, s6, s7, s8, s9
|
||
;
|
||
convert_XADC_bipolar_voltage: TEST s9, 10000000'b ;test sign of sample
|
||
JUMP NZ, negative_bipolar
|
||
JUMP convert_XADC_unipolar_voltage ;includes return
|
||
;
|
||
negative_bipolar: XOR s8, FF ;twos complement sample
|
||
XOR s9, FF ;to make positive
|
||
ADD s8, 01
|
||
ADDCY s9, 00
|
||
CALL convert_XADC_unipolar_voltage ;scale and round positive value
|
||
XOR s2, FF ;twos complement converted value
|
||
XOR s3, FF ;to make negative
|
||
ADD s2, 01
|
||
ADDCY s3, 00
|
||
RETURN ;[s3,s2] holds negative 16-bit mV value
|
||
;
|
||
;
|
||
;------------------------------------------------------------------------------------------
|
||
; 16-bit x 16-bit Multiplication routine (unsigned)
|
||
;------------------------------------------------------------------------------------------
|
||
;
|
||
; 16-bit input [s5,s4] (contents of [s5,s4] are not changed)
|
||
; 16-bit input [s7,s6]
|
||
; 32-bit output [s3,s2,s1,s0]
|
||
;
|
||
mult_16x16: LOAD s8, 16'd ;16-bits to multiply by
|
||
LOAD s3, 00 ;clear result
|
||
LOAD s2, 00 ;[s1,s0] do not need to be reset
|
||
mult_16x16_loop: SR0 s7 ;multiply by LSB to MSB
|
||
SRA s6 ;
|
||
JUMP NC, shift32
|
||
ADD s2, s4 ;add [s5,s4] to upper 16-bits of result
|
||
ADDCY s3, s5
|
||
shift32: SRA s3 ;shift result right (/2)
|
||
SRA s2 ;shift includes any carry from addition
|
||
SRA s1
|
||
SRA s0
|
||
SUB s8, 1'd ;count iterations
|
||
JUMP NZ, mult_16x16_loop
|
||
RETURN
|
||
;
|
||
;
|
||
;------------------------------------------------------------------------------------------
|
||
; End of 'xadc_routines.psm'
|
||
;------------------------------------------------------------------------------------------
|
||
;
|