Full Version : PLL FM Transmitter AVR 2313 LMX1601
avr >>COMMUNICATIONS & WEB PROJECTS >>PLL FM Transmitter AVR 2313 LMX1601


AVR_Admin- 04-29-2006
A Low Power PLL FM Transmitter using the LMX1601
and the ATtiny2313 or AT90S2313


An LMX1601 Phase locked loop, a discreet FET VCO, and an AVR micro controller combine to make a stable, easy to use monophonic FM transmitter that includes a an audio activated switch that turns the transmitter on only when its being used.


Notice: Before operating a radio transmitter, find out what kind of transmitter operation, if any, is permitted in your locality. Radio transmitter operation is a serious legal matter. In the United States, operation of unlicensed intentional radiators is covered by Part 15 of Title 47 of the Code of Federal Regulations. This design can be readily adapted to different frequencies and different power levels. If you choose to build and operate the transmitter described here, you do so at your own risk. I'm only publishing this as an example of what can be done.

Link to Site: http://cappels.org/dproj/LMX1601FMxmttr/LM...ransmitter.html

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.






Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.