Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
632772d4b7 | |||
08a2581297 | |||
18f405aa46 | |||
59dcbaf177 | |||
154980ee10 | |||
8e25479ab5 | |||
7b895a2561 | |||
c5a770a52c | |||
03abf17edc |
19
README.MD
19
README.MD
@ -1 +1,18 @@
|
|||||||
# Sabik WS2812B light signal - CPU Board
|
# WS2812B light signal - CPU Board
|
||||||
|
|
||||||
|
Board to run [colorchord2](https://github.com/cnlohr/colorchord) on a string of WS2812B LEDs with live line-in audio.
|
||||||
|
|
||||||
|
## Errata (Rev 01)
|
||||||
|
|
||||||
|
* Opamp inverting / non-inverting inputs are swapped
|
||||||
|
* Workaround: Lift pads 2 and 3, and 5 and 6, and connect them crossed using magnet wire.
|
||||||
|
* Opamp is not rail-to-rail and does not allow to use the ADC in full range
|
||||||
|
* Workaround: Only use limited range -640 to 520.
|
||||||
|
* LED footprint is wrong.
|
||||||
|
* Workaround: Flip 180 degrees and solder shifted onto the right pads, then use magnet wire to connect the remaining two pads.
|
||||||
|
* Serial boot loader non-functional (uses incompatible UART I/Os).
|
||||||
|
* Workaround: Program via JTAG / SWD.
|
||||||
|
* Missing level shifters for WS2812B LEDs (RX)
|
||||||
|
* Workaround: Don't use WS2812B RX inputs on the board
|
||||||
|
* Missing level shifters for WS2812B LEDs (TX)
|
||||||
|
* Workaround: The first LED will kinda sorta do the level shifting for you, but sometimes fail to display correctly. Just ignore its erratic blinking.
|
||||||
|
@ -13,9 +13,8 @@ OD=$(PREFIX)-objdump
|
|||||||
OBJCOPYFLAGS = -O binary
|
OBJCOPYFLAGS = -O binary
|
||||||
|
|
||||||
BIN=$(CP) -O ihex
|
BIN=$(CP) -O ihex
|
||||||
|
|
||||||
CCBASE = colorchord/embeddedstm32f407
|
CCBASE = colorchord/embeddedstm32f407
|
||||||
DEFS = -DSTM32F40_41xxx -DHSE_VALUE=8000000
|
DEFS = -DSTM32F40_41xxx -DHSE_VALUE=8000000 -DREVISION=\"`git describe --match=NeVeRmAtCh --always --abbrev=40 --dirty`\"
|
||||||
STARTUP = $(CCBASE)/lib/startup_stm32f40_41xxx.s
|
STARTUP = $(CCBASE)/lib/startup_stm32f40_41xxx.s
|
||||||
STLIB = $(CCBASE)/STM32F4xx_StdPeriph_Driver
|
STLIB = $(CCBASE)/STM32F4xx_StdPeriph_Driver
|
||||||
EMCOM = $(CCBASE)/../embeddedcommon
|
EMCOM = $(CCBASE)/../embeddedcommon
|
||||||
|
@ -14,8 +14,6 @@ void adc_init()
|
|||||||
ADC_InitTypeDef ADC_InitStructure;
|
ADC_InitTypeDef ADC_InitStructure;
|
||||||
GPIO_InitTypeDef GPIO_InitStruct;
|
GPIO_InitTypeDef GPIO_InitStruct;
|
||||||
|
|
||||||
printf("ADC init\r\n");
|
|
||||||
|
|
||||||
// Enable Clocks
|
// Enable Clocks
|
||||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
|
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
|
||||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
|
||||||
@ -30,7 +28,7 @@ void adc_init()
|
|||||||
// Set up timer
|
// Set up timer
|
||||||
TIM_TimeBaseInitTypeDef Timer_InitStruct;
|
TIM_TimeBaseInitTypeDef Timer_InitStruct;
|
||||||
TIM_TimeBaseStructInit(&Timer_InitStruct);
|
TIM_TimeBaseStructInit(&Timer_InitStruct);
|
||||||
Timer_InitStruct.TIM_Prescaler = 0x0;
|
Timer_InitStruct.TIM_Prescaler = 0;
|
||||||
Timer_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
|
Timer_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
|
||||||
Timer_InitStruct.TIM_Period = (ADC_F_TIM / ADC_SAMPLE_RATE);
|
Timer_InitStruct.TIM_Period = (ADC_F_TIM / ADC_SAMPLE_RATE);
|
||||||
Timer_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
|
Timer_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
|
||||||
@ -46,7 +44,7 @@ void adc_init()
|
|||||||
TIM_OC1Init (TIM5, &TIM_OCInitStructure);
|
TIM_OC1Init (TIM5, &TIM_OCInitStructure);
|
||||||
|
|
||||||
TIM_SetCompare1(TIM5, 0xFFFF);
|
TIM_SetCompare1(TIM5, 0xFFFF);
|
||||||
TIM_ITConfig(TIM5, TIM_IT_CC1, ENABLE);
|
// Let's leave the interrupt disabled until we are done configuring everything
|
||||||
|
|
||||||
TIM_CCxCmd(TIM5, TIM_Channel_1, TIM_CCx_Enable);
|
TIM_CCxCmd(TIM5, TIM_Channel_1, TIM_CCx_Enable);
|
||||||
TIM_CCxNCmd(TIM5, TIM_Channel_1, TIM_CCx_Enable);
|
TIM_CCxNCmd(TIM5, TIM_Channel_1, TIM_CCx_Enable);
|
||||||
@ -127,44 +125,38 @@ void adc_init()
|
|||||||
// Turn it all on
|
// Turn it all on
|
||||||
ADC_Cmd(ADC1, ENABLE);
|
ADC_Cmd(ADC1, ENABLE);
|
||||||
ADC_DMACmd(ADC1, ENABLE);
|
ADC_DMACmd(ADC1, ENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
printf("adc init done.\r\n");
|
void adc_start()
|
||||||
printf("ADC CR1: %08x, CR2: %08x\r\n", ADC1->CR1, ADC1->CR2);
|
{
|
||||||
printf("ADC SQR1: %08x, SQR3: %08x\r\n", ADC1->SQR1, ADC1->SQR3);
|
TIM_ITConfig(TIM5, TIM_IT_CC1, ENABLE);
|
||||||
printf("DMA2 S0CR: %08x\r\n", ADC_RX_DMA_STREAM->CR);
|
|
||||||
printf("ADC init complete.\r\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DMA2_Stream0_IRQHandler()
|
void DMA2_Stream0_IRQHandler()
|
||||||
{
|
{
|
||||||
int sample;
|
int sample;
|
||||||
DMA_ClearFlag(ADC_RX_DMA_STREAM, DMA_FLAG_TCIF0);
|
int peaking;
|
||||||
//printf("[DMA-IRQ] %d, %d\r\n", adc_buffer[0], adc_buffer[1]);
|
|
||||||
//sample = 2048 - ((adc_buffer[0] + adc_buffer[1]) / 2);
|
|
||||||
sample = 2048 - adc_buffer[0];
|
|
||||||
//printf("ADC0: %4d, ADC1: %4d, SMP: %4d\r\n",
|
|
||||||
// adc_buffer[0], adc_buffer[1], sample);
|
|
||||||
|
|
||||||
GotSample(sample);
|
DMA_ClearFlag(ADC_RX_DMA_STREAM, DMA_FLAG_TCIF0);
|
||||||
|
|
||||||
|
sample = ((adc_buffer[0] + adc_buffer[1]) / 2) - 2048;
|
||||||
|
peaking = (adc_buffer[0] < -640+2048) || (adc_buffer[0] > 520+2048);
|
||||||
|
peaking |= (adc_buffer[1] < -640+2048) || (adc_buffer[1] > 520+2048);
|
||||||
|
|
||||||
|
GotSample(sample, peaking);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not used:
|
// Only for debugging. Currently disabled.
|
||||||
void ADC_IRQHandler()
|
void ADC_IRQHandler()
|
||||||
{
|
{
|
||||||
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
|
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
|
||||||
//printf("[ADC-IRQ] %d, %d\r\n", adc_buffer[0], adc_buffer[1]);
|
// printf("[ADC-IRQ] %d, %d\r\n", adc_buffer[0], adc_buffer[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TIM5_IRQHandler()
|
void TIM5_IRQHandler()
|
||||||
{
|
{
|
||||||
TIM_ClearFlag(TIM5, TIM_FLAG_CC1);
|
TIM_ClearFlag(TIM5, TIM_FLAG_CC1);
|
||||||
// I would really like to this in HW via events, but somehow it's broken...
|
// I would really like to this in HW via events, but somehow it's broken...
|
||||||
/*static int s=0;
|
|
||||||
s=!s;
|
|
||||||
if (s) {
|
|
||||||
LED_ON2;
|
|
||||||
} else {
|
|
||||||
LED_OFF2;
|
|
||||||
}*/
|
|
||||||
ADC_SoftwareStartConv(ADC1);
|
ADC_SoftwareStartConv(ADC1);
|
||||||
}
|
}
|
||||||
|
@ -11,5 +11,6 @@
|
|||||||
// TODO: Update the IRQ handler in adc.c when updating the stream / channel.
|
// TODO: Update the IRQ handler in adc.c when updating the stream / channel.
|
||||||
|
|
||||||
void adc_init();
|
void adc_init();
|
||||||
|
void adc_start();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
#define _CCCONFIG_H
|
#define _CCCONFIG_H
|
||||||
|
|
||||||
#define CCEMBEDDED
|
#define CCEMBEDDED
|
||||||
#define NUM_LIN_LEDS 48
|
#define NUM_LIN_LEDS 60
|
||||||
#define USE_NUM_LIN_LEDS 48
|
#define USE_NUM_LIN_LEDS 60
|
||||||
#define DFREQ (40000)
|
#define DFREQ (40000)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -168,8 +168,9 @@ void ConfigureUART()
|
|||||||
|
|
||||||
void ConfigureLED()
|
void ConfigureLED()
|
||||||
{
|
{
|
||||||
ConfigureGPIO(LEDPIN, INOUT_OUT);
|
ConfigureGPIO(LED_RED, INOUT_OUT);
|
||||||
ConfigureGPIO(LEDPIN2, INOUT_OUT);
|
ConfigureGPIO(LED_GREEN, INOUT_OUT);
|
||||||
|
ConfigureGPIO(LED_BLUE, INOUT_OUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t GetGPIOFromString( const char * str )
|
uint8_t GetGPIOFromString( const char * str )
|
||||||
@ -263,3 +264,29 @@ void ConfigureGPIO( uint8_t gpio, int parameters )
|
|||||||
GPIO_Init(GPIOOf(gpio), &GPIO_InitStructure);
|
GPIO_Init(GPIOOf(gpio), &GPIO_InitStructure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JumpToBootloader(void) {
|
||||||
|
// Many thanks to https://stm32f4-discovery.net/2017/04/tutorial-jump-system-memory-software-stm32/
|
||||||
|
|
||||||
|
void (*SysMemBootJump)(void);
|
||||||
|
volatile uint32_t addr = 0x1FFF0000;
|
||||||
|
|
||||||
|
RCC_DeInit();
|
||||||
|
|
||||||
|
// Disable and reset systick
|
||||||
|
SysTick->CTRL = 0;
|
||||||
|
SysTick->LOAD = 0;
|
||||||
|
SysTick->VAL = 0;
|
||||||
|
|
||||||
|
__disable_irq();
|
||||||
|
|
||||||
|
// Remap system memory
|
||||||
|
SYSCFG->MEMRMP = 0x01;
|
||||||
|
|
||||||
|
SysMemBootJump = (void (*)(void)) (*((uint32_t *)(addr + 4)));
|
||||||
|
|
||||||
|
// Set main stack pointer
|
||||||
|
__set_MSP(*(uint32_t *)addr);
|
||||||
|
|
||||||
|
// Jump
|
||||||
|
SysMemBootJump();
|
||||||
|
}
|
||||||
|
@ -51,19 +51,19 @@ void ConfigureGPIO( gpio gpio, int parameters );
|
|||||||
#define LEDPIN 0x18
|
#define LEDPIN 0x18
|
||||||
#elif defined( STM32F40_41xxx )
|
#elif defined( STM32F40_41xxx )
|
||||||
#define LEDPIN (16+13)
|
#define LEDPIN (16+13)
|
||||||
#define LEDPIN2 (16+14)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define LED_GREEN (LEDPIN+0)
|
||||||
|
#define LED_BLUE (LEDPIN+1)
|
||||||
|
#define LED_RED (LEDPIN+2)
|
||||||
|
|
||||||
void ConfigureUART();
|
void ConfigureUART();
|
||||||
|
|
||||||
void ConfigureLED();
|
void ConfigureLED();
|
||||||
#define LED_TOGGLE {GPIOOf(LEDPIN)->ODR^=(1<<((LEDPIN)&0x0f));}
|
|
||||||
#define LED_ON GPIOOn(LEDPIN)
|
|
||||||
#define LED_OFF GPIOOff(LEDPIN)
|
|
||||||
|
|
||||||
#define LED_ON2 GPIOOn(LEDPIN2)
|
void JumpToBootloader(void);
|
||||||
#define LED_OFF2 GPIOOff(LEDPIN2)
|
|
||||||
|
|
||||||
|
#define LED_ON(p) GPIOOn(p)
|
||||||
|
#define LED_OFF(p) GPIOOff(p)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -25,17 +25,20 @@ int16_t sampbuff[CIRCBUFSIZE];
|
|||||||
volatile int samples;
|
volatile int samples;
|
||||||
|
|
||||||
//This gets called by the ADC/Microphone
|
//This gets called by the ADC/Microphone
|
||||||
void GotSample( int samp )
|
void GotSample(int samp, int peaking)
|
||||||
{
|
{
|
||||||
//printf("[GOT-SMP] %d\r\n", samp);
|
//printf("[GOT-SMP] %d\r\n", samp);
|
||||||
sampbuff[last_samp_pos] = samp;
|
sampbuff[last_samp_pos] = samp;
|
||||||
last_samp_pos = ((last_samp_pos+1)%CIRCBUFSIZE);
|
last_samp_pos = ((last_samp_pos+1)%CIRCBUFSIZE);
|
||||||
samples++;
|
samples++;
|
||||||
|
|
||||||
if (samp > 128) {
|
if (peaking) {
|
||||||
LED_ON2;
|
LED_ON(LED_RED);
|
||||||
|
} else if (samp > 128) {
|
||||||
|
LED_ON(LED_BLUE);
|
||||||
} else {
|
} else {
|
||||||
LED_OFF2;
|
LED_OFF(LED_BLUE);
|
||||||
|
// Red LED reset in main loop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,9 +117,7 @@ int main(void)
|
|||||||
|
|
||||||
RCC_GetClocksFreq( &RCC_Clocks );
|
RCC_GetClocksFreq( &RCC_Clocks );
|
||||||
|
|
||||||
ConfigureLED();
|
ConfigureLED();
|
||||||
|
|
||||||
LED_OFF;
|
|
||||||
|
|
||||||
// SysTick end of count event each 10ms
|
// SysTick end of count event each 10ms
|
||||||
SysTick_Config( RCC_Clocks.HCLK_Frequency / 100);
|
SysTick_Config( RCC_Clocks.HCLK_Frequency / 100);
|
||||||
@ -129,15 +130,14 @@ int main(void)
|
|||||||
InitSPI2812();
|
InitSPI2812();
|
||||||
adc_init();
|
adc_init();
|
||||||
|
|
||||||
printf("Operating at %.3fMHz\r\n", fv );
|
printf("\r\nThis is Sabik-CPU, commit %s.\r\n", REVISION);
|
||||||
|
printf("Operating at %.3fMHz.\r\n", fv );
|
||||||
|
|
||||||
int this_samp = 0;
|
int this_samp = 0;
|
||||||
int wf = 0;
|
int wf = 0;
|
||||||
|
|
||||||
LED_ON;
|
|
||||||
LED_ON2;
|
|
||||||
|
|
||||||
int c = 1;
|
int c = 1;
|
||||||
|
LED_ON(LED_RED);
|
||||||
while (1) {
|
while (1) {
|
||||||
for (int a=0; a < NUM_LIN_LEDS; a++) {
|
for (int a=0; a < NUM_LIN_LEDS; a++) {
|
||||||
ledOut[a*3 + 0] = c/2;
|
ledOut[a*3 + 0] = c/2;
|
||||||
@ -148,17 +148,31 @@ int main(void)
|
|||||||
SendSPI2812(ledOut, NUM_LIN_LEDS);
|
SendSPI2812(ledOut, NUM_LIN_LEDS);
|
||||||
_delay_us(10*1000);
|
_delay_us(10*1000);
|
||||||
c++;
|
c++;
|
||||||
if (c==64)
|
if (c==16) {
|
||||||
|
LED_OFF(LED_RED);
|
||||||
|
LED_ON(LED_BLUE);
|
||||||
|
} else if (c==32) {
|
||||||
|
LED_OFF(LED_BLUE);
|
||||||
|
LED_ON(LED_GREEN);
|
||||||
|
} else if (c==48) {
|
||||||
|
LED_OFF(LED_GREEN);
|
||||||
|
} else if (c==64) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LED_OFF2;
|
LED_OFF(LED_RED);
|
||||||
|
LED_OFF(LED_GREEN);
|
||||||
|
LED_OFF(LED_BLUE);
|
||||||
|
|
||||||
SendSPI2812(ledOut, NUM_LIN_LEDS);
|
SendSPI2812(ledOut, NUM_LIN_LEDS);
|
||||||
|
adc_start();
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
if( this_samp != last_samp_pos )
|
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)
|
LED_OFF(LED_GREEN); //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)
|
PushSample32( sampbuff[this_samp] ); //Can't put in full volume. (here was /2)
|
||||||
|
|
||||||
@ -169,10 +183,11 @@ int main(void)
|
|||||||
{
|
{
|
||||||
NewFrame();
|
NewFrame();
|
||||||
wf = 0;
|
wf = 0;
|
||||||
|
LED_OFF(LED_RED);
|
||||||
}
|
}
|
||||||
LED_ON;
|
LED_ON(LED_GREEN);
|
||||||
}
|
}
|
||||||
LED_ON; //Take up a little more time to make sure we don't miss this.
|
LED_ON(LED_GREEN); //Take up a little more time to make sure we don't miss this.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,8 +133,6 @@ void InitSPI2812()
|
|||||||
GPIO_InitTypeDef GPIO_InitStructure;
|
GPIO_InitTypeDef GPIO_InitStructure;
|
||||||
NVIC_InitTypeDef nvic_init_struct;
|
NVIC_InitTypeDef nvic_init_struct;
|
||||||
|
|
||||||
printf("Init SPI2812: sizeof(MyBuffer)=%d\r\n", sizeof(MyBuffer));
|
|
||||||
|
|
||||||
#ifdef STM32F30X
|
#ifdef STM32F30X
|
||||||
|
|
||||||
//On SPI2, PORT B.15
|
//On SPI2, PORT B.15
|
||||||
|
Loading…
Reference in New Issue
Block a user