;9850.asm .device AT90S2313 ;***** I/O Register Definitions .equ SREG =$3f .equ SPH =$3e .equ SPL =$3d .equ GIMSK =$3b .equ GIFR =$3a .equ TIMSK =$39 .equ TIFR =$38 .equ MCUCR =$35 .equ TCCR0 =$33 .equ TCNT0 =$32 .equ TCCR1A =$2f .equ TCCR1B =$2e .equ TCNT1H =$2d .equ TCNT1L =$2c .equ OCR1AH =$2b .equ OCR1AL =$2a .equ ICR1H =$25 .equ ICR1L =$24 .equ WDTCR =$21 .equ EEAR =$1e .equ EEARL =$1e .equ EEDR =$1d .equ EECR =$1c .equ PORTB =$18 .equ DDRB =$17 .equ PINB =$16 .equ PORTD =$12 .equ DDRD =$11 .equ PIND =$10 .equ UDR =$0c .equ USR =$0b .equ UCR =$0a .equ UBRR =$09 .equ ACSR =$08 ;***** Bit Definitions .equ SP7 =7 .equ SP6 =6 .equ SP5 =5 .equ SP4 =4 .equ SP3 =3 .equ SP2 =2 .equ SP1 =1 .equ SP0 =0 .equ INT1 =$80 .equ INT0 =$40 .equ INTF1 =7 .equ INTF0 =6 .equ TOIE1 =7 .equ OCIE1A =6 .equ TICIE =3 .equ TOIE0 =1 .equ TOV1 =7 .equ OCF1A =6 .equ ICF1 =3 .equ TOV0 =1 .equ SE =32 .equ SM =16 .equ ISC11 =8 .equ ISC10 =4 .equ ISC01 =2 .equ ISC00 =1 .equ CS02 =2 .equ CS01 =1 .equ CS00 =0 .equ COM1A1 =7 .equ COM1A0 =6 .equ PWM11 =1 .equ PWM10 =0 .equ ICNC1 =7 .equ ICES1 =6 .equ CTC1 =3 .equ CS12 =2 .equ CS11 =1 .equ CS10 =0 .equ WDTOE =4 .equ WDE =3 .equ WDP2 =2 .equ WDP1 =1 .equ WDP0 =0 .equ EEMWE =2 .equ EEWE =1 .equ EERE =0 .equ PB7 =7 .equ PB6 =6 .equ PB5 =5 .equ PB4 =4 .equ PB3 =3 .equ PB2 =2 .equ PB1 =1 .equ PB0 =0 .equ DDB7 =7 .equ DDB6 =6 .equ DDB5 =5 .equ DDB4 =4 .equ DDB3 =3 .equ DDB2 =2 .equ DDB1 =1 .equ DDB0 =0 .equ PINB7 =7 .equ PINB6 =6 .equ PINB5 =5 .equ PINB4 =4 .equ PINB3 =3 .equ PINB2 =2 .equ PINB1 =1 .equ PINB0 =0 .equ PD6 =6 .equ PD5 =5 .equ PD4 =4 .equ PD3 =3 .equ PD2 =2 .equ PD1 =1 .equ PD0 =0 .equ DDD6 =6 .equ DDD5 =5 .equ DDD4 =4 .equ DDD3 =3 .equ DDD2 =2 .equ DDD1 =1 .equ DDD0 =0 .equ PIND6 =6 .equ PIND5 =5 .equ PIND4 =4 .equ PIND3 =3 .equ PIND2 =2 .equ PIND1 =1 .equ PIND0 =0 .equ RXC =7 .equ TXC =6 .equ UDRE =5 .equ FE =4 .equ OR =3 .equ RXCIE =7 .equ TXCIE =6 .equ UDRIE =5 .equ RXEN =4 .equ TXEN =3 .equ CHR9 =2 .equ RXB8 =1 .equ TXB8 =0 .equ ACD =7 .equ ACO =5 .equ ACI =4 .equ ACIE =3 .equ ACIC =2 .equ ACIS1 =1 .equ ACIS0 =0 .equ RAMEND =$DF ;Last On-Chip SRAM Location .equ XRAMEND =$DF .equ E2END =$7F .equ FLASHEND=$3FF .equ INT0addr=$001 ;External Interrupt0 Vector Address .equ INT1addr=$002 ;External Interrupt1 Vector Address .equ ICP1addr=$003 ;Input Capture1 Interrupt Vector Address .equ OC1addr =$004 ;Output Compare1 Interrupt Vector Address .equ OVF1addr=$005 ;Overflow1 Interrupt Vector Address .equ OVF0addr=$006 ;Overflow0 Interrupt Vector Address .equ URXCaddr=$007 ;UART Receive Complete Interrupt Vector Address .equ UDREaddr=$008 ;UART Data Register Empty Interrupt Vector Address .equ UTXCaddr=$009 ;UART Transmit Complete Interrupt Vector Address .equ ACIaddr =$00a ;Analog Comparator Interrupt Vector Address .equ PORTLCD = PORTB .equ DDRLCD = DDRB .equ PINLCD = PINB .equ DDSport = PORTB .equ DDSenable = PB6 .equ DDSclock = PB7 .equ DDSdata = PB5 .equ LEDUP =PD6 .equ LEDDN =PD5 .equ PHASE =PD4 .equ STATE =PD2 ;Define register name ; r0 is used by Z-registor .def temp1 =r16 .def temp2 =r17 .def temp3 =r18 .def temp4 =r19 .def temp5 =r20 .def StepRate =r21 .def LCDPOINTER=r22 .def press =r23 .def delay =r24 .def encoder =r25 .def XL =r26 .def XH =r27 .def YL =r28 .def YH =r29 .def ZL =r30 .def ZH =r31 .dseg .org $060 LCDrcve0: .byte 8 ; buffer for decimal freq readout rcve0: .byte 4 ; buffer for DDS freq numbers freq0: .byte 4 ; buffer for 1 freq numbers freq1: .byte 4 ; buffer for 10 freq numbers freq2: .byte 4 ; buffer for 100 freq numbers freq3: .byte 4 ; buffer for 1,000 freq numbers freq4: .byte 4 ; buffer for 10,000 freq numbers freq5: .byte 4 ; buffer for 100,000 freq numbers freq6: .byte 4 ; buffer for 1,000,000 freq numbers freq7: .byte 4 ; buffer for 10,000,000 freq numbers .cseg ;This tells the assembler that what follows is code, and goes in ROMspace .org $000 rjmp RESET rjmp EXT_INT0 ; IRQ0 rjmp EXT_INT1 ; IRQ1 rjmp TIM1_CAPT ; Timer1 Capture rjmp TIM1_COMP ; Timer1 Compare rjmp TIM1_OVF ; Timer1 Overflow rjmp TIM0_OVF ; Timer0 Overflow rjmp UART_RXC ; UART Receive rjmp UART_DRE ; UART empty rjmp UART_TXC ; UART Transmit rjmp ANA_COMP ; Analog comparator RESET: ;init everything here ldi temp1,low(RAMEND) out SPL,temp1 ; Set stack pointer to last internal RAM location ldi temp1,high(RAMEND) out SPH,temp1 ldi temp1,$61 out DDRD,temp1 ;make PD0, PD5 and PD6 pin an output ldi temp1,$FE ;set pullup resistors out PORTD,temp1 ;turn off leds ldi temp1,$E0 ;portb setup out DDRB,temp1 ;PB7, PB6, PB5 used for DDS ldi temp1,$1F out DDSport,temp1 ;PB4,3,2,1 and 0 use pullups ldi StepRate,1 ;set to the 10's position clr encoder ;clear encoder interrupt counts clr press ;clear press interrupt counts ldi temp1,0b00000101 ;set timer0 prescale divisor to 1024 out TCCR0,temp1 ;using 10.24 XTAL you get 10,000 Hz/100uS ldi temp1,0b00000010 out TIMSK,temp1 ;enable TIMER0 overflow interrupts ldi temp1,INT0+INT1 out GIMSK,temp1 ; enable int0 and int1 interrupts ldi temp1,ISC01+ISC00+ISC11 ; int0 on rising edge and int1 on falling edge sbic PIND,STATE ; test state of encoder ldi temp1,ISC01+ISC11 ; int0 on falling edge and int1 on falling edge out MCUCR,temp1 rcall default_freq1 ;move default freq to buffers rcall FreqOut ;set DDS and LCD sei ;global all interrupt enable rcall initlcd rcall lcdclear ldi ZH,high(2*msg1) ldi ZL,low(2*msg1) rcall ShowLine1 ;rcall ShowStepRate rcall ShowFreq menu: ;main program tst encoder ;check for encoder pulses breq menu5 ;exitif no pulses brpl menu1 ;branch if positive cbi PORTD,LEDDN ;turn DN LED on inc encoder rcall DecFreq0 cpi temp1,55 ; if 55 then all is OK brne menu05 rcall IncFreq0 ;correct overflow rjmp menu2 menu05: rcall DecFreq9 ;update the DDS rcall FreqOut rcall ShowFreq rjmp menu2 menu1: cbi PORTD,LEDUP ;turn UP LED on dec encoder rcall IncFreq0 cpi temp1,55 ; if 55 then all is OK brne menu15 rcall DecFreq0 ;correct overflow rjmp menu2 menu15: rcall IncFreq9 ;update the DDS rcall FreqOut rcall ShowFreq menu2: ldi delay,20 rcall wait sbi PORTD,LEDUP ;turn LEDs off sbi PORTD,LEDDN ;turn LEDs off ldi delay,20 rcall wait menu5: tst press breq menu9 dec press in temp1,PIND ; look for reverse StepRate ldi temp2,2 and temp1,temp2 cpi temp1,2 breq menu55 inc StepRate cpi StepRate,8 brne menu6 ldi StepRate,0 rjmp menu6 menu55: dec StepRate brpl menu6 ldi StepRate,7 rjmp menu6 menu6: ;rcall ShowStepRate rcall ShowCursor cbi PORTD,LEDUP ;turn UP LED on cbi PORTD,LEDDN ;turn DN LED on ldi delay,20 rcall wait sbi PORTD,LEDUP ;turn LEDs off sbi PORTD,LEDDN ;turn LEDs off rcall wait menu9: rjmp menu initlcd: ldi temp1,0 out PORTLCD,temp1 ;turn off any pullup resistors ldi temp1,$FF out DDRLCD, temp1 ;set LCD port for output ldi delay,14 ;wait at least 15ms after Vcc=4.5V rcall wait ldi temp1,3 ;function set out PORTLCD,temp1 rcall toggleE ldi delay,10 ;wait 10 ms rcall wait ldi temp1,3 ;function set out PORTLCD,temp1 rcall toggleE ldi delay,10 ;wait 10 ms rcall wait ldi temp1,3 ;function set out PORTLCD,temp1 rcall toggleE ldi temp1,2 ;function set, 4 line interface out PORTLCD,temp1 rcall toggleE ldi temp1,$F0 ;make 4 data lines inputs out DDRLCD,temp1 ldi temp1,$28 ;function set 4-wire, 2-line, 5x7 rcall lcdcmd ;ldi temp1,$0C ;display on, cursor off, blink off ldi temp1,$0E ;display on, cursor on, blink off ;ldi temp1,$0D ;display on, cursor off, blink on rcall lcdcmd ldi temp1,$06 ;address inc, no scroll rcall lcdcmd rcall lcdclear ret lcdwait: ;wait for lcd not busy push temp1 push temp2 ldi temp1,$F0 ;make 4 data lines input out PORTLCD,temp1 sbi PORTLCD,PB5 ;set r/w to read cbi PORTLCD,PB6 ;set register select to command nop ;wait for data setup time nop ;delay 140 ns waitloop: sbi PORTLCD,PB4 ;set E high nop ;delay 450 ns nop nop nop nop cbi PORTLCD,PB4 ;set E low in temp2,PINLCD ;read busy flag rcall toggleE sbrc temp2,3 ;loop until done rjmp waitloop pop temp2 pop temp1 ret lcdcmd: ;send cmd in temp1 rcall lcdcmd2 lcdcmd2: mov temp2,temp1 rcall lcdwait ldi temp1,$FF out DDRLCD,temp1 ;set LCD port for output mov temp1,temp2 swap temp1 andi temp1,$0F out PORTLCD,temp1 rcall toggleE mov temp1,temp2 andi temp1,$0F ;strip off upper bits out PORTLCD,temp1 rcall toggleE ldi temp1,$F0 ;make 4 data lines input out DDRLCD,temp1 mov temp1,temp2 ret lcdput: push temp1 push temp2 cpi temp1,$0A brsh lcdput2 ldi temp2,$30 add temp1,temp2 lcdput2: mov temp2,temp1 rcall lcdwait ldi temp1,$FF out DDRLCD,temp1 ;set LCD port for output mov temp1,temp2 mov temp2,temp1 swap temp1 andi temp1,$0F ;send upper nibble data out PORTLCD,temp1 ;send data to LCD sbi PORTLCD,PB6 ;set register select to data rcall toggleE cbi PORTLCD,PB6 ;set register select to data mov temp1,temp2 andi temp1,$0F ;send lower nibble data out PORTLCD,temp1 ;send data to LCD sbi PORTLCD,PB6 ;set register select to data rcall toggleE cbi PORTLCD,PB6 ;set register select to data ldi temp1,$F0 ;make 4 data lines input out DDRLCD,temp1 pop temp2 pop temp1 ret toggleE: nop ;wait for data setup time nop ;delay 140 ns sbi PORTLCD,PB4 ;set E high nop ;delay 450 ns nop nop nop nop cbi PORTLCD,PB4 ;set E low ret lcdclear: ldi temp1,1 rcall lcdcmd ret lcdhome: ldi temp1,2 rcall lcdcmd ret ShowLine1: ldi temp1,$80 rcall lcdcmd rcall loadbytes ret loadbytes: lpm tst r0 breq bytesloaded mov temp1,r0 rcall lcdput adiw ZL,1 rjmp loadbytes bytesloaded: ret ShowStepRate: ldi temp1,$8F rcall lcdcmd mov temp1,StepRate rcall lcdput ret IncFreq0: mov temp2,StepRate ldi ZH,high(rcve0) ldi ZL,low(rcve0) ldi temp1,9 IncFreq1: dec temp1 dec ZL dec temp2 brpl IncFreq1 IncFreq2: ld temp3,Z inc temp3 cpi temp3,10 clc brne IncFreq3 sec clr temp3 IncFreq3: st Z,temp3 brcc IncFreq7 dec ZL dec temp1 rjmp IncFreq2 IncFreq7: ldi ZH,high(LCDrcve0) ldi ZL,low(LCDrcve0) ld temp1,Z cpi temp1,4 brlo IncFreq8 ldi temp1,55 IncFreq8: ret IncFreq9: ldi ZH,high(freq0) ldi ZL,low(freq0) mov temp2,StepRate lsl temp2 lsl temp2 add ZL,temp2 ldi YH,high(rcve0) ldi YL,low(rcve0) ld temp1,Z+ ld temp2,Y add temp1,temp2 st Y+,temp1 ld temp1,Z+ ld temp2,Y adc temp1,temp2 st Y+,temp1 ld temp1,Z+ ld temp2,Y adc temp1,temp2 st Y+,temp1 ld temp1,Z+ ld temp2,Y adc temp1,temp2 st Y+,temp1 ret DecFreq0: mov temp2,StepRate ldi ZH,high(rcve0) ldi ZL,low(rcve0) ldi temp1,9 DecFreq1: dec temp1 dec ZL dec temp2 brpl DecFreq1 DecFreq2: ld temp3,Z dec temp3 cpi temp3,255 clc brne DecFreq3 sec ldi temp3,9 DecFreq3: st Z,temp3 brcc DecFreq7 dec ZL dec temp1 rjmp DecFreq2 DecFreq7: ldi ZH,high(LCDrcve0) ldi ZL,low(LCDrcve0) ld temp1,Z cpi temp1,4 brlo DecFreq8 ldi temp1,55 DecFreq8: ret DecFreq9: ldi ZH,high(freq0) ldi ZL,low(freq0) mov temp2,StepRate lsl temp2 lsl temp2 add ZL,temp2 ldi YH,high(rcve0) ldi YL,low(rcve0) ld temp2,Z+ ld temp1,Y sub temp1,temp2 st Y+,temp1 ld temp2,Z+ ld temp1,Y sbc temp1,temp2 st Y+,temp1 ld temp2,Z+ ld temp1,Y sbc temp1,temp2 st Y+,temp1 ld temp2,Z+ ld temp1,Y sbc temp1,temp2 st Y+,temp1 ret ShowFreq: ;display freq on LCD ldi temp1,$C1 rcall lcdcmd ldi ZH,high(LCDrcve0) ldi ZL,low(LCDrcve0) clr temp2 ld temp1,Z+ add temp2,temp1 brne ShowFreq1 ldi temp1,' ' ShowFreq1: rcall lcdput ld temp1,Z+ add temp2,temp1 brne ShowFreq2 ldi temp1,' ' ShowFreq2: rcall lcdput ldi temp1,',' tst temp2 brne ShowFreq3 ldi temp1,' ' ShowFreq3: rcall lcdput ld temp1,Z+ add temp2,temp1 brne ShowFreq4 ldi temp1,' ' ShowFreq4: rcall lcdput ld temp1,Z+ add temp2,temp1 brne ShowFreq5 ldi temp1,' ' ShowFreq5: rcall lcdput ld temp1,Z+ add temp2,temp1 brne ShowFreq6 ldi temp1,' ' ShowFreq6: rcall lcdput ldi temp1,',' tst temp2 brne ShowFreq7 ldi temp1,' ' ShowFreq7: rcall lcdput ld temp1,Z+ add temp2,temp1 brne ShowFreq8 ldi temp1,' ' ShowFreq8: rcall lcdput ld temp1,Z+ add temp2,temp1 brne ShowFreq9 ldi temp1,' ' ShowFreq9: rcall lcdput ld temp1,Z+ rcall lcdput ldi temp1,' ' rcall lcdput ldi temp1,'H' rcall lcdput ldi temp1,'z' rcall lcdput rcall ShowCursor ret ShowCursor: ;position cursor to active position ldi temp1,$CA sub temp1,StepRate cpi temp1,$C8 brsh ShowCursor1 dec temp1 ShowCursor1: cpi temp1,$C4 brsh ShowCursor2 dec temp1 ShowCursor2: rcall lcdcmd ret EXT_INT0: push temp1 ;save temp1 register in temp1,SREG ;save the status register push temp1 in temp1,MCUCR cpi temp1,ISC01+ISC11 ; test falling edge breq int05 ldi temp1,ISC01+ISC11 ; set int0 for falling edge and int1 on falling edge out MCUCR,temp1 sbis PIND,PHASE ; test PHASE rjmp int01 dec encoder rjmp int09 int01: inc encoder rjmp int09 int05: ldi temp1,ISC01+ISC00+ISC11 ; set int0 for rising edge and int1 on falling edge out MCUCR,temp1 sbis PIND,PHASE ; test PHASE rjmp int06 inc encoder rjmp int09 int06: dec encoder int09: pop temp1 out SREG,temp1 ;restore the status register pop temp1 ;restore temp1 register reti EXT_INT1: push temp1 in temp1,SREG inc press out SREG,temp1 pop temp1 reti TIM1_CAPT: push temp1 in temp1,SREG out SREG,temp1 pop temp1 reti TIM1_COMP: push temp1 in temp1,SREG out SREG,temp1 pop temp1 reti TIM1_OVF: push temp1 in temp1,SREG out SREG,temp1 pop temp1 reti TIM0_OVF: push temp1 in temp1,SREG push temp1 ;this is for a 10,240 KHz Xtal ldi temp1,246 ;1 ms ;ldi temp1,236 ;2 ms ;ldi temp1,216 ;4 ms ;ldi temp1,206 ;5 ms ;ldi temp1,156 ;10 ms ;ldi temp1,56 ;20 ms out TCNT0,temp1 ;set for next overflow tst delay breq TIM0_X dec delay TIM0_X: pop temp1 out SREG,temp1 pop temp1 reti UART_RXC: push temp1 in temp1,SREG out SREG,temp1 pop temp1 reti UART_DRE: push temp1 in temp1,SREG out SREG,temp1 pop temp1 reti UART_TXC: push temp1 in temp1,SREG out SREG,temp1 pop temp1 reti ANA_COMP: push temp1 in temp1,SREG out SREG,temp1 pop temp1 reti FreqOut: ldi yl,rcve0 clr yh ld temp1,y+ rcall shift8 ;write data bits ld temp1,y+ rcall shift8 ;write data bits ld temp1,y+ rcall shift8 ;write data bits ld temp1,y+ rcall shift8 ;write data bits ldi temp1,0 rcall shift8 ;write data bits sbi PORTD,PD0 ;load goes LOW cbi PORTD,PD0 ;load goes HIGH ret shift8: ldi temp2,8 ; 8 bits movebits: sbi DDSport,DDSdata ;set port bit ror temp1 ;shift dds address byte brcs clockbit ;check for 1/0 cbi DDSport,DDSdata ;clear port bit clockbit: sbi DDSport,DDSclock cbi DDSport,DDSclock ;clock dds dec temp2 ;decrement bit counter brne movebits ;branch if not done ret wait: tst delay brne wait ret default_freq1: ;FlashToRam ldi zh,high(FreqHex*2) ;load default freq ldi zl,low(FreqHex*2) ldi yl,rcve0 clr yh ldi temp1,36 df1: lpm ;get value in R0 st Y+,r0 ;store in SRAM and increment Y-pointer adiw ZL,1 ;increment Z-pointer dec temp1 ;decrememnt counter brne df1 ;if not end of table, loop more ldi zh,high(FreqLCD*2) ;load default freq ldi zl,low(FreqLCD*2) ldi yl,LCDrcve0 clr yh ldi temp1,8 df2: lpm ;get value in R0 st Y+,r0 ;store in SRAM and increment Y-pointer adiw ZL,1 ;increment Z-pointer dec temp1 ;decrememnt counter brne df2 ;if not end of table, loop more ret FreqHex: .db 0x9A,0x99,0x99,0x19 ;10,000,000 Hz .db 0x2B,0x00,0x00,0x00 ; units .db 0xAD,0x01,0x00,0x00 ;10 .db 0xC7,0x10,0x00,0x00 ;100 .db 0xC6,0xA7,0x00,0x00 ;1;000 .db 0xB9,0x8D,0x06,0x00 ;10,000 .db 0x37,0x89,0x41,0x00 ;100,000 .db 0x29,0x5C,0x8F,0x02 ;1,000,000 .db 0x9A,0x99,0x99,0x19 ;10,000,000 FreqLCD: .db 1,0,0,0,0,0,0,0 ;LCD for 10,000,000 Hz msg1: ; 1234567890123456789012345678901234567890 .db "AD9850 DDS DEMO",0