Club PIC DDS VFO Project: Source Code Modifications by Pat Mcguinness G4FDN

Club PIC DDS VFO Project: Source Code Modifications by Pat Mcguinness G4FDN

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:

  1. Change the upper frequency limit from 30MHz to 62MHz
  2. Change the frequency autosave interval from2 seconds to 3 seconds
  3. Add LF Bands (137.5kHz & 472 kHz) and 60m and 6m
  4. Add 10Hz, 100Hz, and 10kHz frequency steps
  5. Incrementing the displayed version number to correlate with each change and also show the set upper frequency limit.
  6. 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.