//ColorChordEmbedded implementation on the STM32F407 for the stm32f4-discovery. //Uses on-board microphone and outputs WS2812 signal for configurable number of LEDs //on PB5 via DMA+SPI #include #include #include #include #include #include #include #include #include "spi2812.h" #include "adc.h" volatile int wasclicked = 0; //Used for if the root change button was clicked. RCC_ClocksTypeDef RCC_Clocks; //Circular buffer for incoming data so we don't spend much time servicing the interrupt and we can handle colorchord in the main thread. #define CIRCBUFSIZE 256 volatile int last_samp_pos; int16_t sampbuff[CIRCBUFSIZE]; volatile int samples; //This gets called by the ADC/Microphone void GotSample( int samp ) { //printf("[GOT-SMP] %d\r\n", samp); sampbuff[last_samp_pos] = samp; last_samp_pos = ((last_samp_pos+1)%CIRCBUFSIZE); samples++; } //Call this once we've stacked together one full colorchord frame. void NewFrame() { // uint8_t led_outs[NUM_LIN_LEDS*3]; int i; HandleFrameInfo(); UpdateLinearLEDs(); //UpdateAllSameLEDs(); SendSPI2812( ledOut, NUM_LIN_LEDS ); } void Configure_PA0(void) { /* Set variables used */ GPIO_InitTypeDef GPIO_InitStruct; EXTI_InitTypeDef EXTI_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; /* Enable clock for GPIOD */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); /* Enable clock for SYSCFG */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); /* Set pin as input */ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); /* Tell system that you will use PA0 for EXTI_Line0 */ SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0); /* PA0 is connected to EXTI_Line0 */ EXTI_InitStruct.EXTI_Line = EXTI_Line0; /* Enable interrupt */ EXTI_InitStruct.EXTI_LineCmd = ENABLE; /* Interrupt mode */ EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; /* Triggers on rising and falling edge */ EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising; /* Add to EXTI */ EXTI_Init(&EXTI_InitStruct); /* Add IRQ vector to NVIC */ /* PA0 is connected to EXTI_Line0, which has EXTI0_IRQn vector */ NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00; /* Set priority */ NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00; /* Set sub priority */ NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; /* Enable interrupt */ NVIC_Init(&NVIC_InitStruct); /* Add to NVIC */ } //Handle button press on PA0. void EXTI0_IRQHandler(void) { static int rootoffset; if (EXTI_GetITStatus(EXTI_Line0) != RESET) { if( wasclicked == 0 ) wasclicked = 10; EXTI_ClearITPendingBit(EXTI_Line0); } } int main(void) { uint32_t i = 0; RCC_GetClocksFreq( &RCC_Clocks ); ConfigureLED(); LED_OFF; // SysTick end of count event each 10ms SysTick_Config( RCC_Clocks.HCLK_Frequency / 100); float fv = RCC_Clocks.HCLK_Frequency / 1000000.0f; ConfigureUART(); InitColorChord(); Configure_PA0(); InitSPI2812(); adc_init(); printf("Operating at %.3fMHz\r\n", fv ); int this_samp = 0; int wf = 0; LED_ON; int c = 1; while (1) { for (int a=0; a < NUM_LIN_LEDS; a++) { ledOut[a*3 + 0] = c/2; ledOut[a*3 + 1] = (64-c)/2 % 255; ledOut[a*3 + 2] = a/8 % 256; } SendSPI2812(ledOut, NUM_LIN_LEDS); _delay_us(10*1000); c++; if (c==64) break; } SendSPI2812(ledOut, NUM_LIN_LEDS); while(1) { if( this_samp != last_samp_pos ) { LED_OFF; //Use led on the board to show us how much CPU we're using. (You can also probe PB15) PushSample32( sampbuff[this_samp] ); //Can't put in full volume. (here was /2) this_samp = (this_samp+1)%CIRCBUFSIZE; wf++; if( wf == 128 ) { NewFrame(); wf = 0; } LED_ON; } LED_ON; //Take up a little more time to make sure we don't miss this. } } void TimingDelay_Decrement() { static int rootoffset; //A way of making sure we debounce the button. if( wasclicked ) { if( wasclicked == 10 ) { if( rootoffset++ >= 12 ) rootoffset = 0; RootNoteOffset = (rootoffset * NOTERANGE) / 12; } wasclicked--; } }