Signal Generator

Dependencies:   IniManager RA8875 Watchdog mbed-rtos mbed

Fork of speaker_demo_Analog by jim hamblen

SignalGenDAC.cpp

Committer:
WiredHome
Date:
2017-01-15
Revision:
2:8f71b71fce1b
Child:
3:d22f3e52d06a

File content as of revision 2:8f71b71fce1b:


#include "SignalGenDAC.h"

#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 signal memory, which is DMA sent to the DAC to play the waveform
///
float /*signed long*/ signal[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);
}

SignalGenDAC::~SignalGenDAC() {
}

void SignalGenDAC::Start(bool oneShot) {
}

void SignalGenDAC::Stop(void) {
}


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;
    int 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 the signal during the change
        isOn = false;
    }
    switch (mode) {
        case SG_SINE:
            for (x=0; x<numSamples; x++) {
                if (x < dcCount) {
                    v = offset + voltage/2 * sin(x * 1 * PI / dcCount);
                    v = rangelimit(v, minV, maxV);
                } else {
                    v = offset - voltage/2 * sin((x - dcCount) * 1 * PI / (numSamples-dcCount));
                    v = rangelimit(v, minV, maxV);
                }
                signal[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);
                }
                signal[x] = v;
            }
            break;
        case SG_TRIANGLE:
            for (x=0; x<numSamples; x++) {
                if (x < firstQtr) {
                    v = (float)x/(firstQtr) * mid + mid;
                } else if (x < dcCount) {
                    v = upp - (float)(x-firstQtr)/(dcCount - firstQtr) * mid;
                } else if (x < lastQtr) {
                    v = mid - (float)(x-dcCount)/(lastQtr - dcCount) * mid;
                } else {
                    v = (float)(x-lastQtr)/(numSamples - lastQtr) * mid;
                }
                signal[x] = v;
            }
            break;
        case SG_SAWTOOTH:
            for (x=0; x<numSamples; x++) {
                if (x < dcCount) {
                    v = (float)x/dcCount * (upp - low)/2 + low;
                } else {
                    v = (float)(x - dcCount)/(numSamples - dcCount) * (upp - low)/2 + (upp - low)/2;
                }
                signal[x] = v;
            }
            break;
        case SG_USER:
            break;
    }
    for (x=0; x<numSamples; x++) {
        printf("%3d, %5.3f\r\n", x, signal[x]);
    }
}

float SignalGenDAC::rangelimit(float value, float min, float max) {
    if (value < min)
        return min;
    else if (value > max)
        return max;
    else
        return value;
}