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.
main.cpp
00001 // **************************************** 00002 // *** frequency ramps with the RAM *** 00003 // **************************************** 00004 00005 #include "mbed.h" 00006 #include "DDS.h" 00007 00008 Serial pc(USBTX, USBRX); 00009 DigitalOut myled(LED1); 00010 DigitalOut cs2(p11); 00011 DigitalOut cs1(p8); 00012 DigitalOut rst(p9); 00013 DigitalOut update(p10); 00014 DigitalOut ps0(p12); 00015 DigitalOut ps1(p14); 00016 DigitalOut trigger(p13); 00017 DigitalOut trigger1(p23); 00018 DigitalOut trigger2(p24); 00019 InterruptIn mcs(p21); //InterruptIn description: http://mbed.org/handbook/InterruptIn 00020 DigitalIn mexp(p22); //DigitalIn description: http://mbed.org/handbook/DigitalIn 00021 DDS DDS(p5, p6, p7, p8, p9, p10); 00022 00023 // counting variables: 00024 int i = 0; 00025 int j = 0; 00026 // frequency of reference clock connected to the DDS board: 00027 double ref_clock = 400.0e6; 00028 00029 // ##################### definition of functions ############################ 00030 00031 // reset the DDS: 00032 int reset() { 00033 rst = 0; 00034 rst = 1; 00035 wait(0.1); 00036 rst = 0 ; 00037 return 0; 00038 } 00039 00040 // choosing one of the two output channels is done with this functions: 00041 int ch_1() { 00042 cs1 = 0; 00043 cs2 = 1; 00044 return 0; 00045 } 00046 int ch_2() { 00047 cs1 = 1; 00048 cs2 = 0; 00049 return 0; 00050 } 00051 00052 // This function always rounds values up (in mode ?? of the DDS a problem occurs 00053 // if the final value is not reached 00054 int round(double a) { 00055 return int(a + 0.5); 00056 } 00057 00058 // Calculate the "Frequency Tuning Word (FTWO)" for the DDS registers: 00059 uint32_t FTWO_func(double frequency) { 00060 return 0xFFFFFFFF & round(frequency/ref_clock*pow(2.0,32.0)); 00061 } 00062 00063 // RSCW0, RSCW1, RSCW2 and RSCW3 are the RAM profiles of the DDS which can be filled with different 00064 // parts of the ramp: 00065 // ************* RSCW0 ****************** 00066 void writeRSCW0(int r0, int r1, uint32_t RSCW, double f[]) { 00067 int R_used = r1-r0; 00068 uint32_t FTWO[R_used]; 00069 ps0 = 0; 00070 ps1 = 0; 00071 update = 0; 00072 // For the structure of the RSCW0 byte see the register map of the DDS. 00073 // Instruction byte: page 25, we want to write (0), so 0100 00074 // and internal adress of the register to be written in 00075 DDS._spi.write(0x00 | (0x07 & 0x1F)); 00076 // byte 5: Ramp rate first part 00077 DDS._spi.write(0xFF & RSCW); 00078 // byte 4: Ramp rate second part 00079 DDS._spi.write(0xFF & (RSCW >> 8)); 00080 // byte 3: final address <7:0> 00081 DDS._spi.write(0xFF & r1); 00082 // byte 2 00083 DDS._spi.write(((r0 << 2) & 0xFC) | ((r1 >> 8) & 0x03)); 00084 // byte 1: beginning address <9:6> 00085 DDS._spi.write(0x20 | (((r0 >> 6) & 0x0F))); 00086 update = 1; 00087 wait_us(10);//5*1/(12.0e6)); 00088 update =0; 00089 00090 // The frequency ramp is given as an array of frequencies. Here the frequency tuning 00091 // words (FTWOs) are calculated: 00092 i = 0; 00093 while (i<=(R_used)) { 00094 FTWO[R_used-i] = FTWO_func(f[i]); 00095 i += 1; 00096 } 00097 // Print start and final value of the RAM part: 00098 pc.printf("RSCW0 written: %lf %lf \r\n", f[0], f[R_used]); 00099 // Select the combination of ps0 and ps1 belonging to RSCW0 and start the RAM writing process: 00100 ps0 = 0; 00101 ps1 = 0; 00102 // Send instruction byte to start the RAM writing process: 00103 DDS._spi.write(0x0B); 00104 // Write the frequency tuning words into the RAM: 00105 i = 0; 00106 while (i<=(R_used)) { 00107 DDS.RAM_write_FTWO(FTWO[i]); 00108 i += 1; 00109 } 00110 } 00111 00112 // ************* RSCW1 ****************** 00113 void writeRSCW1(int r0, int r1, uint32_t RSCW, double f[]) { 00114 int R_used = r1-r0; 00115 uint32_t FTWO[R_used]; 00116 ps0 = 1; 00117 ps1 = 0; 00118 update = 0; 00119 DDS._spi.write(0x00 | (0x08 & 0x1F)); 00120 DDS._spi.write(0xFF & RSCW); 00121 DDS._spi.write(0xFF & (RSCW >> 8)); 00122 DDS._spi.write(0xFF & r1); 00123 DDS._spi.write(((r0 << 2) & 0xFC) | ((r1 >> 8) & 0x03)); 00124 DDS._spi.write(0x20 | (((r0 >> 6) & 0x0F))); 00125 update = 1; 00126 wait_us(10); 00127 update =0; 00128 00129 i = 0; 00130 while (i<=(R_used)) { 00131 FTWO[R_used-i] = FTWO_func(f[i]); 00132 i += 1; 00133 } 00134 pc.printf("RSCW1 written: %lf %lf \r\n", f[0], f[R_used]); 00135 00136 ps0 = 1; 00137 ps1 = 0; 00138 DDS._spi.write(0x0B); 00139 i = 0; 00140 while (i<=(R_used)) { 00141 DDS.RAM_write_FTWO(FTWO[i]); 00142 i += 1; 00143 } 00144 } 00145 00146 // ************* RSCW2 ****************** 00147 void writeRSCW2(int r0, int r1, uint32_t RSCW, double f[]) { 00148 int R_used = r1-r0; 00149 uint32_t FTWO[R_used]; 00150 ps0 = 0; 00151 ps1 = 1; 00152 update = 0; 00153 DDS._spi.write(0x00 | (0x09 & 0x1F)); 00154 DDS._spi.write(0xFF & RSCW); 00155 DDS._spi.write(0xFF & (RSCW >> 8)); 00156 DDS._spi.write(0xFF & r1); 00157 DDS._spi.write(((r0 << 2) & 0xFC) | ((r1 >> 8) & 0x03)); 00158 DDS._spi.write(0x20 | (((r0 >> 6) & 0x0F))); 00159 update = 1; 00160 wait_us(10); 00161 update =0; 00162 00163 i = 0; 00164 while (i<=(R_used)) { 00165 FTWO[R_used-i] = FTWO_func(f[i]); 00166 i += 1; 00167 } 00168 00169 pc.printf("RSCW0 written: %lf %lf \r\n", f[0], f[R_used]); 00170 ps0 = 0; 00171 ps1 = 1; 00172 00173 DDS._spi.write(0x0B); 00174 i = 0; 00175 while (i<=(R_used)) { 00176 DDS.RAM_write_FTWO(FTWO[i]); 00177 i += 1; 00178 } 00179 } 00180 00181 // ************* RSCW3 ****************** 00182 void writeRSCW3(int r0, int r1, uint32_t RSCW, double f[]) { 00183 int R_used = r1-r0; 00184 uint32_t FTWO[R_used]; 00185 ps0 = 1; 00186 ps1 = 1; 00187 update = 0; 00188 DDS._spi.write(0x00 | (0x0A & 0x1F)); 00189 DDS._spi.write(0xFF & RSCW); 00190 DDS._spi.write(0xFF & (RSCW >> 8)); 00191 DDS._spi.write(0xFF & r1); 00192 DDS._spi.write(((r0 << 2) & 0xFC) | ((r1 >> 8) & 0x03)); 00193 DDS._spi.write(0x20 | (((r0 >> 6) & 0x0F))); 00194 update = 1; 00195 wait_us(10); 00196 update =0; 00197 00198 i = 0; 00199 while (i<=(R_used)) { 00200 FTWO[R_used-i] = FTWO_func(f[i]); 00201 i += 1; 00202 } 00203 00204 pc.printf("RSCW0 written: %lf %lf \r\n", f[0], f[R_used]); 00205 00206 ps0 = 1; 00207 ps1 = 1; 00208 DDS._spi.write(0x0B); 00209 i = 0; 00210 while (i<=(R_used)) { 00211 DDS.RAM_write_FTWO(FTWO[i]); 00212 i += 1; 00213 } 00214 } 00215 00216 // Function to calculate the RSCW-word used in RSCW1, RSCW2, RSCW3 and RSCW4 00217 uint64_t RSCW_func(int ram0, int ram1, double trise) { 00218 int RAM_used = ram1-ram0+1; 00219 double tmin = 1.0*4.0/ref_clock*RAM_used; // minimum 1 dwell of time 4/clock at each address 00220 double tmax = 65535.0*4.0/ref_clock*RAM_used; // 16 bit register corresponding to 65535 dwells 00221 if (trise < tmin) { pc.printf("ERROR: ramp time too small. Minimum: %f \r \n", tmin); }; 00222 if (trise > tmax) { pc.printf("ERROR: ramp time too large. Maximum: %f \r \n", tmax); }; 00223 int dwells = round(trise/(4.0/ref_clock*RAM_used)); 00224 pc.printf(" %i dwells at each address ---> %f ramp time. \r \n", dwells, dwells*RAM_used*4.0/ref_clock); 00225 return 0xFFFF & dwells; 00226 } 00227 00228 // The wait-function doesn't offer time resolution of mikroseconds. By using a process like 00229 // counting up an integer number and measuring the time the mbed needs for this process a time 00230 // resolution of some tens of nano-seconds can be reached. "counter()" is used in "start_ramp()" 00231 // below: 00232 int counter(double t) { 00233 int bins = int((t-91.8160e-9)/(41.6664e-9) + 0.5); 00234 return bins; 00235 }; 00236 00237 int start_ramp(double trise, double tstay) { 00238 int i = 0; 00239 int count = counter(trise+tstay); 00240 ps0 = 1; 00241 ps1 = 0; 00242 //----------------------------- 00243 // NEVER EVER change this loop! (Allows for time measurement, see above) 00244 trigger = 0; 00245 trigger = 1; 00246 while(i<count){ 00247 i += 1; 00248 } 00249 trigger = 0; 00250 //----------------------------- 00251 ps0 = 0; 00252 ps1 = 0; 00253 i = 0; 00254 while(i<count){ 00255 i += 1; 00256 } 00257 return 0; 00258 }; 00259 00260 // Functions used to select output channel 1 or 2 upon receive of an external trigger signal: 00261 void check_up(){ 00262 ps0 = 0; 00263 ps1 = 1; 00264 ch_1(); DDS.CFR1_write(0x00000200); 00265 ch_2(); DDS.CFR1_write(0x80000200); 00266 }; 00267 00268 void check_down() { 00269 ps0 = 0; 00270 ps1 = 1; 00271 ch_2(); DDS.CFR1_write(0x00000200); 00272 ch_1(); DDS.CFR1_write(0x80000200); 00273 }; 00274 00275 // ############################################################ 00276 // ##################### main part ############################ 00277 00278 int main() { 00279 00280 pc.printf(" \r \r \n \n ***** frequency sweep with DDS in RAM mode***** \r \r \n \n"); 00281 pc.printf("Enter: \r \n"); 00282 pc.printf("'1' or '2' --> select which of the two output channel should be ramped. \r \n"); 00283 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"); 00284 pc.printf("'t' --> read in a new value for 'tstay' \r \n"); 00285 00286 reset(); 00287 00288 double tstay = 50.0e-6; 00289 00290 // intermediate frequencies 00291 double frequency0 = 79.5e6;// both channels are initiated on this frequency 00292 double frequency1 = 80.5e6; 00293 // tuning word RSCW0 variables 00294 double trise_00 = 100e-6; 00295 int ram0_00 = 1; 00296 int ram1_00 = 156; 00297 const int RAM_used_00 = ram1_00 - ram0_00; 00298 double f00 [RAM_used_00+1]; 00299 double frequency_init [1]; 00300 frequency_init[0] = frequency0; 00301 00302 j = 0; 00303 while (j<=(RAM_used_00)) { 00304 f00[j] = frequency1 - (frequency1-frequency0)/trise_00*j*trise_00/(RAM_used_00); 00305 j += 1; 00306 } 00307 00308 // tuning word RSCW1 variables 00309 double trise_10 = 10.0e-6;//0.1e-6; 00310 int ram0_10 = 250; 00311 int ram1_10 = 500; 00312 int RAM_used_10 = ram1_10-ram0_10; 00313 double f10 [RAM_used_10+1]; 00314 double P [RAM_used_10+1]; 00315 00316 j = 0; 00317 while (j<=(RAM_used_10)) { 00318 f10[j] = frequency0 + (frequency1-frequency0)/trise_10*j*trise_10/(RAM_used_10); 00319 j += 1; 00320 } 00321 00322 // (Logistic function from below could be added here) 00323 00324 // ### calculation of RSCW-words ### 00325 uint64_t RSCW0 = RSCW_func(ram0_00, ram1_00, trise_00); 00326 uint64_t RSCW1 = RSCW_func(ram0_10, ram1_10, trise_10); 00327 uint64_t RSCW2 = RSCW_func(501, 501, 10.0e-6); 00328 00329 // ### initialize both channels on the first intermediate frequency and write into their RAM 00330 ch_1(); 00331 00332 DDS.CFR1_write(0x00000200); 00333 DDS.FTW0_write(FTWO_func(frequency0)); 00334 writeRSCW1(ram0_10, ram1_10, RSCW1, f10); 00335 writeRSCW0(ram0_00, ram1_00, RSCW0, f00); 00336 writeRSCW2(501, 501, RSCW2, frequency_init); 00337 00338 ch_2(); 00339 00340 DDS.CFR1_write(0x00000200); 00341 DDS.FTW0_write(FTWO_func(frequency0)); 00342 writeRSCW1(ram0_10, ram1_10, RSCW1, f10); 00343 writeRSCW0(ram0_00, ram1_00, RSCW0, f00); 00344 writeRSCW2(501, 501, RSCW2, frequency_init); 00345 00346 //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"); 00347 char up_or_down = '0'; 00348 double trise = trise_00; 00349 00350 while(1) { 00351 if(pc.readable()) { 00352 up_or_down = pc.getc(); 00353 if(up_or_down == 'a') { 00354 pc.printf("a --> ramp started"); 00355 while(1) { 00356 start_ramp(trise, tstay); 00357 wait(2e-2); 00358 if(pc.readable()) break; 00359 } 00360 if (up_or_down == 't') { 00361 pc.printf("enter new tstay value in us: \n"); 00362 pc.scanf("%lf", &tstay); 00363 tstay = tstay*1.0e-6; 00364 } 00365 if (up_or_down == 'u') { 00366 pc.printf("u"); 00367 trigger = 1; 00368 wait(trise/4.0); 00369 trigger = 0; 00370 ///// 00371 ps0 = 1; 00372 ps1 = 0; 00373 ///// 00374 } 00375 if (up_or_down == 'd') { 00376 pc.printf("d"); 00377 trigger = 1; 00378 wait(trise/4.0); 00379 trigger = 0; 00380 ///// 00381 ps0 = 0; 00382 ps1 = 0; 00383 ///// 00384 } 00385 if (up_or_down == '1') { 00386 trigger = 0; 00387 trigger = 1; 00388 /*ps0 = 0; 00389 ch_2(); DDS.CFR1_write(0x00000200); 00390 ch_1(); DDS.CFR1_write(0x80000200);*/ 00391 check_down(); 00392 trigger = 0; 00393 pc.printf("ramping channel 1 \r\n"); 00394 } 00395 if (up_or_down == '2') { 00396 trigger = 0; 00397 trigger = 1; 00398 /*ps0 = 0; 00399 ch_1(); DDS.CFR1_write(0x00000200); 00400 ch_2(); DDS.CFR1_write(0x80000200);*/ 00401 check_up(); 00402 trigger = 0; 00403 pc.printf("ramping channel 2 \r\n"); 00404 } 00405 /*if (up_or_down == 's') { 00406 pc.printf("enter new frequency0 value in MHz: \n"); 00407 pc.scanf("%lf", &frequency0); 00408 frequency0 = frequency0*1.0e6; 00409 initialize(frequency0, frequency1, RAM_start, RAM_final, trise); 00410 }*/ 00411 /*if (up_or_down == 'e') { 00412 pc.printf("enter new frequency1 value in MHz: \n"); 00413 pc.scanf("%lf", &frequency1); 00414 frequency1 = frequency1*1.0e6; 00415 initialize(frequency0, frequency1, RAM_start, RAM_final, trise); 00416 }*/ 00417 } 00418 // Wait for a rising or falling edge on the mbed-mcs pin and select accordingly channel 1 or 00419 // channel 2 for ramping 00420 mcs.rise(&check_up); 00421 mcs.fall(&check_down); 00422 // start the ramp when a signal sets the mbed pin 'mexp' to '1' 00423 if(mexp) { 00424 while(mexp); 00425 start_ramp(trise, tstay); 00426 // pc.printf(" exp trigger in registered \r \n"); 00427 } 00428 } 00429 00430 return 0; 00431 } 00432 00433 /* LOGISTIC FUNCTION 00434 j = 0; 00435 double alpha = log(double((RAM_used_10-1.0)*(RAM_used_10-1.0)))*1/RAM_used_10; 00436 pc.printf("alpha %f\r\n",alpha); 00437 double beta = 1/alpha*log(double(RAM_used_10-1)); 00438 pc.printf("beta %f\r\n",beta); 00439 while (j<=(RAM_used_10)) { 00440 P[j] = 1.0/(1.0+exp(-(j-beta)*alpha)); 00441 f10[j] = frequency0*(1-P[j]) + frequency1*P[j]; 00442 j += 1; 00443 } 00444 f10[0] = frequency0; 00445 f10[RAM_used_10] = frequency1; 00446 pc.printf("P(0) = %f P(RAM_used) = %f \r\n", P[0], P[RAM_used_10]);*/ 00447 00448
Generated on Tue Jul 19 2022 00:59:02 by 1.7.2