;SYNTHBLB02.ASM cmd ;Controls LMX1501 synth. Boot synth from EE at turn on ;Full control via RS232 interface using port change interrupt ;Ver 3 with sweep option, port change interrupt for serial I/O ; Serial Command protocol Rxxxx[cr] Input new R data, no update ; Nxxxxx[cr] Input new N data, no update ; Sxxxxx[cr] Input new S data, no update ; U [cr] Update chip and sweep settings with new data ; W [cr] Update chip and write to EE ; S reg format S2 S1 S0 ; ....tttt ttttiinn nnnnnnnn ; n = No of steps (0-1023) of reference ; i = Increment each step 0/123 = 1/2/4/8 * reference ; t = step interval in units of 1ms, 0 = no step PROCESSOR 12F675 INCLUDE "P12F675.INC" errorlevel 1 ; =============================================================== #define SerIn GPIO, 0 ;Also PGD, Port change enabled #define SerOut GPIO, 1 ;Also PGC #define LMXClock GPIO, 2 #define LMXData GPIO, 4 #define LMXStrb GPIO, 5 #define LED GPIO, 1 ;LED on SerOut for debugging RS232POL = 1 ; 1 = RS232 levels, 0 = Logic/FTDI Interface BAUDCONST = d'161' ;Half baud delay, determiine by trial & error! __config 0x3F94 ;INTOSC, I/O on GP4/5 ;CPD Off, CP Off, Boden Off, MCLRE = I/O, PWRTE Off, WDT Off, R = d'320' ;12.5kHz from 4MHz, prescale 128/129 ; (add d'16384' for 64/65 prescale) N = d'36680' ;458.5MHz with 12.5kHz Fref. Using 128/198 prescalar ; 7 bit A and 11 bit N concatenate to allow ; a single word to be specified org 0x2100 de HIGH(R), LOW(R) ;R data (15 bits in total) de (N >> 16) & 0xFF ;N data (19 bits in total) de (N >> 8) & 0xFF de N & 0xFF de 0x02, 0x80, 0x64 ;S = 20ms, single chan increment, 100 steps org 0 nop clrw movwf INTCON ;disable interrupts goto StartUp ;jump to main code ;================================ org 4 ;Interrupt routine, every time RotI goes low to high movwf Wreg ;Save W swapf STATUS , W ; nb. movwf does not affect any STATUS bits movwf StsReg ;Stave STATUS, without affecting it btfss INTCON , GPIF ;Test for port B change goto CarryOnInt ; ; bcf INTCON , GPIE ; call Assemble232 ;MUSTN'T Waste ANY TIME UP TO HERE !!!! sublw 0x0D ;Check for [cr] terminating any command, btfsc STATUS, Z ; otherwise chars are pushed onto stack call CheckSerCmd ;Decode the command and do any actions bcf INTCON , GPIF ;Clear the flag bsf INTCON , GPIE ;Re-enable the interrupt ;............... CarryOnInt swapf StsReg , W ;Restore STATUS movwf STATUS swapf Wreg ;Restore W swapf Wreg , W ; nb. movf affects Z bit retfie ;================================= StartUp movlw 7 movwf CMCON bsf STATUS,RP0 ;ram page 1 clrf ANSEL ;Sets all pins as digital movlw b'00000001' ;GP0 is the serial input, all others out movwf TRISIO ; movwf IOC ;Port change interrupt on GP0 movlw b'00000000' ;Pull-ups enabled movwf OPTION_REG bcf STATUS, RP0 bcf LMXStrb if RS232POL == 1 bcf SerOut ;RS232 idle state (note RS232 polarity !) else bsf SerOut endif call LongDelay ;Give it some time to settle call IntroMessage movlw 0 call GetEE_12F movwf R1 movlw 1 call GetEE_12F movwf R0 movlw 2 call GetEE_12F movwf N2 movlw 3 call GetEE_12F movwf N1 movlw 4 call GetEE_12F movwf N0 movlw 5 call GetEE_12F movwf S2 movlw 6 call GetEE_12F movwf S1 movlw 7 call GetEE_12F movwf S0 call SendData call SendBack movlw b'10001000' ;Port Change interrupt movwf INTCON clrf HopCountHi clrf HopCountLo MainLoop ; movf HopNHi, W addwf HopNLo, W btfsc STATUS, Z ;Both = 0, CW operation goto MainLoop incf HopCountLo btfsc STATUS, Z incf HopCountHi movf HopNHi, W andlw 0x03 ;Get LimitHi subwf HopCountHi,W ;W = CountHi - LimitHi, if -ve, C=0, continue btfss STATUS, C goto CarryOnHopping movf HopNLo, W subwf HopCountLo,W ;W = CountLo - LimitLO, if -ve, C=0, continue btfss STATUS, C goto CarryOnHopping clrf HopCountLo clrf HopCountHi CarryOnHopping movf N0, W ;18 Bit data; 11 bits of N divider at MSB movwf D0 ; 7 bits of A count at LSB movf N1, W movwf D1 movf N2, W movwf D2 movf HopCountHi, W movwf HopOffsetHi movf HopCountLo, W movwf HopOffsetLo movf HopNHi, W ;Get and align ii value movwf Temp rrf Temp rrf Temp, W andlw 0x03 movwf Temp ;0=1, 1=2, 2=4, 3=8 movf Temp btfsc STATUS, Z goto NoHopIncr HopIncrLoop bcf STATUS, C rlf HopOffsetLo rlf HopOffsetHi decfsz Temp goto HopIncrLoop ;Shift left 1/2/3 times NoHopIncr movf HopOffsetLo, W addwf D0 btfsc STATUS, C incf D1 btfsc STATUS, Z incf D2 movf HopOffsetHi, W addwf D1 btfsc STATUS, Z incf D2 call N_Update movf HopDelay, W call DelayHop goto MainLoop ; S reg format S2 S1 S0 ; ....tttt ttttiinn nnnnnnnn ; n = No of steps (0-1023) of reference ; i = Increment each step 0/123 = 1/2/4/8 * reference ; t = step interval in units of 1ms, 0 = no step ;------------------------------------ SendData swapf S2, W ;Decode S data and transfer to andlw 0xF0 ; hop registers movwf HopDelay swapf S1, W andlw 0x0F addwf HopDelay ;0 to 255 units of 1ms movf S0, W movwf HopNLo movf S1, W andlw 0x0F movwf HopNHi ; Also contains ii value in bits 2/3 ;Now Send complete R and N register set movf R0, W ;15 Bit data; 14 bit R value plus movwf D0 ; 1 bit Prescalar control at MSBs movf R1, W movwf D1 AlignRLoop rlf D0 ;Rotate left once so 15 MBSs of D contain the rlf D1 ; data, aligned so MSB of R = MSB of D2 bsf D0, 0 ;Sets the control bit to define R data movlw d'16' ;Clock in the 15 data bits (+ control) movwf Counter bcf LMXClock SendRLoop rlf D0 rlf D1 btfsc STATUS, C bsf LMXData btfss STATUS, C bcf LMXData bsf LMXClock nop bcf LMXClock decfsz Counter goto SendRLoop bsf LMXStrb nop bcf LMXStrb ;~~~~~~~~ Now do the A and N registers movf N0, W ;18 Bit data; 11 bits of N divider at MSB movwf D0 ; 7 bits of A count at LSB movf N1, W movwf D1 movf N2, W movwf D2 N_Update ;Jump in here for new N only, when hopping movlw d'6' movwf Counter AlignNLoop ;Align so MSB sits at D2,7 rlf D0 rlf D1 rlf D2 decfsz Counter goto AlignNLoop bcf D0, 5 ;Clear the control bit to define N data movlw d'19' ;Clock in the 18 data bits + control movwf Counter bcf LMXClock SendNLoop rlf D0 rlf D1 rlf D2 btfsc STATUS, C bsf LMXData btfss STATUS, C bcf LMXData bsf LMXClock nop bcf LMXClock decfsz Counter goto SendNLoop bsf LMXStrb nop bcf LMXStrb return ;------------------------------------ SendBack ;Send contents of R and N registers on RS232 interface call CrLf movlw "R" call SendByte movlw " " call SendByte swapf R1, W call SendHex movf R1, W call SendHex swapf R0, W call SendHex movf R0, W call SendHex call CrLf movlw "N" call SendByte movlw " " call SendByte movf N2, W call SendHex swapf N1, W call SendHex movf N1, W call SendHex swapf N0, W call SendHex movf N0, W call SendHex call CrLf movlw "S" call SendByte movlw " " call SendByte movf S2, W call SendHex swapf S1, W call SendHex movf S1, W call SendHex swapf S0, W call SendHex movf S0, W call SendHex call CrLf return ;------------------------------------ DecodeHex ;Single ASCII character to binary movwf Temp ;Uses Temp movlw 0x30 subwf Temp ;subtract $30 and leave in Temp btfss STATUS , C ;if < $30, result -ve so C=0, error, set=0 clrf Temp movf Temp , W sublw d'9' ;W = 9 - W btfsc STATUS , C ;if -ve, C=0, char > 9, so subtract 7 goto ConvDone movlw d'7' subwf Temp ; ConvDone movf Temp , W ; andlw 0x0F ;mask out any rubbish left in return ;------------------------------------ SendHex ;Send a single Nibble as RS232 andlw 0x0F addlw 0x30 movwf Temp sublw 0x39 btfsc STATUS , C goto CharDone movlw 7 addwf Temp CharDone movf Temp , W call SendByte return ;----------------------------------- IntroMessage movlw "S" call SendByte movlw "Y" call SendByte movlw "N" call SendByte movlw "T" call SendByte movlw "H" call SendByte movlw "B" call SendByte movlw "L" call SendByte movlw "O" call SendByte movlw "B" call SendByte movlw " " call SendByte movlw "C" call SendByte movlw "o" call SendByte movlw "n" call SendByte movlw "t" call SendByte movlw "r" call SendByte movlw "o" call SendByte movlw "l" call SendByte movlw " " call SendByte movlw " " call SendByte movlw " " call SendByte movlw " " call SendByte movlw "G" call SendByte movlw "4" call SendByte movlw "J" call SendByte movlw "N" call SendByte movlw "T" call SendByte call CrLf movlw "C" call SendByte movlw "o" call SendByte movlw "m" call SendByte movlw "m" call SendByte movlw "a" call SendByte movlw "n" call SendByte movlw "d" call SendByte movlw "s" call SendByte movlw ":" call SendByte call CrLf movlw "R" call SendByte movlw "x" call SendByte movlw "x" call SendByte movlw "x" call SendByte movlw "x" call SendByte call CrLf movlw "N" call SendByte movlw "x" call SendByte movlw "x" call SendByte movlw "x" call SendByte movlw "x" call SendByte movlw "x" call SendByte call CrLf movlw "S" call SendByte movlw "x" call SendByte movlw "x" call SendByte movlw "x" call SendByte movlw "x" call SendByte movlw "x" call SendByte call CrLf movlw "[" call SendByte movlw "U" call SendByte movlw "]" call SendByte movlw "p" call SendByte movlw "d" call SendByte movlw "a" call SendByte movlw "t" call SendByte movlw "e" call SendByte call CrLf movlw "[" call SendByte movlw "W" call SendByte movlw "]" call SendByte movlw "r" call SendByte movlw "i" call SendByte movlw "t" call SendByte movlw "e" call SendByte movlw " " call SendByte movlw "E" call SendByte movlw "E" call SendByte call CrLf return ;----------------------------------- CrLf movlw 0x0D call SendByte movlw 0x0A call SendByte return ;--------------------------------- SendByte movwf Temp if RS232POL == 1 bsf SerOut else bcf SerOut ;start bit endif call HalfBitDelay ; call HalfBitDelay movlw 8 movwf Counter SendDatLoop rrf Temp ;bit into C if RS232POL == 1 btfsc STATUS , C bcf SerOut btfss STATUS , C bsf SerOut ;could have 2us jitter depending on 1/0 else btfsc STATUS , C bsf SerOut btfss STATUS , C bcf SerOut ;could have 2us jitter depending on 1/0 endif call HalfBitDelay call HalfBitDelay decfsz Counter goto SendDatLoop ;loop 8 + BitDelay long if RS232POL == 1 bcf SerOut else bsf SerOut endif call HalfBitDelay call HalfBitDelay ;Two stop bits call HalfBitDelay call HalfBitDelay return ;------------------------------- CheckSerCmd ;[cr] terminator has been received, so ; decode the commands in here. Will be in Stack1 movlw "R" ;Rxxxx R register data data subwf Stack6, W ;Stack6/5/4/3/2/1 btfsc STATUS, Z ; R x x x x [cr] goto RCmd movlw "N" ;Nxxxxx New N register data subwf Stack7, W ; btfsc STATUS, Z ;Stack7/6/5/4/3/2/1 goto NCmd ; N x x x x x [cr] movlw "S" ;Sxxxxx New S register data subwf Stack7, W ; btfsc STATUS, Z ;Stack7/6/5/4/3/2/1 goto SCmd ; S x x x x x [cr] movlw "U" ;Update Chip and continue subwf Stack2, W ;Stack2/1 btfsc STATUS, Z ;Stack7/6/5/4/3/2/1 goto UCmd ; U [cr] movlw "W" ;Write to EE and continue subwf Stack2, W ;Stack2/1 btfsc STATUS, Z ;Stack7/6/5/4/3/2/1 goto WCmd ; W [cr] goto DoneCmd ;............. RCmd movf Stack5 , W ; convert to binary in R1/0 call DecodeHex ;MS Nibble movwf R1 ;Stack 6/5/4/3/2/1 swapf R1 ; R x x x x [cr] movf Stack4 , W call DecodeHex addwf R1 bcf R1, 7 ;Mask off any MSB entered in error movf Stack3 , W call DecodeHex movwf R0 swapf R0 movf Stack2 , W ;LSNibble call DecodeHex addwf R0 movlw 0x0D call SendByte movlw 0x0A call SendByte movlw "R" call SendByte movlw "-" call SendByte swapf R1 , W ;Return data on serial link call SendHex movf R1 , W call SendHex swapf R0 , W call SendHex movf R0 , W call SendHex movlw 0x0D call SendByte movlw 0x0A call SendByte ;R1/0 updated, but not written to EE goto DoneCmd ;............. NCmd movf Stack6 , W ; convert to binary in N2/1/0 call DecodeHex ;MS Nibble movwf N2 ;Stack 7/6/5/4/3/2/1 bcf N2, 7 ; N x x x x x [cr] movf Stack5 , W call DecodeHex movwf N1 swapf N1 movf Stack4 , W call DecodeHex addwf N1 movf Stack3 , W call DecodeHex movwf N0 swapf N0 movf Stack2 , W ;LSNibble call DecodeHex addwf N0 movlw 0x0D call SendByte movlw 0x0A call SendByte movlw "N" call SendByte movlw "-" call SendByte movf N2, W ;Return data on serial link call SendHex swapf N1 , W call SendHex movf N1 , W call SendHex swapf N0 , W call SendHex movf N0 , W call SendHex movlw 0x0D call SendByte movlw 0x0A call SendByte goto DoneCmd ;............. SCmd movf Stack6 , W ; convert to binary in S2/1/0 call DecodeHex ;MS Nibble movwf S2 ;Stack 7/6/5/4/3/2/1 ; S x x x x x [cr] movf Stack5 , W call DecodeHex movwf S1 swapf S1 movf Stack4 , W call DecodeHex addwf S1 movf Stack3 , W call DecodeHex movwf S0 swapf S0 movf Stack2 , W ;LSNibble call DecodeHex addwf S0 movlw 0x0D call SendByte movlw 0x0A call SendByte movlw "S" call SendByte movlw "-" call SendByte movf S2, W ;Return data on serial link call SendHex swapf S1 , W call SendHex movf S1 , W call SendHex swapf S0 , W call SendHex movf S0 , W call SendHex movlw 0x0D call SendByte movlw 0x0A call SendByte goto DoneCmd ;............. UCmd call SendBack call SendData movlw "U" call SendByte movlw "p" call SendByte movlw "d" call SendByte movlw "a" call SendByte movlw "t" call SendByte movlw "e" call SendByte movlw "d" call SendByte call CrLf goto DoneCmd ;.............. WCmd call SendBack ;Send back contents of actual R and N registers call SendData call WriteEE movlw "W" call SendByte movlw "r" call SendByte movlw "i" call SendByte movlw "t" call SendByte movlw "t" call SendByte movlw "e" call SendByte movlw "n" call SendByte call CrLf goto DoneCmd ;.............. ;............. DoneCmd call ClearStack ;Prevents spurious commands return ;------------------------------- Assemble232 ;Get here after Port B interrupt call HalfBitDelay if RS232POL == 1 btfss SerIn else btfsc Serin endif goto GetOut232 ;Invalid start bit movlw d'8' ;27 clocks after edge to here movwf Counter clrf RxChar Rx232Loop call HalfBitDelay call HalfBitDelay bcf STATUS , C if RS232POL == 1 btfss SerIn else btfsc SerIn endif bsf STATUS , C rrf RxChar decfsz Counter goto Rx232Loop ;this loop 2 * HalfBitDelay + 9 call HalfBitDelay ;Part into stop bit - should be no more transitions movlw "a" subwf RxChar, W ;W = Char - "a" btfss STATUS, C ;if-ve (C=0) char < "a" so ignore goto UpCaseDone movf RxChar, W sublw "z" ;W = "z" - Char btfss STATUS, C ;if -ve (C=0) char > "z" so ignore goto UpCaseDone bcf RxChar, 5 ;Reset bit 5 to force upper case UpCaseDone movf RxChar, W call PushStack ;RxChar >> Stack1, previous 5 chars move down one movf RxChar , w ;Returns with data in W as well as on stack GetOut232 return ;received byte in RxChar and W ;------------------------- HalfBitDelay ;1200 baud needs 833us, so delay 414 clocks here movlw BAUDCONST ; for a total of 414 * 2 + 8 = 833 clocks movwf DelCount BaudDelLoop ;Total delay = 3.N + 5 = 414 decfsz DelCount goto BaudDelLoop return ;------------------------------- LongDelay movlw d'240' ;Approx 300ms delay movwf Temp2 LongDelLoop2 movlw d'249' movwf DelCount LongDelLoop1 ; nop nop decfsz DelCount goto LongDelLoop1 decfsz Temp2 goto LongDelLoop2 return ;------------------------------------ DelayHop ;Delays by W units of 1ms movwf Temp2 HopDelLoop2 movlw d'199' movwf DelCount HopDelLoop1 ; nop nop decfsz DelCount goto HopDelLoop1 decfsz Temp2 goto HopDelLoop2 return ;------------------------------------ WriteToEE clrf AutoEEADR movf R1, W call StoreEE_12F incf AutoEEADR movf R0, W call StoreEE_12F incf AutoEEADR movf N2, W call StoreEE_12F incf AutoEEADR movf N1, W call StoreEE_12F incf AutoEEADR movf N0, W call StoreEE_12F return ;------------------------------------ GetEE_12F ;Enter with address in W bsf STATUS, RP0 movwf EEADR bsf EECON1, RD movf EEDATA, W bcf STATUS, RP0 return ;Exit with data in W ;----------------------------------------- WriteEE clrf AutoEEADR movf R1, W call StoreEE_12F incf AutoEEADR movf R0, W call StoreEE_12F incf AutoEEADR movf N2, W call StoreEE_12F incf AutoEEADR movf N1, W call StoreEE_12F incf AutoEEADR movf N0, W call StoreEE_12F incf AutoEEADR movf S2, W call StoreEE_12F incf AutoEEADR movf S1, W call StoreEE_12F incf AutoEEADR movf S0, W call StoreEE_12F return ;------------------------------------------- StoreEE_12F ;Enter with W = EE data, AutoEEADR = EE address bsf STATUS, RP0 ;All EE addresses in bank 1 movwf EEDATA bcf STATUS, RP0 movf AutoEEADR, W bsf STATUS, RP0 movwf EEADR bsf EECON1 , WREN ;Enable EEprom writing movlw 0x55 movwf EECON2 movlw 0xAA movwf EECON2 bsf EECON1 , WR bcf STATUS , RP0 EEwaitW btfss PIR1 , EEIF goto EEwaitW bcf PIR1 , EEIF ;has to be cleared manually return ;------------------------- PushStack movf Stack7 , W movwf Stack8 ;Stack8 contains oldest data movf Stack6 , W movwf Stack7 movf Stack5 , W movwf Stack6 movf Stack4 , W movwf Stack5 movf Stack3 , W movwf Stack4 movf Stack2 , W movwf Stack3 movf Stack1 , W movwf Stack2 movf RxChar , W movwf Stack1 return ;------------------------- ClearStack movlw 0 movwf Stack8 movwf Stack7 movwf Stack6 movwf Stack5 movwf Stack4 movwf Stack3 movwf Stack2 movwf Stack1 return ;------------------------------------ cblock 0x20 ;64 Bytes availalble Wreg StsReg Temp Temp2 BitCount Counter DelCount AutoEEADR D0 D1 D2 R0 R1 N0 N1 N2 S0 S1 S2 HopNHi HopNLo HopCountHi HopCountLo HopOffsetHi HopOffsetLo HopDelay HopIncrement RxChar Stack1 Stack2 Stack3 Stack4 Stack5 Stack6 Stack7 Stack8 endc ;---------------------- end