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