mirror of
https://github.com/pConst/basic_verilog.git
synced 2025-01-28 07:02:55 +08:00
665 lines
35 KiB
Plaintext
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
|
|
;
|
|
;
|