Club PIC DDS VFO Project: Source Code Modifications by Pat McGuinness G4FDN
I think most members who undertook the kit construction were aware that the code used for the project originated from VK5TM. After his design was tested by Gareth G4XAT and Steve G4FYF, they requested several changes which I carried out. This short article documents the changes, before and after, and will hopefully encourage others to have a go at doing their own changes. It doesn’t attempt to be a full tutorial of the syntax of the code, but does illustrate what the code fragments are doing. All that is required to start understanding them is an appreciation of decimal and hexadecimal number representation and knowing that hexadecimal numbers are identified in the source code by a ‘0x’ prefix
The changes that were implemented were:
- Change the upper frequency limit from 30MHz to 62MHz
- Change the frequency autosave interval from2 seconds to 3 seconds
- Add LF Bands (137.5kHz & 472 kHz) and 60m and 6m
- Add 10Hz, 100Hz, and 10kHz frequency steps
- Incrementing the displayed version number to correlate with each change and also show the set upper frequency limit.
- In addition, a bug fix for the ‘CAL’ mode not outputting until the rotary encoder was moved has also been implemented.
Blue text is used to indicate the original code and red text the modified code.
Changing the upper frequency limit from 30MHz to 62MHz:
This involved changing four hexdecimal values (bytes) that represented the frequency limit as a 32 bit integer. The four bytes were arranged in order from most significant to least significant.
Original VK5TM Code:
#else // No multiplier
limit_3 equ 0x01 ; Most significant byte for 30 MHz
limit_2 equ 0xC9 ; Next byte
limit_1 equ 0xC3 ; Next byte
limit_0 equ 0x80 ; Least significant byte
#endif
NB: 1C9C380 in hexadecimal = 30000000
G4FDN modified code:
#else // No multiplier
; changed from 30MHz to 62MHz
limit_3 equ 0x03 ; Most significant byte for 62 MHz
limit_2 equ 0xB2 ; Next byte
limit_1 equ 0x0B ; Next byte
limit_0 equ 0x80 ; Least significant byte
#endif
NB: 3B20B80 in hexadecimal = 62000000
Changing the frequency autosave interval from 2 to 3 seconds:
Original VK5TM Code:
main
btfscsaved,0
gotopoll_encoder
; Start 2s timer interrupt routine
bsfSTATUS,RP0; Switch BANK1
MOVLWb'00000111'
MOVWFOPTION_REG
BCFSTATUS,RP0; Switch to BANK0
;
MOVLWb'00000100'
MOVWFINTCON; Enable Timer0 interrupt, Disable all others
BSFINTCON,GIE; Enable general interrupts
BSFINTCON,T0IE; Enable Timer0 interrupt
;
MOVLW39
MOVWFTMR0; Timer0 starting point, writing this will start timer after two ins. cyc.
MOVLW18; Overflow counter for 2 second
MOVWFCNT1
G4FDN modified code:
main
btfscsaved,0
gotopoll_encoder
; Start 3s timer interrupt routine
bsfSTATUS,RP0; Switch BANK1
MOVLWb'00000111'
MOVWFOPTION_REG
BCFSTATUS,RP0; Switch to BANK0
MOVLWb'00000100'
MOVWFINTCON; Enable Timer0 interrupt, Disable all others
BSFINTCON,GIE; Enable general interrupts
BSFINTCON,T0IE; Enable Timer0 interrupt
;
MOVLW39
MOVWFTMR0; Timer0 starting point, writing this will start timer after two ins. cyc.
; G4FDN - changed value from 18 to 27 -approx 3 seconds
MOVLW27; Overflow counter for 3 seconds
MOVWFCNT1
Add LF Bands (137.5kHz & 472 kHz) and 60m and 6m
The code for this is in two parts: an index to the end of a table and the table itself. Each entry in the table is four instructions long, with each group of four hexadecimal values representing the frequency as a 32 bit integer. New entries can be added to the end of the table or between existing entries. The constant ‘band_end’ must be incremented by 4 for each entry added. The band is incremented by pushing button PB_2 such that with every successive push the band is incremented from the current to the next.
Original VK5TM Code:
First code fragment:
band_end equ 0x28 ; The offset to the last band table entry
Second code fragment:
band_table
addwf PCL,f ;
retlw 0x00 ; 0 Hz
retlw 0x00 ;
retlw 0x00 ;
retlw 0x00 ;
retlw 0x00 ; 160 meters
retlw 0x1B ;
retlw 0x77 ;
retlw 0x40 ;
retlw 0x00 ; 80 meters
retlw 0x35 ;
retlw 0x67 ;
retlw 0xE0 ;
retlw 0x00 ; 40 meters
retlw 0x6A ;
retlw 0xCF ;
retlw 0xC0 ;
retlw 0x00 ; 30 meters
retlw 0x9A ;
retlw 0x1D ;
retlw 0x20 ;
retlw 0x00 ; 20 meters
retlw 0xD5 ;
retlw 0x9F ;
retlw 0x80 ;
retlw 0x01 ; 17 meters
retlw 0x13 ;
retlw 0xB2 ;
retlw 0x20 ;
retlw 0x01 ; 15 meters
retlw 0x40 ;
retlw 0x6F ;
retlw 0x40 ;
retlw 0x01 ; 12 meters
retlw 0x7B ;
retlw 0xCA ;
retlw 0x90 ;
retlw 0x01 ; 10 meters
retlw 0xAB ;
retlw 0x3F ;
retlw 0x00 ;
retlw 0x01 ; 30 MHz
retlw 0xC9 ;
retlw 0xC3 ;
retlw 0x80 ;
G4FDN modified code:
First code fragment:
;changed by G4FDN from 40 (0x28) to 52 (0x34) to allow for addition of 136kHz, 472kHz, 60m & 6m, and removal of 30MHz
band_end equ 0x34 ; The offset to the last band table entry (6 metres)
Second code fragment:
band_table
addwf PCL,f ;
retlw 0x00 ; 0 Hz
retlw 0x00 ;
retlw 0x00 ;
retlw 0x00 ;
retlw 0x00 ; 137.5 kHz
retlw 0x02 ;
retlw 0x12 ;
retlw 0x14 ;
retlw 0x00 ; 472 kHz
retlw 0x07 ;
retlw 0x33 ;
retlw 0xC0 ;
retlw 0x00 ; 160 metres
retlw 0x1B ;
retlw 0x77 ;
retlw 0x40 ;
retlw 0x00 ; 80 metres
retlw 0x35 ;
retlw 0x67 ;
retlw 0xE0 ;
retlw 0x00 ; 60 metres
retlw 0x50 ;
retlw 0x3D ;
retlw 0x04 ;
retlw 0x00 ; 40 metres
retlw 0x6A ;
retlw 0xCF ;
retlw 0xC0 ;
retlw 0x00 ; 30 metres
retlw 0x9A ;
retlw 0x1D ;
retlw 0x20 ;
retlw 0x00 ; 20 metres
retlw 0xD5 ;
retlw 0x9F ;
retlw 0x80 ;
retlw 0x01 ; 17 metres
retlw 0x13 ;
retlw 0xB2 ;
retlw 0x20 ;
retlw 0x01 ; 15 metres
retlw 0x40 ;
retlw 0x6F ;
retlw 0x40 ;
retlw 0x01 ; 12 metres
retlw 0x7B ;
retlw 0xCA ;
retlw 0x90 ;
retlw 0x01 ; 10 metres
retlw 0xAB ;
retlw 0x3F ;
retlw 0x00 ;
retlw 0x02 ; 6 metres
retlw 0xFA ;
retlw 0xF0 ;
retlw 0x80 ;
You may also notice I changed ‘meters’ to ‘metres’
Add 10Hz, 100Hz, and 10kHz frequency steps
The first code fragment sets integer values indicating a particular bit in a byte that will be used as a ‘flag’ to indicate the current step size as well as if PB_1 was pressed first and if ‘CAL’ mode is active. VK5TM’s original code only accommodated 1Hz, 1kHz, 100kHz and 1MHz steps. The second code fragment then uses the state of the flag bit to determine the current step size and then uses this to determine the next step size and set this on dependent on the pushbutton PB_1 presses. Embedded within the second code fragment are the hexadecimal values of the required step size. Up to 3 bytes are required for this, e.g. 1Hz requires 1 byte, whereas 1MHz requires 3 bytes
Original VK5TM Code:
First code fragment:
; PB_flags bits
PB1first equ 0 ; Bit set indicates PB1 pressed first
PB1Calibrate_Active equ 1 ; Bit set indicates calibrate is now active
KHZ equ 2
KHZ100 equ 3
MHZ equ 4
Second code fragment:
step
;
; Determine step size to use (1 Hz or 1 kHz or 100kHz or 1MHz).
;
clrffstep_3;
clrffstep_2;
clrffstep_1;
btfscPB_FLAGS,KHZ; test if 1khz flag pb_flags,khz bit is set
gotokhz; yes - goto khz
btfscPB_FLAGS,KHZ100; test if 100khz flag pb_flags,khz100 bit is set
gotokhz100; yes - goto khz100
btfscPB_FLAGS,MHZ; test if 1MHz flag pb_flags,mhz bit is set
gotomhz; yes - goto mhz
movlw0x01; Guess that we want 1 Hz steps by
movwffstep_0; setting fstep to one.
gotogo_step;
khzmovlw0xE8; Setup for step of 1 kHz
movwffstep_0;
movlw0x03;
movwffstep_1;
gotogo_step;
khz100movlw0xA0; Setup for step of 100 kHz
movwffstep_0;
movlw0x86;
movwffstep_1;
movlw0x01;
movwffstep_2;
gotogo_step;
mhzmovlw0x0F; Setup for step of 1 MHz
movwffstep_2;
movlw0x42;
movwffstep_1;
movlw0x40;
movwffstep_0;
G4FDN modified code:
This required additional declarations in the first code fragment to cover the additional step sizes and changes to some existing values of the flag bits so they increased with the step size.
First code fragment:
;
; PB_flags bits
PB1first equ 0 ; Bit set indicates PB1 pressed first
PB1Calibrate_Active equ 1 ; Bit set indicates calibrate is now active
HZ10 equ 2
HZ100 equ 3
KHZ equ 4
KHZ10 equ 5
KHZ100 equ 6
MHZ equ 7
;
Second code fragment:
step
;
; Determine step size to use (1Hz, 10Hz, 100Hz, 1kHz, 10kHz, 100kHz or 1MHz).
;
clrffstep_3;
clrffstep_2;
clrffstep_1;
btfscPB_FLAGS,HZ10; test if 10Hz flag pb_flags,hz10 bit is set
gotohz10; yes - goto hz10
btfscPB_FLAGS,HZ100; test if 100Hz flag pb_flags,hz100 bit is set
gotohz100; yes - goto hz100
btfscPB_FLAGS,KHZ; test if 1khz flag pb_flags,khz bit is set
gotokhz; yes - goto khz
btfscPB_FLAGS,KHZ10; test if 10kHz flag pb_flags,khz10 bit is set
gotokhz10; yes - goto khz10
btfscPB_FLAGS,KHZ100; test if 100khz flag pb_flags,khz100 bit is set
gotokhz100; yes - goto khz100
btfscPB_FLAGS,MHZ; test if 1MHz flag pb_flags,mhz bit is set
gotomhz; yes - goto mhz
movlw0x01; Guess that we want 1 Hz steps by
movwffstep_0; setting fstep to one.
gotogo_step;
hz10movlw0x0A; Setup for step of 10 Hz
movwffstep_0;
gotogo_step;
hz100movlw0x64; Setup for step of 100 Hz
movwffstep_0;
gotogo_step;
khzmovlw0xE8; Setup for step of 1 kHz
movwffstep_0;
movlw0x03;
movwffstep_1;
gotogo_step;
khz10movlw0x10; Setup for step of 10 kHz
movwffstep_0;
movlw0x27;
movwffstep_1;
gotogo_step;
khz100movlw0xA0; Setup for step of 100 kHz
movwffstep_0;
movlw0x86;
movwffstep_1;
movlw0x01;
movwffstep_2;
gotogo_step;
mhzmovlw0x0F; Setup for step of 1 MHz
movwffstep_2;
movlw0x42;
movwffstep_1;
movlw0x40;
movwffstep_0;
Incrementing the displayed version number to correlate with each change and also show the set upper frequency limit.
The original code would have displayed PICELGEN7.4-30 on startup.
Original VK5TM Code:
; Info for power-up display
MCODE_REV_0 equ '7' ; Current code version is 7.4
MCODE_REV_1 equ '.' ;
MCODE_REV_2 equ '4' ;
MCODE_REV_3 equ '-' ;
#ifdef AD9850
MCODE_REV_4 equ '3' ;
MCODE_REV_5 equ '0' ;
#endif
G4FDN modified Code:
The modified code displaysPICELGEN7.4662 on startup.
; Info for power-up display
MCODE_REV_0 equ '7' ; Current code version is 7.4
MCODE_REV_1 equ '.' ;
MCODE_REV_2 equ '4' ;
MCODE_REV_3 equ '6' ;
#ifdef AD9850
; changed from 30 to 62
MCODE_REV_4 equ '6' ;
MCODE_REV_5 equ '2' ;
#endif
Bug fix for the ‘CAL’ mode not outputting until the rotary encoder was moved
This was fixed by adding a piece of code to ensure that the AD9850 chip was initialised to zero twice (just to make sure!) VK5TM has also now implemented this in his 7.4a version code.
Original VK5TM Code:
start
movlw 0x07 ; Code to turn off the analog comparators
movwf CMCON ; Turn off comparators
call wait_8ms ; Wait for LCD to settle
bsf STATUS,RP0 ; Switch to bank 1
bcf 0x01,7 ; Enable weak pullups
movlw 0xFF ; Tristate PORTA (all Inputs )
movwf TRISA ;
clrf TRISB ; Set port B to all outputs
bcf STATUS,RP0 ; Switch back to bank 0
call init_LCD ; Initialize the LCD
call display_version ; Display title and version
bsfsaved,0; set flag to disable interrupts during calibrate
;
G4FDN Modified Code:
start
movlw 0x07 ; Code to turn off the analog comparitors
movwf CMCON ; Turn off comparators
call wait_8ms ; Wait for LCD to settle
bsf STATUS,RP0 ; Switch to bank 1
bcf 0x01,7 ; Enable weak pullups
movlw 0xFF ; Tristate PORTA (all Inputs )
movwf TRISA ;
clrf TRISB ; Set port B to all outputs
bcf STATUS,RP0 ; Switch back to bank 0
call init_LCD ; Initialize the LCD
call display_version ; Display title and version
bsfsaved,0; set flag to disable interrupts during calibrate
;
; Initialize DDS Module with zero freq
clrfAD9851_0; AD9850/51 control word
clrfAD9851_1; (5 bytes)
clrfAD9851_2
clrfAD9851_3
clrfAD9851_4
callsend_dds_word; Send it to the DDS
callsend_dds_word; twice to be sure
call init_LCD ; Initialize the LCD
call display_version ; Display title and version
bsfsaved,0; set flag to disable interrupts during calibrate
A few weeks ago Steve G4FYF asked for further assistance in changing the code again as he was using the DDS VFO in a SWR analyser project and needed bands to be set to mid frequency rather than lower edge and also a reduced number of frequency step changes. He did the mid-band frequencies change himself after explaining how the band table worked, but his request indicated that it could be helpful to explain/show how things were done to a wider audience to get more people having a go at ‘tweaking’
One does not have to fully understand everything about about PIC architecture and assembly language to have a go –no more than one does in say modifying PMR equipment to get it on 2M. You don’t need the full schematic or circuit description –just sufficient knowledge to know which bits need re-tuning and/or additional capacitors or changed capacitors to reduce/change the resonant frequency.
I always feel that one only truly learns by ‘doing’ and making mistakes on the way is part of the process.
If you want some background reading I can recommend the RSGB’s PIC Basics by G8CQZ and ARRL’s PIC Programming for Beginners byWA8SME. Also, if you keep your RadComs have a look at EI9GQ’s Homebrew articles on the PIC based frequency counter (a previous club project) and associated PIC programming and programmer.
It doesn’t cost much to get going on this. A free assembler, compiler, debugger, and programming software in an integrated environment is available from MicroChip, and PIC programmers are available for £5 to £10 on eBay and elsewhere if you are not tempted to build your own for less.
Have a go –I’m sure several of you will find it absorbing and compelling once you have got over the frustration stage of mistakes made.