KIK01 Release

Dependencies:   mcp3008 mbed mbed-rtos AverageMCP3008 VoltageMonitor

main.cpp

Committer:
ryood
Date:
2019-03-01
Revision:
43:e5e2d1761156
Parent:
42:f58bae8771fe

File content as of revision 43:e5e2d1761156:

/*
 * KIK01
 * Kick Machine
 *
 * 2019.02.23 Ver.1.01 Dual SyncIns / SyncOuts 
 * 2018.01.17 Release
 * 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   (0)

#define TITLE_STR1      ("KIK01 Kick Machine Ver.1.0.1")
#define TITLE_STR2      ("20190301")
#define TITLE_STR3      (__TIME__)

#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_KIK_BLINK_CYCLE        (0.15f)
#define LED_BEAT_NOS_BLINK_CYCLE        (0.15f)
#define LED_SYNCIN_KIK_BLINK_CYCLE      (0.04f)
#define LED_SYNCIN_NOS_BLINK_CYCLE      (0.04f)
#define LED_SYNCOUT_KIK_BLINK_CYCLE     (0.04f)
#define LED_SYNCOUT_NOS_BLINK_CYCLE     (0.04f)

// LEDs
DigitalOut LedPower(PB_2);

DigitalOut LedBeatKik(PA_12);
DigitalOut LedSyncInKik(PA_11);
DigitalOut LedSyncOutKik(PC_6);

DigitalOut LedBeatNos(PC_8);
DigitalOut LedSyncInNos(PB_12);
DigitalOut LedSyncOutNos(PC_5);

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

// 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 SyncOutKik(PC_12);
DigitalOut SyncOutNos(PD_2);

InterruptIn SyncInKik(PC_10);
InterruptIn SyncInNos(PC_11);

DigitalIn AutoRunSw(PB_1);

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

EnvelopeAR envelopeFrequencyKik(5, 300, 880.0f, 120.0f, 40.0f, 0.36f, 0.1f);
EnvelopeAR envelopeAmplitudeKik(50, 200, 0.99f, 1.0f, 0.0f);
EnvelopeAR envelopeAmplitudeNos(50, 200, 0.99f, 1.0f, 0.0f);

EnvelopeParam frequencyParamKik;
EnvelopeParam amplitudeParamKik;
EnvelopeParam amplitudeParamNos;

Timeout timeoutLedBeatKik;
Timeout timeoutLedBeatNos;
Timeout timeoutLedSyncInKik;
Timeout timeoutLedSyncInNos;
#if (LED_SYNCOUT_BLINK)
Timeout timeoutLedSyncOutKik;
Timeout timeoutLedSyncOutNos;
#endif

volatile int ticksKik;
volatile int ticksNos;
volatile float frequencyKik;
volatile float amplitudeKik;
volatile float amplitudeNos;

volatile int envelopeLength;
volatile int stepLength;

float bpm;

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

void ledBeatAtTimeoutKik()
{
    LedBeatKik = 0;
}

void ledBeatAtTimeoutNos()
{
    LedBeatNos = 0;
}

void ledSyncInAtTimeoutKik()
{
    LedSyncInKik = 0;
}

void ledSyncInAtTimeoutNos()
{
    LedSyncInNos = 0;
}

#if (LED_SYNCOUT_BLINK)
void ledSyncOutAtTimeoutKik()
{
    LedSyncOutKik = 0;
}

void ledSyncOutAtTimeoutNos()
{
    LedSyncOutNos = 0;
}
#endif

void syncInFunctionKik()
{
    ticksKik = 0;
    LedSyncInKik = 1;
    timeoutLedSyncInKik.attach(&ledSyncInAtTimeoutKik, LED_SYNCIN_KIK_BLINK_CYCLE);
}

void syncInFunctionNos()
{
    ticksNos = 0;
    LedSyncInNos = 1;
    timeoutLedSyncInNos.attach(&ledSyncInAtTimeoutNos, LED_SYNCIN_NOS_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 * frequencyKik * 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 (ticksKik % stepLength == 0) {
        SyncOutKik = 1;
#if (LED_SYNCOUT_BLINK)
        LedSyncOutKik = 1;
        timeoutLedSyncOutKik.attach(&ledSyncOutAtTimeoutKik, LED_SYNCOUT_KIK_BLINK_CYCLE);        
#endif
    }
    
    if (ticksNos % stepLength == 0) {
        SyncOutNos = 1;
#if (LED_SYNCOUT_BLINK)
        LedSyncOutNos = 1;
        timeoutLedSyncOutNos.attach(&ledSyncOutAtTimeoutNos, LED_SYNCOUT_NOS_BLINK_CYCLE);        
#endif
    }

    // set envelope parameters
    envelopeAmplitudeKik.setParam(amplitudeParamKik);
    envelopeFrequencyKik.setParam(frequencyParamKik);
    envelopeAmplitudeNos.setParam(amplitudeParamNos);

    frequencyKik = envelopeFrequencyKik.getAmplitude(ticksKik);
    amplitudeKik = envelopeAmplitudeKik.getAmplitude(ticksKik);
    amplitudeNos = envelopeAmplitudeNos.getAmplitude(ticksNos); 
    
    DcoSetFrequency(frequencyKik);
    DcaSetAmplitude(1, amplitudeKik);
    DcaSetAmplitude(2, amplitudeNos);

    ticksKik++;
    ticksNos++;
    if (AutoRunSw && ticksKik >= envelopeLength) {
        ticksKik = 0;
        LedBeatKik = 1;
        timeoutLedBeatKik.attach(&ledBeatAtTimeoutKik, LED_BEAT_KIK_BLINK_CYCLE);
    }
    if (AutoRunSw && ticksNos >= envelopeLength) {
        ticksNos = 0;
        LedBeatNos = 1;
        timeoutLedBeatNos.attach(&ledBeatAtTimeoutNos, LED_BEAT_NOS_BLINK_CYCLE);
    }

    // Output SyncSignal
    SyncOutKik = 0;
    SyncOutNos = 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;

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

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

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

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

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

int main()
{
    printf("\r\n\n%s %s %s\r\n", TITLE_STR1, TITLE_STR2, TITLE_STR3);

    // 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);
    
    SyncInKik.mode(PullDown);
    SyncInNos.mode(PullDown);
    AutoRunSw.mode(PullUp);

    frequencyKik = 100.0f;
    amplitudeKik = 1.0f;
    amplitudeNos = 1.0f;
    bpm = 120.0f;
    
    readParams();

    ticksKik = 0;
    ticksNos = 0;
    Ticker samplingTicker;
    samplingTicker.attach(&update, (1.0f/ENVELOPE_UPDATE_RATE));
    
    // Sync Interrupt
    SyncInKik.rise(&syncInFunctionKik);
    SyncInNos.rise(&syncInFunctionNos);

    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", amplitudeParamKik.attack, amplitudeParamKik.release);
        printf("%.2f\t%.2f\t%.2f\t", amplitudeParamKik.v0, amplitudeParamKik.v1, amplitudeParamKik.v2);
        printf("%.2f\t%.2f\t", amplitudeParamKik.attackTauRatio, amplitudeParamKik.releaseTauRatio);

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

        PWMon.check();
    }
}