mirror of
https://github.com/supleed2/ELEC60013-ES-CW2.git
synced 2024-12-22 21:55:50 +00:00
Merge branch 'main' of https://github.com/supleed2/ELEC60013-ES-CW2
This commit is contained in:
commit
a9c40e69f0
Binary file not shown.
|
@ -3,14 +3,18 @@
|
||||||
|
|
||||||
class Knob {
|
class Knob {
|
||||||
private:
|
private:
|
||||||
int rotation;
|
int rotation, rotationInternal;
|
||||||
int minimum, maximum;
|
int minimum, maximum, previousRotation;
|
||||||
bool A, B;
|
bool A, B;
|
||||||
bool rotPlusOnePrev, rotMinOnePrev;
|
enum PrevRot {
|
||||||
|
NONE,
|
||||||
|
CW,
|
||||||
|
ACW,
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Knob(int minimum, int max);
|
Knob(int minimum, int maximum, int initialRotation);
|
||||||
Knob(int minimum, int max, int initialRotation);
|
Knob(int minimum, int maximum) : Knob(minimum, maximum, minimum) {} // Delegate to full constructor, using minimum as initial rotation
|
||||||
|
|
||||||
int getRotation();
|
int getRotation();
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,13 @@
|
||||||
#include <knob>
|
#include <knob>
|
||||||
|
|
||||||
Knob::Knob(int minimum, int maximum) {
|
|
||||||
Knob::minimum = minimum;
|
|
||||||
Knob::maximum = maximum;
|
|
||||||
Knob::A = false;
|
|
||||||
Knob::B = false;
|
|
||||||
Knob::rotPlusOnePrev = false;
|
|
||||||
Knob::rotMinOnePrev = false;
|
|
||||||
Knob::rotation = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Knob::Knob(int minimum, int maximum, int initialRotation) {
|
Knob::Knob(int minimum, int maximum, int initialRotation) {
|
||||||
Knob::minimum = minimum;
|
Knob::minimum = minimum;
|
||||||
Knob::maximum = maximum;
|
Knob::maximum = maximum;
|
||||||
Knob::A = false;
|
Knob::A = false;
|
||||||
Knob::B = false;
|
Knob::B = false;
|
||||||
Knob::rotPlusOnePrev = false;
|
Knob::previousRotation = NONE;
|
||||||
Knob::rotMinOnePrev = false;
|
|
||||||
Knob::rotation = initialRotation;
|
Knob::rotation = initialRotation;
|
||||||
|
Knob::rotationInternal = initialRotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Knob::getRotation() {
|
int Knob::getRotation() {
|
||||||
|
@ -25,36 +15,63 @@ int Knob::getRotation() {
|
||||||
};
|
};
|
||||||
|
|
||||||
void Knob::updateRotation(bool ANew, bool BNew) {
|
void Knob::updateRotation(bool ANew, bool BNew) {
|
||||||
bool rotPlusOneNew = (!B && !A && !BNew && ANew) ||
|
if (A == ANew && B == BNew)
|
||||||
|
return; // No change, do not update values
|
||||||
|
|
||||||
|
bool fullstep = (BNew && ANew) || (!BNew && !ANew);
|
||||||
|
|
||||||
|
bool cwRot = (!B && !A && !BNew && ANew) ||
|
||||||
(!B && A && BNew && ANew) ||
|
(!B && A && BNew && ANew) ||
|
||||||
(B && !A && !BNew && !ANew) ||
|
(B && !A && !BNew && !ANew) ||
|
||||||
(B && A && BNew && !ANew);
|
(B && A && BNew && !ANew);
|
||||||
|
|
||||||
bool rotMinOneNew = (!B && !A && BNew && !ANew) ||
|
bool acwRot = (!B && !A && BNew && !ANew) ||
|
||||||
(!B && A && !BNew && !ANew) ||
|
(!B && A && !BNew && !ANew) ||
|
||||||
(B && !A && BNew && ANew) ||
|
(B && !A && BNew && ANew) ||
|
||||||
(B && A && !BNew && ANew);
|
(B && A && !BNew && ANew);
|
||||||
|
|
||||||
bool impossibleState = (!B && !A && BNew && ANew) ||
|
bool impossible = (!B && !A && BNew && ANew) ||
|
||||||
(!B && A && BNew && !ANew) ||
|
(!B && A && BNew && !ANew) ||
|
||||||
(B && !A && !BNew && ANew) ||
|
(B && !A && !BNew && ANew) ||
|
||||||
(B && A && !BNew && !ANew);
|
(B && A && !BNew && !ANew);
|
||||||
|
|
||||||
if (rotPlusOneNew || (impossibleState && rotPlusOnePrev))
|
if (cwRot) {
|
||||||
rotation += 1;
|
if (previousRotation == CW && fullstep) {
|
||||||
if (rotMinOneNew || (impossibleState && rotMinOnePrev))
|
rotationInternal++;
|
||||||
rotation -= 1;
|
} else if (previousRotation == ACW) {
|
||||||
if (rotation < minimum)
|
previousRotation = NONE;
|
||||||
rotation = minimum;
|
} else {
|
||||||
if (rotation > maximum)
|
previousRotation = CW;
|
||||||
rotation = maximum;
|
}
|
||||||
|
} else if (acwRot) {
|
||||||
|
if (previousRotation == ACW && fullstep) {
|
||||||
|
rotationInternal--;
|
||||||
|
} else if (previousRotation == CW) {
|
||||||
|
previousRotation = NONE;
|
||||||
|
} else {
|
||||||
|
previousRotation = ACW;
|
||||||
|
}
|
||||||
|
} else if (impossible) {
|
||||||
|
if (fullstep) {
|
||||||
|
switch (previousRotation) {
|
||||||
|
case NONE: // Step skipped and no previous direction
|
||||||
|
break;
|
||||||
|
case CW:
|
||||||
|
rotationInternal++;
|
||||||
|
break;
|
||||||
|
case ACW:
|
||||||
|
rotationInternal--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
A = ANew;
|
A = ANew;
|
||||||
B = BNew;
|
B = BNew;
|
||||||
if (!impossibleState) {
|
if (rotationInternal < minimum)
|
||||||
rotPlusOnePrev = rotPlusOneNew;
|
rotationInternal = minimum;
|
||||||
rotMinOnePrev = rotMinOneNew;
|
if (rotationInternal > maximum)
|
||||||
}
|
rotationInternal = maximum;
|
||||||
|
rotation = rotationInternal;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Knob::changeLimitsVolume(int newMinimum, int newMaximum) {
|
void Knob::changeLimitsVolume(int newMinimum, int newMaximum) {
|
||||||
|
|
304
src/main.cpp
304
src/main.cpp
|
@ -12,27 +12,30 @@ const uint32_t interval = 10; // Display update interval
|
||||||
const uint32_t samplingRate = 44100; // Sampling rate
|
const uint32_t samplingRate = 44100; // Sampling rate
|
||||||
const uint32_t canID = 0x123;
|
const uint32_t canID = 0x123;
|
||||||
// Variables
|
// Variables
|
||||||
|
std::atomic<bool> isMainSynth;
|
||||||
std::atomic<int32_t> currentStepSize;
|
std::atomic<int32_t> currentStepSize;
|
||||||
std::atomic<uint8_t> keyArray[7];
|
std::atomic<uint8_t> keyArray[7];
|
||||||
std::atomic<uint8_t> octave;
|
std::atomic<uint8_t> octave;
|
||||||
|
std::atomic<uint8_t> selectedWaveform;
|
||||||
|
std::atomic<int> latestKey;
|
||||||
std::atomic<int8_t> volume;
|
std::atomic<int8_t> volume;
|
||||||
std::atomic<bool> volumeFiner;
|
std::atomic<bool> volumeFiner;
|
||||||
std::atomic<int8_t> wave;
|
|
||||||
int8_t volumeHistory = 0;
|
int8_t volumeHistory = 0;
|
||||||
QueueHandle_t msgInQ;
|
QueueHandle_t msgInQ;
|
||||||
uint8_t RX_Message[8] = {0};
|
uint8_t RX_Message[8] = {0};
|
||||||
|
std::atomic<bool> bufferAactive;
|
||||||
|
int32_t bufferA[220];
|
||||||
|
int32_t bufferB[220];
|
||||||
// Objects
|
// Objects
|
||||||
U8G2_SSD1305_128X32_NONAME_F_HW_I2C u8g2(U8G2_R0); // Display driver object
|
U8G2_SSD1305_128X32_NONAME_F_HW_I2C u8g2(U8G2_R0); // Display Driver Object
|
||||||
Knob K0(2,14,8); //Octave encoder
|
Knob K0(1, 7, 4); // Octave Knob Object
|
||||||
Knob K1(0,6); //Waveform encoder
|
Knob K1(0, 3, 1); // Waveform Knob Object
|
||||||
Knob K3(0,10); //Volume encoder
|
Knob K2(0, 1); // Send / Receive Knob Object
|
||||||
|
Knob K3(0, 16); // Volume Knob Object
|
||||||
// Program Specific Structures
|
// Program Specific Structures
|
||||||
typedef struct{
|
const int32_t stepSizes[85] = {0, 3185014, 3374405, 3575058, 3787642, 4012867, 4251484, 4504291, 4772130, 5055895, 5356535, 5675051, 6012507, 6370029, 6748811, 7150116, 7575284, 8025734, 8502969, 9008582, 9544260, 10111791, 10713070, 11350102, 12025014, 12740059, 13497622, 14300233, 15150569, 16051469, 17005939, 18017164, 19088521, 20223583, 21426140, 22700205, 24050029, 25480118, 26995245, 28600466, 30301138, 32102938, 34011878, 36034329, 38177042, 40447167, 42852281, 45400410, 48100059, 50960237, 53990491, 57200933, 60602277, 64205876, 68023756, 72068659, 76354085, 80894335, 85704562, 90800821, 96200119, 101920475, 107980982, 114401866, 121204555, 128411753, 136047513, 144137319, 152708170, 161788670, 171409125, 181601642, 192400238, 203840951, 215961965, 228803732, 242409110, 256823506, 272095026, 288274638, 305416340, 323577341, 342818251, 363203285, 384800476};
|
||||||
int32_t stepSize;
|
const char *notes[85] = {"None", "C1", "C1#", "D1", "D1#", "E1", "F1", "F1#", "G1", "G1#", "A1", "A1#", "B1", "C2", "C2#", "D2", "D2#", "E2", "F2", "F2#", "G2", "G2#", "A2", "A2#", "B2", "C3", "C3#", "D3", "D3#", "E3", "F3", "F3#", "G3", "G3#", "A3", "A3#", "B3", "C4", "C4#", "D4", "D4#", "E4", "F4", "F4#", "G4", "G4#", "A4", "A4#", "B4", "C5", "C5#", "D5", "D5#", "E5", "F5", "F5#", "G5", "G5#", "A5", "A5#", "B5", "C6", "C6#", "D6", "D6#", "E6", "F6", "F6#", "G6", "G6#", "A6", "A6#", "B6", "C7", "C7#", "D7", "D7#", "E7", "F7", "F7#", "G7", "G7#", "A7", "A7#", "B7"};
|
||||||
std::string note;
|
std::atomic<bool> activeNotes[85] = {{0}};
|
||||||
} Note;
|
|
||||||
const Note notes[] = {
|
|
||||||
{0, "None"}, {3185014, "C1"}, {3374405, "C1#"}, {3575058, "D1"}, {3787642, "D1#"}, {4012867, "E1"}, {4251484, "F1"}, {4504291, "F1#"}, {4772130, "G1"}, {5055895, "G1#"}, {5356535, "A1"}, {5675051, "A1#"}, {6012507, "B1"}, {6370029, "C2"}, {6748811, "C2#"}, {7150116, "D2"}, {7575284, "D2#"}, {8025734, "E2"}, {8502969, "F2"}, {9008582, "F2#"}, {9544260, "G2"}, {10111791, "G2#"}, {10713070, "A2"}, {11350102, "A2#"}, {12025014, "B2"}, {12740059, "C3"}, {13497622, "C3#"}, {14300233, "D3"}, {15150569, "D3#"}, {16051469, "E3"}, {17005939, "F3"}, {18017164, "F3#"}, {19088521, "G3"}, {20223583, "G3#"}, {21426140, "A3"}, {22700205, "A3#"}, {24050029, "B3"}, {25480118, "C4"}, {26995245, "C4#"}, {28600466, "D4"}, {30301138, "D4#"}, {32102938, "E4"}, {34011878, "F4"}, {36034329, "F4#"}, {38177042, "G4"}, {40447167, "G4#"}, {42852281, "A4"}, {45400410, "A4#"}, {48100059, "B4"}, {50960237, "C5"}, {53990491, "C5#"}, {57200933, "D5"}, {60602277, "D5#"}, {64205876, "E5"}, {68023756, "F5"}, {72068659, "F5#"}, {76354085, "G5"}, {80894335, "G5#"}, {85704562, "A5"}, {90800821, "A5#"}, {96200119, "B5"}, {101920475, "C6"}, {107980982, "C6#"}, {114401866, "D6"}, {121204555, "D6#"}, {128411753, "E6"}, {136047513, "F6"}, {144137319, "F6#"}, {152708170, "G6"}, {161788670, "G6#"}, {171409125, "A6"}, {181601642, "A6#"}, {192400238, "B6"}, {203840951, "C7"}, {215961965, "C7#"}, {228803732, "D7"}, {242409110, "D7#"}, {256823506, "E7"}, {272095026, "F7"}, {288274638, "F7#"}, {305416340, "G7"}, {323577341, "G7#"}, {342818251, "A7"}, {363203285, "A7#"}, {384800476, "B7"}};
|
|
||||||
enum waveform {
|
enum waveform {
|
||||||
SQUARE = 0,
|
SQUARE = 0,
|
||||||
SAWTOOTH,
|
SAWTOOTH,
|
||||||
|
@ -50,22 +53,39 @@ const unsigned char waveforms[4][18] = {
|
||||||
0x10, 0xc0, 0x18, 0x80, 0x08, 0x80, 0x0d, 0x00, 0x07} // Sine Wave
|
0x10, 0xc0, 0x18, 0x80, 0x08, 0x80, 0x0d, 0x00, 0x07} // Sine Wave
|
||||||
};
|
};
|
||||||
const unsigned char volumes[6][18] = {
|
const unsigned char volumes[6][18] = {
|
||||||
{0x10, 0x02, 0x98, 0x04, 0x1c, 0x05, 0x5f, 0x09, 0x5f,
|
{0x10, 0x00, 0x18, 0x00, 0x5c, 0x04, 0x9f, 0x02, 0x1f,
|
||||||
0x09, 0x5f, 0x09, 0x1c, 0x05, 0x98, 0x04, 0x10, 0x02}, // volume max
|
0x01, 0x9f, 0x02, 0x5c, 0x04, 0x18, 0x00, 0x10, 0x00}, // mute
|
||||||
{0x10, 0x00, 0x98, 0x00, 0x1c, 0x01, 0x5f, 0x01, 0x5f,
|
|
||||||
0x01, 0x5f, 0x01, 0x1c, 0x01, 0x98, 0x00, 0x10, 0x00}, // volume mid higher
|
|
||||||
{0x10, 0x00, 0x18, 0x00, 0x1c, 0x01, 0x5f, 0x01, 0x5f,
|
|
||||||
0x01, 0x5f, 0x01, 0x1c, 0x01, 0x18, 0x00, 0x10, 0x00}, // volume mid lower
|
|
||||||
{0x10, 0x00, 0x18, 0x00, 0x1c, 0x00, 0x5f, 0x00, 0x5f,
|
|
||||||
0x00, 0x5f, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x10, 0x00}, // volume low
|
|
||||||
{0x10, 0x00, 0x18, 0x00, 0x1c, 0x00, 0x1f, 0x00, 0x5f,
|
{0x10, 0x00, 0x18, 0x00, 0x1c, 0x00, 0x1f, 0x00, 0x5f,
|
||||||
0x00, 0x1f, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x10, 0x00}, // volume lowest
|
0x00, 0x1f, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x10, 0x00}, // volume lowest
|
||||||
{0x10, 0x00, 0x18, 0x00, 0x5c, 0x04, 0x9f, 0x02, 0x1f,
|
{0x10, 0x00, 0x18, 0x00, 0x1c, 0x00, 0x5f, 0x00, 0x5f,
|
||||||
0x01, 0x9f, 0x02, 0x5c, 0x04, 0x18, 0x00, 0x10, 0x00} // mute
|
0x00, 0x5f, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x10, 0x00}, // volume low
|
||||||
|
{0x10, 0x00, 0x18, 0x00, 0x1c, 0x01, 0x5f, 0x01, 0x5f,
|
||||||
|
0x01, 0x5f, 0x01, 0x1c, 0x01, 0x18, 0x00, 0x10, 0x00}, // volume mid lower
|
||||||
|
{0x10, 0x00, 0x98, 0x00, 0x1c, 0x01, 0x5f, 0x01, 0x5f,
|
||||||
|
0x01, 0x5f, 0x01, 0x1c, 0x01, 0x98, 0x00, 0x10, 0x00}, // volume mid higher
|
||||||
|
{0x10, 0x02, 0x98, 0x04, 0x1c, 0x05, 0x5f, 0x09, 0x5f,
|
||||||
|
0x09, 0x5f, 0x09, 0x1c, 0x05, 0x98, 0x04, 0x10, 0x02}, // volume max
|
||||||
};
|
};
|
||||||
const unsigned char icon_bits[] = {
|
const unsigned char icon_bits[] = {
|
||||||
0x00, 0x00, 0x00, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x02, 0x01, 0x02, 0x01, 0xfe, 0x01, 0x00, 0x00};
|
0x00, 0x00, 0x02, 0x01, 0x02, 0x01, 0xfe, 0x01, 0x00, 0x00};
|
||||||
|
const int8_t sinLUT[256] = {
|
||||||
|
0, 3, 6, 9, 12, 15, 18, 21, 24, 28, 31, 34, 37, 40, 43, 46,
|
||||||
|
48, 51, 54, 57, 60, 63, 65, 68, 71, 73, 76, 78, 81, 83, 85, 88,
|
||||||
|
90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 109, 111, 112, 114, 115, 117,
|
||||||
|
118, 119, 120, 121, 122, 123, 124, 124, 125, 126, 126, 127, 127, 127, 127, 127,
|
||||||
|
127, 127, 127, 127, 127, 127, 126, 126, 125, 124, 124, 123, 122, 121, 120, 119,
|
||||||
|
118, 117, 115, 114, 112, 111, 109, 108, 106, 104, 102, 100, 98, 96, 94, 92,
|
||||||
|
90, 88, 85, 83, 81, 78, 76, 73, 71, 68, 65, 63, 60, 57, 54, 51,
|
||||||
|
48, 46, 43, 40, 37, 34, 31, 28, 24, 21, 18, 15, 12, 9, 6, 3,
|
||||||
|
0, -4, -7, -10, -13, -16, -19, -22, -25, -29, -32, -35, -38, -41, -44, -47,
|
||||||
|
-49, -52, -55, -58, -61, -64, -66, -69, -72, -74, -77, -79, -82, -84, -86, -89,
|
||||||
|
-91, -93, -95, -97, -99, -101, -103, -105, -107, -109, -110, -112, -113, -115, -116, -118,
|
||||||
|
-119, -120, -121, -122, -123, -124, -125, -125, -126, -127, -127, -128, -128, -128, -128, -128,
|
||||||
|
-128, -128, -128, -128, -128, -128, -127, -127, -126, -125, -125, -124, -123, -122, -121, -120,
|
||||||
|
-119, -118, -116, -115, -113, -112, -110, -109, -107, -105, -103, -101, -99, -97, -95, -93,
|
||||||
|
-91, -89, -86, -84, -82, -79, -77, -74, -72, -69, -66, -64, -61, -58, -55, -52,
|
||||||
|
-49, -47, -44, -41, -38, -35, -32, -29, -25, -22, -19, -16, -13, -10, -7, -4};
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region Pin Definitions
|
#pragma region Pin Definitions
|
||||||
|
@ -124,81 +144,77 @@ void setRow(const uint8_t rowIdx) {
|
||||||
digitalWrite(REN_PIN, HIGH);
|
digitalWrite(REN_PIN, HIGH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scales output signal according to global volume value, to range 0-255
|
||||||
uint32_t scaleVolume(uint32_t Vout){
|
uint32_t scaleVolume(uint32_t Vout) {
|
||||||
uint32_t newVout = 0;
|
uint32_t newVout = 0;
|
||||||
if(volumeFiner){
|
if (volumeFiner) {
|
||||||
newVout = (Vout*12*volume) >> 16;
|
newVout = (Vout * 12 * volume) >> 16;
|
||||||
}else{ // 25 = floor( (1/10) << 8 )
|
} else { // 25 = floor( (1/10) << 8 )
|
||||||
newVout = (Vout*25*volume) >> 16; //scale by 2*8 cuz 16-bit*8-bit=24-bit -> scale by 16 to get to 8
|
newVout = (Vout * 25 * volume) >> 16; // scale by 2*8 cuz 16-bit*8-bit=24-bit -> scale by 16 to get to 8
|
||||||
}
|
}
|
||||||
return newVout;
|
return newVout;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns key value (as notes[] index) of highest currently pressed key
|
|
||||||
uint16_t getTopKey() {
|
|
||||||
uint16_t topKey = 0;
|
|
||||||
for (uint8_t i = 0; i < 3; i++) {
|
|
||||||
for (uint8_t j = 0; j < 4; j++) {
|
|
||||||
if (keyArray[i] & (0x1 << j)) {
|
|
||||||
topKey = (octave - 1) * 12 + i * 4 + j + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return topKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interrupt driven routine to send waveform to DAC
|
// Interrupt driven routine to send waveform to DAC
|
||||||
void sampleISR(){
|
void sampleISR() {
|
||||||
static int32_t phaseAcc = 0;
|
static int32_t phaseAcc = 0;
|
||||||
phaseAcc += currentStepSize;
|
phaseAcc += currentStepSize;
|
||||||
int32_t Vout = 0;
|
int32_t Vout = 0;
|
||||||
if(wave==SAWTOOTH){
|
if (selectedWaveform == SAWTOOTH) {
|
||||||
Vout = phaseAcc >> 16;
|
Vout = phaseAcc >> 16;
|
||||||
}else if(wave==SQUARE){
|
} else if (selectedWaveform == SQUARE) {
|
||||||
if(phaseAcc<0){
|
if (phaseAcc < 0) {
|
||||||
Vout = 0x8000;
|
Vout = 0x00007FFF;
|
||||||
}else{
|
} else {
|
||||||
Vout = 0;
|
Vout = 0xFFFF8000;
|
||||||
}
|
}
|
||||||
}else if(wave==TRIANGLE){
|
} else if (selectedWaveform == TRIANGLE) {
|
||||||
//TODO
|
Vout = (abs(phaseAcc) - 1073741824) >> 15;
|
||||||
}else if(wave==SINE){
|
} else if (selectedWaveform == SINE) {
|
||||||
//TODO
|
Vout = (sinLUT[(uint32_t)phaseAcc >> 24]) << 8;
|
||||||
}
|
}
|
||||||
Vout = scaleVolume(Vout);
|
Vout = scaleVolume(Vout);
|
||||||
analogWrite(OUTR_PIN, Vout + 128);
|
analogWrite(OUTR_PIN, Vout + 128);
|
||||||
}
|
}
|
||||||
|
|
||||||
// void CAN_RX_ISR() {
|
//
|
||||||
// uint8_t ISR_RX_Message[8];
|
void CAN_RX_ISR() {
|
||||||
// uint32_t ISR_rxID;
|
uint8_t ISR_RX_Message[8];
|
||||||
// CAN_RX(ISR_rxID, ISR_RX_Message);
|
uint32_t ISR_rxID;
|
||||||
// xQueueSendFromISR(msgInQ, ISR_RX_Message, nullptr);
|
CAN_RX(ISR_rxID, ISR_RX_Message);
|
||||||
// }
|
xQueueSendFromISR(msgInQ, ISR_RX_Message, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
// void decodeTask(void *pvParameters) {
|
// Task to update activeNotes[] and currentStepSize based on received CAN message
|
||||||
// while (1) {
|
void decodeTask(void *pvParameters) {
|
||||||
// xQueueReceive(msgInQ, RX_Message, portMAX_DELAY);
|
while (1) {
|
||||||
// if (RX_Message[0] == 0x50) { // Pressed
|
xQueueReceive(msgInQ, RX_Message, portMAX_DELAY);
|
||||||
// currentStepSize = notes[(RX_Message[1] - 1) * 12 + RX_Message[2]].stepSize;
|
if (RX_Message[0] == 0x50) { // Pressed
|
||||||
// } else { // Released
|
activeNotes[(RX_Message[1] - 1) * 12 + RX_Message[2]] = true;
|
||||||
// currentStepSize = 0;
|
latestKey = (RX_Message[1] - 1) * 12 + RX_Message[2];
|
||||||
// }
|
currentStepSize = stepSizes[latestKey];
|
||||||
// }
|
} else { // Released
|
||||||
// }
|
activeNotes[(RX_Message[1] - 1) * 12 + RX_Message[2]] = false;
|
||||||
|
if (latestKey == (RX_Message[1] - 1) * 12 + RX_Message[2]) {
|
||||||
|
latestKey = 0;
|
||||||
|
currentStepSize = stepSizes[latestKey]; // Atomic Store
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// void keyChangedSendTXMessage(uint8_t octave, uint8_t key, bool pressed) {
|
//
|
||||||
// uint8_t TX_Message[8] = {0};
|
void keyChangedSendTXMessage(uint8_t octave, uint8_t key, bool pressed) {
|
||||||
// if (pressed) {
|
uint8_t TX_Message[8] = {0};
|
||||||
// TX_Message[0] = 0x50; // "P"
|
if (pressed) {
|
||||||
// } else {
|
TX_Message[0] = 0x50; // "P"
|
||||||
// TX_Message[0] = 0x52; // "R"
|
} else {
|
||||||
// }
|
TX_Message[0] = 0x52; // "R"
|
||||||
// TX_Message[1] = octave;
|
}
|
||||||
// TX_Message[2] = key;
|
TX_Message[1] = octave;
|
||||||
// CAN_TX(canID, TX_Message);
|
TX_Message[2] = key;
|
||||||
// }
|
CAN_TX(canID, TX_Message);
|
||||||
|
}
|
||||||
|
|
||||||
// Task to update keyArray values at a higher priority
|
// Task to update keyArray values at a higher priority
|
||||||
void scanKeysTask(void *pvParameters) {
|
void scanKeysTask(void *pvParameters) {
|
||||||
|
@ -215,27 +231,30 @@ void scanKeysTask(void *pvParameters) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
keyArray[i] = newRow;
|
keyArray[i] = newRow;
|
||||||
|
if (i < 3) {
|
||||||
for (uint8_t j = 0; j < 4; j++) {
|
for (uint8_t j = 0; j < 4; j++) {
|
||||||
if ((oldRow & (0x1 << j)) ^ (newRow & (0x1 << j))) {
|
if ((oldRow & (0x1 << j)) ^ (newRow & (0x1 << j))) {
|
||||||
//keyChangedSendTXMessage(octave, i * 4 + j + 1, newRow & (0x1 << j));
|
keyChangedSendTXMessage(octave, i * 4 + j + 1, newRow & (0x1 << j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
if(volumeFiner){
|
}
|
||||||
K3.changeLimitsVolume(0,20);
|
if (volumeFiner) {
|
||||||
}else{
|
K3.changeLimitsVolume(0, 10);
|
||||||
K3.changeLimitsVolume(0,10);
|
} else {
|
||||||
};
|
K3.changeLimitsVolume(0, 5);
|
||||||
currentStepSize = notes[getTopKey()].stepSize; // Atomic Store
|
}
|
||||||
K0.updateRotation(keyArray[4] & 0x4, keyArray[4] & 0x8);
|
K0.updateRotation(keyArray[4] & 0x4, keyArray[4] & 0x8);
|
||||||
octave = K0.getRotation()/2;
|
|
||||||
K1.updateRotation(keyArray[4] & 0x1, keyArray[4] & 0x2);
|
K1.updateRotation(keyArray[4] & 0x1, keyArray[4] & 0x2);
|
||||||
wave = K1.getRotation()/2;
|
K2.updateRotation(keyArray[3] & 0x4, keyArray[3] & 0x8);
|
||||||
K3.updateRotation(keyArray[3] & 0x1, keyArray[3] & 0x2);
|
K3.updateRotation(keyArray[3] & 0x1, keyArray[3] & 0x2);
|
||||||
|
octave = K0.getRotation();
|
||||||
|
selectedWaveform = K1.getRotation();
|
||||||
|
isMainSynth = !K2.getRotation();
|
||||||
volume = K3.getRotation();
|
volume = K3.getRotation();
|
||||||
volumeHistory = (volumeHistory << 1) + ((keyArray[5]&0x2)>>1);
|
volumeHistory = (volumeHistory << 1) + ((keyArray[5] & 0x2) >> 1);
|
||||||
volumeFiner = ((!(volumeHistory==1))&volumeFiner) | ((volumeHistory==1)&!volumeFiner);
|
volumeFiner = ((!(volumeHistory == 1)) & volumeFiner) | ((volumeHistory == 1) & !volumeFiner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,65 +264,49 @@ void displayUpdateTask(void *pvParameters) {
|
||||||
TickType_t xLastWakeTime = xTaskGetTickCount();
|
TickType_t xLastWakeTime = xTaskGetTickCount();
|
||||||
while (1) {
|
while (1) {
|
||||||
vTaskDelayUntil(&xLastWakeTime, xFrequency);
|
vTaskDelayUntil(&xLastWakeTime, xFrequency);
|
||||||
uint32_t rxID;
|
|
||||||
|
|
||||||
u8g2.clearBuffer(); // clear the internal memory
|
u8g2.clearBuffer(); // clear the internal memory
|
||||||
u8g2.setFont(u8g2_font_profont12_mf); // choose a suitable font
|
u8g2.setFont(u8g2_font_profont12_mf); // choose a suitable font
|
||||||
uint16_t key = getTopKey();
|
u8g2.drawStr(2, 10, notes[latestKey]); // Print the currently pressed keys
|
||||||
u8g2.drawStr(2, 10, notes[key].note.c_str()); // Print the current key
|
|
||||||
digitalToggle(LED_BUILTIN);
|
|
||||||
u8g2.setCursor(2, 20);
|
|
||||||
for (uint8_t i = 0; i < 7; i++) {
|
|
||||||
u8g2.print(keyArray[i], HEX);
|
|
||||||
};
|
|
||||||
u8g2.setCursor(100, 10);
|
|
||||||
u8g2.print((char)RX_Message[0]);
|
|
||||||
u8g2.print(RX_Message[1]);
|
|
||||||
u8g2.print(RX_Message[2], HEX);
|
|
||||||
|
|
||||||
// Print waveform icon
|
// u8g2.setCursor(2, 20);
|
||||||
int K1_rot = K1.getRotation();
|
// for (uint8_t i = 0; i < 7; i++) {
|
||||||
if(K1_rot<2){
|
// u8g2.print(keyArray[i], HEX);
|
||||||
u8g2.drawXBM(38,22,13,9,waveforms[SQUARE]);
|
// };
|
||||||
}else if(K1_rot<4){
|
// u8g2.setCursor(100, 10); // Debug print of received CAN message
|
||||||
u8g2.drawXBM(38,22,13,9,waveforms[SAWTOOTH]);
|
// u8g2.print((char)RX_Message[0]);
|
||||||
}else if(K1_rot<6){
|
// u8g2.print(RX_Message[1]);
|
||||||
u8g2.drawXBM(38,22,13,9,waveforms[TRIANGLE]);
|
// u8g2.print(RX_Message[2], HEX);
|
||||||
}else if(K1_rot==6){
|
|
||||||
u8g2.drawXBM(38,22,13,9,waveforms[SINE]);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Print octave number
|
// Print current octave number above knob 0
|
||||||
u8g2.setCursor(2, 30);
|
u8g2.drawStr(2, 30, "O:");
|
||||||
u8g2.print("O:");
|
|
||||||
u8g2.setCursor(14, 30);
|
u8g2.setCursor(14, 30);
|
||||||
u8g2.print(octave);
|
u8g2.print(octave);
|
||||||
|
|
||||||
// Print volume indicator
|
// Draw currently selected waveform above knob 1
|
||||||
if(!volumeFiner){
|
u8g2.drawXBM(38, 22, 13, 9, waveforms[K1.getRotation()]);
|
||||||
if(volume==0){
|
|
||||||
u8g2.drawXBM(116,22,13,9,volumes[5]);
|
// Print Send / Receive State above knob 2
|
||||||
}else if(volume<3){
|
if (K2.getRotation()) {
|
||||||
u8g2.drawXBM(116,22,13,9,volumes[4]);
|
u8g2.drawStr(74, 30, "SEND");
|
||||||
}else if(volume<5){
|
} else {
|
||||||
u8g2.drawXBM(116,22,13,9,volumes[3]);
|
u8g2.drawStr(74, 30, "RECV");
|
||||||
}else if(volume<7){
|
}
|
||||||
u8g2.drawXBM(116,22,13,9,volumes[2]);
|
|
||||||
}else if(volume<9){
|
// Print volume indicator above knob 3
|
||||||
u8g2.drawXBM(116,22,13,9,volumes[1]);
|
if (!volumeFiner) {
|
||||||
}else if(volume<11){
|
u8g2.drawXBM(116, 22, 13, 9, volumes[volume]);
|
||||||
u8g2.drawXBM(116,22,13,9,volumes[0]);
|
} else {
|
||||||
};
|
|
||||||
}else{
|
|
||||||
u8g2.setCursor(117, 30);
|
u8g2.setCursor(117, 30);
|
||||||
u8g2.print(volume/2);
|
u8g2.print(volume);
|
||||||
};
|
}
|
||||||
|
|
||||||
u8g2.sendBuffer(); // transfer internal memory to the display
|
u8g2.sendBuffer(); // transfer internal memory to the display
|
||||||
|
digitalToggle(LED_BUILTIN); // Toggle LED to show display update rate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Arduino framework setup function, sets up Pins, Display, UART, CAN and Tasks
|
||||||
void setup() {
|
void setup() {
|
||||||
octave = 4;
|
|
||||||
#pragma region Pin Setup
|
#pragma region Pin Setup
|
||||||
pinMode(RA0_PIN, OUTPUT);
|
pinMode(RA0_PIN, OUTPUT);
|
||||||
pinMode(RA1_PIN, OUTPUT);
|
pinMode(RA1_PIN, OUTPUT);
|
||||||
|
@ -320,6 +323,10 @@ void setup() {
|
||||||
pinMode(JOYX_PIN, INPUT);
|
pinMode(JOYX_PIN, INPUT);
|
||||||
pinMode(JOYY_PIN, INPUT);
|
pinMode(JOYY_PIN, INPUT);
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
#pragma region Variables Setup
|
||||||
|
isMainSynth = true;
|
||||||
|
octave = 4;
|
||||||
|
#pragma endregion
|
||||||
#pragma region Display Setup
|
#pragma region Display Setup
|
||||||
setOutMuxBit(DRST_BIT, LOW); // Assert display logic reset
|
setOutMuxBit(DRST_BIT, LOW); // Assert display logic reset
|
||||||
delayMicroseconds(2);
|
delayMicroseconds(2);
|
||||||
|
@ -331,13 +338,13 @@ void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
Serial.println("Hello World");
|
Serial.println("Hello World");
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
// #pragma region CAN Setup
|
#pragma region CAN Setup
|
||||||
// msgInQ = xQueueCreate(36, 8);
|
msgInQ = xQueueCreate(36, 8);
|
||||||
// CAN_Init(true);
|
CAN_Init(true);
|
||||||
// setCANFilter(0x123, 0x7ff);
|
setCANFilter(0x123, 0x7ff);
|
||||||
// CAN_RegisterRX_ISR(CAN_RX_ISR);
|
CAN_RegisterRX_ISR(CAN_RX_ISR);
|
||||||
// CAN_Start();
|
CAN_Start();
|
||||||
// #pragma endregion
|
#pragma endregion
|
||||||
#pragma region Task Scheduler Setup
|
#pragma region Task Scheduler Setup
|
||||||
TIM_TypeDef *Instance = TIM1;
|
TIM_TypeDef *Instance = TIM1;
|
||||||
HardwareTimer *sampleTimer = new HardwareTimer(Instance);
|
HardwareTimer *sampleTimer = new HardwareTimer(Instance);
|
||||||
|
@ -346,14 +353,23 @@ void setup() {
|
||||||
sampleTimer->resume();
|
sampleTimer->resume();
|
||||||
TaskHandle_t scanKeysHandle = nullptr;
|
TaskHandle_t scanKeysHandle = nullptr;
|
||||||
TaskHandle_t displayUpdateHandle = nullptr;
|
TaskHandle_t displayUpdateHandle = nullptr;
|
||||||
|
TaskHandle_t decodeHandle = nullptr;
|
||||||
xTaskCreate(
|
xTaskCreate(
|
||||||
scanKeysTask, // Function that implements the task
|
scanKeysTask, // Function that implements the task
|
||||||
"scanKeys", // Text name for the task
|
"scanKeys", // Text name for the task
|
||||||
64, // Stack size in words, not bytes
|
64, // Stack size in words, not bytes
|
||||||
nullptr, // Parameter passed into the task
|
nullptr, // Parameter passed into the task
|
||||||
2, // Task priority
|
3, // Task priority
|
||||||
&scanKeysHandle // Pointer to store the task handle
|
&scanKeysHandle // Pointer to store the task handle
|
||||||
);
|
);
|
||||||
|
xTaskCreate(
|
||||||
|
decodeTask, // Function that implements the task
|
||||||
|
"decode", // Text name for the task
|
||||||
|
256, // Stack size in words, not bytes
|
||||||
|
nullptr, // Parameter passed into the task
|
||||||
|
2, // Task priority
|
||||||
|
&decodeHandle // Pointer to store the task handle
|
||||||
|
);
|
||||||
xTaskCreate(
|
xTaskCreate(
|
||||||
displayUpdateTask, // Function that implements the task
|
displayUpdateTask, // Function that implements the task
|
||||||
"displayUpdate", // Text name for the task
|
"displayUpdate", // Text name for the task
|
||||||
|
|
Loading…
Reference in a new issue