F150/155 Software development
Introduction
These instructions are intended for those
who want to write their own software to drive the F150/155 generators.
If you want to drive one of our other generators, please email us and
we will outline the differences. In this text, we will refer to the
generator as a F150 but the instructions for the F155 are the same. The
F150 is driven via a serial port. It can be driven by any
computer that supports a serial port (or a USB port on MAC or PC via a
third party adapter). This includes some models of Palm Pilot, Pocket
PC, Psion and cellular phones.
The F150 is driven by very simple
low level byte instructions. For each of the two channels, the
instructions are:
-Run a specific frequency
-Stop running frequencies
-Change the duty cycle
Any other higher level control needs to
be implemented by your software. For example, in the F100 software for
PC and PalmOS, the commands sweep, dwell, converge, goto, fuzz are all
implemented in the PC/Palm software.
Setting up communication with the
F150
You need to setup your communication port
at 19200 baud, 8 bits, no parity, one stop bit. The F150 uses only 3
wires for serial communication: transmit, receive and ground (we do not use
cts/rts). So you also need to set hardware handshake to off and software handshake (xon/xoff) to off.
Example
double xtals[4];
double pXtals[4];
double nw;
double Nw;
double xtal; // channel a accumulator freq
double pXtal; // channel b accumulator freq
double nwx;
double Nwx;
my_u32 N; // main freq accumulator factor
xtals[0]=5000000.0;xtals[1]=50000000.0;xtals[2]=180000000.0; //channel
a frequencies, varies with generator model
pXtals[0] = 800000;pXtals[1] =
1600000;pXtals[2]=1454545.45454545454545454545; //channel b frequencies
//Query the generator for its ID
and from that, figure out the DDS xtal frequency for both channels
//here we assume you have already opened the serial port at 19200,8,N,1, no hardware/software handshake
int res;
reset();//reset generator
u8 cmd[]={120}; //id query character command
is 'x'
u8 rsp[255];
writeDevice(cmd,1); //send id command to generator
if (readDevice(rsp,11,100)!=11) {//read id string from generator, exit
if we do not get 11 characters back
close();
return false;
}
//The generaotr will return a 11
character string in the format
"PFG nnn X x"
if (rsp[0]!='P' || rsp[1]!='F' || rsp[2]!='G' || rsp[3]!='
' || rsp[4]!='0' || rsp[5]!='0') {
//response is invalid, exit
close();
exit();
}
X=rsp[8]-0x30;
x=rsp[10]-0x30;
//now that we know the speed of
each DDS crystal, lets compute a couple of variables used when sending
frequency commands
nw=16777216.0; // 24 bits DDS: 2 exp 24
Nw=536870912.0; // 29 bits DDS: 2 exp 29
xtal=50000000.0; // chan A default accumulator freq
pXtal=800000.0; // chan B default accumulator freq
if ((X>2) || (X<0)) xtal=xtals[2];
else xtal=xtals[X];
if ((x>2) ||(x<0) ) pXtal=pXtals[2];
else pXtal=pXtals[x];
nwx=nw/pXtal;
Nwx=Nw/xtal;
chanHigh(1);
// make sure channel B is high since we are not using it yet
setDuty (0,50.0); //set duty on channel A to 50%
runSingle(1000.0,0); //run 1000HZ on channel A
setDuty (0,75.0); //set duty on channel
A to 75%
setDuty (1,50.0);
//set duty on channel B to 50%
runSingle(1,4.0); //run 4HZ on channel B
setDuty (1,20.0); /set duty on channel B
to 20%
chanLow(1); //effectively stops all frequency generation
//==================================================================
//Sets the specified channel to low (0 volt) output
bool FGen::chanLow(int
channel) {
//channel not used yet since B is always used
u8 cmd2[]={99,0}; // c0
writeDevice(cmd2,2);
u8 cmd[]={110,0,0,0}; //n000
writeDevice(cmd,4);
return true;
}
//==================================================================
//Set the specified channel to high (5 volt) output
bool FGen::chanHigh(int channel) {
u8 cmd[]={99,0x01,0,0}; // c1
switch (channel) {
case 1: //channel B
writeDevice(cmd,2);
cmd[0]=110;cmd[1]=0;cmd[2]=0;cmd[3]=0; //n000
writeDevice(cmd,4);
break;
case 0: //channel A
u8 cmd4[]= {78,0,0,0};
writeDevice(cmd4,4);
cmd4[0]=67; // setDuty byte to 11111111
cmd4[1]=255;
writeDevice(cmd4,2);
break;
}//switch
return true;
}
//=========================================================================================================
// Send command to run a frequency on specified channel
bool runSingle(double inFreq,int
progChan) {
switch (progChan) {
case 0: //Channel A
//This channel is 29 bit dds but we send only 24 bits since the 5 MSB are fixed in hardware. (We do not use the full bandwidth to reduce jitter)
N=(my_u32)((inFreq*Nwx)+.5);
u8 *cmd;
u8 cmd4[]=
{78,(u8)((N&0xff0000)>>16),(u8)((N&0xff00)>>8),(u8)(N&0xff)};
cmd=cmd4;
writeDevice(cmd,4);
break;
case 1: //Channel B
bFreq=inFreq;
N=(my_u32)((inFreq*nwx)+.5);
u8
cmd5[]={110,(u8)((N&0xff0000)>>16),(u8)((N&0xff00)>>8),(u8)(N&0xff)};
//n
writeDevice(cmd5,4);
break;
}//switch
return true;
}
//==========================================================================================
// Send command to set duty in percentage on the specified channel
bool setDuty(int channel,double tmpDuty) {
u8 cmd[]={67,0};
switch (channel) {
case 0: // channel A
cmd[0]=67;
if (tmpDuty>96.875) tmpDuty=96.875;
if (tmpDuty<3.125) tmpDuty=3.125;
cmd[1]=(u8)((tmpDuty*32.0/100.0)+.5);
writeDevice(cmd,2);
return true;
break;
case 1: //channel B
if (tmpDuty<=0) tmpDuty=.39;
if (tmpDuty>=100) tmpDuty=99.6;
cmd[0]=99;
cmd[1]=(u8)((tmpDuty*255.0/100.0)+.5);
//rounding
bDuty=tmpDuty;
writeDevice(cmd,2);
return true;
break;
} //switch
return true;
}
//=====================================================================================
//Empty serial receive buffer on generator. Allways do this when
starting a new program sequence
reset() {
int res;
u8 cmd[]={0,0,0,0,0,0,0,0,0,0,116}; // 116=reset DDS
writeDevice(cmd,11);
PurgeComm(hCom,PURGE_RXABORT&PURGE_RXCLEAR);
//flush buffer on windows serial comm
return true;
}