Carson Brown
/
AFG_project
Waveform generator
Embed:
(wiki syntax)
Show/hide line numbers
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
Generated on Thu Dec 8 2022 05:04:37 by 1.7.2