;__________________________________________________________________________ ; ; PROGRAM : Huff_Puff.asm ; ; DATE : 25/12/06 ; LAST UPDATE : 29/12/06 ; ; DESCRIPTION : Fast Huff Puff VFO Stabiliser. ; ; HARDWARE : H_P_PIC board with 16F88 @ 20 MHz ; ASSEMBLER : MPASM v3.20.08 / case sensitive ; ; AUTHOR : Thanks to Ron G4GXO for the initial program ; Rewritten by F6HSI ; ; TESTS : seems to work. needs intensive tests... ;-------------------------------------------------------------------------- ; This program does exactly the same job as the original. ; (only minor variations) ; ; First it has been rewritten only for fun and to understand how it works. ; Then it has be done in such a way that it is an useful tool to play with ; various step sizes without to retype anything. ; The "BIG" shift register is only defined by it's starting address. ; Once the step size is defined, the number of registers in each bank are ; automatically allocated. ; The last register is always at the same place (in common RAM) ; The output bit position is also set automatically. ; As the 3 major functions (Detect, Shift and Sample_Delay) are used only ; once, they are not subroutines, but macros.(side effect, no stack usage) ; These macros (especially Shift) use all the possibilities of MPASM to ; avoid repetitive typing. ; ; 1- Get_Input_Sample (was in line) : ;------------------------------------ ; Shift_Register_Input = input sample from Timer_1 ; 2- Compute_Control_Voltage (was Detect) : ;------------------------------------------ ; Control_Voltage = (Shift_Register_Input XOR Shift_Register_Output) ; ; As it is a "true xor bit", it could work with any bit and the result ; could go to any pin. ; ; 3- Shift_One_Bit (was Shift) : ;------------------------------- ; Does exactly the same job as previous, but avoids to type 251 rlf xxx,f ; ; 4- Adjust_Sample_Time_To_100us (was Sample_Delay) : ;---------------------------------------------------- ; To make modifications easier, the computational time for each piece ; of code is automatically update for the final delay. ; Furthermore this delay is automatically defined, so no nops to count. ; ; 5- Trigger_ON / Trigger_OFF : ;------------------------------ ; If DEBUG is defined as YES Then a signal of 100 µs period can be ; measured on RB1 (pin7). ;__________________________________________________________________________ ; ; DIRECTIVES ;__________________________________________________________________________ list p = 16F88, n = 0 , r = dec , x = ON, st = ON errorlevel -203, -207,-302 #define _OSC_TYPE _HS_OSC #define _OSC_FREQUENCY 20 MHz #include P16F88.inc ; Original file from MICROCHIP #include NewDir.inc ; New/modified directives for MPASM #include Aliases_88.inc #include Fuses_88.inc ; Configuration word setup ;__________________________________________________________________________ ; ; CONSTANTS ;__________________________________________________________________________ DEBUG = YES START_OF_BANK0 = 0x20 SIZE_OF_BANK0 = 80 START_OF_BANK1 = 0xA0 SIZE_OF_BANK1 = 80 START_OF_BANK2 = 0x110 SIZE_OF_BANK2 = 96 START_OF_BANK3 = 0x190 SIZE_OF_BANK3 = 96 MAX_REGISTERS = SIZE_OF_BANK0 + SIZE_OF_BANK1 + SIZE_OF_BANK2 + SIZE_OF_BANK3 START_OF_COMMON = 0x70 ; 16 bytes reserved for variables ;__________________________________________________________________________ ; ; ALLOCATE THE BIG SHIFT REGISTER ;__________________________________________________________________________ ; 1 - Define the number of bits (taps) for the shift register ;------------------------------------------------------------ SAMPLE_FREQUENCY = 10 kHz ; is a constant at present time step_size = 10 Hz ; Tests have been done with 8, 10, 20, 25, 33, 50 and 100 Hz step_size ; also with 12.5 Hz but as MPASM works only with integers, you have to modify ; the next line as : NUMBER_OF_BITS = 1600 NUMBER_OF_BITS = 2 * SAMPLE_FREQUENCY / step_size ; 2- Define the number of registers required ;------------------------------------------- NUMBER_OF_REGISTERS = NUMBER_OF_BITS / 8 LAST_BIT = NUMBER_OF_BITS - (NUMBER_OF_REGISTERS *8) ; 3- Allocate registers in the 4 available banks ;----------------------------------------------- REGISTERS_IN_BANK0 = 0 REGISTERS_IN_BANK1 = 0 REGISTERS_IN_BANK2 = 0 REGISTERS_IN_BANK3 = 0 if(NUMBER_OF_REGISTERS <= MAX_REGISTERS) REMAINING_REGISTERS = NUMBER_OF_REGISTERS n = 0 while(n <= 3) ; Allocate_Registers_In_Bank(n) ;------------------------------ if(REMAINING_REGISTERS !=0) _min REGISTERS_IN_BANK#v(n), REMAINING_REGISTERS, SIZE_OF_BANK#v(n) REMAINING_REGISTERS = REMAINING_REGISTERS - REGISTERS_IN_BANK#v(n) endif _inc n endw else error "not enough memory" endif ;__________________________________________________________________________ ; ; VARIABLES ;__________________________________________________________________________ cblock START_OF_BANK0 Shift_Register endc cblock START_OF_COMMON Last_Register endc ; Aliases ;-------- #define Shift_Register_Input Shift_Register, 0 #define Shift_Register_Output Last_Register , LAST_BIT #define Save_W FSR #define Control_Voltage PortB,0 #define Trigger PortB,1 ; Only for debug purpose (100 µs signal) ;__________________________________________________________________________ ; ; SOME DEFINES ;__________________________________________________________________________ #define Forever goto Do ;__________________________________________________________________________ ; ; INIT RESET & INTERRUPT VECTORS ;__________________________________________________________________________ org 0 goto Main ;__________________________________________________________________________ ; ; INCLUDE DRIVERS, EXTERNAL MACROS, etc ;__________________________________________________________________________ ; none ;__________________________________________________________________________ ; ; MACROS ;__________________________________________________________________________ ; This MPASM variable is used to cumulate the timing of each function ;-------------------------------------------------------------------- elapsed_time = 2 ; 2 for Do / Forever loop ;-------------------------------------------------------------------------- Adjust_Sample_Time_To_100us macro ;------------------------------------------------------------------------ok ; A 100 µs loop requires 500 cycles with a 20 MHz Xtal ; elapsed_time has been updated in each other macro Delay_N_Cycles(500 - elapsed_time) endm ;-------------------------------------------------------------------------- Compute_Control_Voltage macro ; 8 cycles ;------------------------------------------------------------------------ok ; Compares states of input and output of the shift register with an XOR ; function. This output will be integrated via a low-pass filter to provide ; a clean, slow changing control voltage for the varactor. local case_00, case_01, case_10, case_11, end_case ; Control_Voltage = (Shift_Register_Input ^ Shift_Register_Output) ;----------------------------------------------------------------- ; b0 = 0 | b0 = 0 | b0 = 1 | b0 = 1 ;------------------------------------------------- btfsc Shift_Register_Input ; 2 | 2 | 1 | 1 goto $+4 ; 0 | 0 | 2 | 2 btfss Shift_Register_Output ; 2 if b7 = 1 | 1 if b7 = 0 | 0 | 0 goto case_00 ; 0 | 2 | 0 | 0 goto case_01 ; 2 | 0 | 0 | 0 btfss Shift_Register_Output ; 0 | 0 | 2 if b7 = 1 | 1 if b7 = 0 goto case_10 ; 0 | 0 | 0 | 2 case_11 case_00 bcf Control_Voltage ; 0 | 1 | 1 | 0 goto end_case ; 0 | 2 | 2 | 0 case_01 case_10 bsf Control_Voltage ; 1 | 0 | 0 | 1 nop ; 1 | 0 | 0 | 1 end_case ;--- --- --- --- ; 8 | 8 | 8 | 8 elapsed_time = elapsed_time + 8 endm ;-------------------------------------------------------------------------- Delay_N_Cycles macro n ; n cycles ;------------------------------------------------------------------------ok ; With 1 <= n <= 1020 local count, remainder count = n / 4 remainder = n -(count * 4) ; Timing loop ;------------ if(count != 0) movlw count ; ; addlw -1 ; -> (4 * count) cycles btfss Status, Z ; goto $-2 ; endif ; Add 1, 2 or 3 cycles to get exact time ;--------------------------------------- while(remainder >=1) nop _dec remainder endw endm ;-------------------------------------------------------------------------- Get_Input_Sample macro ; 3 cycles ;------------------------------------------------------------------------ok ; Shift_Register_Input = Timer1,0 ;--------------------------------- bsf Shift_Register_Input ; 1 btfss Timer1,0 ; 1 bcf Shift_Register_Input ; 1 elapsed_time = elapsed_time + 3 endm ;-------------------------------------------------------------------------- Init macro ;------------------------------------------------------------------------ok clrf InterruptControlRegister ; Digital I/O on PORTS A&B ;------------------------- banksel ANSEL clrf ANSEL ; No weak pull ups ;----------------- bsf FlagPullUpDisable ; VFO = input on RB6 Control_Voltage = output on RB0 ;---------------------------------------------------- ; 76543210 movlw b'11111100' ; Plus Trigger on RB1 movwf TrisB ; Timer_1 enabled with : timer ON bit 0 = 1 ; external clock from RB6 bit 1 = 1 ; async operation bit 2 = 1 ; no prescaler bit 4 & 5 = 0 ;------------------------------------------------------------- movlw b'00000111' banksel Timer1_ControlRegister movwf Timer1_ControlRegister endm ;-------------------------------------------------------------------------- Trigger_OFF macro ; Only for debug purpose ;------------------------------------------------------------------------ok if(DEBUG == YES) bcf Trigger endif endm ;-------------------------------------------------------------------------- Trigger_ON macro ; Only for debug purpose ; 2 cycles ;------------------------------------------------------------------------ok if(DEBUG == YES) bsf Trigger elapsed_time = elapsed_time +2; always used with Trigger_OFF endif endm ;-------------------------------------------------------------------------- Shift_One_Bit macro ;------------------------------------------------------------------------ok clrc ; 1 elapsed_time = elapsed_time +1 n = 0 while(n <=3) if(REGISTERS_IN_BANK#v(n) !=0) banksel START_OF_BANK#v(n) Shift_Registers START_OF_BANK#v(n), REGISTERS_IN_BANK#v(n) elapsed_time = elapsed_time + REGISTERS_IN_BANK#v(n) +2 endif _inc n endw rlf Last_Register, f ; 1 banksel START_OF_BANK0 ; 2 elapsed_time = elapsed_time + 3 ; elapsed_time = NUMBER_OF_REGISTERS + (NB_OF_BANKS_USED * 2) + 4 cycles endm ;-------------------------------------------------------------------------- Shift_Registers macro start_address, nb_of_registers ; nb_of_registers cycles ;------------------------------------------------------------------------ok nolist ; not very useful to see all the rlf xx,f local next_address next_address = start_address while(next_address < start_address + nb_of_registers) rlf next_address, f ; 1 _inc next_address endw list endm ;__________________________________________________________________________ ; ; SUBROUTINES ;__________________________________________________________________________ ; none ;__________________________________________________________________________ ;__________________________________________________________________________ ; ; MAIN PROGRAM ;__________________________________________________________________________ ;__________________________________________________________________________ Main Init Do Trigger_ON Get_Input_Sample Compute_Control_Voltage Shift_One_Bit Adjust_Sample_Time_To_100us Trigger_OFF Forever ;__________________________________________________________________________ ; ; INTERRUPT SERVICE ;__________________________________________________________________________ IntServ retfie ; Nothing to do with IT !!! ;__________________________________________________________________________ ; EndOfProgram end