With the DDS RAM registers a desired function "frequency (time)" can be implemented for one of the output channels and triggered either by the serial terminal or by an external signal on one of the mbed pins.

Dependencies:   mbed

main.cpp

Committer:
ahambi
Date:
2012-11-09
Revision:
7:c186636817d0
Parent:
0:2160f1821475

File content as of revision 7:c186636817d0:

//      ****************************************
//      *** frequency ramps with the RAM ***
//      ****************************************

#include "mbed.h"
#include "DDS.h"

Serial          pc(USBTX, USBRX);
DigitalOut      myled(LED1);
DigitalOut      cs2(p11);
DigitalOut      cs1(p8);
DigitalOut      rst(p9);
DigitalOut      update(p10);
DigitalOut      ps0(p12);
DigitalOut      ps1(p14);
DigitalOut      trigger(p13);
DigitalOut      trigger1(p23);
DigitalOut      trigger2(p24);
InterruptIn     mcs(p21);  //InterruptIn description: http://mbed.org/handbook/InterruptIn
DigitalIn       mexp(p22);   //DigitalIn description: http://mbed.org/handbook/DigitalIn
DDS             DDS(p5, p6, p7, p8, p9, p10);

// counting variables:
int     i = 0;
int     j = 0;
// frequency of reference clock connected to the DDS board:
double  ref_clock = 400.0e6;

// ##################### definition of functions ############################

// reset the DDS: 
int reset() {
    rst = 0;
    rst = 1;
    wait(0.1);
    rst = 0 ;
    return 0;
}

// choosing one of the two output channels is done with this functions:
int ch_1() {
    cs1 = 0;
    cs2 = 1;
    return 0;
}
int ch_2() {
    cs1 = 1;
    cs2 = 0;
    return 0;
}

// This function always rounds values up (in mode ?? of the DDS a problem occurs
// if the final value is not reached
int round(double a) {
    return int(a + 0.5);
}

// Calculate the "Frequency Tuning Word (FTWO)" for the DDS registers:
uint32_t FTWO_func(double frequency) {
    return 0xFFFFFFFF & round(frequency/ref_clock*pow(2.0,32.0));
    }

// RSCW0, RSCW1, RSCW2 and RSCW3 are the RAM profiles of the DDS which can be filled with different
// parts of the ramp: 
// ************* RSCW0 ******************    
void writeRSCW0(int r0, int r1, uint32_t RSCW, double f[]) {
    int         R_used        = r1-r0;
    uint32_t    FTWO[R_used];
    ps0 = 0;
    ps1 = 0; 
    update = 0;
    // For the structure of the RSCW0 byte see the register map of the DDS.
    // Instruction byte: page 25, we want to write (0), so 0100
    // and internal adress of the register to be written in
    DDS._spi.write(0x00 | (0x07 & 0x1F));
    // byte 5: Ramp rate first part
    DDS._spi.write(0xFF & RSCW);
    // byte 4: Ramp rate second part
    DDS._spi.write(0xFF & (RSCW >> 8));
    // byte 3: final address <7:0>
    DDS._spi.write(0xFF & r1);
    // byte 2
    DDS._spi.write(((r0 << 2) & 0xFC) | ((r1 >> 8) & 0x03));
    // byte 1: beginning address <9:6>
    DDS._spi.write(0x20 | (((r0 >> 6) & 0x0F)));
        update = 1;
        wait_us(10);//5*1/(12.0e6));
        update =0;
    
    // The frequency ramp is given as an array of frequencies. Here the frequency tuning 
    // words (FTWOs) are calculated:  
    i = 0;
    while (i<=(R_used)) {
        FTWO[R_used-i] = FTWO_func(f[i]);
        i += 1;
        }
    // Print start and final value of the RAM part:
    pc.printf("RSCW0 written: %lf %lf \r\n", f[0], f[R_used]);
    // Select the combination of ps0 and ps1 belonging to RSCW0 and start the RAM writing process:    
    ps0 = 0;
    ps1 = 0; 
    // Send instruction byte to start the RAM writing process:   
    DDS._spi.write(0x0B);
    // Write the frequency tuning words into the RAM:
    i = 0;
    while (i<=(R_used)) {
        DDS.RAM_write_FTWO(FTWO[i]);
        i += 1;
        }
    }
    
// ************* RSCW1 ******************  
void writeRSCW1(int r0, int r1, uint32_t RSCW, double f[]) {
    int         R_used        = r1-r0;
    uint32_t    FTWO[R_used];
    ps0 = 1;
    ps1 = 0; 
    update = 0;
    DDS._spi.write(0x00 | (0x08 & 0x1F));
    DDS._spi.write(0xFF & RSCW);
    DDS._spi.write(0xFF & (RSCW >> 8));
    DDS._spi.write(0xFF & r1);
    DDS._spi.write(((r0 << 2) & 0xFC) | ((r1 >> 8) & 0x03));
    DDS._spi.write(0x20 | (((r0 >> 6) & 0x0F)));
        update = 1;
        wait_us(10);
        update =0;
       
    i = 0;
    while (i<=(R_used)) {
        FTWO[R_used-i] = FTWO_func(f[i]);
        i += 1;
        } 
    pc.printf("RSCW1 written: %lf %lf \r\n", f[0], f[R_used]);
        
    ps0 = 1;
    ps1 = 0; 
    DDS._spi.write(0x0B);
    i = 0;
    while (i<=(R_used)) {
        DDS.RAM_write_FTWO(FTWO[i]);
        i += 1;
        }
    }

// ************* RSCW2 ******************     
void writeRSCW2(int r0, int r1, uint32_t RSCW, double f[]) {
    int         R_used        = r1-r0;
    uint32_t    FTWO[R_used];
    ps0 = 0;
    ps1 = 1; 
    update = 0;
    DDS._spi.write(0x00 | (0x09 & 0x1F));
    DDS._spi.write(0xFF & RSCW);
    DDS._spi.write(0xFF & (RSCW >> 8));
    DDS._spi.write(0xFF & r1);
    DDS._spi.write(((r0 << 2) & 0xFC) | ((r1 >> 8) & 0x03));
    DDS._spi.write(0x20 | (((r0 >> 6) & 0x0F)));
        update = 1;
        wait_us(10);
        update =0;
      
    i = 0;
    while (i<=(R_used)) {
        FTWO[R_used-i] = FTWO_func(f[i]);
        i += 1;
        }

    pc.printf("RSCW0 written: %lf %lf \r\n", f[0], f[R_used]);        
    ps0 = 0;
    ps1 = 1; 
   
    DDS._spi.write(0x0B);
    i = 0;
    while (i<=(R_used)) {
        DDS.RAM_write_FTWO(FTWO[i]);
        i += 1;
        }
    }
    
// ************* RSCW3 ****************** 
void writeRSCW3(int r0, int r1, uint32_t RSCW, double f[]) {
    int         R_used        = r1-r0;
    uint32_t    FTWO[R_used];
    ps0 = 1;
    ps1 = 1; 
    update = 0;
    DDS._spi.write(0x00 | (0x0A & 0x1F));
    DDS._spi.write(0xFF & RSCW);
    DDS._spi.write(0xFF & (RSCW >> 8));
    DDS._spi.write(0xFF & r1);
    DDS._spi.write(((r0 << 2) & 0xFC) | ((r1 >> 8) & 0x03));
    DDS._spi.write(0x20 | (((r0 >> 6) & 0x0F)));
        update = 1;
        wait_us(10);
        update =0;
      
    i = 0;
    while (i<=(R_used)) {
        FTWO[R_used-i] = FTWO_func(f[i]);
        i += 1;
        }

    pc.printf("RSCW0 written: %lf %lf \r\n", f[0], f[R_used]);
        
    ps0 = 1;
    ps1 = 1; 
    DDS._spi.write(0x0B);
    i = 0;
    while (i<=(R_used)) {
        DDS.RAM_write_FTWO(FTWO[i]);
        i += 1;
        }
    }

// Function to calculate the RSCW-word used in RSCW1, RSCW2, RSCW3 and RSCW4
uint64_t RSCW_func(int ram0, int ram1, double trise) {
    int RAM_used = ram1-ram0+1;
    double tmin = 1.0*4.0/ref_clock*RAM_used;       // minimum 1 dwell of time 4/clock at each address
    double tmax = 65535.0*4.0/ref_clock*RAM_used;   // 16 bit register corresponding to 65535 dwells
    if (trise < tmin) { pc.printf("ERROR: ramp time too small. Minimum: %f \r \n", tmin); };
    if (trise > tmax) { pc.printf("ERROR: ramp time too large. Maximum: %f \r \n", tmax); };
    int dwells  = round(trise/(4.0/ref_clock*RAM_used));
    pc.printf(" %i dwells at each address ---> %f ramp time. \r \n", dwells, dwells*RAM_used*4.0/ref_clock);
    return 0xFFFF & dwells;
    }
   
// The wait-function doesn't offer time resolution of mikroseconds. By using a process like
// counting up an integer number and measuring the time the mbed needs for this process a time
// resolution of some tens of nano-seconds can be reached. "counter()" is used in "start_ramp()" 
// below:
int counter(double t) {
    int bins = int((t-91.8160e-9)/(41.6664e-9) + 0.5);
    return bins;
     };
   
int start_ramp(double trise, double tstay) {
            int i = 0;
            int count = counter(trise+tstay);
            ps0 = 1;
            ps1 = 0;
            //-----------------------------
            // NEVER EVER change this loop! (Allows for time measurement, see above)
            trigger = 0;
            trigger = 1;
            while(i<count){
                i += 1;
            }
            trigger = 0;
            //-----------------------------
            ps0 = 0;
            ps1 = 0;
            i = 0;
            while(i<count){
                i += 1;
            }
    return 0;
    };
   
// Functions used to select output channel 1 or 2 upon receive of an external trigger signal:
void check_up(){
    ps0 = 0;
    ps1 = 1;
    ch_1(); DDS.CFR1_write(0x00000200);
    ch_2(); DDS.CFR1_write(0x80000200);
    };
   
void check_down() {
    ps0 = 0;
    ps1 = 1;
    ch_2(); DDS.CFR1_write(0x00000200);
    ch_1(); DDS.CFR1_write(0x80000200);
    };

// ############################################################
// ##################### main part ############################

int main() {

    pc.printf(" \r \r \n \n ***** frequency sweep with DDS in RAM mode***** \r \r \n \n");
    pc.printf("Enter: \r \n");
    pc.printf("'1' or '2' --> select which of the two output channel should be ramped. \r \n");
    pc.printf("'a' --> frequency ramp with parameters 'trise' and 'tstay' and the frequency values in the mbed code is started and repeated with about 50 Hz. A trigger signal lies on output pin 13 of the mbed. \r \n");
    pc.printf("'t' --> read in a new value for 'tstay' \r \n");

    reset();
    
    double      tstay           = 50.0e-6;
    
    // intermediate frequencies
    double      frequency0      = 79.5e6;// both channels are initiated on this frequency
    double      frequency1      = 80.5e6;
    // tuning word RSCW0 variables
    double      trise_00        = 100e-6;
    int         ram0_00         = 1;
    int         ram1_00         = 156; 
    const int   RAM_used_00     = ram1_00 - ram0_00;
    double      f00 [RAM_used_00+1];
    double      frequency_init [1];
    frequency_init[0] = frequency0;
    
    j = 0;
    while (j<=(RAM_used_00)) {
        f00[j] = frequency1 - (frequency1-frequency0)/trise_00*j*trise_00/(RAM_used_00);
        j += 1;
    }
    
    // tuning word RSCW1 variables 
    double      trise_10        = 10.0e-6;//0.1e-6;
    int         ram0_10         = 250;
    int         ram1_10         = 500;
    int         RAM_used_10     = ram1_10-ram0_10; 
    double      f10 [RAM_used_10+1];   
    double      P [RAM_used_10+1];
    
    j = 0;
    while (j<=(RAM_used_10)) {
        f10[j] = frequency0 + (frequency1-frequency0)/trise_10*j*trise_10/(RAM_used_10);
        j += 1;
    }
    
    // (Logistic function from below could be added here) 
    
    // ### calculation of RSCW-words ### 
    uint64_t RSCW0 = RSCW_func(ram0_00, ram1_00, trise_00);
    uint64_t RSCW1 = RSCW_func(ram0_10, ram1_10, trise_10);
    uint64_t RSCW2 = RSCW_func(501, 501, 10.0e-6);
    
    // ### initialize both channels on the first intermediate frequency and write into their RAM
    ch_1();
   
    DDS.CFR1_write(0x00000200);
    DDS.FTW0_write(FTWO_func(frequency0));
    writeRSCW1(ram0_10, ram1_10, RSCW1, f10);
    writeRSCW0(ram0_00, ram1_00, RSCW0, f00); 
    writeRSCW2(501, 501, RSCW2, frequency_init);
    
    ch_2();

    DDS.CFR1_write(0x00000200);
    DDS.FTW0_write(FTWO_func(frequency0));
    writeRSCW1(ram0_10, ram1_10, RSCW1, f10); 
    writeRSCW0(ram0_00, ram1_00, RSCW0, f00);
    writeRSCW2(501, 501, RSCW2, frequency_init);

    //pc.printf("enter: \r \n 'u' to trigger ramp up \r \n 'd' to trigger ramp down \r \n 't' to enter new ramp time \r \n 's' for new start frequency \r \n 'e' for new end frequency \r \n");
    char up_or_down = '0';
    double trise = trise_00;  
    
    while(1) {
            if(pc.readable()) {
                up_or_down = pc.getc();
                if(up_or_down == 'a') {
                    pc.printf("a --> ramp started");
                    while(1) {
                        start_ramp(trise, tstay);
                        wait(2e-2);
                        if(pc.readable()) break;
                        }
                 if (up_or_down == 't') {
                    pc.printf("enter new tstay value in us: \n");
                    pc.scanf("%lf", &tstay);
                    tstay = tstay*1.0e-6;
                    }
                if (up_or_down == 'u') {
                        pc.printf("u");
                        trigger = 1;
                        wait(trise/4.0);
                        trigger = 0;
                         /////
                        ps0 = 1;
                        ps1 = 0;
                         /////
                        }
               if (up_or_down == 'd') {
                        pc.printf("d");
                        trigger = 1;
                        wait(trise/4.0);
                        trigger = 0;
                        /////
                        ps0 = 0;
                        ps1 = 0;
                        /////
                         }
                if (up_or_down == '1') {
                    trigger = 0;
                    trigger = 1;
                    /*ps0 = 0;
                    ch_2(); DDS.CFR1_write(0x00000200);
                    ch_1(); DDS.CFR1_write(0x80000200);*/
                    check_down();
                    trigger = 0;
                    pc.printf("ramping channel 1 \r\n");
                    }
                if (up_or_down == '2') {
                    trigger = 0;
                    trigger = 1;
                    /*ps0 = 0;
                    ch_1(); DDS.CFR1_write(0x00000200);
                    ch_2(); DDS.CFR1_write(0x80000200);*/
                    check_up();
                    trigger = 0;
                    pc.printf("ramping channel 2 \r\n");
                    }
                /*if (up_or_down == 's') {
                    pc.printf("enter new frequency0 value in MHz: \n");
                    pc.scanf("%lf", &frequency0);
                    frequency0 = frequency0*1.0e6;
                    initialize(frequency0, frequency1, RAM_start, RAM_final, trise);
                    }*/
                /*if (up_or_down == 'e') {
                    pc.printf("enter new frequency1 value in MHz: \n");
                    pc.scanf("%lf", &frequency1);
                    frequency1 = frequency1*1.0e6;
                    initialize(frequency0, frequency1, RAM_start, RAM_final, trise);
                    }*/
            }
            // Wait for a rising or falling edge on the mbed-mcs pin and select accordingly channel 1 or 
            // channel 2 for ramping
            mcs.rise(&check_up);
            mcs.fall(&check_down);
            // start the ramp when a signal sets the mbed pin 'mexp' to '1'
            if(mexp) {
                    while(mexp);
                    start_ramp(trise, tstay);
                   // pc.printf(" exp trigger in registered \r \n");
                }
    }
   
    return 0;
}

    /* LOGISTIC FUNCTION
    j = 0;
    double alpha = log(double((RAM_used_10-1.0)*(RAM_used_10-1.0)))*1/RAM_used_10;
    pc.printf("alpha %f\r\n",alpha);
    double beta = 1/alpha*log(double(RAM_used_10-1));
    pc.printf("beta %f\r\n",beta);
    while (j<=(RAM_used_10)) {
        P[j] = 1.0/(1.0+exp(-(j-beta)*alpha));
        f10[j] = frequency0*(1-P[j]) + frequency1*P[j];
        j += 1;
    }
    f10[0]              = frequency0;
    f10[RAM_used_10]    = frequency1;
    pc.printf("P(0) = %f P(RAM_used) = %f \r\n", P[0], P[RAM_used_10]);*/