Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mcp3008 mbed mbed-rtos AverageMCP3008 VoltageMonitor
main.cpp
- Committer:
- ryood
- Date:
- 2019-03-01
- Revision:
- 42:f58bae8771fe
- Parent:
- 41:ac576c48eace
- Child:
- 43:e5e2d1761156
File content as of revision 42:f58bae8771fe:
/*
* 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 + 1;
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 + 1;
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 + 1;
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();
}
}