| CODE |
;****************************************************** ;Version LMX060331D ; ;PLL FM Transmitter control firmware for AT90S2313 or ATtin2313 ;controlling a National Semiconductor LMX1601 PLL chip. Both chips ;are clocked at 4 Mhz. Accuracy of the clock affects accuracy of the ;PLL frequency. ; ; ;The AUX PLL is used since its operational range includes ;the FM broadcast band. The 4 Mhz clock from the microcontroller ;is devided by 320 to make a 12.5 kHz reference frequency. The AUX ;prescaler devides by 8, so each count into the 16 bit AUX N Counter ;counts for 100 kHz. Therefore, a value of 1000 in the AUX N Counter ;will result the PLL operating at 100.0 MHz. Each increase in the ;value written to the AUX N Counter will increase the oscillator frequency ;by 100 kHz. So, a value of 1001 will make the PLL drive the oscillator ;to 100.1 kHz. ; ; The SendAUX_N: routine adds an offset of 825 to the contents of ;the register named "channel", and channel is a single 8 bit variable. ;Thus, the maximum range of the PLL is: ;Minimum frequency = 100 kHz X (825 + 0) = 82.5 kHz. ;Maximum frequency = 100 kHz x (825 + 255) = 108.0 MHz ; ;Tests in the Plusbutton and Minusbutton routines restirct the ;range of the PLL to 88.0 to 108.0 MHz. ; ;Read the LMX1601 datasheet carefully. ; ;****************************************************** .nolist ;Don't include 2313 defitiions in the .include "2313def.inc" ;listing file. .list ;****************************************************** ;************* MEMO OF I/O PORT ASSIGNMENTS ************* ;Port B pin assignments ;B0 Comparitor + input INPUT ;B1 Comparitor - input INPUT ;B2 - Button INPUT with pullup ;B3 + Button INPUT with pullup ;B4 Oscillator Enable OUTPUT ;B5 LMX1601 Clock Pin, Microwire OUTPUT ;B6 LMX1601 Data Pin, Microwire OUTPUT ;B7 LMX1601 Latch Enablem Microwire OUTPUT ;PORT D pin assignments ;D0 ;D1 ;D2 ;D3 ;D4 Daignostic - high during interrupts OUTPUT ;D5 Status LED. 1 = ON OUTPUT ;D6 Beep output OUTPUT ;D7 ;************* DEFINE FEGISTER USAGE ************* ;Variables for shifting into LMX1601 AUX_N register. .def AUX_Nr2 = r5 .def AUX_Nr1 = r6 .def AUX_Nr0 = r7 ;Variables for VOX timer. .def voxt0 = r8 .def voxt1 = r9 ;Variables for button and EEPROM management. .def temp = r16 ;Scratch register. .def temp2 = r17 ;Scratch register. .def delayone = r18 ;Used for button filtering delay. .def delaytwo = r19 ;Used for button filtering delay. .def Dreg = r20 ;PORTD data output buffer .def EEPROMpntr = r21 ;Pointer to EEPOROM location to ;be read/written. Bits zero .def flagreg = r22 ;Flags for firmware. ;LMX1601 loader Register assignments. .def delayc = r2 ;Variable for delay routine. .def secondelay = r3 ;Variable for delay routine. .def channel = r4 .def tempreg = r23 ;General purpose working ;register for non-interrupt ;times ;Notaitonal (dummy) register assignments. ;def XL = r26 ;Used for Channel calculation. ;def XH = r27 ;Used for Channel calculation. ;def YL = r28 ;AUX_N counter value calculation ;def YH = 2r9 ;AUX_N counter value calculation ;def ZL = r30 ;EEPROM write delay ;def ZH = r31 ;EEPROM write delay ;flagreg bit assignments Single bit flags. ;0 ;1 ;2 ;3 ;4 ;5 Set in On mode to indicate that oscillator is on. ;6 Set by comparitor interrupt routine. ;7 If set, data in dreg needs to be written to EEPROM. ;************* ESTABLISH CONSTANTS ************* .equ DataPin = 6 ;Bit 6 of PORTB is the Microwire ;data pin. .equ ClockPin = 5 ;Bit 5 of PORTB is the Microwire ;data pin. .equ LEPin = 7 ;Bit 7 of PORTB is the Microwire ;data pin. .equ waitL = 0 .equ waitH = 3 ;waitH is the number of 10 ;second increments. ;Initial data for LMX1601 registgers ;Make bit 7 of AuxR2 = 1 to look at ;Aux_R otuput, make it 1 to look at ;Aux_N output. Maker 4 upper bits (FoLD) ;= 0101 for Aux lock with xtal. .equ AuxR2 = 0b11000000 ;Most significant byte. Upper two bits ;contain bits 16 and 17. The rest are; ;unused. .equ AuxR1 = 0b11000101 ;Middle byte;Div by 320 for 12.5 kHz ;from 4 MHz xtal .equ AuxR0 = 0b00000000 ;Least significant byte. Devide by 8. .equ AUX_N2 = 0b00000000 ;With a 12.5 kHz reference frequency, ;osc freq = 100 kHz X N .equ AUX_N1 = 0b11111010 ;Frequency can be changed by ;incrementing and decrementing N. .equ AUX_N0 = 0b10000001 ;The AUX_N vlaues 00000000 11111010 ;10000001 get 100 MHz out of the ;synthesizer. ;The AUX_N vlaues $00 $FA $81 get ;100 MHz out of the synthesizer .equ Main_R2 = 0b11110000 .equ Main_R1 = 0b11000000 .equ Main_R0 = 0b00000010 .equ Main_N2 = 0b00000000 ;These values should not matter. .equ Main_N1 = 0b00000000 .equ Main_N0 = 0b00000011 .equ nominalchannel = 175 ;Channel 175 corresponds to 100 MHz. ;82.5 MHz + (175 X 100 kHz) = 100 MHz. ;************* START EXECUTABLE CODE ************* .org $0000 rjmp start .org ACIaddr rjmp ANA_COMP ;Analog Comparator Handle (Strictly ;speaking, the jump is not needed this ;time.) ANA_COMP: push tempreg ;Save tempreg on stack in tempreg,SREG ;Temporarily store the Status register. sbi PORTD,4 ;Diagnotic - set D4 high (So one can see ;the interrupts externally) sbi PORTD,5 ;Turn the status LED on. (Make sure it ;is on) sbr flagreg,0b01000000 ;Set comparitor tripped flag for ;foreground control of indicator light. cbi PORTD,4 ;Diagnotic - set D4 low. out SREG,temp ;Restore Status register. pop tempreg ;Restore tempreg. reti on: ;Turn oscillator on. push tempreg ;Turn on the oscillator and reset the ;vox timer. sbi PORTB,4 ;Turn oscillator poin on. sbr flagreg,0b00100000 ;Set oscillator running flag. sbi PORTD,5 ;Turn status LED on. clr voxt0 ;Below is the vox timer, which shuts off ;the oscillator if a preset amount ;of time passes without an analog ;comparitor interrupt occurring. ;test modify the code between "test" and " ;endtest" to shorten timer period for ;test pruposes. ; ldi tempreg,20 ;This ine ACTIVE for TEST (For 9 ;second timeout, make this value 20) ; mov voxt0,tempreg ;This ine ACTIVE for TEST ; ldi tempreg,1 ;This ine ACTIVE for TEST (For 9 second tiemout, make this value 1) ldi tempreg,30 ;This line NOT ACTIVE for test. About 10 ;seconds per count. ;endtest mov voxt1,tempreg ;Each count in voxt1 is worth about 9 ;seconds. pop tempreg ret off: ;Turn oscillator off, clear indicators. cbi PORTB,4 ;Turn off oscillator. cbr flagreg,0b00100000 ;Clear oscillator running flag. cbi PORTD,5 ;Make sure power LED is in OFF state. cbi ACSR,ACIE ;Disable Analog Comparator interrup. ldi tempreg,10 ;Delay for a second or two so oscillator ;off glictch does not retrigger. Powerup2: dec tempreg breq PowerupDone2 rcall DelayLoader ;Wait for power supply to settle before ;loading LMX1601 rjmp Powerup2 PowerupDone2: sbi ACSR,ACIE ;Enable Analog Comparator interrupt. ret start: ;COMES HERE AFTER POWER-ON RESET ldi r16,RAMEND ;Init Stack Pointer out SPL,r16 ldi tempreg,10 ;DelayLoader at startup. Powerup: dec tempreg breq PowerupDone rcall DelayLoader ;Wait for power supply to settle before ;loading LMX1601 rjmp Powerup PowerupDone: ldi tempreg,0b00001100 ;Set Port B pullups. out PORTB,tempreg ldi tempreg,0b11110000 ;Set port B direction bits. out DDRB,tempreg rcall DelayLoader ;DelayLoader before loading ldi temp, AUX_N2 ;Load variables for LMX AUX_N register. mov AUX_Nr2,temp ldi temp, AUX_N1 mov AUX_Nr1,temp ldi temp, AUX_N0 mov AUX_Nr0,temp ;Get the oscillator channel data from the EEPROM, bute $AA ldi EEPROMpntr,$AA ;Get channel number from EEPROM. rcall ReadEE rcall LoadLMX ;Load initial control bits into LMX1601 ;registers. ldi temp, 00 ;Set PORTD as output. out PORTD, temp ;Set bits to initial value. ldi temp, $FF out DDRD, temp clr flagreg ldi ZL, waitL ldi ZH, waitH rcall on ;Initially turn the oscillator on. It ;will time out if there is no stimulus. ldi temp,(ACI<<1) ;Clear interrupt flag and ACIS1/ACIS0... out ACSR,temp ;to select interrupt on toggle. sei ;Enablfsbre global interrupts. sbi ACSR,ACIE ;Enable Analog Comparator interrupt. ldi temp,255 rcall Buzzloop Loadbuttons: ;********Main loop entry point. ******** ;Make LED blink, working with comparitor interrupt routine. sbrc flagreg,5 ;In in On mode, then turn on LED. sbi PORTD,5 sbrc flagreg,5 ;In in On mode, then turn on Oscillator. sbi PORTB,4 sbrs flagreg,6 ;Turn on if comparitor has beentripped, and reset comparitor flag. rjmp NotTripped rcall on cbi PORTD,5 ;Turn off LED cbr flagreg,0b01000000 ;Clear the camparitor interrupt flag. NotTripped: dec ZL ;Wait some number of times through this loop before writing ; channel number to EEPROM. brne noprog dec ZH brne noprog ldi ZL, waitL ldi ZH, waitH sbrs flagreg,7 rjmp noprog ldi EEPROMpntr,$AA rcall WriteEE ;Write cuttent channel number to EEPROM. andi flagreg,0b01111111 noprog: dec voxt0 brne NoShutoff dec voxt1 brne NoShutoff rcall off NoShutoff: in temp ,PINB ;Get the button status. andi temp,0b00001100 ;Only bits 2 and 3 can contain button ;information. rcall delay ;Wait debounce period. in temp2, pinB ;If button changed, start over andi temp2,0b00001100 ;Only bits 2 and 3 can contain button ;information. cp temp, temp2 brne loadbuttons rcall InterpretButtons rjmp loadbuttons InterpretButtons: ;Interpret buttons routines called by ;this must terminate with ret ;instruction. cpi temp,0b00000100 ;Is "+" button down? breq Plusbutton cpi temp,0b00001000 ;Is "-" button down? breq Minusbutton ret ;Both butttns case taken care of in debounce. Plusbutton: ;Increment channel number and send new ;AUX_N value. mov temp,channel cpi temp,$FF ;Skip if channel number is already 255 (corresponds to 108 MHz). breq DontIncrement inc channel rcall SendAUX_N DontIncrement: rcall on ;Assure that the oscillator is on while being adjusted. rjmp Buttonack Minusbutton: ;Increment channel number and send new ;AUX_N value. mov temp,channel cpi temp,55 breq DontDecrement ;Skip if channel value is already 55 ;(corresponds to 88 MHz). dec channel rcall SendAUX_N DontDecrement: rcall on ;Assure that the oscillator is on while being adjusted. rjmp Buttonack delay: ;Delay for button debounce and noise ;filtering. ldi delayone,200 ;Count of 200 @ 4 MHz should cuase about ;39 ms for electrical noise.. outerloop: ldi delaytwo,0 innerloop: dec delaytwo brne innerloop dec delayone brne outerloop ret writeEE: ;Write data in channel to location ;EEPROMpntr points to. cli ;Disable interrupts. sbic EECR,EEWE ;If EEWE not clear, rjmp writeEE ;Wait. out EEAR,EEPROMpntr ;Output address out EEDR,channel ;Output data sbi EECR,EEMWE ;Set master write enable. sbi EECR,EEWE ;Set EEPROM Write strobe, ldi temp,100 ;Set number of beep cycles, rcall Buzzloop ;Beep the beeper. sei ;Enable interrupts. ret ReadEE: ;Read from EERPOM. Enter with address in ;EEPROMpntr. Returns with data in ;channel. sbic EECR,EEWE ;If EEWE not clear rjmp ReadEE ;Wait more out EEAR,EEPROMpntr ;Output address sbi EECR,EERE ;Set EEPROM Read strobe in channel,EEDR ;Get data ret Buttonack: ;Emit a keyclick, set EEPROM write flag ;& timer, output PORTD, then wait for ;button up. ldi ZL, waitL ;Set waiting time until programming the ;EEPROM ldi ZH, waitH ori flagreg,0b10000000 ;Set flag to write to EEPROM after time ;is up. ldi temp,50 ;Atart keyclick code. Buzzloop: ;Emit a tone out of D6, the number of cbi PORTD,5 ;Turn the status LED off. ;cycles = contents of temp. sbi PORTD,6 rcall delay2 cbi PORTD,6 rcall delay2 dec temp brne Buzzloop ;end keyclick code. out PORTD, dreg ;Output PORTD data to the output port. sbrs dreg, 7 ;Set DDRD,0 according to dreg,7 rjmp D0Low2 sbi DDRD ,0 rjmp D0Done2 D0Low2: cbi DDRD, 0 D0Done2: sbi PORTD,5 ;Turn the status LED on (if it beeped, it must be on). Wait4ButtonsUp: in temp, PINB ;Wait for all buttons to be up before ;proceeding. andi temp,0b00001100 ;Buttons are only connected to bits 2 ;and 3. cpi temp,0 breq Bothbuttons ;If both buttons are down, go interpret ;this special case. rcall delay ;Debounce in temp2, PINB andi temp2,0b00001100 ;Buttons are only connected to bits ;2 and 3. cp temp, temp2 brne Wait4ButtonsUp cpi temp,0b00001100 ;Both buttons up? brne Wait4ButtonsUp; ret Bothbuttons: rcall on ;Assure that the oscillator is on while being adjusted. ldi temp,nominalchannel ;Set channel number to nominal ;(Channel 175 gets 100 MHz ;operation) mov channel,temp rcall SendAUX_N rjmp Buttonack ;Reset channel number to default and ;send new AUX_N value. delay2: ;Setts the frequency for the beeps. ldi delayone,1 ;Delay for 1/2 cycle of button click. outerloop2: ldi delaytwo,150 innerloop2: dec delaytwo brne innerloop2 dec delayone brne outerloop2 ret shiftout: ;Clock MSB of tempreg into LMX1601 ;Microwire interface, exits with tempreg ;shifted left one bit. cbi PORTB,DataPin ;Clear PORTB,Datapin lsl tempreg ;Get bit 7 into carry brcc s1 sbi PORTB,DataPin ;If carry set, set PORTB,Datapin s1: sbi PORTB,ClockPin ;Toggle Clock high then low. nop cbi PORTB,ClockPin nop ret LoadData: sbi PORTB,LEPin nop cbi PORTB,LEPin ret DelayLoader: ;Short delay routine clr delayc ;used varioius places. outerloop9: clr secondelay innerloop9: dec secondelay brne innerloop9 dec delayc brne outerloop9 ret LoadLMX: ;Aux_N values are calculated in SendAUX_N subroutine. ldi tempreg,AuxR2 ;Load the values into AuxR into LMX1601 rcall shiftout rcall shiftout ldi tempreg,AuxR1 rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout ldi tempreg,AuxR0 rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall LoadData ldi tempreg,Main_R2 ;Load Main_R into LMX1601 rcall shiftout rcall shiftout ldi tempreg,Main_R1 rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout ldi tempreg,Main_R0 rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall LoadData rcall SendAUX_N ldi tempreg,Main_N2 ;Load AUX_N into LMX1601 rcall shiftout rcall shiftout ldi tempreg,Main_N1 rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout ldi tempreg,Main_N0 rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall LoadData ret SendAUX_N: ;Add counter to the offset then load ;into AUX_Nr2..AUX_Nr0, and then load ;into LXM1601. ldi XH,0 mov XL,channel ldi YH,3 ldi YL,57 clc adc YL,XL ;Add the channel number to the constant ;offset (825) adc YH,XH mov temp,YH ;Get YH bits 3 and 4 into AUX_N2 bits 7 ;and 6 respecitively. lsl YH lsl YH lsl YH lsl YH andi YH,0b11000000 ;YH bits 0 and 1 are now in positions 7 ;and 6 and other bits are zero. mov tempreg,AUX_Nr2 ;Get the current value of AUX_Nr2. andi tempreg,0b00111111 ;Clear bits 7 and 6. or tempreg,YH ;Or new bits into it. mov AUX_Nr2,tempreg ;Save AUX_Nr2 value with new values for ;bits 7 and 6. lsl temp ;Work with copy of YH data. Move bits 1 ;and 0 into positions 7 and 6. lsl temp lsl temp lsl temp lsl temp lsl temp andi temp,0b11000000 ;Bits are now in poistions 7 and 6, and ;all other bits are zero. clr AUX_Nr1 ;Clear AUX_Nr1 because all bits for; ;AUX_Nr1 will be replaced by oring in. or AUX_Nr1,temp ;YL bits 1 and 0 have been moved to ;AUX_Nr1 bits 7 and 6 ;Get the six upper bits of YL into the ;lower six bits of AUX_Nr1. mov temp,YL ;Save a copy of YL in temp. lsr temp lsr temp andi temp,0b00111111 or AUX_Nr1,temp ;Not the upper six bits of YL have been ;placed in the lower six bit positions ;of AUX_Nr1. lsl YL ;Get two lower bits from YL into the two lsl YL ;uppper bits of AUX_Nr0. lsl YL lsl YL lsl YL lsl YL andi YL,0b11000000 ;Bits are now in poistions 7 and 6, and ;all other bits are zero. mov temp,AUX_Nr0 ;Clear AUX_Nro bits 7 and 6 in ;preparation to or new values into the ;register. andi temp,0b00111111 or temp,YL mov AUX_Nr0,temp mov tempreg,AUX_Nr2 rcall shiftout rcall shiftout mov tempreg,AUX_Nr1 rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout mov tempreg,AUX_Nr0 rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall shiftout rcall LoadData ret ;Finished calculating data and loading ;AUX_N register in LMX1601 .exit ;Assembler will stop at this line. |