Generate sine waves with 2 mbeds synchronised. Configurable amplitude and phase. Built for 50 Hz mains simulations.
main.cpp
00001 /* 00002 * 2 Channel DAC WaveSimulator with 2 lpc1768 mbed's. 00003 * Command line or GUI controlled. 00004 */ 00005 00006 #include "mbed.h" 00007 #include "MODDMA.h" 00008 #include <cmath> 00009 #include "watchdog.h" 00010 #include "xIFO.h" 00011 #include <stdio.h> 00012 #include <stdlib.h> 00013 #include <ctype.h> 00014 00015 Serial pc(USBTX, USBRX); 00016 Serial sr(p9, p10); 00017 Watchdog wdt; 00018 00019 const double PI = 3.141592653589793238462; 00020 const float PI_F = 3.14159265358979f; 00021 00022 // Make the buffer size match the number of degrees 00023 // in a circle since we are going to output a sinewave. 00024 #define BUFFER_SIZE 360 00025 00026 // Set DAC output power mode. 00027 #define DAC_POWER_MODE (1 << 16) 00028 00029 DigitalOut led1(LED1); 00030 DigitalOut led2(LED2); 00031 DigitalOut led3(LED3); 00032 DigitalOut led4(LED4); 00033 DigitalIn modesel(p22); // mode selector 00034 DigitalInOut trigger(p21); // sync trigger output 00035 00036 uint32_t buffer[3][BUFFER_SIZE]; 00037 00038 AnalogOut signal(p18); /* Do not forget output RC filter! */ 00039 00040 MODDMA dma; 00041 MODDMA_Config *conf0, *conf1, *conf2, *conf3; 00042 00043 // Config phase (2*pi is one period) 00044 double phase_master = PI * 1; 00045 double phase_slave = PI * 1; 00046 // Config amplitude, x * 3.3 Volt 00047 double amplitude_master = 0.75; 00048 double amplitude_slave = 0.75; 00049 // Config frequency, (if using synchronisation these must be identical) 00050 double freq_master = 50; 00051 double freq_slave = freq_master; 00052 // copy calc buffer[2] to ch0/1 00053 volatile uint32_t toch0 = 0; 00054 volatile uint32_t toch1 = 0; 00055 // Mode typedef 00056 typedef enum {MASTER, SLAVE} modesel_t; 00057 modesel_t mode; 00058 // Ringbuffer for cmd 00059 xifo_t com; 00060 xifo_pool_t compool[128]; 00061 00062 /* Dma callbacks */ 00063 void TC0_callback(void); 00064 void ERR0_callback(void); 00065 00066 void TC1_callback(void); 00067 void ERR1_callback(void); 00068 00069 // Sync function 00070 void wait_for_sync(){ 00071 switch(mode){ 00072 case MASTER: 00073 // Wait a few clocks to make sure slave is waiting 00074 for(uint32_t i=0; i<10; i++){ __NOP(); __NOP(); __NOP(); __NOP(); } 00075 // Trigger toggle 00076 LPC_GPIO2->FIOPIN ^= (1<<5); 00077 break; 00078 case SLAVE: 00079 // Wait for pinchange 00080 { 00081 uint32_t pinstate = trigger; 00082 while( pinstate == trigger); 00083 } 00084 break; 00085 } 00086 } 00087 00088 // Calculate function 00089 void calculate_sines(){ 00090 // Create a sinewave buffer for testing. 00091 switch(mode){ 00092 case MASTER: 00093 for (int i = 0; i <= 359; i++) 00094 { 00095 double rads = (PI/180.0 * i); 00096 buffer[0][i] = amplitude_master * (512*( cos( rads + phase_master ) ))+512; 00097 } 00098 break; 00099 case SLAVE: 00100 for (int i = 0; i <= 359; i++) 00101 { 00102 double rads = (PI/180.0 * i); 00103 buffer[0][i] = amplitude_slave * (512 * cos(rads + phase_slave)) + 511; 00104 } 00105 break; 00106 } 00107 00108 // Adjust the sinewave buffer for use with DAC hardware. 00109 for (int i = 0; i < 360; i++) { 00110 if( buffer[0][i] > 1023 ) buffer[0][i] = 1023; 00111 buffer[0][i] = DAC_POWER_MODE | ((buffer[0][i] << 6) & 0xFFC0); 00112 buffer[1][i] = buffer[0][i]; // Just create a copy of buffer0 to continue sinewave. 00113 } 00114 } 00115 00116 void copycallback(){ 00117 if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); 00118 } 00119 00120 // Main 00121 int main() { 00122 volatile int life_counter = 0; 00123 pc.baud(115200); 00124 00125 if(modesel == 1){ 00126 pc.printf("slave\r\n"); 00127 trigger.input(); 00128 mode = SLAVE; 00129 led2 = 0; 00130 }else{ 00131 pc.printf("master\r\n"); 00132 trigger.output(); 00133 led2 = 1; 00134 mode = MASTER; 00135 // Print command set 00136 pc.printf("Command descriptions: <[master][slave]><[frequency][amplitude][phase]> <number>\r\n"); 00137 pc.printf("Commands: <[m][s]><[f][a][p]> <n>\r\n"); 00138 pc.printf("Min F = 1.02 Hz\r\n"); 00139 pc.printf("Max F limited to synchronisation and DAC speed (200 Hz with sync, max 1000 Hz without)\r\n"); 00140 } 00141 00142 calculate_sines(); 00143 00144 // Prepare the GPDMA system for buffer0. 00145 conf0 = new MODDMA_Config; 00146 conf0 00147 ->channelNum ( MODDMA::Channel_0 ) 00148 ->srcMemAddr ( (uint32_t) &buffer[0] ) 00149 ->dstMemAddr ( MODDMA::DAC ) 00150 ->transferSize ( 360 ) 00151 ->transferType ( MODDMA::m2p ) 00152 ->dstConn ( MODDMA::DAC ) 00153 ->attach_tc ( &TC0_callback ) 00154 ->attach_err ( &ERR0_callback ) 00155 ; // config end 00156 00157 // Prepare the GPDMA system for buffer1. 00158 conf1 = new MODDMA_Config; 00159 conf1 00160 ->channelNum ( MODDMA::Channel_1 ) 00161 ->srcMemAddr ( (uint32_t) &buffer[1] ) 00162 ->dstMemAddr ( MODDMA::DAC ) 00163 ->transferSize ( 360 ) 00164 ->transferType ( MODDMA::m2p ) 00165 ->dstConn ( MODDMA::DAC ) 00166 ->attach_tc ( &TC1_callback ) 00167 ->attach_err ( &ERR1_callback ) 00168 ; // config end 00169 00170 00171 // Calculating the transfer frequency: 00172 // By default, the Mbed library sets the PCLK_DAC clock value 00173 // to 24MHz. One complete sinewave cycle in each buffer is 360 00174 // points long. So, for a 1Hz wave we would need to transfer 360 00175 // values per second. That would be 24000000/360 which is approx 00176 // 66,666. But that's no good! The count val is only 16bits in size 00177 // so bare this in mind. If you need to go slower you will need to 00178 // alter PCLK_DAC from CCLK/4 to CCLK/8. 00179 // For our demo we are going to have the sinewave run at 1kHz. 00180 // That's 24000000/360000 which is approx 66. Experimentation 00181 // however showed 65 to get closer to 1kHz (on my Mbed and scope 00182 // at least). 00183 const double dacclk = 24000000; 00184 const double dacper = dacclk / 360; 00185 double ddacdiv; 00186 switch(mode){ 00187 case MASTER: 00188 ddacdiv = dacper / (freq_master); 00189 break; 00190 case SLAVE: 00191 ddacdiv = dacper / (freq_slave); 00192 break; 00193 } 00194 unsigned int dacdiv = ddacdiv; 00195 LPC_DAC->DACCNTVAL = dacdiv; // 6500 for 10Hz 00196 00197 // Watchdogtimer to reset if sync failed 00198 wdt.kick(10.0*(1.0/(dacper/ddacdiv))); 00199 00200 // Prepare first configuration. 00201 if (!dma.Prepare( conf0 )) { 00202 error("Doh!"); 00203 } 00204 // Wait period for master (slaves waits for sync) 00205 if(mode == MASTER){ 00206 wait(0.1); 00207 } 00208 wait_for_sync(); 00209 00210 // Begin (enable DMA and counter). Note, don't enable 00211 // DBLBUF_ENA as we are using DMA double buffering. 00212 LPC_DAC->DACCTRL |= (3UL << 2); 00213 00214 // Disable copy calc buffer flags 00215 toch0 = 0; 00216 toch1 = 0; 00217 00218 // Create ringbuffer for parsing 00219 xifo_init(&com, 128, (uint32_t *)&compool); 00220 xifo_clear(&com); 00221 uint32_t do_calc=0; 00222 00223 while (1) { 00224 // There's not a lot to do as DMA and interrupts are 00225 // now handling the buffer transfers. So we'll just 00226 // flash led1 to show the Mbed is alive and kicking. 00227 if (life_counter++ > 1000000) { 00228 //led1 = !led1; // Show some sort of life. 00229 life_counter = 0; 00230 } 00231 00232 /* Do UART data processing */ 00233 if(mode==MASTER){ 00234 while(pc.readable()){ 00235 xifo_write(&com, pc.getc()); 00236 } 00237 while(sr.readable()){ 00238 pc.putc(sr.getc()); 00239 } 00240 }else{ 00241 while(sr.readable()){ 00242 xifo_write(&com, sr.getc()); 00243 } 00244 } 00245 00246 00247 00248 { /* BLOCK with command parsing */ 00249 uint32_t do_parse=0; 00250 // 123456.123456 accurate 00251 char number[13] = {0,0,0,0,0,0,0,0,0,0,0,0,0}; 00252 uint32_t p=0; 00253 // Only parse USB master commands on master mode 00254 if(mode==MASTER){ 00255 // MASTER mode 00256 if( xifo_read_mr(&com,0) == '\n'){ 00257 xifo_pop_mr(&com); 00258 // We have a line 00259 if( xifo_read_lr(&com,0)== 's' ){ // Slave 00260 xifo_pop_lr(&com); 00261 pc.printf("Slave "); 00262 // command for slave, forward over serial sr 00263 while(xifo_get_used(&com)) 00264 sr.putc(xifo_pop_lr(&com)); 00265 sr.putc('\n'); 00266 xifo_init(&com, 128, (uint32_t *)&compool); 00267 xifo_clear(&com); 00268 } else if( xifo_read_lr(&com,0) == 'm' ){ // Master 00269 xifo_pop_lr(&com); 00270 pc.printf("Master "); 00271 // master 00272 // Parsing 00273 do_parse =1; 00274 } else if( xifo_read_lr(&com,0) == 'f' ){ // Frequency on MASTER and SLAVE 00275 // Parse data 00276 xifo_pop_lr(&com); // space 00277 // Get number 00278 while( xifo_get_used(&com) && p < sizeof(number)) 00279 number[p++] = (char)xifo_pop_lr(&com); 00280 freq_master = strtod(number,0); 00281 int t = dacper / (freq_master); 00282 pc.printf("Master Frequency %f, approximate: %f\nSlave ", freq_master, dacper/t); 00283 sr.printf("f %f\n", freq_master); 00284 do_calc = 1; 00285 } else { 00286 pc.printf("fout "); 00287 while(xifo_get_used(&com)) 00288 pc.putc(xifo_pop_lr(&com)); 00289 pc.putc('\n'); 00290 xifo_init(&com, 128, (uint32_t *)&compool); 00291 xifo_clear(&com); 00292 }} 00293 }else{ 00294 // SLAVE mode 00295 if( xifo_read_mr(&com,0) == '\n'){ 00296 xifo_pop_mr(&com); 00297 do_parse = 1; 00298 } 00299 } 00300 if(do_parse){ 00301 do_parse=0; 00302 00303 // Parse data 00304 char filter = xifo_pop_lr(&com); 00305 xifo_pop_lr(&com) ; // space 00306 // Get number 00307 while( xifo_get_used(&com) && p < sizeof(number)) 00308 number[p++] = (char)xifo_pop_lr(&com); 00309 00310 if(mode==MASTER){ 00311 // frequency 00312 if( filter == 'f' ){ 00313 freq_master = strtod(number,0); 00314 int t = dacper / (freq_master); 00315 pc.printf("Frequency %f, approximate: %f\n", freq_master, dacper/t); 00316 do_calc = 1; 00317 }else{ 00318 // amplitude 00319 if( filter == 'a'){ 00320 amplitude_master = strtod(number,0); 00321 pc.printf("Amplitude %f\n", amplitude_master); 00322 do_calc = 1; 00323 }else{ 00324 // phase 00325 if( filter == 'p' ){ 00326 phase_master = strtod(number,0) * PI; 00327 pc.printf("Phase %f\n", phase_master); 00328 do_calc = 1; 00329 } else{ 00330 pc.printf("fout "); 00331 while(xifo_get_used(&com)) 00332 pc.putc(xifo_pop_lr(&com)); 00333 pc.putc('\n'); 00334 xifo_init(&com, 128, (uint32_t *)&compool); 00335 xifo_clear(&com); 00336 }}} 00337 }else{ 00338 // frequency 00339 if( filter == 'f' ){ 00340 freq_slave = strtod(number,0); 00341 int t = dacper / (freq_slave); 00342 sr.printf("Frequency %f, approximate: %f\n", freq_slave, dacper/t); 00343 do_calc = 1; 00344 }else{ 00345 // amplitude 00346 if( filter == 'a'){ 00347 amplitude_slave = strtod(number,0); 00348 sr.printf("Amplitude %f\n", amplitude_slave); 00349 do_calc = 1; 00350 }else{ 00351 // phase 00352 if( filter == 'p' ){ 00353 phase_slave = strtod(number,0) * PI; 00354 sr.printf("Phase %f\n", phase_slave); 00355 do_calc = 1; 00356 } else{ 00357 sr.printf("fout "); 00358 while(xifo_get_used(&com)) 00359 sr.putc(xifo_pop_lr(&com)); 00360 sr.putc('\n'); 00361 xifo_init(&com, 128, (uint32_t *)&compool); 00362 xifo_clear(&com); 00363 }}} 00364 } 00365 } 00366 } /* BLOCK with command parsing */ 00367 00368 // recalculate 00369 if(do_calc){ 00370 do_calc = 0; 00371 // only continue if previous update is complete 00372 if( !toch0 && !toch1 ){ 00373 // calc frequency 00374 switch(mode){ 00375 case MASTER: 00376 ddacdiv = dacper / (freq_master); 00377 //pc.printf("set dacdiv to %f\n",ddacdiv); 00378 break; 00379 case SLAVE: 00380 ddacdiv = dacper / (freq_slave); 00381 break; 00382 } 00383 unsigned int dacdiv = ddacdiv; 00384 LPC_DAC->DACCNTVAL = dacdiv; // 6500 for 10Hz 00385 wdt.kick(10.0*(1.0/(dacper/ddacdiv))); 00386 // calculate_sines sine 00387 switch(mode){ 00388 case MASTER: 00389 for (int i = 0; i <= 359; i++) 00390 { 00391 double rads = (PI/180.0 * i); 00392 buffer[2][i] = amplitude_master * (512 * cos( rads + phase_master)) + 512; 00393 } 00394 break; 00395 case SLAVE: 00396 for (int i = 0; i <= 359; i++) 00397 { 00398 double rads = (PI/180.0 * i); 00399 buffer[2][i] = amplitude_slave * (512 * cos( rads + phase_slave)) + 512; 00400 } 00401 break; 00402 } 00403 // Adjust the sinewave buffer for use with DAC hardware. 00404 for (int i = 0; i < 360; i++) { 00405 if( buffer[2][i] > 1023 ) buffer[2][i] = 1023; 00406 buffer[2][i] = DAC_POWER_MODE | ((buffer[2][i] << 6) & 0xFFC0); 00407 } 00408 toch0 = 1; 00409 toch1 = 1; 00410 } 00411 } 00412 } 00413 } 00414 00415 // Configuration callback on TC 00416 void TC0_callback(void) { 00417 00418 // Just show sending buffer0 complete. 00419 led3 = !led3; 00420 00421 // Implement wait for trigger if slave mode 00422 wait_for_sync(); 00423 wdt.kick(); 00424 00425 // Get configuration pointer. 00426 MODDMA_Config *config = dma.getConfig(); 00427 00428 // Finish the DMA cycle by shutting down the channel. 00429 dma.Disable( (MODDMA::CHANNELS)config->channelNum() ); 00430 00431 // Swap to buffer1 00432 dma.Prepare( conf1 ); 00433 00434 // Clear DMA IRQ flags. 00435 if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); 00436 00437 // Copy to channel 0? 00438 if ( toch0 ){ 00439 for (int i = 0; i <= 359; i++) buffer[0][i] = buffer[2][i]; 00440 toch0=0; 00441 } 00442 } 00443 00444 // Configuration callback on Error 00445 void ERR0_callback(void) { 00446 error("Oh no! My Mbed EXPLODED! :( Only kidding, go find the problem"); 00447 } 00448 00449 // Configuration callback on TC 00450 void TC1_callback(void) { 00451 // Just show sending buffer1 complete. 00452 //led4 = !led4; 00453 00454 // Implement wait for trigger if slave mode 00455 wait_for_sync(); 00456 wdt.kick(); 00457 00458 // Get configuration pointer. 00459 MODDMA_Config *config = dma.getConfig(); 00460 00461 // Finish the DMA cycle by shutting down the channel. 00462 dma.Disable( (MODDMA::CHANNELS)config->channelNum() ); 00463 00464 // Swap to buffer0 00465 dma.Prepare( conf0 ); 00466 00467 // Clear DMA IRQ flags. 00468 if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); 00469 00470 // Copy to channel 1? 00471 if ( toch1 ){ 00472 for (int i = 0; i <= 359; i++) buffer[1][i] = buffer[2][i]; 00473 toch1=0; 00474 } 00475 } 00476 00477 // Configuration callback on Error 00478 void ERR1_callback(void) { 00479 error("Oh no! My Mbed EXPLODED! :( Only kidding, go find the problem"); 00480 } 00481
Generated on Thu Jul 14 2022 08:02:50 by 1.7.2