Signal Generator
Dependencies: IniManager RA8875 Watchdog mbed-rtos mbed
Fork of speaker_demo_Analog by
SignalGenDAC.cpp
- Committer:
- WiredHome
- Date:
- 2017-01-16
- Revision:
- 4:10281ddb673d
- Parent:
- 3:d22f3e52d06a
- Child:
- 5:49dd0c647a40
File content as of revision 4:10281ddb673d:
#include "SignalGenDAC.h" DigitalOut led(LED1); #define PI 3.14159 /// The linked list structure used to control the DMA transfer /// typedef struct { uint32_t source; /// start of source area uint32_t destination;/// start of destination area uint32_t next; /// address of next strLLI in chain uint32_t control; /// DMACCxControl register } LinkListItem_t; /// The DACsignal memory, which is DMA sent to the DAC to play the waveform, /// produced by scaling the VoltSignal array /// float VoltSignal[SIGNAL_MEM_ENTRIES] __attribute__ ((section("AHBSRAM0"))); signed long DACsignal[SIGNAL_MEM_ENTRIES] __attribute__ ((section("AHBSRAM0"))); /// The linked list item record, used by the DMA engine to decide how to play /// LinkListItem_t llio __attribute__ ((section("AHBSRAM0"))); SignalGenDAC::SignalGenDAC(PinName _aout, float _minV, float _maxV) : minV(_minV), maxV(_maxV) { aout = new AnalogOut(_aout); #if 1 #include "mbed.h" aout->write(0.25); wait_ms(25); aout->write(0.50); wait_ms(25); aout->write(0.75); wait_ms(25); aout->write(1.00); wait_ms(25); #endif } SignalGenDAC::~SignalGenDAC() { } void SignalGenDAC::Start(bool oneShot) { printf("Start(%d) w/%d samples\r\n", oneShot ? 1 : 0, numSamples); isOn = (oneShot) ? false : true; led = 1; for (int x=0; x<numSamples; x++) { DACsignal[x] = ((uint16_t)(VoltSignal[x]/maxV * 1023) << 6); printf("%3d, %5.3f, %d\r\n", x, VoltSignal[x], DACsignal[x]); } llio.source = (uint32_t)DACsignal; llio.destination = (uint32_t)&LPC_DAC->DACR; llio.next = (uint32_t)&llio; llio.control = (1<<26) | (2<<21) | (2<<18) | numSamples; LPC_SC->PCONP |= (1<<29); /* Enable GPDMA and sync logic */ LPC_GPDMA->DMACConfig = 1; LPC_GPDMA->DMACSync = (1<<6); /* Load DMA Channel0 */ LPC_GPDMACH0->DMACCSrcAddr = (uint32_t)DACsignal; LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_DAC->DACR; LPC_GPDMACH0->DMACCLLI = (uint32_t)&llio; // Free Running //LPC_GPDMACH0->DMACCLLI = 0; // One-Shot LPC_GPDMACH0->DMACCControl = numSamples // transfer size (0 - 11) = 64 | (0 << 12) // source burst size (12 - 14) = 1 | (0 << 15) // destination burst size (15 - 17) = 1 | (2 << 18) // source width (18 - 20) = 32 bit | (2 << 21) // destination width (21 - 23) = 32 bit | (0 << 24) // source AHB select (24) = AHB 0 | (0 << 25) // destination AHB select (25) = AHB 0 | (1 << 26) // source increment (26) = increment | (0 << 27) // destination increment (27) = no increment | (0 << 28) // mode select (28) = access in user mode | (0 << 29) // (29) = access not bufferable | (0 << 30) // (30) = access not cacheable | (0 << 31); // terminal count interrupt disabled LPC_GPDMACH0->DMACCConfig = 1 | (0 << 1) // source peripheral (1 - 5) = none | (7 << 6) // destination peripheral (6 - 10) = DAC | (1 << 11) // flow control (11 - 13) = mem to per | (0 << 14) // (14) = mask out error interrupt | (0 << 15) // (15) = mask out terminal count interrupt | (0 << 16) // (16) = no locked transfers | (0 << 18); // (27) = no HALT /* DACclk = 25 MHz, so 10 usec interval */ LPC_DAC->DACCNTVAL = 20; // 16-bit reload value /* DMA, timer running, dbuff */ LPC_DAC->DACCTRL = 1<<3 // DMA_ENA dma burst is enabled | 1<<2 // CNT_ENA Timeout couner is enabled | 1<<1; // DBLBUF_ENA double-buffering enabled } void SignalGenDAC::Stop(void) { printf("Stop()\r\n"); LPC_GPDMACH0->DMACCLLI = 0; isOn = false; led = 0; } void SignalGenDAC::PrepareWaveform(SG_Mode mode, float frequency, float dutycycle, float voltage, float offset) { int x, dcCount, firstQtr, lastQtr; float upp = rangelimit(offset + voltage/2, minV, maxV); float mid = rangelimit(offset, minV, maxV); float low = rangelimit(offset - voltage/2, minV, maxV); float v; numSamples = 32; // Ideally, compute this based on the frequency for good resolution dcCount = dutycycle/100.0 * numSamples; firstQtr = dcCount / 2; lastQtr = dcCount + (numSamples - dcCount)/2; // Set the timebased based on the frequency if (isOn) { Stop(); } printf("Generate wave for mode: %d\r\n", mode); switch (mode) { case SG_SINE: for (x=0; x<numSamples; x++) { if (x < dcCount) { v = offset + voltage/2 * sin(x * 1 * PI / dcCount); } else { v = offset - voltage/2 * sin((x - dcCount) * 1 * PI / (numSamples-dcCount)); } v = rangelimit(v, minV, maxV); VoltSignal[x] = v; } break; case SG_SQUARE: for (x=0; x<numSamples; x++) { if (x < dcCount) { v = rangelimit(offset + voltage/2, minV, maxV); } else { v = rangelimit(offset - voltage/2, minV, maxV); } VoltSignal[x] = v; } break; case SG_TRIANGLE: for (x=0; x<numSamples; x++) { if (x < firstQtr) { v = voltage/2 * (float)x/(firstQtr); v += offset; } else if (x < dcCount) { v = voltage/2 * (float)x/(firstQtr); v = voltage - (v - offset); } else if (x < lastQtr) { v = voltage * (float)(x - dcCount)/(numSamples - dcCount); v = offset - v; } else { v = voltage * (float)(x - dcCount)/(numSamples - dcCount); v = v + offset - voltage; } VoltSignal[x] = v; } break; case SG_SAWTOOTH: for (x=0; x<numSamples; x++) { if (x < dcCount) { v = offset - voltage/2 + (float)x/dcCount * voltage/2; } else { v = offset + (float)(x - dcCount)/(numSamples - dcCount) * voltage/2; } v = rangelimit(v, minV, maxV); VoltSignal[x] = v; } break; case SG_USER: break; } //printf("DAC Data %3.2f %3.2f\r\n", voltage, offset); for (x=0; x<numSamples; x++) { DACsignal[x] = ((uint16_t)(VoltSignal[x]/maxV * 1023) << 6); printf("%3d, %5.3f, %d\r\n", x, VoltSignal[x], DACsignal[x]); } Start(false); } float SignalGenDAC::rangelimit(float value, float min, float max) { if (value < min) return min; else if (value > max) return max; else return value; }