6.115 Final Project - Grid Sequencer
/* ======================================== | |
* | |
* 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