Waveform generator

Dependencies:   MODDMA mbed

Committer:
carsonbrown27
Date:
Thu Dec 08 05:04:05 2022 +0000
Revision:
1:2fa202e02c48
Parent:
0:c1a4c1e9618c
Final Version

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jisakson3 0:c1a4c1e9618c 1 //
jisakson3 0:c1a4c1e9618c 2 // Signal Generate DAC Driver
jisakson3 0:c1a4c1e9618c 3 //
jisakson3 0:c1a4c1e9618c 4 // Derived from AN10917: Memory to DAC data transfers using the LPC1700's DMA
jisakson3 0:c1a4c1e9618c 5 //
jisakson3 0:c1a4c1e9618c 6
jisakson3 0:c1a4c1e9618c 7 #include "SignalGenDAC.h"
jisakson3 0:c1a4c1e9618c 8
jisakson3 0:c1a4c1e9618c 9 #define PI 3.14159 // for the sine-wave
jisakson3 0:c1a4c1e9618c 10
jisakson3 0:c1a4c1e9618c 11 /// The linked list structure used to control the DMA transfer
jisakson3 0:c1a4c1e9618c 12 ///
jisakson3 0:c1a4c1e9618c 13 typedef struct {
jisakson3 0:c1a4c1e9618c 14 uint32_t source; /// start of source area
jisakson3 0:c1a4c1e9618c 15 uint32_t destination;/// start of destination area
jisakson3 0:c1a4c1e9618c 16 uint32_t next; /// address of next strLLI in chain
jisakson3 0:c1a4c1e9618c 17 uint32_t control; /// DMACCxControl register
jisakson3 0:c1a4c1e9618c 18 } LinkListItem_t;
jisakson3 0:c1a4c1e9618c 19
jisakson3 0:c1a4c1e9618c 20 /// The DACsignal memory, which is DMA sent to the DAC to play the waveform,
jisakson3 0:c1a4c1e9618c 21 /// produced by scaling the VoltSignal array
jisakson3 0:c1a4c1e9618c 22 ///
jisakson3 0:c1a4c1e9618c 23 float VoltSignal[SIGNAL_MEM_ENTRIES] __attribute__ ((section("AHBSRAM0")));
jisakson3 0:c1a4c1e9618c 24 signed long DACsignal[SIGNAL_MEM_ENTRIES] __attribute__ ((section("AHBSRAM0")));
jisakson3 0:c1a4c1e9618c 25
jisakson3 0:c1a4c1e9618c 26 /// The linked list item record, used by the DMA engine to decide how to play
jisakson3 0:c1a4c1e9618c 27 ///
jisakson3 0:c1a4c1e9618c 28 LinkListItem_t llio __attribute__ ((section("AHBSRAM0")));
jisakson3 0:c1a4c1e9618c 29
jisakson3 0:c1a4c1e9618c 30
jisakson3 0:c1a4c1e9618c 31 SignalGenDAC::SignalGenDAC(PinName _aout, float _minV, float _maxV) :
jisakson3 0:c1a4c1e9618c 32 minV(_minV), maxV(_maxV) {
jisakson3 0:c1a4c1e9618c 33 aout = new AnalogOut(_aout);
jisakson3 0:c1a4c1e9618c 34 }
jisakson3 0:c1a4c1e9618c 35
jisakson3 0:c1a4c1e9618c 36 SignalGenDAC::~SignalGenDAC() {
jisakson3 0:c1a4c1e9618c 37 }
jisakson3 0:c1a4c1e9618c 38
jisakson3 0:c1a4c1e9618c 39 void SignalGenDAC::Start(bool oneShot) {
jisakson3 0:c1a4c1e9618c 40 printf("Start(%d) w/%d samples\r\n", oneShot ? 1 : 0, numSamples);
jisakson3 0:c1a4c1e9618c 41 isOn = (oneShot) ? false : true;
jisakson3 0:c1a4c1e9618c 42
jisakson3 0:c1a4c1e9618c 43 llio.source = (uint32_t)DACsignal;
jisakson3 0:c1a4c1e9618c 44 llio.destination = (uint32_t)&LPC_DAC->DACR;
jisakson3 0:c1a4c1e9618c 45 llio.next = (uint32_t)&llio;
jisakson3 0:c1a4c1e9618c 46 llio.control = (1<<26) | (2<<21) | (2<<18) | numSamples;
jisakson3 0:c1a4c1e9618c 47
jisakson3 0:c1a4c1e9618c 48 LPC_SC->PCONP |= (1<<29);
jisakson3 0:c1a4c1e9618c 49
jisakson3 0:c1a4c1e9618c 50 /* Enable GPDMA and sync logic */
jisakson3 0:c1a4c1e9618c 51 LPC_GPDMA->DMACConfig = 1;
jisakson3 0:c1a4c1e9618c 52 LPC_GPDMA->DMACSync = (1<<6);
jisakson3 0:c1a4c1e9618c 53
jisakson3 0:c1a4c1e9618c 54 /* Load DMA Channel0 */
jisakson3 0:c1a4c1e9618c 55 LPC_GPDMACH0->DMACCSrcAddr = (uint32_t)DACsignal;
jisakson3 0:c1a4c1e9618c 56 LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_DAC->DACR;
jisakson3 0:c1a4c1e9618c 57 LPC_GPDMACH0->DMACCLLI = (oneShot) ? 0 : (uint32_t)&llio;
jisakson3 0:c1a4c1e9618c 58
jisakson3 0:c1a4c1e9618c 59 int playSampleCount = numSamples + oneShot;
jisakson3 0:c1a4c1e9618c 60 LPC_GPDMACH0->DMACCControl = playSampleCount // transfer size (0 - 11) = 64
jisakson3 0:c1a4c1e9618c 61 | (0 << 12) // source burst size (12 - 14) = 1
jisakson3 0:c1a4c1e9618c 62 | (0 << 15) // destination burst size (15 - 17) = 1
jisakson3 0:c1a4c1e9618c 63 | (2 << 18) // source width (18 - 20) = 32 bit
jisakson3 0:c1a4c1e9618c 64 | (2 << 21) // destination width (21 - 23) = 32 bit
jisakson3 0:c1a4c1e9618c 65 | (0 << 24) // source AHB select (24) = AHB 0
jisakson3 0:c1a4c1e9618c 66 | (0 << 25) // destination AHB select (25) = AHB 0
jisakson3 0:c1a4c1e9618c 67 | (1 << 26) // source increment (26) = increment
jisakson3 0:c1a4c1e9618c 68 | (0 << 27) // destination increment (27) = no increment
jisakson3 0:c1a4c1e9618c 69 | (0 << 28) // mode select (28) = access in user mode
jisakson3 0:c1a4c1e9618c 70 | (0 << 29) // (29) = access not bufferable
jisakson3 0:c1a4c1e9618c 71 | (0 << 30) // (30) = access not cacheable
jisakson3 0:c1a4c1e9618c 72 | (0 << 31); // terminal count interrupt disabled
jisakson3 0:c1a4c1e9618c 73
jisakson3 0:c1a4c1e9618c 74 LPC_GPDMACH0->DMACCConfig = 1
jisakson3 0:c1a4c1e9618c 75 | (0 << 1) // source peripheral (1 - 5) = none
jisakson3 0:c1a4c1e9618c 76 | (7 << 6) // destination peripheral (6 - 10) = DAC
jisakson3 0:c1a4c1e9618c 77 | (1 << 11) // flow control (11 - 13) = mem to per
jisakson3 0:c1a4c1e9618c 78 | (0 << 14) // (14) = mask out error interrupt
jisakson3 0:c1a4c1e9618c 79 | (0 << 15) // (15) = mask out terminal count interrupt
jisakson3 0:c1a4c1e9618c 80 | (0 << 16) // (16) = no locked transfers
jisakson3 0:c1a4c1e9618c 81 | (0 << 18); // (27) = no HALT
jisakson3 0:c1a4c1e9618c 82
jisakson3 0:c1a4c1e9618c 83 /* DACclk = 25 MHz, so 10 usec interval */
jisakson3 0:c1a4c1e9618c 84 LPC_DAC->DACCNTVAL = 18; // 16-bit reload value
jisakson3 0:c1a4c1e9618c 85 /* DMA, timer running, dbuff */
jisakson3 0:c1a4c1e9618c 86 LPC_DAC->DACCTRL =
jisakson3 0:c1a4c1e9618c 87 1<<3 // DMA_ENA dma burst is enabled
jisakson3 0:c1a4c1e9618c 88 | 1<<2 // CNT_ENA Timeout couner is enabled
jisakson3 0:c1a4c1e9618c 89 | 1<<1; // DBLBUF_ENA double-buffering enabled
jisakson3 0:c1a4c1e9618c 90 }
jisakson3 0:c1a4c1e9618c 91
jisakson3 0:c1a4c1e9618c 92 void SignalGenDAC::Stop(void) {
jisakson3 0:c1a4c1e9618c 93 printf("Stop()\r\n");
jisakson3 0:c1a4c1e9618c 94 LPC_GPDMACH0->DMACCLLI = 0;
jisakson3 0:c1a4c1e9618c 95 while (LPC_GPDMACH0->DMACCConfig & 1)
jisakson3 0:c1a4c1e9618c 96 wait_ms(1);
jisakson3 0:c1a4c1e9618c 97 aout->write(offset / maxV);
jisakson3 0:c1a4c1e9618c 98 isOn = false;
jisakson3 0:c1a4c1e9618c 99 }
jisakson3 0:c1a4c1e9618c 100
jisakson3 0:c1a4c1e9618c 101
jisakson3 0:c1a4c1e9618c 102 void SignalGenDAC::PrepareWaveform(SG_Waveform mode, float _frequency, float _dutycycle, float _voltage, float _offset) {
jisakson3 0:c1a4c1e9618c 103 int x, dcCount, firstQtr, lastQtr;
jisakson3 0:c1a4c1e9618c 104 frequency = _frequency;
jisakson3 0:c1a4c1e9618c 105 dutycycle = _dutycycle;
jisakson3 0:c1a4c1e9618c 106 voltage = _voltage;
jisakson3 0:c1a4c1e9618c 107 offset = _offset;
jisakson3 0:c1a4c1e9618c 108 float upp = rangelimit(offset + voltage/2, minV, maxV);
jisakson3 0:c1a4c1e9618c 109 float mid = rangelimit(offset, minV, maxV);
jisakson3 0:c1a4c1e9618c 110 float low = rangelimit(offset - voltage/2, minV, maxV);
jisakson3 0:c1a4c1e9618c 111 float v;
carsonbrown27 1:2fa202e02c48 112 numSamples = 128 * (10000 / frequency); // Ideally, compute this based on the frequency for good resolution
jisakson3 0:c1a4c1e9618c 113 dcCount = dutycycle/100.0 * numSamples;
jisakson3 0:c1a4c1e9618c 114 firstQtr = dcCount / 2;
jisakson3 0:c1a4c1e9618c 115 lastQtr = dcCount + (numSamples - dcCount)/2;
jisakson3 0:c1a4c1e9618c 116
jisakson3 0:c1a4c1e9618c 117 // Set the timebased based on the frequency
jisakson3 0:c1a4c1e9618c 118 if (isOn) {
jisakson3 0:c1a4c1e9618c 119 Stop();
jisakson3 0:c1a4c1e9618c 120 }
jisakson3 0:c1a4c1e9618c 121 printf("Generate wave for mode: %d\r\n", mode);
jisakson3 0:c1a4c1e9618c 122 switch (mode) {
jisakson3 0:c1a4c1e9618c 123 case SG_SINE:
jisakson3 0:c1a4c1e9618c 124 for (x=0; x<numSamples; x++) {
jisakson3 0:c1a4c1e9618c 125 if (x < dcCount) {
jisakson3 0:c1a4c1e9618c 126 v = offset + voltage/2 * sin(x * 1 * PI / dcCount);
jisakson3 0:c1a4c1e9618c 127 } else {
jisakson3 0:c1a4c1e9618c 128 v = offset - voltage/2 * sin((x - dcCount) * 1 * PI / (numSamples-dcCount));
jisakson3 0:c1a4c1e9618c 129 }
jisakson3 0:c1a4c1e9618c 130 v = rangelimit(v, minV, maxV);
jisakson3 0:c1a4c1e9618c 131 VoltSignal[x] = v;
jisakson3 0:c1a4c1e9618c 132 }
jisakson3 0:c1a4c1e9618c 133 VoltSignal[numSamples] = rangelimit(offset, minV, maxV);
jisakson3 0:c1a4c1e9618c 134 break;
jisakson3 0:c1a4c1e9618c 135 case SG_SQUARE:
jisakson3 0:c1a4c1e9618c 136 for (x=0; x<numSamples; x++) {
jisakson3 0:c1a4c1e9618c 137 if (0 && x == 0) {
jisakson3 0:c1a4c1e9618c 138 v = rangelimit(offset, minV, maxV);
jisakson3 0:c1a4c1e9618c 139 } else if (x < dcCount) {
jisakson3 0:c1a4c1e9618c 140 v = rangelimit(offset + voltage/2, minV, maxV);
jisakson3 0:c1a4c1e9618c 141 } else {
jisakson3 0:c1a4c1e9618c 142 v = rangelimit(offset - voltage/2, minV, maxV);
jisakson3 0:c1a4c1e9618c 143 }
jisakson3 0:c1a4c1e9618c 144 VoltSignal[x] = v;
jisakson3 0:c1a4c1e9618c 145 }
jisakson3 0:c1a4c1e9618c 146 VoltSignal[numSamples] = rangelimit(offset, minV, maxV);
jisakson3 0:c1a4c1e9618c 147 break;
jisakson3 0:c1a4c1e9618c 148 case SG_TRIANGLE:
jisakson3 0:c1a4c1e9618c 149 for (x=0; x<numSamples; x++) {
jisakson3 0:c1a4c1e9618c 150 if (x < firstQtr) {
jisakson3 0:c1a4c1e9618c 151 v = voltage/2 * (float)x/(firstQtr);
jisakson3 0:c1a4c1e9618c 152 v += offset;
jisakson3 0:c1a4c1e9618c 153 } else if (x < dcCount) {
jisakson3 0:c1a4c1e9618c 154 v = voltage/2 * (float)x/(firstQtr);
jisakson3 0:c1a4c1e9618c 155 v = voltage - (v - offset);
jisakson3 0:c1a4c1e9618c 156 } else if (x < lastQtr) {
jisakson3 0:c1a4c1e9618c 157 v = voltage * (float)(x - dcCount)/(numSamples - dcCount);
jisakson3 0:c1a4c1e9618c 158 v = offset - v;
jisakson3 0:c1a4c1e9618c 159 } else {
jisakson3 0:c1a4c1e9618c 160 v = voltage * (float)(x - dcCount)/(numSamples - dcCount);
jisakson3 0:c1a4c1e9618c 161 v = v + offset - voltage;
jisakson3 0:c1a4c1e9618c 162 }
jisakson3 0:c1a4c1e9618c 163 VoltSignal[x] = v;
jisakson3 0:c1a4c1e9618c 164 }
jisakson3 0:c1a4c1e9618c 165 VoltSignal[numSamples] = rangelimit(offset, minV, maxV);
jisakson3 0:c1a4c1e9618c 166 break;
jisakson3 0:c1a4c1e9618c 167 case SG_SAWTOOTH:
jisakson3 0:c1a4c1e9618c 168 for (x=0; x<numSamples; x++) {
jisakson3 0:c1a4c1e9618c 169 if (x < dcCount) {
jisakson3 0:c1a4c1e9618c 170 v = offset - voltage/2 + (float)x/dcCount * voltage/2;
jisakson3 0:c1a4c1e9618c 171 } else {
jisakson3 0:c1a4c1e9618c 172 v = offset + (float)(x - dcCount)/(numSamples - dcCount) * voltage/2;
jisakson3 0:c1a4c1e9618c 173 }
jisakson3 0:c1a4c1e9618c 174 v = rangelimit(v, minV, maxV);
jisakson3 0:c1a4c1e9618c 175 VoltSignal[x] = v;
jisakson3 0:c1a4c1e9618c 176 }
jisakson3 0:c1a4c1e9618c 177 VoltSignal[numSamples] = rangelimit(offset, minV, maxV);
jisakson3 0:c1a4c1e9618c 178 break;
jisakson3 0:c1a4c1e9618c 179 case SG_USER:
jisakson3 0:c1a4c1e9618c 180 break;
jisakson3 0:c1a4c1e9618c 181 }
jisakson3 0:c1a4c1e9618c 182 //printf("DAC Data %3.2f %3.2f\r\n", voltage, offset);
jisakson3 0:c1a4c1e9618c 183 for (x=0; x<=numSamples; x++) {
jisakson3 0:c1a4c1e9618c 184 DACsignal[x] = ((uint16_t)(VoltSignal[x]/maxV * 1023) << 6);
jisakson3 0:c1a4c1e9618c 185 printf("%3d, %5.3f, %d\r\n", x, VoltSignal[x], DACsignal[x]);
jisakson3 0:c1a4c1e9618c 186 }
jisakson3 0:c1a4c1e9618c 187 if (!isOn) {
jisakson3 0:c1a4c1e9618c 188 aout->write(offset / maxV);
jisakson3 0:c1a4c1e9618c 189 }
jisakson3 0:c1a4c1e9618c 190 }
jisakson3 0:c1a4c1e9618c 191
jisakson3 0:c1a4c1e9618c 192 float SignalGenDAC::rangelimit(float value, float min, float max) {
jisakson3 0:c1a4c1e9618c 193 if (value < min)
jisakson3 0:c1a4c1e9618c 194 return min;
jisakson3 0:c1a4c1e9618c 195 else if (value > max)
jisakson3 0:c1a4c1e9618c 196 return max;
jisakson3 0:c1a4c1e9618c 197 else
jisakson3 0:c1a4c1e9618c 198 return value;
jisakson3 0:c1a4c1e9618c 199 }
jisakson3 0:c1a4c1e9618c 200