;+---------------------------------------------------------------------------------+ ; ; dds.asm Program for Software-DDS with AT90S1200 ; ; Version 1.0 ; ; fq = 13 MHz ; ; Historie: 18.08.2001 Start of Development ; 19.08.2001 Hardmeasurement shows that VCXO middle ; frequency is 10,0033 MHz -> Adder adjusted ; 10MHz VCXO locks perfectly after adjustment ; 15.09.2001 remote control from master CPU with 3wirebus ; implementation started (ext. interrupt based) ; status LED on PD5 introduced ; 20.09.2001 First tests on adder-changing with ; interrupt service routine successful ; 21.09.2001 Data download algorithm in isr implemented ; 23.09.2001 Bug fixed: LSL in isr was after bit reading ; and is no moved before reading ; Extensive testing -> adder download from ; from master processor works perfectly ; Version 1.0 released ; ;+---------------------------------------------------------------------------------+ ; Remote control via 3wire bus - Description: ; The master sends a positive pulse to INT0 which triggers the external interrupt. ; This stops the main loop and the slave (which is running this software) awaits ; the adder data. Each bit is put to the data pin, then a positive pulse on the ; clock pin orders the slave to take over that bit. After all bits have been received ; (the slave simply counts the number of clock pulses), the interrupt service routine ; is left automatically and the DDS starts to run the new values. ; (add3 and add2 are fix for the full operating range are are not send from the master; ; add1 is loaded first, then add0, each with the MSB first, LSB last) ; Hardware is a AT90S1200 running on 5Volts Vcc with 13MHz clock frequeny .include "1200def.inc" ; This is the 4Byte accu which is holding the 'phase-information' .def accu0 = r16 .def accu1 = r17 .def accu2 = r18 .def accu3 = r19 ; This is the adder. At every main loop cycle this value is added ; to the 4Byte accu (see above) .def add0 = r20 .def add1 = r21 .def add2 = r22 .def add3 = r23 ; The dummy register is used for all kind of procedures which require a ; temporary variable to shift some data through etc. .def dummy = r24 ; For counting the bits in the data transfer algorithm .def counter = r25 ; Another dummy register from the the lower 16 registers. Has limited ; usage by commands, e.g. ldi does not work with this .def lrdummy = r1 .equ twb_clock = 0b00000010 ; 3wirebus (PORTD) Bit1 is the clock signal .equ twb_data = 0b00000001 ; 3wirebus (PORTD) Bit0 is the data signal .equ led = 0b00100000 ; status LED bit on PORTD ;------------------- all definitions done, lets go ----------------------- ; This software used interrupts, so the interrupt service routines ; must be listed at the fix interrupt vectors 0x0000 to 0x0003 rjmp reset ; 0x0000 interrupt vector for a reset rjmp ext_int0 ; 0x0001 interrupt vector for the external interrupt reti ; 0x0002 interrupt vector for Timer 0 overflow (not used) reti ; 0x0003 interrupt vector for Analog Comparator (not used) ;--------------------------- main loop ----------------------------------- loop: add accu0, add0 ; add 4Byte adder to 4Byte accu adc accu1, add1 adc accu2, add2 adc accu3, add3 out PORTB, accu3 ; send highest Byte of accu to Port B rjmp loop ; next loop ;------------ end of main loop, subroutines from here on ----------------- ;++++++++++++++++++++++++++ reset handling routine +++++++++++++++++++++++ reset: ;set Port B, MSB as output for the DDS signal ;(other Port B pins are not connected anyhow) ldi dummy, 0b10000000 out DDRB, dummy ;set Port D pins for input/output ;PD0 data input ;PD1 clock input ;PD2 int0 input ;PD3 NC input ;PD4 NC input ;PD5 LED output ;PD6 NC input ;PD7 does not exist ldi dummy, 0b00100000 out DDRD, dummy ;clear acuu to start at zero clr accu0 clr accu1 clr accu2 clr accu3 ;to have a default startfrequency that is within the pulling range ;of the VCXO we preset the adder with a valid value ;setup adder registers for an output frequency of 10MHz/256 = 39,0625kHz ;main loop has 7 cycles -> mainloop frequency is 1,857 MHz (fq=13MHz) ;=> max. DDS output frequency is 928,571 kHz ;for 10MHz VCXO frequency without shift the ;adder value for 39,0625kHz is 39,0625kHz * 2^31/928,571kHz = 90338897 ;in Hex: 05 62 76 51 ;for 10MHz + 117ppm (which is the max. necessary shift that occurs when ;a 850MHz carrier shall be shifted for 100kHz) the adder value is ;90349520, in Hex: 05 62 9F D0 ;=>for all cases add3 and add2 are always 05 and 62 hex respectively ;only add1 and add0 ldi add0, 0x51 ;preset the variable adder bytes ldi add1, 0x76 ;add0 and add1 for zero frequency shift ldi add2, 0x62 ;set the fixed adder bytes add2 and add3 ldi add3, 0x05 ldi dummy, 0b01000000 ;switch on the external interrupt out GIMSK, dummy ldi dummy, 0b00000011 ;set the external interrupt to positive edge sensitive out MCUCR, dummy ldi dummy, 0x80 ;global interrupt enable (from now on interrupts can happen out SREG, dummy ;if the specific interrupt is switched on) rjmp loop ;now lets go to the main loop and start the DDS-work ;++++++++++++++++++ ext. interrupt service routine +++++++++++++++++++++++ ; this subroutine is triggered by a high-level on PD2 (int0) ; it reads two times 8 bit as the new adder value (first add1 then add0) ; the serial bitstream for both byts starts with the MSB and ends with the LSB ext_int0: clr add1 ;start with 0 as new value ldi counter, 8 ;prepare for reading of 8 bits byte_one: lsl add1 ;shift the value one bit left rcall wait_clk ;wait for a full clock pulse in dummy, PIND ;read from Port D andi dummy, twb_data ;mask out the data bit or add1, dummy ;add the read bit to the new value dec counter ;decrease the counter brne byte_one ; and go up to read next bit if not zero clr add0 ;same procedure again for the adder byte zero ldi counter, 8 byte_zero: lsl add0 rcall wait_clk in dummy, PIND andi dummy, twb_data or add0, dummy dec counter brne byte_zero ;cpi add0, 0x90 ; for debugging -> check if data is received correctly ;brne isr_end ; by comparing it with a fixed value and sending this value from master ;ldi dummy, led ;switch on status LED if condition was true ;out PORTD, dummy isr_end: reti ;return to DDS loop ;(also enables again the global interrupt) ;++++++++++++++++++ wait for a full clock pulse ++++++++++++++++++++++++ wait_clk: wait_clk_high: in dummy, PIND ;read the PORTD andi dummy, twb_clock ;check for the clock-bit breq wait_clk_high ;repeat loop until clock-bit is high wait_clk_low: in dummy, PIND ;read the PORTD andi dummy, twb_clock ;check for the clock-bit brne wait_clk_low ;repeat loop until clock-bit is low ret ;return to calling routine