Created
June 9, 2019 22:01
-
-
Save shannonpeng/1657018d92a1b81b7fcb56381519141a to your computer and use it in GitHub Desktop.
6.115 Final Project - Grid Sequencer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* ======================================== | |
* | |
* Shannon Peng | |
* 6.115 Final Project -- Grid Sequencer | |
* Spring 2019 | |
* | |
* ======================================== | |
*/ | |
#include <device.h> | |
#include <math.h> | |
#define NUM_COLS 8 | |
#define NUM_ROWS 4 | |
/* VARIABLES */ | |
// persistent grid state. used to light LEDs and choose sounds to play | |
uint8 grid[NUM_COLS][NUM_ROWS]; | |
// transient button states. used to detect a keyup event | |
uint8 button_states[NUM_COLS][NUM_ROWS]; | |
// current highlighted column | |
uint8 current_col = 0; | |
// tempo -- number of timer interrupts needed before cycling to the next column | |
// 16-bit timer period = 2.731ms | |
uint16 num_interrupts = 140; | |
uint16 interrupt_count; | |
uint16 adcResult = 0; // read from potentiometer to set tempo | |
// toggle notes/drums mode here and in TopDesign.cysch | |
// 0 -- play notes (CDEF) | |
// 1 -- play drums (kick, hi hat, snare, clap) | |
uint8 notes = 0; | |
/* HELPER FUNCTIONS */ | |
// starts a WaveDAC given an index i [0:3] | |
void startWaveDAC(uint8 i) { | |
if (i == 0) { | |
WaveDAC8_1_Start(); | |
} | |
else if (i == 1) { | |
WaveDAC8_2_Start(); | |
} | |
else if (i == 2) { | |
WaveDAC8_3_Start(); | |
} | |
else if (i == 3) { | |
WaveDAC8_4_Start(); | |
} | |
} | |
/* INTERRUPT HANDLERS */ | |
// Timer interrupt | |
CY_ISR(timerInterrupt) | |
{ | |
Timer_1_STATUS; // clear TC flag | |
interrupt_count++; // increment interrupt count | |
if (interrupt_count > num_interrupts) { | |
current_col += 1; | |
current_col = current_col % NUM_COLS; // cycle through columns | |
interrupt_count = 0; | |
if (notes) { // if in notes mode, WaveDACs need to be manually stopped | |
WaveDAC8_1_Stop(); | |
WaveDAC8_2_Stop(); | |
WaveDAC8_3_Stop(); | |
WaveDAC8_4_Stop(); | |
} | |
int i = 0; // start WaveDACs for selected sounds | |
for (i = 0; i < NUM_ROWS; i++) { | |
if (grid[current_col][i] > 0) { | |
startWaveDAC(i); | |
} | |
} | |
} | |
} | |
// Create interrupt handlers for stopping WaveDAC components. | |
// These are called when a drum sample has finished playing (on w1 rising edge for each component) | |
CY_ISR(wavInterrupt1) | |
{ | |
WaveDAC8_1_Stop(); | |
} | |
CY_ISR(wavInterrupt2) | |
{ | |
WaveDAC8_2_Stop(); | |
} | |
CY_ISR(wavInterrupt3) | |
{ | |
WaveDAC8_3_Stop(); | |
} | |
CY_ISR(wavInterrupt4) | |
{ | |
WaveDAC8_4_Stop(); | |
} | |
// Main loop of program | |
int main() | |
{ | |
/* Global interrupt enable */ | |
CyGlobalIntEnable; | |
/* Assign interrupt handlers to timer and WaveDAC components. */ | |
TimerISR_StartEx(timerInterrupt); | |
wavisr_1_StartEx(wavInterrupt1); | |
wavisr_2_StartEx(wavInterrupt2); | |
wavisr_3_StartEx(wavInterrupt3); | |
wavisr_4_StartEx(wavInterrupt4); | |
/* Start the timer */ | |
Timer_1_Start(); | |
/* Start ADC conversion */ | |
ADC_DelSig_1_Start(); | |
ADC_DelSig_1_StartConvert(); | |
while (1) | |
{ | |
// Read value from potentiometer to set tempo | |
if( ADC_DelSig_1_IsEndConversion(ADC_DelSig_1_WAIT_FOR_RESULT) ) { | |
adcResult = ADC_DelSig_1_GetResult16(); | |
if (adcResult & 0x8000) { | |
adcResult = 0; // ignore negatives | |
} | |
else if (adcResult >= 0x0fff) { | |
adcResult = 0x0fff; // max | |
} | |
num_interrupts = 400 - (adcResult * 300 / 0xfff); // range 100 to 400 interrupts (220 to 55 bpm) | |
if (num_interrupts > 400) { | |
num_interrupts = 400; | |
} | |
else if (num_interrupts < 80) { | |
num_interrupts = 80; | |
} | |
} | |
// Scan button matrix and update LED matrix concurrently | |
int i = 0; | |
int j = 0; | |
for (i = 0; i < NUM_ROWS; i++) { | |
uint8 row_vals = 1u << (NUM_ROWS - 1 - i); | |
BUTTON_ROWS_Write(row_vals); // raise each row individually | |
uint8 button_col_val = BUTTON_COLS_Read(); // read the values of columns in this row | |
for (j = 0; j < NUM_COLS; j++) { | |
int b = (button_col_val >> (NUM_COLS - 1 - j)) & 1; // shift and only keep last bit | |
if (b == 0 && button_states[j][i] == 1) { | |
grid[j][i] = (~grid[j][i]) & 1; // toggle grid state at this button | |
} | |
button_states[j][i] = b; | |
uint8 r = grid[j][i] << (NUM_ROWS - 1 - i); | |
uint8 c = grid[j][i] << (NUM_COLS - 1 - j); | |
uint8 col_val = 1 << (NUM_COLS - 1 - current_col); | |
if (current_col == j) { // selected column | |
LED_ROWS_Write(0); | |
LED_COLS_Write(c | col_val); | |
} | |
else { | |
LED_ROWS_Write(~r); | |
LED_COLS_Write(c); | |
} | |
} | |
} | |
LED_ROWS_Write(0); | |
LED_COLS_Write(0); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment