1
0
mirror of https://github.com/pConst/basic_verilog.git synced 2025-01-28 07:02:55 +08:00

665 lines
35 KiB
Plaintext

;KCPSM3 Program - SPI Control of D/A converter on Spartan-3E Starter Kit.
;
;
;Ken Chapman - Xilinx Ltd
;
;Version v1.00 - 24th November 2005
;
;This program uses an 8KHz interrupt to generate test waveforms on the
;4 analogue outputs provided by the Linear Technology LTC2624 device.
;
;As well as the port connections vital to communication with the UART and the SPI
;FLASH memory, there are additional port connections used to disable the other
;devices sharing the SPI bus on the Starter Kit board. Although these could have been
;controlled at the hardware level, they are included in this code to aid
;future investigations of communication with the other SPI devices using PicoBlaze.
;
;Connections to the LEDs, switches and press buttons are provided to aid
;development and enable further experiments. Otherwise know as having fun!
;
;Port definitions
;
;
CONSTANT SPI_control_port, 08 ;SPI clock and chip selects
CONSTANT SPI_sck, 01 ; SCK - bit0
CONSTANT SPI_rom_cs, 02 ; serial rom select - bit1
CONSTANT SPI_spare_control, 04 ; spare - bit2
CONSTANT SPI_amp_cs, 08 ; amplifier select - bit3
CONSTANT SPI_adc_conv, 10 ; A/D convert - bit4
CONSTANT SPI_dac_cs, 20 ; D/A select - bit5
CONSTANT SPI_amp_shdn, 40 ; amplifier SHDN - bit6
CONSTANT SPI_dac_clr, 80 ; D/A clear - bit7
;
CONSTANT SPI_output_port, 04 ;SPI data output
CONSTANT SPI_sdo, 80 ; SDO - bit7
;
CONSTANT SPI_input_port, 01 ;SPI data input
CONSTANT SPI_sdi, 80 ; SDI - bit7
CONSTANT SPI_amp_sdi, 40 ; amplifier SDI - bit6
;
;
CONSTANT LED_port, 80 ;8 simple LEDs
CONSTANT LED0, 01 ; LED 0 - bit0
CONSTANT LED1, 02 ; 1 - bit1
CONSTANT LED2, 04 ; 2 - bit2
CONSTANT LED3, 08 ; 3 - bit3
CONSTANT LED4, 10 ; 4 - bit4
CONSTANT LED5, 20 ; 5 - bit5
CONSTANT LED6, 40 ; 6 - bit6
CONSTANT LED7, 80 ; 7 - bit7
;
;
CONSTANT switch_port, 00 ;Read switches and press buttons
CONSTANT BTN_north, 01 ; Buttons North - bit0
CONSTANT BTN_east, 02 ; East - bit1
CONSTANT BTN_south, 04 ; South - bit2
CONSTANT BTN_west, 08 ; West - bit3
CONSTANT switch0, 10 ; Switches 0 - bit4
CONSTANT switch1, 20 ; 1 - bit5
CONSTANT switch2, 40 ; 2 - bit6
CONSTANT switch3, 80 ; 3 - bit7
;
;
;
;
;Special Register usage
;
;
;Useful data constants
;
;
;Constant to define a software delay of 1us. This must be adjusted to reflect the
;clock applied to KCPSM3. Every instruction executes in 2 clock cycles making the
;calculation highly predictable. The '6' in the following equation even allows for
;'CALL delay_1us' instruction in the initiating code.
;
; delay_1us_constant = (clock_rate - 6)/4 Where 'clock_rate' is in MHz
;
;Example: For a 50MHz clock the constant value is (10-6)/4 = 11 (0B Hex).
;For clock rates below 10MHz the value of 1 must be used and the operation will
;become lower than intended.
;
CONSTANT delay_1us_constant, 0B
;
;
;
;
;
;
;Scratch Pad Memory Locations
;
;Values to be written to the D/A converter
;
;
CONSTANT chan_A_lsb, 00 ;Channel A value LS-Byte
CONSTANT chan_A_msb, 01 ; MS-Byte
;
CONSTANT chan_B_lsb, 02 ;Channel B value LS-Byte
CONSTANT chan_B_msb, 03 ; MS-Byte
;
CONSTANT chan_C_lsb, 04 ;Channel C value LS-Byte
CONSTANT chan_C_msb, 05 ; MS-Byte
;
CONSTANT chan_D_lsb, 06 ;Channel D value LS-Byte
CONSTANT chan_D_msb, 07 ; MS-Byte
;
;
;Value used to synthesise a triangle wave
;
CONSTANT triangle_up_down, 08 ;Determines up or down slope
;
;Value used to synthesise a square wave
;
CONSTANT square_count, 09 ;Counts samples in square wave
;
;
;Values used to synthesise a sine wave
;
CONSTANT sine_y_lsb, 10 ;Sine wave value LS-Byte
CONSTANT sine_y_msb, 11 ; MS-Byte
CONSTANT sine_y1_lsb, 12 ;Sine wave delayed LS-Byte
CONSTANT sine_y1_msb, 13 ; MS-Byte
CONSTANT sine_k_lsb, 14 ;Sine constant LS-Byte
CONSTANT sine_k_msb, 15 ; MS-Byte
;
;
;Sample counter used to give activity indication on LEDs
;
CONSTANT sample_count_lsb, 20 ;16-bit counter LS-Byte
CONSTANT sample_count_msb, 21 ; MS-Byte
;
;Initialise the system
;
;
cold_start: CALL SPI_init ;initialise SPI bus ports
CALL init_sine_wave ;initialise sine wave synthesis values
CALL delay_1s ;bus settling delay
LOAD s0, 00 ;clear all internal D/A values
STORE s0, chan_A_lsb
STORE s0, chan_A_msb
STORE s0, chan_B_lsb
STORE s0, chan_B_msb
STORE s0, chan_C_lsb
STORE s0, chan_C_msb
STORE s0, chan_D_lsb
STORE s0, chan_D_msb
STORE s0, triangle_up_down ;initial slope is up
CALL dac_reset ;reset D/A converter on all channels
ENABLE INTERRUPT ;Interrupts define 8KHz sample rate
;
;
;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
wait_int: COMPARE sF, FF
JUMP Z, wait_int ;interrupt clears the flag
;
;
;Channel A is a square wave of 2KHz.
;
;This is formed from the 2KHz square wave on channel C and demonstrates that the
;D/A converter echoes the previously sent 32-bit command word.
;
;Following the interrupt service routine (ISR), the register set [s9,s8,s7,s6]
;will contain the command which was last sent for the setting of channel C. The
;12-bit sample value is extracted from this word and stored in the location for
;channel A. This should mean that channel A is one sample behind channel C. In this
;version that does not mean a lag of 90 degrees because each output is updated
;sequentially and that takes approximatly 14.5us per channel.
;
;This will also demonstrate that the reference voltage on channels A and B is 3.3v
;compared with 2.5v on channels C and D. So whilst the square wave on channel C is
;set for 0.50v to 2.00v, it should be 0.66v to 2.64v on channel A.
;
SR0 s7 ; shift 12-bit value right 4 places
SRA s6
SR0 s7
SRA s6
SR0 s7
SRA s6
SR0 s7
SRA s6
STORE s7, chan_A_msb ;store value for D/A output
STORE s6, chan_A_lsb
;
;
;
;
;Channel B is a triangle waveform of 200Hz.
;
;Given the sample rate of 8KHz, there are 40 samples per waveform period.
;To achieve close to full scale deflection, the waveform needs to increase or
;decrease by 204 each sample so that over the first 20 samples it rises from
;0 to 4080 and then over the next 20 samples it reduces back to zero.
;
FETCH s0, chan_B_lsb ;load current value into [s1,s0]
FETCH s1, chan_B_msb
FETCH s2, triangle_up_down ;read current slope direction
COMPARE s2, 00 ;determine current direction
JUMP NZ, slope_down
ADD s0, CC ;add 204 (00CC hex) to current value
ADDCY s1, 00
COMPARE s1, 0F ;test for peak value of 4080 (0FF0 hex)
JUMP NZ, store_channel_B
COMPARE s0, F0
JUMP NZ, store_channel_B
LOAD s2, 01 ;change to slope down next time
STORE s2, triangle_up_down
JUMP store_channel_B
slope_down: SUB s0, CC ;subtract 204 (00CC hex) from current value
SUBCY s1, 00
COMPARE s1, 00 ;test for zero (0000 hex)
JUMP NZ, store_channel_B
COMPARE s0, 00
JUMP NZ, store_channel_B
LOAD s2, 00 ;change to slope up next time
STORE s2, triangle_up_down
store_channel_B: STORE s0, chan_B_lsb ;store value for D/A output
STORE s1, chan_B_msb
;
;
;Channel C is a square wave of 2KHz.
;
;Since the sample rate is 8KHz, this square wave is formed of two samples at a
;low level and two samples at a high level. This is used to demonstrate when the
;D/A converter output actually changes and how to determine the voltage levels.
;It is also used indirectly to form the signal for channel A.
;
;The low level voltage is 0.50v.
; The 12-bit value is therefore 4096 x 0.5 / 2.5 = 819 (333 hex)
;
;The high level voltage is 2.00v.
; The 12-bit value is therefore 4096 x 2.0 / 2.5 = 3277 (CCD hex)
;
;
FETCH s2, square_count ;read sample counter
TEST s2, 02 ;bit 1 has correct frequency
JUMP NZ, square_high
LOAD s1, 03 ;Set low level
LOAD s0, 33
JUMP store_channel_C
square_high: LOAD s1, 0C ;Set high level
LOAD s0, CD
store_channel_C: STORE s0, chan_C_lsb ;store value for D/A output
STORE s1, chan_C_msb
ADD s2, 01 ;increment sampel count
STORE s2, square_count ;store new sample count
;
;Sine wave for channel D
;
;A synthesis algorithm is used to generate a stable 770Hz sine wave
;which is one of the 8 tines used in DTMF telephone dialing.
;
CALL calc_next_sine
SR0 s9 ;reduce value to 12-bits
SRA s8
SR0 s9
SRA s8
SR0 s9
SRA s8
ADD s9, 08 ;Scale signed number to mid-rail of unsigned output
STORE s9, chan_D_msb ;store value for D/A output
STORE s8, chan_D_lsb
;
;
;Drive LEDs with simple binary count of the samples to indicate
;that the design is active.
;
FETCH s0, sample_count_lsb ;read sample counter
FETCH s1, sample_count_msb
ADD s0, 01 ;increment counter
ADDCY s1, 00
STORE s0, sample_count_lsb ;store new value
STORE s1, sample_count_msb
OUTPUT s1, LED_port ;upper bits are 31.25Hz and lower
;
JUMP warm_start ;wait for next interrupt
;
;**************************************************************************************
;Sine wave synthesis algorithm
;**************************************************************************************
;
;This example is set to generate 770Hz at a sample rate of 8KHz. 770Hz is one of
;the eight DTMF frequences. Please see design documentation for more details.
;
init_sine_wave: LOAD s0, 24 ;initial value 9216 (2400 hex)
STORE s0, sine_y_msb
LOAD s0, 00
STORE s0, sine_y_lsb
LOAD s0, 00 ;initial delayed value 0 (0000 hex)
STORE s0, sine_y1_msb
STORE s0, sine_y1_lsb
LOAD s0, D2 ;Coefficient for 770Hz is UFIX_16_15 value 53913/32768 = 1.64529
STORE s0, sine_k_msb
LOAD s0, 99
STORE s0, sine_k_lsb
RETURN
;
;
;Calculate a new output sample for a single tone.
;
;The tone sample is generated as a 16-bit signed integer.
;The waveform is virtually full scale deflection for a 15-bit integer
;such that the addition of two tones for DTMF will not exceed the 16-bits
;provided by two registers.
;
;Obtain current values from wscratch pad memory
;
calc_next_sine: FETCH sF, sine_y_msb ;[sF,sE] is Y
FETCH sE, sine_y_lsb
FETCH sD, sine_y1_msb ;[sD,sC] is Y1
FETCH sC, sine_y1_lsb
FETCH sB, sine_k_msb ;[sB,sA] is K
FETCH sA, sine_k_lsb
;
;16-bit signed by 16-bit unsigned multiplication. [s9,s8]=[sB,sA]x[sF,sE]
;
;The unsigned number is of format UFIX_16_15 resulting
;in a FIX_32_15 product. Since only the integer part of the
;product is to be retained as a 16-bit value, their is no
;shift of the result on the last cycle of the multiplication.
;Execution requires a maximum of 145 instructions.
;
LOAD s9, 00 ;clear temporary result registers [s9,s8]
LOAD s8, 00
LOAD s0, 10 ;16 bit multiply
mult_loop: SRX s9 ;signed divide result by 2
SRA s8
SR0 sB ;shift coefficient
SRA sA
JUMP NC, no_mult_add ;test for active bit
ADD s8, sE ;16-bit signed addition
ADDCY s9, sF
no_mult_add: SUB s0, 01 ;test for 16 cycles
JUMP NZ, mult_loop
;
;Subtract of delayed sample
;
SUB s8, sC ;16-bit signed subtract
SUBCY s9, sD
;
;Update scratch pad memory with new sample values
;
STORE sF, sine_y1_msb ;delayed sample gets previous output
STORE sE, sine_y1_lsb
STORE s9, sine_y_msb ;new current sample
STORE s8, sine_y_lsb
RETURN
;
;
;**************************************************************************************
;SPI communication routines for D/A Converter
;**************************************************************************************
;
;These routines will work with two output ports and one input port which should be
;defined as follows using CONSTANT directives.
; (replace 'pp' with appropriate port address in each case)
;In the list of CONSTANT directives, only the ones marked with a * are really required
;for the D/A Converter system. The other directives are to control (disable) or
;communicate with the other SPI components on the same SPI bus of the Spartan-3E Starter Kit.
;
;
;
;CONSTANT SPI_control_port, pp ;SPI clock and chip selects *
;CONSTANT SPI_sck, 01 ; SCK - bit0 *
;CONSTANT SPI_rom_cs, 02 ; serial rom select - bit1
;CONSTANT SPI_spare_control, 04 ; spare - bit2
;CONSTANT SPI_amp_cs, 08 ; amplifier select - bit3
;CONSTANT SPI_adc_conv, 10 ; A/D convert - bit4
;CONSTANT SPI_dac_cs, 20 ; D/A select - bit5 *
;CONSTANT SPI_amp_shdn, 40 ; amplifier SHDN - bit6
;CONSTANT SPI_dac_clr, 80 ; D/A clear - bit7 *
;
;CONSTANT SPI_output_port, pp ;SPI data output *
;CONSTANT SPI_sdo, 80 ; SDO - bit7 *
;
;CONSTANT SPI_input_port, pp ;SPI data input *
;CONSTANT SPI_sdi, 80 ; SDI - bit7 *
;CONSTANT SPI_amp_sdi, 40 ; amplifier SDI - bit6
;
;
;
;
;Initialise SPI bus
;
;This routine should be used to initialise the SPI bus.
;The SCK clock is made low.
;Device selections are made inactive as follows
; SPI_sck = 0 Clock is Low (required)
; SPI_rom_cs = 1 Deselect ROM
; spare = 1 spare control bit
; SPI_amp_cs = 1 Deselect amplifier
; SPI_adc_conv = 0 A/D convert ready to apply positive pulse
; SPI_dac_cs = 1 Deselect D/A
; SPI_amp_shdn = 0 Amplifier active and available
; SPI_dac_clr = 1 D/A clear off
;
SPI_init: LOAD s0, AE ;normally AE
OUTPUT s0, SPI_control_port
RETURN
;
;
;
;Send and receive one byte to and from the SPI D/A converter.
;
;The data supplied in register 's2' is transmitted to the SPI bus and
;at the same time the received byte is used to replace the value in 's2'.
;The SCK clock is generated by software and results in a communication rate of
;2.5Mbit/s with a 50MHz clock.
;
;Note that you must have previously selected the required device on the bus
;before attempting communication and you must subsequently deselect the device
;when appropriate.
;
;Entry to this routine assumes that register s0 defines the state of the SPI
;control signals including SCK which should be Low. The easiest way to achieve this is
;to use the SPI_init routine before calling this one for the first time.
;
;As a 'master' the signal sequence is as follows..
; Transmit data bit on SDO line
; Drive SCK transition from low to high
; Receive data bit from SDI line (D/A transmits on previous falling edge)
; Drive SCK transition from high to low.
;
;Important note
; The received data bit must be captured some time before SCK goes low.
; However the combination of relatively slow clock to output time of the
; LTC2624 combined with the low drive strength of its SDO output means that
; the received bit needs maximum time to settle. Therefore this routine
; schedules the read as late as it can.
;
SPI_dac_tx_rx: LOAD s1, 08 ;8-bits to transmit and receive
next_SPI_dac_bit: OUTPUT s2, SPI_output_port ;output data bit ready to be used on rising edge
XOR s0, SPI_sck ;clock High (bit0)
OUTPUT s0, SPI_control_port ;drive clock High
XOR s0, SPI_sck ;prepare clock Low (bit0)
INPUT s3, SPI_input_port ;read input bit
TEST s3, SPI_sdi ;detect state of received bit
SLA s2 ;shift new data into result and move to next transmit bit
OUTPUT s0, SPI_control_port ;drive clock Low
SUB s1, 01 ;count bits
JUMP NZ, next_SPI_dac_bit ;repeat until finished
RETURN
;
;
;
;Set a voltage on one of the LTC2624 D/A converter outputs
;
;The D/A converter has 4 channels. Specify which channel is to be set using
;register sC as follows....
; sC Channel Nominal Voltage Range
; 00 A 0 to 3.30v (or VREFAB)
; 01 B 0 to 3.30v (or VREFAB)
; 02 C 0 to 2.50v (or VREFCD)
; 03 D 0 to 2.50v (or VREFCD)
; 0F All channels various as above.
;
;The analogue level is a 12-bit value to be supplied in lower 12-bits of register
;pair [sB,sA]. If this value is called 'k' and is in the range 0 to 4095 (000 to FFF)
;then
; Vout = (k/4096) * VREFx
;Hence it is not possible to reach the absolute level of the reference.
;
;Here are some useful values..
; Voltage A or B C or D
; 0.0 000 000
; 0.5 26D 333
; 0.65 327 A/D reference -1.00v
; 1.0 4D9 666
; 1.5 746 99A
; 1.65 800 A8F converter reference = 3.3/2 = 1.65v
; 2.0 9B2 CCD
; 2.5 C1F FFF
; 2.65 CD9 A/D reference +1.00v
; 3.0 E8C n/a
; 3.3 FFF n/a
;
;Note that the full scale deflection of FFF will result in different output
;voltages due to different reference voltages for each pair of channels.
;
;SPI communication with the DAC only requires a 24-bit word to be transmitted.
;However, the device internally contains a 32-bit shift register. When writing
;a command word, the previous contents are shifted out and can be observed by
;the master (Spartan-3E in this case). If you do not use a 32-bit format, then
;the read back is confusing. Hence this routine uses a 32-bit format by transmitting
;a dummy byte first.
;
; Byte 1 = 00 8 dummy bits
; Byte 2 = 3c Command nibble (3=write and update) and channel selection
; Byte 3 = dd Upper 8-bits of the 12-bit voltage value
; Byte 4 = d0 lower 4-bits of the 12-bit voltage value and 4 dummy bits.
;
;At the end of this communication, the register set [s9,s8,s7,s6] will contain the
;data received back from the D/A converter which should be the previous command.
;
set_dac: CALL SPI_init ;ensure known state of bus and s0 register
XOR s0, SPI_dac_cs ;select low on D/A converter
OUTPUT s0, SPI_control_port
LOAD s2, 00 ;Write dummy byte to DAC
CALL SPI_dac_tx_rx
LOAD s9, s2 ;capture response
LOAD s2, sC ;Select channel for update
AND s2, 0F ;isolate channel bits to be certain of correct command
OR s2, 30 ;Use immediate Write and Update command is "0011"
CALL SPI_dac_tx_rx
LOAD s8, s2 ;capture response
SL0 sA ;data shift bits into correct position
SLA sB ;with 4 dummy bits ('0') in the least significant bits.
SL0 sA
SLA sB
SL0 sA
SLA sB
SL0 sA
SLA sB
LOAD s2, sB ;Write 12 bit value followed by 4 dummy bits
CALL SPI_dac_tx_rx
LOAD s7, s2 ;capture response
LOAD s2, sA
CALL SPI_dac_tx_rx
LOAD s6, s2 ;capture response
XOR s0, SPI_dac_cs ;deselect the D/A converter to execute
OUTPUT s0, SPI_control_port
RETURN
;
;Perform a hard reset of the D/A converter
;
dac_reset: CALL SPI_init ;ensure known state of bus and s0 register
XOR s0, SPI_dac_clr ;pulse the clear signal.
OUTPUT s0, SPI_control_port
XOR s0, SPI_dac_clr
OUTPUT s0, SPI_control_port
RETURN
;
;
;**************************************************************************************
;Software delay routines
;**************************************************************************************
;
;
;
;Delay of 1us.
;
;Constant value defines reflects the clock applied to KCPSM3. Every instruction
;executes in 2 clock cycles making the calculation highly predictable. The '6' in
;the following equation even allows for 'CALL delay_1us' instruction in the initiating code.
;
; delay_1us_constant = (clock_rate - 6)/4 Where 'clock_rate' is in MHz
;
;Registers used s0
;
delay_1us: LOAD s0, delay_1us_constant
wait_1us: SUB s0, 01
JUMP NZ, wait_1us
RETURN
;
;Delay of 40us.
;
;Registers used s0, s1
;
delay_40us: LOAD s1, 28 ;40 x 1us = 40us
wait_40us: CALL delay_1us
SUB s1, 01
JUMP NZ, wait_40us
RETURN
;
;
;Delay of 1ms.
;
;Registers used s0, s1, s2
;
delay_1ms: LOAD s2, 19 ;25 x 40us = 1ms
wait_1ms: CALL delay_40us
SUB s2, 01
JUMP NZ, wait_1ms
RETURN
;
;Delay of 20ms.
;
;Delay of 20ms used during initialisation.
;
;Registers used s0, s1, s2, s3
;
delay_20ms: LOAD s3, 14 ;20 x 1ms = 20ms
wait_20ms: CALL delay_1ms
SUB s3, 01
JUMP NZ, wait_20ms
RETURN
;
;Delay of approximately 1 second.
;
;Registers used s0, s1, s2, s3, s4
;
delay_1s: LOAD s4, 14 ;50 x 20ms = 1000ms
wait_1s: CALL delay_20ms
SUB s4, 01
JUMP NZ, wait_1s
RETURN
;
;
;
;**************************************************************************************
;Interrupt Service Routine (ISR)
;**************************************************************************************
;
;Interrupts occur at a rate of 8KHz.
;
;Each interrupt is the fundamental timing trigger used to set the sample rate and
;it is therefore use to set the D/A outputs by copying the values stored in
;scratch pad memory and outputting them to the D/A converter using the SPI bus.
;
;Because the SPI communication is in itself a predictable process, the sample rate
;is preserved without sample jitter. All variable activities are left to the main
;program.
;
;Each time PicoBlaze transmits a 32-bit command word to the D/A converter, the
;D/A responds with the last command it was sent. So as the end of this service routine
;the register set [s9,s8,s7,s6] will contain the command which has just been sent
;for the setting of channel C.
;
;Set channel A
;
ISR: LOAD sC, 00 ;channel A
FETCH sB, chan_A_msb ;12-bit value
FETCH sA, chan_A_lsb
CALL set_dac
;
;Set channel B
;
LOAD sC, 01 ;channel B
FETCH sB, chan_B_msb ;12-bit value
FETCH sA, chan_B_lsb
CALL set_dac
;
;Set channel C
;
LOAD sC, 02 ;channel C
FETCH sB, chan_C_msb ;12-bit value
FETCH sA, chan_C_lsb
CALL set_dac
;
;Set channel A
;
LOAD sC, 03 ;channel D
FETCH sB, chan_D_msb ;12-bit value
FETCH sA, chan_D_lsb
CALL set_dac
;
LOAD sF, 00 ;clear flag
RETURNI ENABLE
;
;
;**************************************************************************************
;Interrupt Vector
;**************************************************************************************
;
ADDRESS 3FF
JUMP ISR
;
;