;**** Sine wave DDS ;* ;* Title: DDS using external DAC ;* Version: 1.00 (demo, no calib., presets, mute) ;* Target: AT90S2313 .include "2313def.inc" .org 0x200 .include "sin4.asm" ;Sine wave table ;***** Constantes .equ TVal = 40 ;Time base 4.000 uS .equ Cal_0 = 180143985 ;Initial calibration value .equ Freq_0 = 100000 ;Initial frequency x 0.01 Hz .equ Fmax = 5000000 ;F max x0.01 Hz .equ Fmin = 100 ;F min x0.01 Hz .equ Pos_0 = 3 ;Initial edit position .equ T0Val = -98 ;x1024x0.0001=10mS program timer .equ KiniD = 80 ;x10mS Initial autorepeat delay .equ KrepD = 20 ;x10mS Autorepeat rate .equ DebVal = 3 ;x10mS Debounce delay .equ BliVal = 20 ;Blink delay (x blink period) ;Keys codes: .equ COD_NO =0 ;keys are released .equ COD_UP =1 ;key "UP" pressed .equ COD_DN =2 ;key "DOWN" pressed .equ COD_LF =4 ;key "LEFT" pressed .equ COD_RT =8 ;key "RIGHT" pressed ;LCD special symbols .equ Blank =0x00 ;Blank .equ Ch_P =0x0e ;Char "P" .equ Ch_F =0x0b ;Char "F" .equ Ch_min =0x0f ;Char "-" ;***** Variables .DSEG ;data segment (internal RAM) Dig: .byte 10 ;Display data (Digits 1..10, chars) .equ Dig0 =Dig+0 ;8--------- .equ Dig1 =Dig+1 ;-8-------- .equ Dig2 =Dig+2 ;--8------- .equ Dig3 =Dig+3 ;---8------ .equ Dig4 =Dig+4 ;----8----- .equ Dig5 =Dig+5 ;-----8---- .equ Dig6 =Dig+6 ;------8--- .equ Dig7 =Dig+7 ;-------8-- .equ Dig8 =Dig+8 ;--------8- .equ Dig9 =Dig+9 ;---------8 MulB: .byte 7 ;Multiply buffer COD: .byte 1 ;Keyboard last code ;Frequency calibration value (RAM copy) ;Freq = Fval x Calib / 16777216 ;Nominal Calib = 180143985 ;for Ttimer = 4.000 uS Cal: .byte 4 .equ CalibK =Cal+0 .equ CalibL =Cal+1 .equ CalibM =Cal+2 .equ CalibN =Cal+3 ;***** Global Register Variables .def temp0 =r0 ;Used in SUM (with lpm) .def tsreg =r1 ;Used in SUM .def PhaseK =r2 ;Phase code,used in SUM .def PhaseL =r3 .def PhaseM =r4 .def PhaseN =r5 .def FreqK =r6 ;Frequency code (delta Phase),used in SUM .def FreqL =r7 .def FreqM =r8 .def FreqN =r9 .def DebTM =r10 ;Debounce timer .def KeyTM =r11 ;Keyboard timer .def BliTM =r12 ;Blink timer .def tempA =r13 ;Temporary register tempA .def tempB =r14 ;Temporary register tempB .def tempC =r15 ;Temporary register tempC .def FvalK =r16 ;Frequency value (x 0.01 Hz) .def FvalL =r17 .def FvalM =r18 .def FLAGS =r19 .equ D_UPD =0 ;Display update flag .equ NewPr =1 ;Keyboard new press flag .equ Edit =2 ;Edit mode flag .equ Blnk =3 ;Digit blank flag .def temp =r20 ;Temporary register temp .def tempX =r21 ;Temporary register tempX .def Cnt =r22 ;Temporary register Cnt .def Cnt1 =r23 ;Temporary register Cnt1 .def Del =r24 ;Temporary register Del .def Pos =r25 ;Cursor position .def Tm_10 =r26 ;10ms timer .equ Blb =5 ;Blink bit ;r28,r29 used as Y-register ;r30,r31 used as Z-register in SUM ;***** Port Definitions .equ PB = PORTB ;Port B .equ DIRB = 0b11111111 ;Port B direction .equ PUPB = 0b00000000 ;Port B pull-ups .equ PD = PORTD ;Port D .equ DIRD = 0b01000011 ;Port D direction .equ PUPD = 0b00111100 ;Port D pull-ups .equ SD = PD0 ;Serial data .equ SC = PD1 ;Serial clock .equ K_RT = PD2 ;Key RIGHT .equ K_DN = PD3 ;Key DOWN .equ K_LF = PD4 ;Key LEFT .equ K_UP = PD5 ;Key UP .equ MSB = PD6 ;DAC MSB ;***** Macros .macro clbr ;clear bit in register cbr @0,exp2(@1) .endm .macro stbr ;set bit in register sbr @0,exp2(@1) .endm .macro bbrc ;branch if bit in register clear sbrs @0,@1 rjmp @2 .endm .macro bbrs ;branch if bit in register set sbrc @0,@1 rjmp @2 .endm .macro bbic ;branch if bit in I/O clear sbis @0,@1 rjmp @2 .endm .macro bbis ;branch if bit in I/O set sbic @0,@1 rjmp @2 .endm ;***** Interrupt Vectors .CSEG ;Code segment .org 0 rjmp INIT ;Reset Handle ;***** Timer1 output compare interrupt handle ;To minimize execution time handle is located ;just at vector address. It eliminates rjmp command. .org OC1addr SUM: in tsreg,SREG ;Save status register add PhaseK,FreqK ;Phase(0..31)=Phase(0..31)+Freq(0..31) adc PhaseL,FreqL adc PhaseM,FreqM adc PhaseN,FreqN mov ZL,PhaseM ;ZL <- Phase(16..23) mov ZH,PhaseN ;ZH <- Phase(24..31) sbrc PhaseN,2 com ZL ;ZL=!ZL if Phase.26==1 sbrc PhaseN,2 com ZH ;ZH=!ZH if Phase.26==1 andi ZH,0x03 ;Table address is 10 bit width ori ZH,0x04 ;Table base is 0x0400 (0x200*2) lpm ;r0 <- table[Z] sbrc PhaseN,3 rjmp ph_ab ;jump if Phase.27==1 ph_cd: com r0 ;r0=!r0 cbi PORTD,MSB ;To minimize glitch, clear DAC.9, out PORTB,r0 ;and then setup DAC.1 - DAC.8 out SREG,tsreg ;Restore status register reti ph_ab: out PORTB,r0 ;To minimize glitch, setup DAC.1 - DAC.8, sbi PORTD,MSB ;and then set DAC.9 out SREG,tsreg ;Restore status register reti ;***** Program Execution Starts Here INIT: ldi temp,RAMEND ;Locate stack out SPL,temp ldi temp,PUPB out PORTB,temp ;Init PORTB and on/off pullup ldi temp,DIRB out DDRB,temp ;Set PORTB direction ldi temp,PUPD out PORTD,temp ;Init PORTD and on/off pullup ldi temp,DIRD out DDRD,temp ;Set PORTD direction ;Variables init clr FLAGS ;Clear all flags ldi Pos,Pos_0 ;Initial cursor position ldi temp,COD_NO sts COD,temp clr BliTM ;Clear blink timer ;Periphery setup: ldi temp,0x00 out TCCR1A,temp ;OC disable, PWM disable out GIMSK,temp ldi temp,0x40 out TIFR,temp ;Clear pending timer interrupt out TIMSK,temp ;Enable output compare interrupt ldi temp,0x09 out TCCR1B,temp ;Clear on compare match, CK/1 ldi temp,high(TVal-1) ;Load compare register out OCR1AH,temp ldi temp,low(TVal-1) out OCR1AL,temp ldi temp,0x05 out TCCR0,temp ;CK/1024 ;Initial delay 2S ldi Cnt,133 DE3: ldi tempX,250 DE2: ldi temp,200 DE1: dec temp ;1 brne DE1 ;2 dec tempX brne DE2 dec Cnt brne DE3 ;Load calibratin value ldi temp,Low(Cal_0) sts CalibK,temp ldi temp,High(Cal_0) sts CalibL,temp ldi temp,Byte3(Cal_0) sts CalibM,temp ldi temp,Byte4(Cal_0) sts CalibN,temp ;Load initial frequency value ldi temp,Low(Freq_0) mov FvalK,temp ldi temp,High(Freq_0) mov FvalL,temp ldi temp,Byte3(Freq_0) mov FvalM,temp ;Init internal variables rcall MakeF ;Calculate Freq rcall F2BCD ;Convert Fval to BCD stbr FLAGS,D_UPD ;Set display update flag sei ;Enble global interrupt ;Main loop MAIN: rcall SCAN ;Scan keyboard lds tempX,COD cp tempX,temp ;Compare codes breq Same sts COD,temp ;New code, save it ldi temp,DebVal mov DebTM,temp ;Load debounce timer stbr FLAGS,NewPr ;Set new press flag rjmp MA10 Same: mov tempX,temp tst DebTM ;Check debounce timer brne MA10 ;Jump if no overflow bbrc FLAGS,NewPr,Re ;NewPr=0, jump to repeat action ldi temp,KiniD ;Load initial autorepeat delay mov KeyTM,temp ;Load key timer rjmp COD0 ;Function processing Re: tst KeyTM ;Check key timer brne MA10 ;Skip processing ldi temp,KrepD mov KeyTM,temp ;Reload key timer with autorepeat delay ;Control Functions Analysis and Processing COD0: cpi tempX,COD_UP ;key UP brne COD1 rcall KEY_UP COD1: cpi tempX,COD_DN ;key DN brne COD2 rcall KEY_DN COD2: cpi tempX,COD_LF ;key LEFT brne COD3 rcall KEY_LF COD3: cpi tempX,COD_RT ;key RIGHT brne COD4 rcall KEY_RT COD4: clbr FLAGS,NewPr ;Clear new press flag ;Timer check MA10: in temp,TIFR bbrc temp,TOV0,MA50 andi temp,exp2(TOV0) out TIFR,temp ;Timer 0 overflow flag clear ldi temp,T0Val out TCNT0,temp ;Timer 0 reload inc Tm_10 ;Advance 10 ms timer tst DebTM ;Advance debounce timer breq MA41 dec DebTM MA41: tst KeyTM ;Advance key timer breq MA50 dec KeyTM ;Check blink timer MA50: bbrc FLAGS,Edit,MA60 ;Skip if not edit mode tst BliTM brne MA60 ;Skip if no overflow clbr FLAGS,Edit ;Clear edit flag stbr FLAGS,D_UPD ;Set display update flag ;Update LCD MA60: rcall LCD ;Update LCD rjmp MAIN ;Main loop ;***** Subroutines Area ;===== Key UP processing KEY_UP: bbrs FLAGS,Edit,UP_F ;Frequency step up rjmp E_Ent ;Frequency step up UP_F: rcall Z_Pos ;Zero lower digits rcall BCD_I ;Inc BCD value rcall BCD2F ;BCD -> Fval rcall Valid ;Validate Fval brtc UP_OK rcall F2BCD ;Correct BCD value UP_OK: rcall MakeF ;Calculate Freq rjmp E_Ent ;===== Key DOWN processing KEY_DN: bbrs FLAGS,Edit,DN_F ;Frequency step up rjmp E_Ent ;Frequency step down DN_F: rcall Z_Pos ;Zero lower digits brts No_d rcall BCD_D ;Dec BCD value No_d: rcall BCD2F ;BCD -> Fval rcall Valid ;Validate Fval brtc DN_OK rcall F2BCD ;Correct BCD value DN_OK: rcall MakeF ;Calculate Freq rjmp E_Ent ;===== Key LEFT processing KEY_LF: bbrs FLAGS,Edit,LF_F ;Position left rjmp E_Ent ;Position left LF_F: cpi Pos,7 breq E_Ent inc Pos ;Pos + 1 rjmp E_Ent ;===== Key RIGHT processing KEY_RT: bbrs FLAGS,Edit,RT_F ;Position right rjmp E_Ent ;Position right RT_F: cpi Pos,1 breq E_Ent dec Pos ;Pos - 1 rjmp E_Ent ;Enter to edit mode E_Ent: stbr FLAGS,Edit ;Set edit flag stbr FLAGS,D_UPD ;Set display update flag ldi temp,BliVal mov BliTM,temp ;Blink timer reload clr Tm_10 ;Clear 10 ms timer (on blinking digit) ret ;Zero positions at right of cursor ;Input: Pos ;Out: [Dig...] = 0 ;Out: T=0 if no action performed Z_Pos: mov Cnt,Pos clt ;Clear T flag Z_loop: dec Cnt breq Z_done ldi YH,high(Dig+10) ;Calculate pointer ldi YL,low(Dig+10) sub YL,Cnt sbci YH,0 ld temp,Y tst temp breq Z_loop clr temp st Y,temp set ;Set T flag rjmp Z_loop Z_done: ret ;BCD buffer inc ;Input: Pos ;Out: [Dig+3]..[Dig+9] BCD_I: ldi Cnt,8 sub Cnt,Pos ;Pos = 7..1 -> Cnt = 1..7 -> [Dig+3]..[Dig+9] I_loop: rcall LD_Dig inc temp cpi temp,10 brne I_done clr temp st Y,temp dec Cnt brne I_loop I_done: st Y,temp ret ;BCD buffer dec ;Input: Pos ;Out: [Dig+3]..[Dig+9] BCD_D: ldi Cnt,8 sub Cnt,Pos ;Pos = 7..1 -> Cnt = 1..7 -> [Dig+3]..[Dig+9] D_loop: rcall LD_Dig dec temp cpi temp,-1 brne D_done ldi temp,9 st Y,temp dec Cnt brne D_loop D_done: st Y,temp ret ;Load [Dig..] to temp LD_Dig: clr temp ldi YH,high(Dig+2) ;Calculate pointer ldi YL,low(Dig+2) add YL,Cnt adc YH,temp ld temp,Y ;Load digit from buffer ret ;Converts BCD to frequency value ;Input: [Dig+3]..[Dig+9] - BCD ;Out: FvalK,FvalL,FvalM BCD2F: ldi YH,high(Dig+3) ;Load pointer ldi YL,low(Dig+3) ld FvalK,Y+ clr FvalL clr FvalM ldi Cnt,6 DoConv: ld temp,Y+ rcall mul10 dec Cnt brne DoConv ret ;multiplies FvalK,FvalL,FvalM with 10 and adds temp mul10: mov tempA,FvalK ;make copy mov tempB,FvalL mov tempC,FvalM lsl FvalK ;multiply original by 2 rol FvalL rol FvalM rcall Rl_ABC ;multiply copy by 2 rcall Rl_ABC ;multiply copy by 2 (4) rcall Rl_ABC ;multiply copy by 2 (8) add FvalK,tempA ;add copy to original adc FvalL,tempB adc FvalM,tempC add FvalK,temp ;add temp ldi temp,0 adc FvalL,temp adc FvalM,temp ret Rl_ABC: lsl tempA ;multiply copy by 2 rol tempB rol tempC ret ;Fval validate ;If Fval>Fmax then Fval=Fmax ;If Fval [MulB+0]..[MulB+2] ;m - [MulB+0]..[MulB+6] MakeF: push tempX ldi YH,High(MulB) ldi YL,Low(MulB) ldi Cnt,7 clr temp ClrM: st Y+,temp ;Clear m dec Cnt brne ClrM ldi Cnt,24 ;Load cycle counter mov temp,FvalM lsr temp sts MulB+2,temp ;Init mp mov temp,FvalL ror temp sts MulB+1,temp mov temp,FvalK ror temp sts MulB+0,temp M24_32: brcc NoAdd ldi YH,High(MulB+3) ldi YL,Low(MulB+3) ld temp,Y lds tempX,CalibK add temp,tempX st Y+,temp ld temp,Y lds tempX,CalibL adc temp,tempX st Y+,temp ld temp,Y lds tempX,CalibM adc temp,tempX st Y+,temp ld temp,Y lds tempX,CalibN adc temp,tempX st Y+,temp NoAdd: ldi YH,High(MulB+7) ldi YL,Low(MulB+7) ldi Cnt1,7 RRY: ld temp,-Y ror temp st Y,temp dec Cnt1 brne RRY dec Cnt brne M24_32 ;FreqK,L,M,N = [MulB+3]..[MulB+6] + 0.5 ldi YH,High(MulB+2) ldi YL,Low(MulB+2) ldi Cnt,0x80 ld temp,Y+ add temp,Cnt clr Cnt cli ;Interrupts disable ld FreqK,Y+ adc FreqK,Cnt ld FreqL,Y+ adc FreqL,Cnt ld FreqM,Y+ adc FreqM,Cnt ld FreqN,Y+ adc FreqN,Cnt sei ;Interrupts enable pop tempX ret ;Loads 10 chars from RAM buffer (Dig) to LCD controller LCD: bbrc FLAGS,Edit,LCDa ;Jump to display if not edit mode cpi tempX,COD_NO brne LCDa ;Jump to display if key pressed bbrc Tm_10,Blb,Dblf ;Check bit Blb of 10 ms timer bbrs FLAGS,Blnk,Lre ;Blb = 1, off blinking digit stbr FLAGS,Blnk ;Set blank flag tst BliTM ;Advance blink timer breq LCD0 dec BliTM rjmp LCD0 Dblf: bbrc FLAGS,Blnk,Lre ;Blb = 0, on blinking digit clbr FLAGS,Blnk ;Clear blank flag rjmp LCD0 LCDa: clbr FLAGS,Blnk ;Blinking not used, clear blank flag bbrc FLAGS,D_UPD,Lre ;Check update flag LCD0: ldi Cnt,10 ;Load digits counter ldi YH,high(Dig) ;Load pointer ldi YL,low(Dig) clt LCD1: ld temp,Y+ ;Load char bbrc FLAGS,Edit,LCD4 ;Skip if not edit mode cp Cnt,Pos ;Check position brne LCD4 ;Edit position not match set bbrc FLAGS,Blnk,LCD4 ;Skip if digit must be on clr temp ;Load blank code rjmp LCD3 ;Jump to display LCD4: tst temp ;Check char for zero brne LCD2 ;non-zero char brtc LCD3 ;skip if leading zero ldi temp,10 ;non-leading zero, load "0" code LCD2: set ;set non-zero char flag LCD3: rcall LCDLD ;Load LCD controller dec Cnt ;Next digit brne LCD1 clbr FLAGS,D_UPD ;Clear display update flag Lre: ret ;Loads char from temp to LCD controller LCDLD: push Cnt ldi Cnt,4 swap temp LDL: rol temp brcs LD1 LD0: cbi PORTD,SD rjmp STR LD1: sbi PORTD,SD STR: sbi PORTD,SC ldi Del,5 HNG1: dec Del brne HNG1 cbi PORTD,SC ldi Del,10 HNG2: dec Del brne HNG2 dec Cnt brne LDL ldi Del,25 HNG3: dec Del brne HNG3 cbi PORTD,SD pop Cnt ret ;Local keyboard scan ;Out: temp - scan code ; SCAN: clr temp sbis PIND,K_UP stbr temp,0 sbis PIND,K_DN stbr temp,1 sbis PIND,K_LF stbr temp,2 sbis PIND,K_RT stbr temp,3 ret