With the DDS RAM registers a desired function "phase (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:
1:163c47ba88bd
Parent:
0:461186c994f0

File content as of revision 1:163c47ba88bd:

//      ****************************************
//      *** phase ramps with the RAM ***
//      ****************************************
// This program basically contains the same code as "Frequency_ramps_with_RAM".

/* Changes to be made comparing to Frequency Tuning via RAM:

CFR1: RAM Destination bit <30>=1 --> RAM drives the Phase Word
RAM write operation:
phase[j] = phase0 + (phase1-phase0)/trise*j*trise/RAM_used;
PHWO[j] = 0x3FFF & int(phase[j]/360.0*pow(2.0,14.0)); // PHWO = 0011 FFF = 3FFF --> implemented in PHWO_func
DDS.RAM_write_FTWO((PHWO[i] << 18) & 0xFFFFFFFF);
*/

#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 ############################
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 Frequency tuning word (FTWO): 
uint32_t FTWO_func(double frequency) {
    return 0xFFFFFFFF & round(frequency/ref_clock*pow(2.0,32.0));
    }
  
// calculate Phase tuning word (PHWO):  
uint32_t PHWO_func(double phase) {
    return 0x3FFF & int(phase/360.0*pow(2.0,14.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    PHWO[R_used];
    ps0 = 0;
    ps1 = 0; 
    update = 0;
    // Instruction byte: page 25, we want to write (0), so 0100
    // + 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(0x40 | (((r0 >> 6) & 0x0F)));
        update = 1;
        wait_us(10);//5*1/(12.0e6));
        update =0;
      
    i = 0;
    while (i<=(R_used)) {
        //FTWO[i] = FTWO_func(frequency[i]);
        PHWO[R_used-i] = PHWO_func(f[i]);
        //pc.printf("written %i %lf \r \n", i, f[i]);
        i += 1;
        }

    pc.printf("RSCW0 written: %lf %lf \r\n", f[0], f[R_used]);
        
    ps0 = 0;
    ps1 = 0; 
   
    DDS._spi.write(0x0B);
    
    i = 0;
    while (i<=(R_used)) {
        DDS.RAM_write_FTWO((PHWO[i] << 18) & 0xFFFFFFFF);
       // pc.printf("calculated %d : %x, %f \n", i, FTWO[i], frequency[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;
    // Instruction byte: page 25, we want to write (0), so 0100
    // + internal adress of the register to be written in
    DDS._spi.write(0x00 | (0x08 & 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;
       
    i = 0;
    while (i<=(R_used)) {
        //FTWO[i] = FTWO_func(frequency[i]);
        FTWO[R_used-i] = FTWO_func(f[i]);
        //pc.printf("written %i %lf \r \n", i, 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]);
       // pc.printf("calculated %d : %x, %f \n", i, FTWO[i], frequency[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;
    // Instruction byte: page 25, we want to write (0), so 0100
    // + internal adress of the register to be written in
    DDS._spi.write(0x00 | (0x09 & 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;
      
    i = 0;
    while (i<=(R_used)) {
        //FTWO[i] = FTWO_func(frequency[i]);
        FTWO[R_used-i] = FTWO_func(f[i]);
        //pc.printf("written %i %lf \r \n", i, 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]);
       // pc.printf("calculated %d : %x, %f \n", i, FTWO[i], frequency[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;
    // Instruction byte: page 25, we want to write (0), so 0100
    // + internal adress of the register to be written in
    DDS._spi.write(0x00 | (0x10 & 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;
      
    i = 0;
    while (i<=(R_used)) {
        //FTWO[i] = FTWO_func(frequency[i]);
        FTWO[R_used-i] = FTWO_func(f[i]);
        //pc.printf("written %i %lf \r \n", i, 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]);
       // pc.printf("calculated %d : %x, %f \n", i, FTWO[i], frequency[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;
    }
   
int counter(double t) {// for t in us
    int bins = int((t-91.8160e-9)/(41.6664e-9) + 0.5);
    //pc.printf("bins = %i", bins);
    return bins;
     };
     
// 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 start_ramp(double trise, double tstay) {
            int i = 0;
            int count = counter(trise+tstay);
            ps0 = 1;
            ps1 = 0;
            //-----------------------------
            // NEVER EVER change this loop!
            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:
void check_up(){
    ps0 = 0;
    ps1 = 0;
    ch_1(); DDS.CFR1_write(0x00000200);
    ch_2(); DDS.CFR1_write(0xC0000200);
    };
   
void check_down() {
    ps0 = 0;
    ps1 = 0;
    ch_2(); DDS.CFR1_write(0x00000200);
    ch_1(); DDS.CFR1_write(0xC0000200);
    };
    
void slow_ramp_360() {
    pc.printf("entered r -> starting slow phase ramp 0-->360 degree \r \n");
    int i;
    int steps = 700;
    double phase0 = 0;
    double phase1 = 359;
    double phase_array[steps+1];
    uint32_t PHWO [steps+1];
    i = 0;
    while(i<=steps) {
        phase_array[i] = phase0 + (phase1-phase0)/steps*i;
        // pc.printf("phase value: %lf", phase_array[i]);
        PHWO[i]=rint(phase_array[i]/360.0*pow(2.0,14.0));
        i += 1;
    }
    // * The Ramp *  //
    while(1) {
    DDS.PHWO_write(PHWO[0]); 
    trigger = 0;
    wait(1e-3);
    i = 0;
    trigger = 1;
    while(i<=steps) {
        DDS.PHWO_write(PHWO[i]);
        //if (i==0) {trigger = 1;};
        i+=1;
    }  
    trigger = 0;       
    wait(10e-3);
    DDS.PHWO_write(PHWO[0]); 
    if (pc.readable()) break;
    }
    // 
    };
    
void initialize(double phase1, double trise_00) {
    double      tstay           = 500.0e-6;
    
    // intermediate frequencies
    double      phase0      = 0;
    //double      phase1      = 20;
    // tuning word RSCW0 variables
    //double      trise_00        = 100e-6;//0.1e-6;//20.0e-6;
    int         ram0_00         = 50;
    int         ram1_00         = 100; 
    const int   RAM_used_00     = ram1_00 - ram0_00;
    double      p00 [RAM_used_00+1];
    double      frequency_init [1];
    double frequency0 = 80.0e6;
    frequency_init[0] = frequency0;
    
    j = 0;
    while (j<=(RAM_used_00)) {
        p00[j] = phase0 + (phase1-phase0)/trise_00*j*trise_00/RAM_used_00;
        j += 1;
    }
    
    // ### calculation of RSCW-words ### 
    uint64_t RSCW0 = RSCW_func(ram0_00, ram1_00, trise_00);
    
    // ### 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));
    writeRSCW0(ram0_00, ram1_00, RSCW0, p00); 
    
    ch_2();

    DDS.CFR1_write(0x00000200);
    DDS.FTW0_write(FTWO_func(frequency0));
    writeRSCW0(ram0_00, ram1_00, RSCW0, p00);
    }

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

int main() {

    pc.printf(" \r \r \n \n ***** Phase ramp with DDS in RAM mode***** \r \r \n \n");
    pc.printf("Enter: \r\n");
    pc.printf("'1' or '2' --> which output channel should be phase ramped. (Can be chosen over the mbed pin 'mcs' as well.) \r \n ");
    pc.printf("'r' --> start a slow phase ramp from 0 to 359 degree in milliseconds. Trigger on mbed pin 13. Repetition rate of the ramp approx. 1 kHz. \r \n");
    pc.printf("'a' --> starts the RAM phase ramp with rise time 'trise' and repeats the phase ramp until another key is pressed. \r \n ");
    pc.printf("'t' --> change the parameter 'trise', i.e. the rise time to reach the final phase value (100 us initially) \r \n");
    pc.printf("'p' --> final phase difference between the output channels (20 degree initially) \r \n");    
      
            
    reset();
    
    double tstay = 10e-6;
    double trise = 100e-6;
    double phase1 = 20.0;
    
    initialize(phase1, trise);
    char up_or_down = '0';
    
    while(1) {
            if(pc.readable()) {
                up_or_down = pc.getc();
                 if (up_or_down == 't') {
                    // Get out of RAM mode
                    ps0 = 0;
                    ps1 = 1;
                    ch_2(); DDS.CFR1_write(0x00000200);
                    ch_1(); DDS.CFR1_write(0x00000200);
                    // Get new time value
                    pc.printf("enter new trise value in us: \n");
                    pc.scanf("%lf", &trise);
                    trise = trise*1.0e-6;
                    // Initialize again
                    initialize(phase1, trise);
                    }
                 if (up_or_down == 'p') {
                    // Get out of RAM mode
                    ps0 = 0;
                    ps1 = 1;
                    ch_2(); DDS.CFR1_write(0x00000200);
                    ch_1(); DDS.CFR1_write(0x00000200);
                    // Get new time value
                    pc.printf("enter final phase value in degree: \n");
                    pc.scanf("%lf", &phase1);
                    // Initialize again
                    initialize(phase1, trise);
                    }
                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 == '0') {
                        ps0 = 0;
                        ps1 = 1;
                        ch_2(); DDS.CFR1_write(0x00000200);
                        ch_1(); DDS.CFR1_write(0x00000200);
                    }
                if (up_or_down == 'r') {
                    slow_ramp_360();
                    }
                if (up_or_down == 'a') {
                    while(1) {
                    /*
                    trigger = 0;
                    trigger = 1;
                    ps0 = 1;
                    wait(4*trise);
                    ps0 = 0;
                    trigger = 0;
                    wait(4*trise);
                    */
                    start_ramp(trise, 10*trise);
                    if (pc.readable()) break;
                    }
                    }
            }
            // Select the ramping channel with the mbed - mcs pin:
            mcs.rise(&check_up);
            mcs.fall(&check_down);
            /*
            if(mexp) {
                    while(mexp);
                    start_ramp(trise, tstay);
                   // pc.printf(" exp trigger in registered \r \n");
                }*/
    }
   
    return 0;
}