📄 adc_ctrl.psm
字号:
CALL LCD_reset ;initialise LCD display
;
;Write welcome message to LCD display
;
LOAD s5, 10 ;Line 1 position 0
CALL LCD_cursor
CALL disp_PicoBlaze ;Display 'PicoBlaze Inside'
LOAD s5, 23 ;Line 2 position 3
CALL LCD_cursor
CALL disp_ADC_Control
CALL delay_1s ;wait 5 seconds
CALL delay_1s
CALL delay_1s
CALL delay_1s
CALL delay_1s
CALL LCD_clear ;Clear display
;
LOAD s0, 00 ;clear event counter
STORE s0, sample_count
;
;
;
;
LOAD s0, 01 ;set initial amplifier gain to 1 on both channels
STORE s0, amp_A_gain
STORE s0, amp_B_gain
JUMP new_gain_set ;set, display the initial gain and enable interrupts
;
;
;The program is interrupt driven to maintain an 8KHz sample rate. The main body
;of the program waits for an interrupt to occur. The interrupt updates all four
;analogue outputs with values stored in scratch pad memory. This takes approximately
;58us of the 125us available between interrupts. The main program then prepares
;new values for the analogue outputs (in less than 67us) before waiting for the
;next interrupt.
;
;
warm_start: LOAD sF, FF ;flag set and wait for interrupt to be serviced
ENABLE INTERRUPT ;normal operation
wait_int: INPUT sE, switch_port ;test for button press changes to amplifier gain
TEST sE, BTN_north ;sE used as this in not effected by ISR
JUMP NZ, gain_increase
TEST sE, BTN_south
JUMP NZ, gain_decrease
COMPARE sF, FF ;wait for interrupt
JUMP Z, wait_int ;interrupt clears the flag
;
;
;
;Drive LEDs with simple binary count of the samples to indicate
;that the design is active.
;
FETCH s0, sample_count ;increment counter
ADD s0, 01
STORE s0, sample_count
OUTPUT s0, LED_port ;count increments at 1Hz
;
;
;Display the A/D Channel 0 value as hex on LCD
;
LOAD s5, 2C ;Line 2 position 12
CALL LCD_cursor
FETCH s0, ADC0_msb
CALL disp_hex_byte
FETCH s0, ADC0_lsb
CALL disp_hex_byte
;
;
;
;Convert A/D channel 0 value to decimal voltage
;
;The 14-bit signed value from the A/D (sign extended to 16-bits)
;relates to a voltage in the range -1.25v to +1.25v at the input
;to the A/D converter relative to the 1.65v mid-rail reference point.
;
;The 14-bit value can be translated into the -1.25v to +1.25v using the
;simple equation...
;
; ADin = AD_value x 1.25/8192
;
;It is possible to scale the AD_value by 1.25/8192 using a fixed point
;representation.
;
;However, it is also possible to scale it by another factor at the
;same time which nicely converts to a binary value which is readily
;converted to decimal. This can be achieved by example...
;
;For an input to the A/D converter of +1.25v relative to the reference,
;the A/D will output the maximum conversion of 1FFF (+8191).
;
;In this case we would like to have the result value +1.250v which can be represented
;by the integer value +1250 with appropiate positioning of the decimal point.
;The constant to achieve this conversion is +1250/8191=+0.152606...
;Also a number requiring fixed point representation but how many bits to use?
;
;The way to resolve this is to realise that a multiplication will be
;performed and it would be nice if the +1250 result ended up in a register pair.
;So if we perform a 16x16-bit multiplication such that the upper 16-bits of
;the 32-bit result is the required value, then everything will resolve itself.
;
;Hence the constant required is actually (1250x(2^16))/8191=+10001 (2711 hex).
;
;Using the example 1FFF x 2711 = 04E1F8EF
; of which the upper 16-bits = 04E1 (+1249 decimal)
;
;Likewise the other limit case is E000 x 2711 = FB1DE000
; of which the upper 16-bits = FB1D (-1251 decimal)
;
;The values can be made perfect by rounding before truncation
;
FETCH s2, ADC0_lsb ;Read A/D channel 0 value
FETCH s3, ADC0_msb
LOAD s0, 11 ;scaling value for input to A/D converter
LOAD s1, 27
CALL mult_16x16s ;[s7,s6,s5,s4]=[s3,s2]x[s1,s0]
SL0 s5 ;round value before truncation
ADDCY s6, 00
ADDCY s7, 00
;
;The register pair [s7,s6] now holds the binary value
;representing the input level to the A/D converter in milli-volts.
;This is now displayed on the LCD. Negative values need to be converted to
;signed magnitude for display.
;
LOAD s5, 20 ;Line 2 position 0
CALL LCD_cursor
CALL disp_AD ;display A/D=
TEST s7, 80 ;test sign bit of value
JUMP NZ, neg_AD
LOAD s5, character_plus
JUMP AD_sign
neg_AD: XOR s6, FF ;complement [s7,s6] to make positive
XOR s7, FF
ADD s6, 01
ADDCY s7, 00
LOAD s5, character_minus
AD_sign: CALL LCD_write_data ;display sign of value
CALL disp_volts ;display 4 digit value as X.XXXv
;
;Convert A/D channel 0 value to display the VINA decimal voltage
;
;The same fundamental technique can be used to convert the 14-bit
;A/D value into the level at the VINA input except that two more factors
;must be considered.
;
;The first is that the amplifier inverts and has gain. Therefore the
;VINA input level is opposite polarity and could be a smaller deviation
;from the mid rail 1.65v reference.
;
;Secondly, to display the actual voltage level at the VINA terminal
;the 1.65v offset must be added.
;
;The voltage at the VINA input is therefore...
;
; VINA = [AD_value x (1.25/(8192 x G))]+1.65
;
;Following the same methodology as for the A/D value, it means that there
;is a set of scaling factors to deal with the negative gain values.
;
; K = (+1250 x (2^16)) / (8191 x G)
;
; G K (K Hex)
; -1 -10001 (D8EF)
; -2 -5001 (EC77)
; -5 -2000 (F830)
; -10 -1000 (FC18)
; -20 -500 (FE0C)
; -50 -200 (FF38)
; -100 -100 (FF9C)
;
FETCH s2, ADC0_lsb ;Read A/D channel 0 value
FETCH s3, ADC0_msb
FETCH s4, amp_A_gain ;read A gain and select appropiate gain setting
LOAD s0, EF ;scaling value for amplifier gain of -1
LOAD s1, D8
COMPARE s4, 01
JUMP Z, mult_VINA
LOAD s0, 77 ;scaling value for amplifier gain of -2
LOAD s1, EC
COMPARE s4, 02
JUMP Z, mult_VINA
LOAD s0, 30 ;scaling value for amplifier gain of -5
LOAD s1, F8
COMPARE s4, 03
JUMP Z, mult_VINA
LOAD s0, 18 ;scaling value for amplifier gain of -10
LOAD s1, FC
COMPARE s4, 05
JUMP Z, mult_VINA
LOAD s0, 0C ;scaling value for amplifier gain of -20
LOAD s1, FE
COMPARE s4, 06
JUMP Z, mult_VINA
LOAD s0, 38 ;scaling value for amplifier gain of -50
LOAD s1, FF
COMPARE s4, 01
JUMP Z, mult_VINA
LOAD s0, 9C ;scaling value for amplifier gain of -100
LOAD s1, FF
mult_VINA: CALL mult_16x16s ;[s7,s6,s5,s4]=[s3,s2]x[s1,s0]
SL0 s5 ;round value before truncation
ADDCY s6, 00
ADDCY s7, 00
ADD s6, VREF_lsb ;add 1.65v offset represented at 1650 (0672 hex)
ADDCY s7, VREF_msb
;
;The register pair [s7,s6] now holds the binary value
;representing the VINA input level in milli-volts.
;This must be a positive value due to the offset of 1.65v
;being greater than the maximum relative range of -1.25v to +1.25v.
;This binary value can now be converted to a decimal digits
;and displayed on the LCD.
;
;If the A/D value is maximum negative (E000) or maximum positive (1FFF)
;then an indication of the actual value being applied being greater or
;less than that computed will be made.
;
LOAD s5, 17 ;Line 1 position 7
CALL LCD_cursor
CALL disp_VA ;display VA=
FETCH s2, ADC0_lsb ;Read A/D channel 0 value
FETCH s3, ADC0_msb
COMPARE s3, E0 ;test for maximum negative
JUMP NZ, test_max_pos
COMPARE s2, 00
JUMP NZ, test_max_pos
LOAD s5, character_greater_than ;display >
CALL LCD_write_data
JUMP disp_VINA_volts
test_max_pos: COMPARE s3, 1F ;test for maximum positive
JUMP NZ, disp_VINA_volts
COMPARE s2, FF
JUMP NZ, disp_VINA_volts
LOAD s5, character_less_than ;display <
CALL LCD_write_data
disp_VINA_volts: CALL disp_volts ;display 4 digit value as X.XXXv
JUMP warm_start
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -