diff --git a/lib/ES_CAN/ES_CAN.cpp b/lib/ES_CAN/ES_CAN.cpp deleted file mode 100644 index 6061069..0000000 --- a/lib/ES_CAN/ES_CAN.cpp +++ /dev/null @@ -1,214 +0,0 @@ -#include -#include -#include -#include - -//Overwrite the weak default IRQ Handlers and callabcks -extern "C" void CAN1_RX0_IRQHandler(void); -extern "C" void CAN1_TX_IRQHandler(void); - -//Pointer to user ISRS -void (*CAN_RX_ISR)() = NULL; -void (*CAN_TX_ISR)() = NULL; - -//CAN handle struct with initialisation parameters -//Timing from http://www.bittiming.can-wiki.info/ with bit rate = 125kHz and clock frequency = 80MHz -CAN_HandleTypeDef CAN_Handle = { - CAN1, - { - 40, //Prescaler - CAN_MODE_NORMAL, //Normal/loopback/silent mode - CAN_SJW_2TQ, //SyncJumpWidth - CAN_BS1_13TQ, //TimeSeg1 - CAN_BS2_2TQ, //TimeSeg2 - DISABLE, //TimeTriggeredMode - DISABLE, //AutoBusOff - ENABLE, //AutoWakeUp - ENABLE, //AutoRetransmission - DISABLE, //ReceiveFifoLocked - ENABLE //TransmitFifoPriority - }, - HAL_CAN_STATE_RESET, //State - HAL_CAN_ERROR_NONE //Error Code -}; - - -//Initialise CAN dependencies: GPIO and clock -void HAL_CAN_MspInit(CAN_HandleTypeDef* CAN_Handle) { - - //Set up the pin initialisation - GPIO_InitTypeDef GPIO_InitCAN_TX = { - GPIO_PIN_12, //PA12 is CAN TX - GPIO_MODE_AF_PP, //Alternate function, push-pull driver - GPIO_NOPULL, //No pull-up - GPIO_SPEED_FREQ_MEDIUM, //Medium slew rate - GPIO_AF9_CAN1 //Alternate function is CAN - }; - - GPIO_InitTypeDef GPIO_InitCAN_RX = { - GPIO_PIN_11, //PA11 is CAN RX - GPIO_MODE_AF_PP, //Alternate function, push-pull driver - GPIO_PULLUP, //Pull-up enabled - GPIO_SPEED_FREQ_MEDIUM, //Medium slew rate - GPIO_AF9_CAN1 //Alternate function is CAN - }; - - //Enable the CAN and GPIO clocks - __HAL_RCC_CAN1_CLK_ENABLE(); //Enable the CAN interface clock - __HAL_RCC_GPIOA_CLK_ENABLE(); //Enable the clock for the CAN GPIOs - - //Initialise the pins - HAL_GPIO_Init(GPIOA, &GPIO_InitCAN_TX); //Configure CAN pin - HAL_GPIO_Init(GPIOA, &GPIO_InitCAN_RX); //Configure CAN pin -} - - -uint32_t CAN_Init(bool loopback=false) { - if (loopback) - CAN_Handle.Init.Mode = CAN_MODE_LOOPBACK; - return (uint32_t) HAL_CAN_Init(&CAN_Handle); -} - - -uint32_t setCANFilter(uint32_t filterID, uint32_t maskID, uint32_t filterBank) { - - //Set up the filter definition - CAN_FilterTypeDef filterInfo = { - (filterID << 5) & 0xffe0, //Filter ID - 0, //Filter ID LSBs = 0 - (maskID << 5) & 0xffe0, //Mask MSBs - 0, //Mask LSBs = 0 - 0, //FIFO selection - filterBank & 0xf, //Filter bank selection - CAN_FILTERMODE_IDMASK, //Mask mode - CAN_FILTERSCALE_32BIT, //32 bit IDs - CAN_FILTER_ENABLE, //Enable filter - 0 //uint32_t SlaveStartFilterBank - }; - - return (uint32_t) HAL_CAN_ConfigFilter(&CAN_Handle, &filterInfo); -} - - -uint32_t CAN_Start() { - return (uint32_t) HAL_CAN_Start(&CAN_Handle); -} - - -uint32_t CAN_TX(uint32_t ID, uint8_t data[8]) { - - //Set up the message header - CAN_TxHeaderTypeDef txHeader = { - ID & 0x7ff, //Standard ID - 0, //Ext ID = 0 - CAN_ID_STD, //Use Standard ID - CAN_RTR_DATA, //Data Frame - 8, //Send 8 bytes - DISABLE //No time triggered mode - }; - - //Wait for free mailbox - while (!HAL_CAN_GetTxMailboxesFreeLevel(&CAN_Handle)); - - //Start the transmission - return (uint32_t) HAL_CAN_AddTxMessage(&CAN_Handle, &txHeader, data, NULL); -} - - -uint32_t CAN_CheckRXLevel() { - return HAL_CAN_GetRxFifoFillLevel(&CAN_Handle, 0); -} - - -uint32_t CAN_RX(uint32_t &ID, uint8_t data[8]) { - CAN_RxHeaderTypeDef rxHeader; - - //Wait for message in FIFO - while (!HAL_CAN_GetRxFifoFillLevel(&CAN_Handle, 0)); - - //Get the message from the FIFO - uint32_t result = (uint32_t) HAL_CAN_GetRxMessage(&CAN_Handle, 0, &rxHeader, data); - - //Store the ID from the header - ID = rxHeader.StdId; - - return result; -} - - -uint32_t CAN_RegisterRX_ISR(void(& callback)()) { - //Store pointer to user ISR - CAN_RX_ISR = &callback; - - //Enable message received interrupt in HAL - uint32_t status = (uint32_t) HAL_CAN_ActivateNotification (&CAN_Handle, CAN_IT_RX_FIFO0_MSG_PENDING); - - //Switch on the interrupt - HAL_NVIC_SetPriority (CAN1_RX0_IRQn, 6, 0); - HAL_NVIC_EnableIRQ (CAN1_RX0_IRQn); - - return status; -} - - -uint32_t CAN_RegisterTX_ISR(void(& callback)()) { - //Store pointer to user ISR - CAN_TX_ISR = &callback; - - //Enable message received interrupt in HAL - uint32_t status = (uint32_t) HAL_CAN_ActivateNotification (&CAN_Handle, CAN_IT_TX_MAILBOX_EMPTY); - - //Switch on the interrupt - HAL_NVIC_SetPriority (CAN1_TX_IRQn, 6, 0); - HAL_NVIC_EnableIRQ (CAN1_TX_IRQn); - - return status; -} - - -void HAL_CAN_RxFifo0MsgPendingCallback (CAN_HandleTypeDef * hcan){ - - //Call the user ISR if it has been registered - if (CAN_RX_ISR) - CAN_RX_ISR(); -} - - -void HAL_CAN_TxMailbox0CompleteCallback (CAN_HandleTypeDef * hcan){ - - //Call the user ISR if it has been registered - if (CAN_TX_ISR) - CAN_TX_ISR(); -} - - -void HAL_CAN_TxMailbox1CompleteCallback (CAN_HandleTypeDef * hcan){ - - //Call the user ISR if it has been registered - if (CAN_TX_ISR) - CAN_TX_ISR(); -} - - -void HAL_CAN_TxMailbox2CompleteCallback (CAN_HandleTypeDef * hcan){ - - //Call the user ISR if it has been registered - if (CAN_TX_ISR) - CAN_TX_ISR(); -} - - -//This is the base ISR at the interrupt vector -void CAN1_RX0_IRQHandler(void){ - - //Use the HAL interrupt handler - HAL_CAN_IRQHandler(&CAN_Handle); -} - - -//This is the base ISR at the interrupt vector -void CAN1_TX_IRQHandler(void){ - - //Use the HAL interrupt handler - HAL_CAN_IRQHandler(&CAN_Handle); -} diff --git a/lib/ES_CAN/ES_CAN.h b/lib/ES_CAN/ES_CAN.h deleted file mode 100644 index add9c50..0000000 --- a/lib/ES_CAN/ES_CAN.h +++ /dev/null @@ -1,24 +0,0 @@ -//Initialise the CAN module -uint32_t CAN_Init(bool loopback=false); - -//Enable the CAN module -uint32_t CAN_Start(); - -//Set up a recevie filter -//Defaults to receive everything -uint32_t setCANFilter(uint32_t filterID=0, uint32_t maskID=0, uint32_t filterBank=0); - -//Send a message -uint32_t CAN_TX(uint32_t ID, uint8_t data[8]); - -//Get the number of received messages -uint32_t CAN_CheckRXLevel(); - -//Get a received message from the FIFO -uint32_t CAN_RX(uint32_t &ID, uint8_t data[8]); - -//Set up an interrupt on received messages -uint32_t CAN_RegisterRX_ISR(void(& callback)()); - -//Set up an interrupt on transmitted messages -uint32_t CAN_RegisterTX_ISR(void(& callback)()); \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index b796a80..5f7427e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,23 +5,58 @@ #include #include -volatile std::atomic currentStepSize; -static std::atomic keyArray[7]; - +#pragma region Globals(Config values, Variables, Objects, Types, etc.) +// Config values const uint32_t interval = 10; // Display update interval const uint8_t octave = 4; // Octave to start on const uint32_t samplingRate = 44100; // Sampling rate +// Variables +std::atomic currentStepSize; +std::atomic keyArray[7]; +// Objects +U8G2_SSD1305_128X32_NONAME_F_HW_I2C u8g2(U8G2_R0); // Display driver object +Knob K3 = Knob(0, 16); // Knob driver object +// Program Specific Structures typedef struct { int32_t stepSize; std::string note; } 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"}}; -#define icon_width 10 -#define icon_height 10 +enum waveform { + SQUARE = 0, + SAWTOOTH, + TRIANGLE, + SINE +}; +const unsigned char waveforms[4][18] = { + {0x7f, 0x10, 0x41, 0x10, 0x41, 0x10, 0x41, 0x10, 0x41, + 0x10, 0x41, 0x10, 0x41, 0x10, 0x41, 0x10, 0xc1, 0x1f}, // Square Wave + {0x70, 0x10, 0x58, 0x18, 0x48, 0x08, 0x4c, 0x0c, 0x44, + 0x04, 0x46, 0x06, 0x42, 0x02, 0x43, 0x03, 0xc1, 0x01}, // Sawtooth Wave + {0x08, 0x00, 0x1c, 0x00, 0x36, 0x00, 0x63, 0x00, 0xc1, + 0x00, 0x80, 0x11, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x04}, // Triangle Wave + {0x1c, 0x00, 0x36, 0x00, 0x22, 0x00, 0x63, 0x00, 0x41, + 0x10, 0xc0, 0x18, 0x80, 0x08, 0x80, 0x0d, 0x00, 0x07} // Sine Wave +}; +const unsigned char volumes[6][18] = { + {0x10, 0x02, 0x98, 0x04, 0x1c, 0x05, 0x5f, 0x09, 0x5f, + 0x09, 0x5f, 0x09, 0x1c, 0x05, 0x98, 0x04, 0x10, 0x02}, // volume max + {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, + 0x00, 0x1f, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x10, 0x00}, // volume lowest + {0x10, 0x00, 0x18, 0x00, 0x5c, 0x04, 0x9f, 0x02, 0x1f, + 0x01, 0x9f, 0x02, 0x5c, 0x04, 0x18, 0x00, 0x10, 0x00} // mute +}; const unsigned char icon_bits[] = { 0x00, 0x00, 0x00, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x02, 0x01, 0xfe, 0x01, 0x00, 0x00}; +#pragma endregion #pragma region Pin Definitions // Row select and enable @@ -48,9 +83,6 @@ const int HKOW_BIT = 5; const int HKOE_BIT = 6; #pragma endregion -U8G2_SSD1305_128X32_NONAME_F_HW_I2C u8g2(U8G2_R0); // Display driver object -Knob K3 = Knob(0, 16); // Knob driver object - // Function to set outputs using key matrix void setOutMuxBit(const uint8_t bitIdx, const bool value) { digitalWrite(REN_PIN, LOW); @@ -73,7 +105,7 @@ uint8_t readCols() { return row; } -// Set current row +// Set multiplexer bits to select row void setRow(const uint8_t rowIdx) { digitalWrite(REN_PIN, LOW); digitalWrite(RA0_PIN, rowIdx & 0x01); @@ -82,6 +114,7 @@ void setRow(const uint8_t rowIdx) { digitalWrite(REN_PIN, HIGH); } +// 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++) { @@ -94,13 +127,15 @@ uint16_t getTopKey() { return topKey; } +// Interrupt driven routine to send waveform to DAC void sampleISR() { static int32_t phaseAcc = 0; phaseAcc += currentStepSize; - int32_t Vout = phaseAcc >> (32 - K3.getRotation() / 2); + int32_t Vout = phaseAcc >> (32 - K3.getRotation() / 2); // Volume range from (>> 32) to (>> 24), range of 8 analogWrite(OUTR_PIN, Vout + 128); } +// Task to update keyArray values at a higher priority void scanKeysTask(void *pvParameters) { const TickType_t xFrequency = 50 / portTICK_PERIOD_MS; TickType_t xLastWakeTime = xTaskGetTickCount(); @@ -116,14 +151,16 @@ void scanKeysTask(void *pvParameters) { } } +// Task containing display graphics and update code void displayUpdateTask(void *pvParameters) { const TickType_t xFrequency = 100 / portTICK_PERIOD_MS; TickType_t xLastWakeTime = xTaskGetTickCount(); while (1) { vTaskDelayUntil(&xLastWakeTime, xFrequency); - u8g2.clearBuffer(); // clear the internal memory - u8g2.setFont(u8g2_font_profont12_mf); // choose a suitable font - u8g2.drawStr(2, 10, notes[getTopKey()].note.c_str()); // Print the current key + u8g2.clearBuffer(); // clear the internal memory + u8g2.setFont(u8g2_font_profont12_mf); // choose a suitable font + uint16_t key = getTopKey(); + 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++) { @@ -160,17 +197,16 @@ void setup() { u8g2.begin(); setOutMuxBit(DEN_BIT, HIGH); // Enable display power supply #pragma endregion - - // Initialise UART +#pragma region UART Setup Serial.begin(115200); Serial.println("Hello World"); - +#pragma endregion +#pragma region Task Scheduler Setup TIM_TypeDef *Instance = TIM1; HardwareTimer *sampleTimer = new HardwareTimer(Instance); sampleTimer->setOverflow(samplingRate, HERTZ_FORMAT); sampleTimer->attachInterrupt(sampleISR); sampleTimer->resume(); - TaskHandle_t scanKeysHandle = NULL; TaskHandle_t displayUpdateHandle = NULL; xTaskCreate( @@ -190,6 +226,7 @@ void setup() { &displayUpdateHandle // Pointer to store the task handle ); vTaskStartScheduler(); +#pragma endregion } -void loop() {} \ No newline at end of file +void loop() {} // No code in loop, as everything is done in the tasks