KIK01 Release

Dependencies:   mcp3008 mbed mbed-rtos AverageMCP3008 VoltageMonitor

main.cpp

Committer:
ryood
Date:
2017-12-30
Revision:
38:90dde01f8255
Parent:
37:85eb8e38cac8
Child:
39:3c73531d13a2

File content as of revision 38:90dde01f8255:

/*
 * KIK01
 * Kick Machine
 *
 * 2017.12.15 Proto08: LEDs
 * 2017.12.03 Proto07: SyncIn
 * 2017.11.29 Proto06: Add Power Monitor
 * 2017.10.19 Proto05: Add NOS01 Controller
 * 2017.09.16 Proto04: SPI1 for AD8402 Wein Bridge DCO & Internal DAC for Dual-OTA-VCA
 * 2017.07.04 Proto03: MCP4922 DCA
 * 2017.06.19 Proto02
 * 2017.06.04 created.
 *
 */

#include "mbed.h"
#include "rtos.h"
#include "mcp3008.h"
#include "AverageMCP3008.h"
#include "EnvelopeAR.h"

#define UART_TRACE      (0)
#include "VoltageMonitor.h"

#define PIN_CHECK       (0)
#define LED_SYNCOUT_BLINK   (1)

#define TITLE_STR1      ("KIK01 Kick Machine Proto08")
#define TITLE_STR2      ("20171230")

#define PI_F            (3.1415926f)

#define MCP3008_SPI_SPEED       (1406250)
#define AD8402_SPI_SPEED        (10000000)
#define ENVELOPE_UPDATE_RATE    (32000)  //  Hz

#define AD8402_RMAX (10000.0f)
#define AD8402_RMIN (50.0f)

#define AVERAGE_BUFFER_SIZE (4)

#define PM_VDD           (3.32f)
#define PM_LoThreshold   (2.3f)
#define PM_HiThreshold   (2.7f)

#define LED_BEAT_BLINK_CYCLE        (0.15f)
#define LED_SYNCIN_BLINK_CYCLE      (0.04f)
#define LED_SYNCOUT_BLINK_CYCLE     (0.04f)

// LEDs
DigitalOut LedPower(PB_2);
DigitalOut LedBeat(PA_12);
DigitalOut LedSyncIn(PA_11);
DigitalOut LedSyncOut(PB_12);

// Envelope Output
AnalogOut Dac1(PA_4);
AnalogOut Dac2(PA_5);

// AD8402 SPI (SPI2)
// SPI (PinName mosi, PinName miso, PinName sclk, PinName ssel=NC)
SPI SpiMAD8402(PB_15, PB_14, PB_13);
DigitalOut AD8402Cs(PC_4, 1);   // Initaially Inactive

// MCP3008 SPI
// SPI (PinName mosi, PinName miso, PinName sclk, PinName ssel=NC)
SPI SpiMAdc(PB_5, PB_4, PB_3);
MCP3008 Adc1(&SpiMAdc, PA_9);
MCP3008 Adc2(&SpiMAdc, PA_8);
MCP3008 Adc3(&SpiMAdc, PB_10);
AverageMCP3008 AvgAdc1(&Adc1, AVERAGE_BUFFER_SIZE); 
AverageMCP3008 AvgAdc2(&Adc2, AVERAGE_BUFFER_SIZE); 
AverageMCP3008 AvgAdc3(&Adc3, AVERAGE_BUFFER_SIZE);

// Power Monitor
AnalogIn PowerMonitorIn(PA_0);
VoltageMonitor PWMon(&PowerMonitorIn, PM_VDD, PM_LoThreshold, PM_HiThreshold, &LedPower);

// Sync
DigitalOut SyncOut(PC_10);
InterruptIn SyncIn(PC_11);
DigitalIn AutoRunSw(PB_1);

// Check pins
DigitalOut Dout1(D14);
DigitalOut Dout2(D15);
DigitalOut Dout3(D2);

EnvelopeAR envelopeFrequency(5, 300, 880.0f, 120.0f, 40.0f, 0.36f, 0.1f);
EnvelopeAR envelopeAmplitude(50, 200, 0.99f, 1.0f, 0.0f);
EnvelopeAR envelopeNoiseAmplitude(50, 200, 0.99f, 1.0f, 0.0f);

EnvelopeParam frequencyParam;
EnvelopeParam amplitudeParam;
EnvelopeParam noiseAmplitudeParam;

Timeout timeoutLedBeat;
Timeout timeoutLedSyncIn;
#if (LED_SYNCOUT_BLINK)
Timeout timeoutLedSyncOut;
#endif

volatile int ticks;
volatile float frequency;
volatile float amplitude;
volatile float noiseAmplitude;

volatile int envelopeLength;
volatile int stepLength;

float bpm;

//-----------------------------------------------------------------------------
// Interrupt Service Routine
//-----------------------------------------------------------------------------

void ledBeatAtTimeout()
{
    LedBeat = 0;
}

void ledSyncInAtTimeout()
{
    LedSyncIn = 0;
}

#if (LED_SYNCOUT_BLINK)
void ledSyncOutAtTimeout()
{
    LedSyncOut = 0;
}
#endif

void syncInFunction()
{
    ticks = 0;
    LedSyncIn = 1;
    timeoutLedSyncIn.attach(&ledSyncInAtTimeout, LED_SYNCIN_BLINK_CYCLE);
}

void AD8402Write(uint8_t address, uint8_t value)
{
#if (PIN_CHECK)
    Dout2 = 1;
#endif    

    AD8402Cs = 0;
    SpiMAD8402.write(address);
    SpiMAD8402.write(value);
    AD8402Cs = 1;
    wait_us(1);

#if (PIN_CHECK)
    Dout2 = 0;
#endif
}

void DcoSetFrequency(float freq)
{
    const float c = 0.00000047;
    float r = 1.0f / (2.0f * PI_F * frequency * c);
    if (r < AD8402_RMIN) r = AD8402_RMIN;
    if (r > AD8402_RMAX) r = AD8402_RMAX;
    
    uint8_t v = 256.0f * (r - AD8402_RMIN) / AD8402_RMAX;

    AD8402Write(0, v);
    AD8402Write(1, v);
}

void DcaSetAmplitude(int channel, float amp)
{
    switch (channel) {
    case 1:
        Dac1.write(amp);
        break;
    case 2:
        //Dac2.write(amp);
        Dac2.write(amp * 0.8f); // Avoid LED,s Non-Linearity
        break;
    default:
        error("DcaSetAmplitude(): invalid channel");
    }
}

void update()
{
#if (PIN_CHECK)
    Dout1 = 1;
#endif

    // Output Sync Signal per steps
    if (ticks % stepLength == 0) {
        SyncOut = 1;
#if (LED_SYNCOUT_BLINK)
        LedSyncOut = 1;
        timeoutLedSyncOut.attach(&ledSyncOutAtTimeout, LED_SYNCOUT_BLINK_CYCLE);        
#endif
    }

    // set envelope parameters
    envelopeAmplitude.setParam(amplitudeParam);
    envelopeFrequency.setParam(frequencyParam);
    envelopeNoiseAmplitude.setParam(noiseAmplitudeParam);

    frequency = envelopeFrequency.getAmplitude(ticks);
    amplitude = envelopeAmplitude.getAmplitude(ticks);
    noiseAmplitude = envelopeNoiseAmplitude.getAmplitude(ticks); 
    
    DcoSetFrequency(frequency);
    DcaSetAmplitude(1, amplitude);  // DCO
    DcaSetAmplitude(2, noiseAmplitude);  // NOS01

    ticks++;
    if (AutoRunSw && ticks >= envelopeLength) {
        ticks = 0;
        LedBeat = 1;
        timeoutLedBeat.attach(&ledBeatAtTimeout, LED_BEAT_BLINK_CYCLE);
    }

    // Output SyncSignal
    SyncOut = 0;

#if (PIN_CHECK)
    Dout1 = 0;
#endif
}

//-----------------------------------------------------------------------------
// Functions
//-----------------------------------------------------------------------------

void readParams()
{
    bpm = AvgAdc1.read_input(7) * 180.0f + 60.0f;
    envelopeLength = 60 * ENVELOPE_UPDATE_RATE / bpm;
    stepLength = envelopeLength / 4;

    amplitudeParam.attack = AvgAdc1.read_input(0) * envelopeLength;
    amplitudeParam.release = AvgAdc1.read_input(1) * envelopeLength;
    amplitudeParam.v0 = AvgAdc1.read_input(4);
    amplitudeParam.v1 = AvgAdc1.read_input(5);
    amplitudeParam.v2 = AvgAdc1.read_input(6);
    amplitudeParam.attackTauRatio = AvgAdc1.read_input(2) + 0.01f;
    amplitudeParam.releaseTauRatio = AvgAdc1.read_input(3) + 0.01f;

    frequencyParam.attack = AvgAdc2.read_input(0) * envelopeLength * 0.1f;
    frequencyParam.release = AvgAdc2.read_input(1) * envelopeLength + 1;
    frequencyParam.v0 = AvgAdc2.read_input(4) * 4000.0f;
    frequencyParam.v1 = AvgAdc2.read_input(5) * 400.0f;
    frequencyParam.v2 = AvgAdc2.read_input(6) * 400.0f;
    frequencyParam.attackTauRatio = AvgAdc2.read_input(2) + 0.01f;
    frequencyParam.releaseTauRatio = AvgAdc2.read_input(3) + 0.01f;
    
    noiseAmplitudeParam.attack = AvgAdc3.read_input(0) * envelopeLength;
    noiseAmplitudeParam.release = AvgAdc3.read_input(1) * envelopeLength;
    noiseAmplitudeParam.v0 = AvgAdc3.read_input(4);
    noiseAmplitudeParam.v1 = AvgAdc3.read_input(5);
    noiseAmplitudeParam.v2 = AvgAdc3.read_input(6);
    noiseAmplitudeParam.attackTauRatio = AvgAdc3.read_input(2) + 0.01f;
    noiseAmplitudeParam.releaseTauRatio = AvgAdc3.read_input(3) + 0.01f;
}

void LedsCheck(int n, int wait)
{
    for (int i = 0; i < n; i++) {
        LedBeat = 1;
        Thread::wait(wait);
        LedBeat = 0;

        LedSyncIn = 1;
        Thread::wait(wait);
        LedSyncIn = 0;

        LedSyncOut = 1;
        LedSyncOut = 0;
        Thread::wait(wait);
    }
}

int main()
{
#if UART_TRACE
    printf("\r\n\n%s %s\r\n", TITLE_STR1, TITLE_STR2);
#endif

    // LEDs Check
    LedsCheck(4, 100);  // 4 counts, 100ms cycle

    SpiMAD8402.format(8, 0);
    SpiMAD8402.frequency(AD8402_SPI_SPEED);

    SpiMAdc.format(8, 0);
    SpiMAdc.frequency(MCP3008_SPI_SPEED);
    
    SyncIn.mode(PullDown);
    AutoRunSw.mode(PullUp);

    frequency = 100.0f;
    amplitude = 1.0f;
    noiseAmplitude = 1.0f;
    bpm = 120.0f;
    
    readParams();

    ticks = 0;
    Ticker samplingTicker;
    samplingTicker.attach(&update, (1.0f/ENVELOPE_UPDATE_RATE));
    
    // Sync Interrupt
    SyncIn.rise(&syncInFunction);
    SyncIn.mode(PullDown);

    for (;;) {
#if (PIN_CHECK)
        Dout3 = 1;
#endif

        readParams();

#if (PIN_CHECK)
        Dout3 = 0;
#endif


#if UART_TRACE
        printf("%.1f\t%d\t", bpm, envelopeLength);

        printf("| %d\t%d\t", amplitudeParam.attack, amplitudeParam.release);
        printf("%.2f\t%.2f\t%.2f\t", amplitudeParam.v0, amplitudeParam.v1, amplitudeParam.v2);
        printf("%.2f\t%.2f\t", amplitudeParam.attackTauRatio, amplitudeParam.releaseTauRatio);

        printf("| %d\t%d\t", frequencyParam.attack, frequencyParam.release);
        printf("%.2f\t%.2f\t%.2f\t", frequencyParam.v0, frequencyParam.v1, frequencyParam.v2);
        printf("%.2f\t%.2f\t", frequencyParam.attackTauRatio, frequencyParam.releaseTauRatio);
        
        printf("| %d\t%d\t", noiseAmplitudeParam.attack, noiseAmplitudeParam.release);
        printf("%.2f\t%.2f\t%.2f\t", noiseAmplitudeParam.v0, noiseAmplitudeParam.v1, noiseAmplitudeParam.v2);
        printf("%.2f\t%.2f\t", noiseAmplitudeParam.attackTauRatio, noiseAmplitudeParam.releaseTauRatio);
        
        printf("| AutoRun:%d\t", int(AutoRunSw));
#endif

        PWMon.check();

        Thread::wait(1);
    }
}