Nucleo SPI Sequencer

Dependencies:   AverageAnalogIn N5110 Nucleo_rtos_UI_Test PinDetect RotaryEncoder Sequence mbed-rtos mbed FilterController

Fork of Nucleo_rtos_UI_Test by Ryo Od

main.cpp

Committer:
ryood
Date:
2016-06-21
Revision:
11:3aab82f74a75
Parent:
10:28082577ed5f

File content as of revision 11:3aab82f74a75:

/*
 * Nucleo SPI Sequencer
 *
 * 2016.06.12
 *
 */ 
 
#define UART_TRACE  (0)
 
#include "mbed.h"
#include "rtos.h"
#include "PinDetect.h"
#include "RotaryEncoder.h"
#include "N5110.h"
#include "AverageAnalogIn.h"
#include "SpiSequenceSender.h"
#include "SpiFilterController.h"

#define UART_TRACE  (0)
#define SPI_RATE    (8000000)

#define SEQUENCE_N  (16)
#define PITCH_MAX   (12)

DigitalOut CheckPin(PC_8);

//------------------------------------------------------------------------
// SPI Sequencer
//------------------------------------------------------------------------
SPI spiMaster(SPI_MOSI, SPI_MISO, SPI_SCK);
Sequence sequence[SEQUENCE_N];
SpiSequenceSender sequenceSender(&spiMaster, D9, sequence, SEQUENCE_N, 5);

SpiFilterController filterController(&spiMaster, D10);

//------------------------------------------------------------------------
// User Interface
//------------------------------------------------------------------------
// SPI2 Morpho
//        VCC,   SCE,  RST,  D/C,   MOSI,  SCLK,  LED
N5110 Lcd(PA_12, PB_1, PB_2, PB_12, PB_15, PB_13, PA_11);

RotaryEncoder RotEnc1(D2, D3, 0, SEQUENCE_N - 1, 0);
RotaryEncoder RotEnc2(D4, D5, 0, PITCH_MAX, 0);

AverageAnalogIn Pots[] = {
    AverageAnalogIn(A0),
    AverageAnalogIn(A1),
    AverageAnalogIn(A2),
    AverageAnalogIn(A3),
    AverageAnalogIn(A4),
};

PinDetect Pins[] = {
    PinDetect(PA_13, PullUp),
    PinDetect(PA_14, PullUp),
    PinDetect(PA_15, PullUp),
    PinDetect(PB_7,  PullUp),
    PinDetect(PC_13, PullUp),
    PinDetect(PB_10, PullUp),
    PinDetect(PA_8,  PullUp),
};

#if 0
// ToDo: Filterにモジュレーション信号を送る方法を考える。
struct Filter {
    int cutOff;
    int resonance;
    int envMod;
} Filter;
#endif

int currentStep = 0;
bool isRunning = true;
bool isDirty = true;

//------------------------------------------------------------------------
// Fuctions
//------------------------------------------------------------------------
void updateLCD()
{
    char buff[20];
    
    //Lcd.clear();
    sprintf(buff, "step#: %d  ", currentStep);
    Lcd.printString(buff, 0, 0);
    sprintf(buff, "pitch: %d  ", sequence[currentStep].getPitch());
    Lcd.printString(buff, 0, 1);
    sprintf(buff, "octave: %d  " ,sequence[currentStep].getOctave());
    Lcd.printString(buff, 0, 2);
    sprintf(buff, "%1d %1d %1d %1d %3d", 
        sequence[currentStep].noteOn, sequence[currentStep].tie, sequence[currentStep].accent,
        isRunning, sequenceSender.getWaveShape());
    Lcd.printString(buff, 0, 3);
    sprintf(buff, "%3d %3d %3d", 
        sequenceSender.getPulseWidth(), filterController.getEnvMod(), sequenceSender.getBpm());
    Lcd.printString(buff, 0, 4);
    sprintf(buff, "%3d %3d", filterController.getCutoff(), filterController.getResonance());
    Lcd.printString(buff, 0, 5);
    Lcd.refresh();
}

void initSequence()
{
    for (int i = 0; i < SEQUENCE_N; i++) {
        Sequence& seq = sequenceSender.getSequences()[i];
        seq.setPitch(i);
        seq.setOctave(0);
        seq.tie = true;
    }
}

//------------------------------------------------------------------------
// CallBack routines
//------------------------------------------------------------------------
void swOctaveUpPressed()
{
    sequence[currentStep].setOctave(sequence[currentStep].getOctave() + 1);
    isDirty = true;
    #if (UART_TRACE)
    printf("swOctaveUpPressed\r\n");
    #endif
}

void swOctaveDownPressed()
{
    sequence[currentStep].setOctave(sequence[currentStep].getOctave() - 1);
    isDirty = true;
    #if (UART_TRACE)
    printf("swOctaveDownPressed\r\n");
    #endif
}

void swNoteOnOffPressed()
{
    sequence[currentStep].noteOn = !sequence[currentStep].noteOn;
    isDirty = true;
    #if (UART_TRACE)
    printf("swNoteOnOffPressed\r\n");
    #endif
}

void swTiePressed()
{
    sequence[currentStep].tie = !sequence[currentStep].tie;
    isDirty = true;
    #if (UART_TRACE)
    printf("swTiePressed\r\n");
    #endif
}

void swAccentPressed()
{
    sequence[currentStep].accent = !sequence[currentStep].accent;
    isDirty = true;
    #if (UART_TRACE)
    printf("swAccentPressed\r\n");
    #endif
}

void swRunStopPressed()
{
    isRunning = !isRunning;
    if (isRunning) {
        sequenceSender.run(currentStep);
    } else {
        sequenceSender.stop();
    }
    isDirty = true;
    #if (UART_TRACE)
    printf("swRunStopPressed\r\n");
    #endif
}

void swWaveShapePressed()
{
    uint8_t shape = sequenceSender.getWaveShape();
    shape++;
    if (shape == sequenceSender.WAVESHAPE_N) {
        shape = 0;
    }
    sequenceSender.setWaveShape(shape);
    isDirty = true;
    #if (UART_TRACE)
    printf("swWaveShapePressed\r\n");
    #endif
}

//------------------------------------------------------------------------
// Thread
//------------------------------------------------------------------------
void pollingRotEncs(void const *argument)
{
    while (true) {
        int _step = RotEnc1.getVal();
        if (_step != currentStep) {
            currentStep = _step;
            // syncronize sequence value & Rotary Encoder's value
            RotEnc2.setVal(sequence[currentStep].getPitch());
            isDirty = true;
        }
        int _pitch = RotEnc2.getVal();
        if (_pitch != sequence[currentStep].getPitch()) {
            sequence[currentStep].setPitch(_pitch);
            isDirty = true;
        }
        Thread::wait(10);
    }
}

void pollingPots(void const *argument)
{
    unsigned short tmp;
    
    while (true) {
        // pulse width
        tmp = Pots[0].read_u16() >> 9;    // 7bit width
        if (tmp != (sequenceSender.getPulseWidth() >> 1)) {
            sequenceSender.setPulseWidth(tmp << 1);
            isDirty = true;
        }
        // filter envelope moduration 
        tmp = Pots[1].read_u16() >> 8;
        if (tmp != filterController.getEnvMod()) {
            filterController.setEnvMod(tmp);
            isDirty = true;
        }
        // bpm
        tmp = Pots[2].read_u16() >> 9;    // 7bit precission
        tmp <<= 1;
        if (tmp != sequenceSender.getBpm()) {
            sequenceSender.setBpm(tmp);
            isDirty = true;
        }
        // cutoff
        tmp = Pots[3].read_u16() >> 8;
        if (tmp != filterController.getCutoff()) {
            filterController.setCutoff(tmp);
            isDirty = true;
        }
        // resonance
        tmp = Pots[4].read_u16() >> 8;
        if (tmp != filterController.getResonance()) {
            filterController.setResonance(tmp);
            isDirty = true;
        }
        Thread::wait(20);
    }
}

//------------------------------------------------------------------------
// Main routine
//------------------------------------------------------------------------
int main()
{
    #if (UART_TRACE)
    printf("\n\n\r*** RTOS UI Test ***\r\n");
    #endif
    
    spiMaster.format(0, 8);
    spiMaster.frequency(SPI_RATE);

    // Init devices
    RotEnc1.setInterval(500);
    RotEnc2.setInterval(500);
    
    Pins[0].attach_asserted(&swOctaveUpPressed);
    Pins[1].attach_asserted(&swOctaveDownPressed);
    Pins[2].attach_asserted(&swNoteOnOffPressed);
    Pins[3].attach_asserted(&swTiePressed);
    Pins[4].attach_asserted(&swAccentPressed);
    Pins[5].attach_asserted(&swRunStopPressed);
    Pins[6].attach_asserted(&swWaveShapePressed);
    for (int i = 0; i < 7; i++) {
        Pins[i].setAssertValue(0);
        Pins[i].setSampleFrequency();
    }
    
    Lcd.init();
    Lcd.normalMode();      // normal colour mode
    Lcd.setBrightness(0.5); // put LED backlight on 50%
    
    // Thread start
    Thread thRotEnc(pollingRotEncs, NULL, osPriorityNormal, DEFAULT_STACK_SIZE);
    Thread thPots(pollingPots, NULL, osPriorityNormal, DEFAULT_STACK_SIZE);

    initSequence();
    sequenceSender.run(0);
    
    // Main loop
    while (true) {
        if (!isRunning && isDirty) {
            CheckPin = !CheckPin;
            filterController.outDCF();
            updateLCD();
            isDirty = false;
        }
    }
}