Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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