Waveform generator

Dependencies:   MODDMA mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SignalGenDAC.cpp Source File

SignalGenDAC.cpp

00001 //
00002 // Signal Generate DAC Driver
00003 //
00004 // Derived from AN10917: Memory to DAC data transfers using the LPC1700's DMA
00005 // 
00006 
00007 #include "SignalGenDAC.h"
00008 
00009 #define PI 3.14159      // for the sine-wave
00010 
00011 /// The linked list structure used to control the DMA transfer
00012 ///
00013 typedef struct {
00014     uint32_t  source;     /// start of source area
00015     uint32_t  destination;/// start of destination area
00016     uint32_t  next;       /// address of next strLLI in chain
00017     uint32_t  control;    /// DMACCxControl register
00018 } LinkListItem_t;    
00019 
00020 /// The DACsignal memory, which is DMA sent to the DAC to play the waveform,
00021 /// produced by scaling the VoltSignal array
00022 ///
00023 float VoltSignal[SIGNAL_MEM_ENTRIES] __attribute__ ((section("AHBSRAM0")));
00024 signed long DACsignal[SIGNAL_MEM_ENTRIES] __attribute__ ((section("AHBSRAM0")));
00025 
00026 /// The linked list item record, used by the DMA engine to decide how to play
00027 ///
00028 LinkListItem_t llio __attribute__ ((section("AHBSRAM0")));
00029 
00030 
00031 SignalGenDAC::SignalGenDAC(PinName _aout, float _minV, float _maxV) :
00032     minV(_minV), maxV(_maxV) {
00033     aout = new AnalogOut(_aout);
00034 }
00035 
00036 SignalGenDAC::~SignalGenDAC() {
00037 }
00038 
00039 void SignalGenDAC::Start(bool oneShot) {
00040     printf("Start(%d) w/%d samples\r\n", oneShot ? 1 : 0, numSamples);
00041     isOn = (oneShot) ? false : true;
00042     
00043     llio.source = (uint32_t)DACsignal;
00044     llio.destination = (uint32_t)&LPC_DAC->DACR;
00045     llio.next = (uint32_t)&llio;
00046     llio.control = (1<<26) | (2<<21) | (2<<18) | numSamples;
00047 
00048     LPC_SC->PCONP |= (1<<29);
00049 
00050     /* Enable GPDMA  and sync logic */
00051     LPC_GPDMA->DMACConfig        = 1;
00052     LPC_GPDMA->DMACSync          = (1<<6); 
00053 
00054     /* Load DMA Channel0 */
00055     LPC_GPDMACH0->DMACCSrcAddr   = (uint32_t)DACsignal;
00056     LPC_GPDMACH0->DMACCDestAddr  = (uint32_t)&LPC_DAC->DACR;
00057     LPC_GPDMACH0->DMACCLLI       = (oneShot) ? 0 : (uint32_t)&llio;
00058 
00059     int playSampleCount = numSamples + oneShot;
00060     LPC_GPDMACH0->DMACCControl = playSampleCount  // transfer size (0 - 11) = 64
00061                   | (0 << 12)         // source burst size (12 - 14) = 1
00062                   | (0 << 15)         // destination burst size (15 - 17) = 1
00063                   | (2 << 18)         // source width (18 - 20) = 32 bit
00064                   | (2 << 21)         // destination width (21 - 23) = 32 bit
00065                   | (0 << 24)         // source AHB select (24) = AHB 0
00066                   | (0 << 25)         // destination AHB select (25) = AHB 0
00067                   | (1 << 26)         // source increment (26) = increment
00068                   | (0 << 27)         // destination increment (27) = no increment
00069                   | (0 << 28)         // mode select (28) = access in user mode
00070                   | (0 << 29)         // (29) = access not bufferable
00071                   | (0 << 30)         // (30) = access not cacheable
00072                   | (0 << 31);        // terminal count interrupt disabled
00073 
00074     LPC_GPDMACH0->DMACCConfig = 1
00075                   | (0 << 1)          // source peripheral (1 - 5) = none
00076                   | (7 << 6)          // destination peripheral (6 - 10) = DAC
00077                   | (1 << 11)         // flow control (11 - 13) = mem to per
00078                   | (0 << 14)         // (14) = mask out error interrupt
00079                   | (0 << 15)         // (15) = mask out terminal count interrupt
00080                   | (0 << 16)         // (16) = no locked transfers
00081                   | (0 << 18);        // (27) = no HALT
00082 
00083     /* DACclk = 25 MHz, so 10 usec interval */
00084     LPC_DAC->DACCNTVAL = 18;               // 16-bit reload value
00085     /* DMA, timer running, dbuff */
00086     LPC_DAC->DACCTRL = 
00087           1<<3          // DMA_ENA dma burst is enabled
00088         | 1<<2          // CNT_ENA Timeout couner is enabled
00089         | 1<<1;         // DBLBUF_ENA double-buffering enabled
00090 }
00091 
00092 void SignalGenDAC::Stop(void) {
00093     printf("Stop()\r\n");
00094     LPC_GPDMACH0->DMACCLLI       = 0;
00095     while (LPC_GPDMACH0->DMACCConfig & 1)
00096         wait_ms(1);
00097     aout->write(offset / maxV);
00098     isOn = false;
00099 }
00100 
00101 
00102 void SignalGenDAC::PrepareWaveform(SG_Waveform mode, float _frequency, float _dutycycle, float _voltage, float _offset) {
00103     int x, dcCount, firstQtr, lastQtr;
00104     frequency = _frequency;
00105     dutycycle = _dutycycle;
00106     voltage = _voltage;
00107     offset = _offset;
00108     float upp = rangelimit(offset + voltage/2, minV, maxV);
00109     float mid = rangelimit(offset, minV, maxV);
00110     float low = rangelimit(offset - voltage/2, minV, maxV);
00111     float v;
00112     numSamples = 128 * (10000 / frequency);    // Ideally, compute this based on the frequency for good resolution
00113     dcCount = dutycycle/100.0 * numSamples;
00114     firstQtr = dcCount / 2;
00115     lastQtr = dcCount + (numSamples - dcCount)/2;
00116     
00117     // Set the timebased based on the frequency
00118     if (isOn) {
00119         Stop();
00120     }
00121     printf("Generate wave for mode: %d\r\n", mode);
00122     switch (mode) {
00123         case SG_SINE:
00124             for (x=0; x<numSamples; x++) {
00125                 if (x < dcCount) {
00126                     v = offset + voltage/2 * sin(x * 1 * PI / dcCount);
00127                 } else {
00128                     v = offset - voltage/2 * sin((x - dcCount) * 1 * PI / (numSamples-dcCount));
00129                 }
00130                 v = rangelimit(v, minV, maxV);
00131                 VoltSignal[x] = v;
00132             }
00133             VoltSignal[numSamples] = rangelimit(offset, minV, maxV);
00134             break;
00135         case SG_SQUARE:
00136             for (x=0; x<numSamples; x++) {
00137                 if (0 && x == 0) {
00138                     v = rangelimit(offset, minV, maxV);                    
00139                 } else if (x < dcCount) {
00140                     v = rangelimit(offset + voltage/2, minV, maxV);
00141                 } else {
00142                     v = rangelimit(offset - voltage/2, minV, maxV);
00143                 }
00144                 VoltSignal[x] = v;
00145             }
00146             VoltSignal[numSamples] = rangelimit(offset, minV, maxV);
00147             break;
00148         case SG_TRIANGLE:
00149             for (x=0; x<numSamples; x++) {
00150                 if (x < firstQtr) {
00151                     v = voltage/2 * (float)x/(firstQtr);
00152                     v += offset;
00153                 } else if (x < dcCount) {
00154                     v = voltage/2 * (float)x/(firstQtr);
00155                     v = voltage - (v - offset);
00156                 } else if (x < lastQtr) {
00157                     v = voltage * (float)(x - dcCount)/(numSamples - dcCount);
00158                     v = offset - v;
00159                 } else {
00160                     v = voltage * (float)(x - dcCount)/(numSamples - dcCount);
00161                     v = v + offset - voltage;
00162                 }
00163                 VoltSignal[x] = v;
00164             }
00165             VoltSignal[numSamples] = rangelimit(offset, minV, maxV);
00166             break;
00167         case SG_SAWTOOTH:
00168             for (x=0; x<numSamples; x++) {
00169                 if (x < dcCount) {
00170                     v = offset - voltage/2 + (float)x/dcCount * voltage/2;
00171                 } else {
00172                     v = offset + (float)(x - dcCount)/(numSamples - dcCount) *  voltage/2;
00173                 }
00174                 v = rangelimit(v, minV, maxV);
00175                 VoltSignal[x] = v;
00176             }
00177             VoltSignal[numSamples] = rangelimit(offset, minV, maxV);
00178             break;
00179         case SG_USER:
00180             break;
00181     }
00182     //printf("DAC Data %3.2f %3.2f\r\n", voltage, offset);
00183     for (x=0; x<=numSamples; x++) {
00184         DACsignal[x] = ((uint16_t)(VoltSignal[x]/maxV * 1023) << 6);
00185         printf("%3d, %5.3f, %d\r\n", x, VoltSignal[x], DACsignal[x]);
00186     }
00187     if (!isOn) {
00188         aout->write(offset / maxV);
00189     }
00190 }
00191 
00192 float SignalGenDAC::rangelimit(float value, float min, float max) {
00193     if (value < min)
00194         return min;
00195     else if (value > max)
00196         return max;
00197     else
00198         return value;
00199 }
00200