Partial Merge

Knob Driver to be rewritten
This commit is contained in:
Aadi Desai 2022-03-24 18:21:34 +00:00
parent c51638ee4f
commit e952f4ccb6
No known key found for this signature in database
GPG key ID: CFFFE425830EF4D9
3 changed files with 55 additions and 256 deletions

View file

@ -1,214 +0,0 @@
#include <stm32l4xx_hal_can.h>
#include <stm32l4xx_hal_rcc.h>
#include <stm32l4xx_hal_gpio.h>
#include <stm32l4xx_hal_cortex.h>
//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);
}

View file

@ -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)());

View file

@ -5,23 +5,58 @@
#include <knob> #include <knob>
#include <string> #include <string>
volatile std::atomic<int32_t> currentStepSize; #pragma region Globals(Config values, Variables, Objects, Types, etc.)
static std::atomic<uint8_t> keyArray[7]; // Config values
const uint32_t interval = 10; // Display update interval const uint32_t interval = 10; // Display update interval
const uint8_t octave = 4; // Octave to start on const uint8_t octave = 4; // Octave to start on
const uint32_t samplingRate = 44100; // Sampling rate const uint32_t samplingRate = 44100; // Sampling rate
// Variables
std::atomic<int32_t> currentStepSize;
std::atomic<uint8_t> 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 { typedef struct {
int32_t stepSize; int32_t stepSize;
std::string note; std::string note;
} Note; } Note;
const Note notes[] = { 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"}}; {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 enum waveform {
#define icon_height 10 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[] = { 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};
#pragma endregion
#pragma region Pin Definitions #pragma region Pin Definitions
// Row select and enable // Row select and enable
@ -48,9 +83,6 @@ const int HKOW_BIT = 5;
const int HKOE_BIT = 6; const int HKOE_BIT = 6;
#pragma endregion #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 // Function to set outputs using key matrix
void setOutMuxBit(const uint8_t bitIdx, const bool value) { void setOutMuxBit(const uint8_t bitIdx, const bool value) {
digitalWrite(REN_PIN, LOW); digitalWrite(REN_PIN, LOW);
@ -73,7 +105,7 @@ uint8_t readCols() {
return row; return row;
} }
// Set current row // Set multiplexer bits to select row
void setRow(const uint8_t rowIdx) { void setRow(const uint8_t rowIdx) {
digitalWrite(REN_PIN, LOW); digitalWrite(REN_PIN, LOW);
digitalWrite(RA0_PIN, rowIdx & 0x01); digitalWrite(RA0_PIN, rowIdx & 0x01);
@ -82,6 +114,7 @@ void setRow(const uint8_t rowIdx) {
digitalWrite(REN_PIN, HIGH); digitalWrite(REN_PIN, HIGH);
} }
// Returns key value (as notes[] index) of highest currently pressed key
uint16_t getTopKey() { uint16_t getTopKey() {
uint16_t topKey = 0; uint16_t topKey = 0;
for (uint8_t i = 0; i < 3; i++) { for (uint8_t i = 0; i < 3; i++) {
@ -94,13 +127,15 @@ uint16_t getTopKey() {
return topKey; return topKey;
} }
// 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 = 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); analogWrite(OUTR_PIN, Vout + 128);
} }
// Task to update keyArray values at a higher priority
void scanKeysTask(void *pvParameters) { void scanKeysTask(void *pvParameters) {
const TickType_t xFrequency = 50 / portTICK_PERIOD_MS; const TickType_t xFrequency = 50 / portTICK_PERIOD_MS;
TickType_t xLastWakeTime = xTaskGetTickCount(); TickType_t xLastWakeTime = xTaskGetTickCount();
@ -116,6 +151,7 @@ void scanKeysTask(void *pvParameters) {
} }
} }
// Task containing display graphics and update code
void displayUpdateTask(void *pvParameters) { void displayUpdateTask(void *pvParameters) {
const TickType_t xFrequency = 100 / portTICK_PERIOD_MS; const TickType_t xFrequency = 100 / portTICK_PERIOD_MS;
TickType_t xLastWakeTime = xTaskGetTickCount(); TickType_t xLastWakeTime = xTaskGetTickCount();
@ -123,7 +159,8 @@ void displayUpdateTask(void *pvParameters) {
vTaskDelayUntil(&xLastWakeTime, xFrequency); vTaskDelayUntil(&xLastWakeTime, xFrequency);
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
u8g2.drawStr(2, 10, notes[getTopKey()].note.c_str()); // Print the current key uint16_t key = getTopKey();
u8g2.drawStr(2, 10, notes[key].note.c_str()); // Print the current key
digitalToggle(LED_BUILTIN); digitalToggle(LED_BUILTIN);
u8g2.setCursor(2, 20); u8g2.setCursor(2, 20);
for (uint8_t i = 0; i < 7; i++) { for (uint8_t i = 0; i < 7; i++) {
@ -160,17 +197,16 @@ void setup() {
u8g2.begin(); u8g2.begin();
setOutMuxBit(DEN_BIT, HIGH); // Enable display power supply setOutMuxBit(DEN_BIT, HIGH); // Enable display power supply
#pragma endregion #pragma endregion
#pragma region UART Setup
// Initialise UART
Serial.begin(115200); Serial.begin(115200);
Serial.println("Hello World"); Serial.println("Hello World");
#pragma endregion
#pragma region Task Scheduler Setup
TIM_TypeDef *Instance = TIM1; TIM_TypeDef *Instance = TIM1;
HardwareTimer *sampleTimer = new HardwareTimer(Instance); HardwareTimer *sampleTimer = new HardwareTimer(Instance);
sampleTimer->setOverflow(samplingRate, HERTZ_FORMAT); sampleTimer->setOverflow(samplingRate, HERTZ_FORMAT);
sampleTimer->attachInterrupt(sampleISR); sampleTimer->attachInterrupt(sampleISR);
sampleTimer->resume(); sampleTimer->resume();
TaskHandle_t scanKeysHandle = NULL; TaskHandle_t scanKeysHandle = NULL;
TaskHandle_t displayUpdateHandle = NULL; TaskHandle_t displayUpdateHandle = NULL;
xTaskCreate( xTaskCreate(
@ -190,6 +226,7 @@ void setup() {
&displayUpdateHandle // Pointer to store the task handle &displayUpdateHandle // Pointer to store the task handle
); );
vTaskStartScheduler(); vTaskStartScheduler();
#pragma endregion
} }
void loop() {} void loop() {} // No code in loop, as everything is done in the tasks