Compare commits

...

9 Commits
wip ... master

9 changed files with 115 additions and 48 deletions

View File

@ -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.

View File

@ -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

View File

@ -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);
@ -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,24 +125,28 @@ 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;
int peaking;
DMA_ClearFlag(ADC_RX_DMA_STREAM, DMA_FLAG_TCIF0); DMA_ClearFlag(ADC_RX_DMA_STREAM, DMA_FLAG_TCIF0);
//printf("[DMA-IRQ] %d, %d\r\n", adc_buffer[0], adc_buffer[1]);
sample = 2048 - ((adc_buffer[0] + adc_buffer[1]) / 2); sample = ((adc_buffer[0] + adc_buffer[1]) / 2) - 2048;
GotSample(sample); 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);
@ -155,5 +157,6 @@ 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...
ADC_SoftwareStartConv(ADC1); ADC_SoftwareStartConv(ADC1);
} }

View File

@ -2,7 +2,7 @@
#define _ADC_H #define _ADC_H
#define ADC_F_TIM 50000000 #define ADC_F_TIM 50000000
#define ADC_SAMPLE_RATE 44130 #define ADC_SAMPLE_RATE (40000)
#define ADC_RX_DMA_CHANNEL DMA_Channel_0 #define ADC_RX_DMA_CHANNEL DMA_Channel_0
@ -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

View File

@ -4,7 +4,7 @@
#define CCEMBEDDED #define CCEMBEDDED
#define NUM_LIN_LEDS 60 #define NUM_LIN_LEDS 60
#define USE_NUM_LIN_LEDS 60 #define USE_NUM_LIN_LEDS 60
#define DFREQ 44130 #define DFREQ (40000)
#endif #endif

View File

@ -168,7 +168,9 @@ void ConfigureUART()
void ConfigureLED() void ConfigureLED()
{ {
ConfigureGPIO( LEDPIN, INOUT_OUT ); ConfigureGPIO(LED_RED, INOUT_OUT);
ConfigureGPIO(LED_GREEN, INOUT_OUT);
ConfigureGPIO(LED_BLUE, INOUT_OUT);
} }
uint8_t GetGPIOFromString( const char * str ) uint8_t GetGPIOFromString( const char * str )
@ -262,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();
}

View File

@ -50,16 +50,20 @@ void ConfigureGPIO( gpio gpio, int parameters );
#ifdef STM32F30X #ifdef STM32F30X
#define LEDPIN 0x18 #define LEDPIN 0x18
#elif defined( STM32F40_41xxx ) #elif defined( STM32F40_41xxx )
#define LEDPIN (16+14) #define LEDPIN (16+13)
#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)
void JumpToBootloader(void);
#define LED_ON(p) GPIOOn(p)
#define LED_OFF(p) GPIOOff(p)
#endif #endif

View File

@ -25,12 +25,21 @@ 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 (peaking) {
LED_ON(LED_RED);
} else if (samp > 128) {
LED_ON(LED_BLUE);
} else {
LED_OFF(LED_BLUE);
// Red LED reset in main loop
}
} }
//Call this once we've stacked together one full colorchord frame. //Call this once we've stacked together one full colorchord frame.
@ -40,8 +49,8 @@ void NewFrame()
int i; int i;
HandleFrameInfo(); HandleFrameInfo();
// UpdateLinearLEDs(); UpdateLinearLEDs();
UpdateAllSameLEDs(); //UpdateAllSameLEDs();
SendSPI2812( ledOut, NUM_LIN_LEDS ); SendSPI2812( ledOut, NUM_LIN_LEDS );
} }
@ -110,32 +119,25 @@ int main(void)
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);
float fv = RCC_Clocks.HCLK_Frequency / 1000000.0f; float fv = RCC_Clocks.HCLK_Frequency / 1000000.0f;
// We can use printf to print back through the debugging interface, but that's slow and
// it also takes up a bunch of space. No printf = no space wasted in printf.
// printf( "Operating at %.3fMHz\n", fv );
ConfigureUART(); ConfigureUART();
InitColorChord(); InitColorChord();
Configure_PA0(); Configure_PA0();
//InitMP45DT02();
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;
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;
@ -146,19 +148,33 @@ 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_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]/2 ); //Can't put in full volume. PushSample32( sampbuff[this_samp] ); //Can't put in full volume. (here was /2)
this_samp = (this_samp+1)%CIRCBUFSIZE; this_samp = (this_samp+1)%CIRCBUFSIZE;
@ -167,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.
} }
} }

View File

@ -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