Add initial version of firmware

wip
Markus Koch 2021-02-23 19:05:43 +01:00
parent 70b8a38941
commit cac80f1c65
20 changed files with 2994 additions and 0 deletions

3
.gitmodules vendored 100644
View File

@ -0,0 +1,3 @@
[submodule "firmware/colorchord"]
path = firmware/colorchord
url = https://github.com/cnlohr/colorchord.git

2
firmware/.gitignore vendored 100644
View File

@ -0,0 +1,2 @@
*.bin
*.out

30
firmware/LICENSE 100644
View File

@ -0,0 +1,30 @@
Note: This contains libraries from CM and ST that are under a different
license than this file. See those folders respectively.
STM32F303-based ColorChord 2.0 Build
Copyright (c) 2015 Charles Lohr
Roughly based off of: https://github.com/devthrash/0xWS2812
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

77
firmware/Makefile 100644
View File

@ -0,0 +1,77 @@
TARGET=main
all: $(TARGET).bin
PREFIX=arm-none-eabi
CC=$(PREFIX)-gcc
LD=$(PREFIX)-gcc
AS=$(PREFIX)-as
CP=$(PREFIX)-objcopy
OD=$(PREFIX)-objdump
OBJCOPYFLAGS = -O binary
BIN=$(CP) -O ihex
CCBASE = colorchord/embeddedstm32f407
DEFS = -DSTM32F40_41xxx -DHSE_VALUE=8000000
STARTUP = $(CCBASE)/lib/startup_stm32f40_41xxx.s
STLIB = $(CCBASE)/STM32F4xx_StdPeriph_Driver
EMCOM = $(CCBASE)/../embeddedcommon
MCU = cortex-m3
MCFLAGS = -mcpu=$(MCU) -mthumb -mlittle-endian -mthumb-interwork
STM32_INCLUDES = -Ilib -I. -I$(STLIB)/inc -I$(CCBASE)/lib
OPTIMIZE = -Os
CFLAGS = $(MCFLAGS) $(OPTIMIZE) $(DEFS) \
-I. \
$(STM32_INCLUDES) \
-I$(EMCOM) \
-Wl,-T,lib/stm32f410.ld
CFLAGS+=-DDEBUG
CFLAGS+=-I.
AFLAGS = $(MCFLAGS)
SRC = main.c \
stm32f4xx_it.c \
lib/system_stm32f4xx.c \
lib/systems.c \
spi2812.c \
adc.c \
$(STLIB)/src/misc.c \
$(STLIB)/src/stm32f4xx_dma.c \
$(STLIB)/src/stm32f4xx_spi.c \
$(STLIB)/src/stm32f4xx_syscfg.c \
$(STLIB)/src/stm32f4xx_exti.c \
$(STLIB)/src/stm32f4xx_rcc.c \
$(STLIB)/src/stm32f4xx_gpio.c \
$(STLIB)/src/stm32f4xx_usart.c \
$(STLIB)/src/stm32f4xx_adc.c \
$(STLIB)/src/stm32f4xx_tim.c \
$(EMCOM)/DFT32.c \
$(EMCOM)/embeddednf.c \
$(EMCOM)/embeddedout.c
burn : $(TARGET).bin
openocd -f flash.cfg #-d3
terminal :
openocd -f terminal.cfg
$(TARGET).bin : $(TARGET).out
$(CP) $(OBJCOPYFLAGS) $< $@
$(TARGET).hex: $(EXECUTABLE)
$(CP) -O ihex $^ $@
$(TARGET).out : $(SRC) $(STARTUP)
$(CC) $(CFLAGS) $^ -lm -lc -lnosys -o $@
clean:
rm -f $(TARGET).lst $(TARGET).out $(TARGET).hex $(TARGET).bin $(TARGET).map $(EXECUTABLE)

159
firmware/adc.c 100644
View File

@ -0,0 +1,159 @@
#include "adc.h"
#include <stm32f4xx_adc.h>
#include <stm32f4xx_rcc.h>
#include <stm32f4xx_dma.h>
#include <stdio.h>
#include "systems.h"
#include <stm32f4xx.h>
volatile uint16_t adc_buffer[2] = {0,};
void adc_init()
{
ADC_CommonInitTypeDef ADC_CommonInitStruct;
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStruct;
printf("ADC init\r\n");
// Enable Clocks
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_DMA1, ENABLE);
// Set up GPIO
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// Set up timer
TIM_TimeBaseInitTypeDef Timer_InitStruct;
TIM_TimeBaseStructInit(&Timer_InitStruct);
Timer_InitStruct.TIM_Prescaler = 0;
Timer_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
Timer_InitStruct.TIM_Period = (ADC_F_TIM / ADC_SAMPLE_RATE);
Timer_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
Timer_InitStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM5, &Timer_InitStruct);
TIM_Cmd(TIM5, ENABLE);
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit (&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCNIdleState_Reset;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Active;
TIM_OC1Init (TIM5, &TIM_OCInitStructure);
TIM_SetCompare1(TIM5, 0xFFFF);
TIM_ITConfig(TIM5, TIM_IT_CC1, ENABLE);
TIM_CCxCmd(TIM5, TIM_Channel_1, TIM_CCx_Enable);
TIM_CCxNCmd(TIM5, TIM_Channel_1, TIM_CCx_Enable);
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = TIM5_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
// Set up DMA
DMA_InitTypeDef DMA_InitStruct;
DMA_StructInit(&DMA_InitStruct);
DMA_DeInit(ADC_RX_DMA_STREAM);
DMA_InitStruct.DMA_Channel = ADC_RX_DMA_CHANNEL;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t) & (ADC1->DR);
DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)adc_buffer;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStruct.DMA_BufferSize = 2;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(ADC_RX_DMA_STREAM, &DMA_InitStruct);
DMA_ITConfig(ADC_RX_DMA_STREAM, DMA_IT_TC, ENABLE);
NVIC_InitStruct.NVIC_IRQChannel = ADC_RX_DMA_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
DMA_Cmd(ADC_RX_DMA_STREAM, ENABLE);
// Set up ADC
ADC_DeInit();
ADC_CommonStructInit(&ADC_CommonInitStruct);
ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div8;
ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;
ADC_CommonInit(&ADC_CommonInitStruct);
ADC_StructInit(&ADC_InitStructure);
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; // TODO: trig via event
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T5_CC1;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 2;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
NVIC_InitStruct.NVIC_IRQChannel = ADC_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelCmd = DISABLE; // !
NVIC_Init(&NVIC_InitStruct);
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
ADC_EOCOnEachRegularChannelCmd(ADC1, DISABLE);
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_28Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 2, ADC_SampleTime_28Cycles);
// Turn it all on
ADC_Cmd(ADC1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
printf("adc init done.\r\n");
printf("ADC CR1: %08x, CR2: %08x\r\n", ADC1->CR1, ADC1->CR2);
printf("ADC SQR1: %08x, SQR3: %08x\r\n", ADC1->SQR1, ADC1->SQR3);
printf("DMA2 S0CR: %08x\r\n", ADC_RX_DMA_STREAM->CR);
printf("ADC init complete.\r\n");
}
void DMA2_Stream0_IRQHandler()
{
int sample;
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);
GotSample(sample);
}
// Not used:
void ADC_IRQHandler()
{
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
//printf("[ADC-IRQ] %d, %d\r\n", adc_buffer[0], adc_buffer[1]);
}
void TIM5_IRQHandler()
{
TIM_ClearFlag(TIM5, TIM_FLAG_CC1);
// I would really like to this in HW via events, but somehow it's broken...
ADC_SoftwareStartConv(ADC1);
}

15
firmware/adc.h 100644
View File

@ -0,0 +1,15 @@
#ifndef _ADC_H
#define _ADC_H
#define ADC_F_TIM 50000000
#define ADC_SAMPLE_RATE 44130
#define ADC_RX_DMA_CHANNEL DMA_Channel_0
#define ADC_RX_DMA_STREAM DMA2_Stream0
#define ADC_RX_DMA_IRQn DMA2_Stream0_IRQn
// TODO: Update the IRQ handler in adc.c when updating the stream / channel.
void adc_init();
#endif

View File

@ -0,0 +1,10 @@
#ifndef _CCCONFIG_H
#define _CCCONFIG_H
#define CCEMBEDDED
#define NUM_LIN_LEDS 60
#define USE_NUM_LIN_LEDS 60
#define DFREQ 44130
#endif

@ -0,0 +1 @@
Subproject commit 9cae6dc38d288618d7a7163a0e9abcb4fb9234a2

26
firmware/flash.cfg 100644
View File

@ -0,0 +1,26 @@
set TRANSPORT hla_swd
source [find interface/ftdi/olimex-arm-usb-ocd-h.cfg]
source [find target/stm32f4x.cfg]
#reset_config none separate
#reset_config srst_push_pull
#separate trst_push_pull
#reset_config srst_nogate
init
reset halt
halt 20
reset
sleep 10
reset halt
flash write_image erase main.bin 0x08000000
sleep 10
reset
sleep 10
#arm semihosting enable
reset run
sleep 10
shutdown

View File

@ -0,0 +1,114 @@
/*. Entry Point *./
ENTRY( Reset_Handler )
/* Highest address of the user mode stack .*/
_estack = 0x20008000; /* end of 32K RAM */
/* Generate a link error if heap and s tack dont fit int o RAM */
_Min_Heap_Size = 0; /* required amount of heap .*/
_Min_Stack_Size = 0x200; /* required amount of stack .*/
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K
MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
/*RAM_BACKUP (rw) : ORIGIN = 0x40024000, LENGTH = 4K*/
}
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .;
*(.data)
*(.data*)
. = ALIGN(4);
_edata = .;
} >RAM AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
_sbss = .;
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .;
__bss_end__ = _ebss;
} >RAM
}

View File

@ -0,0 +1,122 @@
/**
******************************************************************************
* @file ADC/ADC_DMA/stm32f4xx_conf.h
* @author MCD Application Team
* @version V1.5.0
* @date 06-March-2015
* @brief Library configuration file.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F4xx_CONF_H
#define __STM32F4xx_CONF_H
/* Includes ------------------------------------------------------------------*/
/* Uncomment the line below to enable peripheral header file inclusion */
#include "stm32f4xx_adc.h"
#include "stm32f4xx_crc.h"
#include "stm32f4xx_dbgmcu.h"
#include "stm32f4xx_dma.h"
#include "stm32f4xx_exti.h"
#include "stm32f4xx_flash.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_i2c.h"
#include "stm32f4xx_iwdg.h"
#include "stm32f4xx_pwr.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_rtc.h"
#include "stm32f4xx_sdio.h"
#include "stm32f4xx_spi.h"
#include "stm32f4xx_syscfg.h"
#include "stm32f4xx_tim.h"
#include "stm32f4xx_usart.h"
#include "stm32f4xx_wwdg.h"
#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
#if defined (STM32F429_439xx)
#include "stm32f4xx_cryp.h"
#include "stm32f4xx_hash.h"
#include "stm32f4xx_rng.h"
#include "stm32f4xx_can.h"
#include "stm32f4xx_dac.h"
#include "stm32f4xx_dcmi.h"
#include "stm32f4xx_dma2d.h"
#include "stm32f4xx_fmc.h"
#include "stm32f4xx_ltdc.h"
#include "stm32f4xx_sai.h"
#endif /* STM32F429_439xx */
#if defined (STM32F427_437xx)
#include "stm32f4xx_cryp.h"
#include "stm32f4xx_hash.h"
#include "stm32f4xx_rng.h"
#include "stm32f4xx_can.h"
#include "stm32f4xx_dac.h"
#include "stm32f4xx_dcmi.h"
#include "stm32f4xx_dma2d.h"
#include "stm32f4xx_fmc.h"
#include "stm32f4xx_sai.h"
#endif /* STM32F427_437xx */
#if defined (STM32F40_41xxx)
#include "stm32f4xx_cryp.h"
#include "stm32f4xx_hash.h"
#include "stm32f4xx_rng.h"
#include "stm32f4xx_can.h"
#include "stm32f4xx_dac.h"
#include "stm32f4xx_dcmi.h"
#include "stm32f4xx_fsmc.h"
#endif /* STM32F40_41xxx */
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* If an external clock source is used, then the value of the following define
should be set to the value of the external clock source, else, if no external
clock is used, keep this define commented */
/*#define I2S_EXTERNAL_CLOCK_VAL 12288000 */ /* Value of the external clock in Hz */
/* Uncomment the line below to expanse the "assert_param" macro in the
Standard Peripheral Library drivers code */
/* #define USE_FULL_ASSERT 1 */
/* Exported macro ------------------------------------------------------------*/
#ifdef USE_FULL_ASSERT
/**
* @brief The assert_param macro is used for function's parameters check.
* @param expr: If expr is false, it calls assert_failed function
* which reports the name of the source file and the source
* line number of the call that failed.
* If expr is true, it returns no value.
* @retval None
*/
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0)
#endif /* USE_FULL_ASSERT */
#endif /* __STM32F4xx_CONF_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,105 @@
/**
******************************************************************************
* @file system_stm32f4xx.h
* @author MCD Application Team
* @version V1.5.0
* @date 06-March-2015
* @brief CMSIS Cortex-M4 Device System Source File for STM32F4xx devices.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup stm32f4xx_system
* @{
*/
/**
* @brief Define to prevent recursive inclusion
*/
#ifndef __SYSTEM_STM32F4XX_H
#define __SYSTEM_STM32F4XX_H
#ifdef __cplusplus
extern "C" {
#endif
/** @addtogroup STM32F4xx_System_Includes
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F4xx_System_Exported_types
* @{
*/
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
/**
* @}
*/
/** @addtogroup STM32F4xx_System_Exported_Constants
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F4xx_System_Exported_Macros
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F4xx_System_Exported_Functions
* @{
*/
extern void SystemInit(void);
extern void SystemCoreClockUpdate(void);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /*__SYSTEM_STM32F4XX_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -0,0 +1,264 @@
#include <stdint.h>
#include "systems.h"
#include <string.h>
#ifdef STM32F30X
#include <stm32f30x.h>
#include <stm32f30x_rcc.h>
#include <stm32f30x_gpio.h>
#elif defined( STM32F40_41xxx )
#include <stm32f4xx.h>
#include <stm32f4xx_rcc.h>
#include <stm32f4xx_gpio.h>
#endif
#include <core_cm4.h>
#include <core_cmFunc.h>
extern RCC_ClocksTypeDef RCC_Clocks;
//For precise timing.
volatile unsigned int *DWT_CYCCNT = (volatile unsigned int *)0xE0001004; //address of the register
volatile unsigned int *SCB_DEMCR = (volatile unsigned int *)0xE000EDFC; //address of the register
volatile unsigned int *DWT_CONTROL = (volatile unsigned int *)0xE0001000; //address of the register
void send_openocd_command(int command, void *message)
{
#ifdef DEBUG
asm("mov r0, %[cmd];"
"mov r1, %[msg];"
"bkpt #0xAB"
:
: [cmd] "r" (command), [msg] "r" (message)
: "r0", "r1", "memory");
#endif
}
void send_text( const char * text )
{
uint32_t m[] = { 2, (uint32_t)text, strlen(text) };
send_openocd_command(0x05, m);
}
int __attribute__((used)) _write (int fd, const void *buf, size_t count)
{
//uint32_t m[] = { 2, (uint32_t)buf, count };
//send_openocd_command(0x05, m);
int i;
for (i=count; i > 0; --i) {
while (!(USART1->SR & USART_SR_TXE));
USART1->DR = (uint16_t)(*((char*) buf) & 0x01FF);
buf++;
}
return count;
}
int __attribute__((used)) _read(int fd, void *buf, size_t count)
{
int i;
for (i=0; i < count; ++i) {
while (!(USART1->SR & USART_SR_RXNE));
*((char*) buf) = USART1->DR;
_write(0, buf, 1);
if (*((char*) buf) == '\r')
break;
buf++;
}
i++;
return i;
}
void __attribute__((used)) * _sbrk(int incr) {
extern char _ebss; // Defined by the linker
static char *heap_end;
char *prev_heap_end;
if (heap_end == 0) {
heap_end = &_ebss;
}
prev_heap_end = heap_end;
char * stack = (char*) __get_MSP();
if (heap_end + incr > stack)
{
return (void*)(-1);
}
heap_end += incr;
return (void*) prev_heap_end;
}
void _delay_us(uint32_t us) {
if( us ) us--; //Approximate extra overhead time.
us *= RCC_Clocks.HCLK_Frequency/1000000;
*SCB_DEMCR = *SCB_DEMCR | 0x01000000;
*DWT_CYCCNT = 0; // reset the counter
*DWT_CONTROL = *DWT_CONTROL | 1 ; // enable the counter
while( *DWT_CYCCNT < us );
}
void ConfigureUART()
{
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
// Enable clock for GPIOB
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
/**
* Enable clock for USART1 peripheral
*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
/**
* Set Baudrate to value you pass to function
* Disable Hardware Flow control
* Set Mode To TX and RX, so USART will work in full-duplex mode
* Disable parity bit
* Set 1 stop bit
* Set Data bits to 8
*
* Initialize USART1
* Activate USART1
*/
USART_InitStruct.USART_BaudRate = 115200;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStruct);
USART_Cmd(USART1, ENABLE);
/**
* Enable RX interrupt
*/
//USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
/**
* Set Channel to USART1
* Set Channel Cmd to enable. That will enable USART1 channel in NVIC
* Set Both priorities to 0. This means high priority
*
* Initialize NVIC
*/
/*NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStruct);*/
}
void ConfigureLED()
{
ConfigureGPIO( LEDPIN, INOUT_OUT );
}
uint8_t GetGPIOFromString( const char * str )
{
int mode = 0;
int port = -1;
int pin = -1;
const char * st = str;
for( ; *st; st++ )
{
char c = *st;
if( mode == 0 )
{
if( c >= 'A' && c <= 'F' )
{
port = c - 'A';
mode = 2;
}
else if( c >= 'a' && c <= 'f' )
{
port = c - 'a';
mode = 2;
}
}
else if( mode == 2 )
{
if( c >= '0' && c <= '9' )
{
pin = 0;
mode = 3;
}
}
if( mode == 3 )
{
if( c >= '0' && c <= '9' )
{
pin = pin * 10;
pin+= c - '0';
}
else
{
break;
}
}
}
if( port > 0 && pin > 0 && port <= 6 && pin <= 15)
{
return (port<<4)|pin;
}
else
{
return 0xff;
}
}
void ConfigureGPIO( uint8_t gpio, int parameters )
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable the GPIO_LED Clock */
#ifdef STM32F30X
RCC_AHBPeriphClockCmd( 1<<(17+(gpio>>4)), ENABLE);
#elif defined( STM32F40_41xxx )
RCC_AHB1PeriphClockCmd( 1<<((gpio>>4)), ENABLE);
#endif
if( parameters & DEFAULT_VALUE_FLAG )
{
GPIOOn( gpio );
}
else
{
GPIOOff( gpio );
}
/* Configure the GPIO_LED pin */
GPIO_InitStructure.GPIO_Pin = 1<<(gpio&0xf);
GPIO_InitStructure.GPIO_Mode = (parameters&INOUT_FLAG)?GPIO_Mode_OUT:GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = (parameters&PUPD_FLAG)?( (parameters&PUPD_UP)?GPIO_PuPd_UP:GPIO_PuPd_DOWN ):GPIO_PuPd_NOPULL;
#ifdef STM32F30X
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
#elif defined( STM32F40_41xxx )
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
#endif
GPIO_Init(GPIOOf(gpio), &GPIO_InitStructure);
}

View File

@ -0,0 +1,65 @@
#ifndef _SYSTEMS_H
#define _SYSTEMS_H
void send_openocd_command(int command, void *message);
void send_text( const char * text );
void _delay_us(uint32_t us);
typedef uint8_t gpio;
gpio GetGPIOFromString( const char * str );
#define DEFAULT_VALUE_FLAG 0x00000001
#define DEFAULT_ON 0x00000001
#define DEFAULT_OFF 0x00000000
#define INOUT_FLAG 0x00000002
#define INOUT_OUT 0x00000002
#define INOUT_IN 0x00000000
#define PUPD_FLAG 0x0000000C
#define PUPD_NONE 0x00000000
#define PUPD_UP 0x00000004
#define PUPD_DOWN 0x00000008
void ConfigureGPIO( gpio gpio, int parameters );
#ifdef STM32F30X
#define GPIOOf(x) ((GPIO_TypeDef *) ((((x)>>4)<=6)?(AHB2PERIPH_BASE+0x400*((x)>>4)):0x60000000) )
#elif defined( STM32F40_41xxx )
#define GPIOOf(x) ((GPIO_TypeDef *) ((((x)>>4)<=6)?(AHB1PERIPH_BASE+0x400*((x)>>4)):0x60000000) )
#endif
#define GPIOPin(x) ((1<<((x)&0x0f)))
#define GPIOLatch(x) GPIOOf(x)->ODR
#ifdef STM32F30X
#define GPIOOn(x) GPIOOf(x)->BSRR = (1<<((x)&0x0f));
#define GPIOOff(x) GPIOOf(x)->BRR = (1<<((x)&0x0f));
#elif defined( STM32F40_41xxx )
#define GPIOOn(x) GPIOOf(x)->BSRRH = (1<<((x)&0x0f));
#define GPIOOff(x) GPIOOf(x)->BSRRL = (1<<((x)&0x0f));
#endif
#ifdef STM32F30X
#define LEDPIN 0x18
#elif defined( STM32F40_41xxx )
#define LEDPIN (16+14)
#endif
void ConfigureUART();
void ConfigureLED();
#define LED_TOGGLE {GPIOOf(LEDPIN)->ODR^=(1<<((LEDPIN)&0x0f));}
#define LED_ON GPIOOn(LEDPIN)
#define LED_OFF GPIOOff(LEDPIN)
#endif

195
firmware/main.c 100644
View File

@ -0,0 +1,195 @@
//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 <stdint.h>
#include <stdio.h>
#include <systems.h>
#include <math.h>
#include <stm32f4xx_exti.h>
#include <DFT32.h>
#include <embeddednf.h>
#include <embeddedout.h>
#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;
// 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();
InitColorChord();
Configure_PA0();
//InitMP45DT02();
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]/2 ); //Can't put in full volume.
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--;
}
}

334
firmware/spi2812.c 100644
View File

@ -0,0 +1,334 @@
//Parts stolen from:
// https://javakys.wordpress.com/2014/09/04/how-to-implement-full-duplex-spi-communication-using-spi-dma-mode-on-stm32f2xx-or-stm32f4xx/
//Timing from:
// https://cpldcpu.wordpress.com/2014/01/14/light_ws2812-library-v2-0-part-i-understanding-the-ws2812/
//Also...
// https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Discovery/Flat.aspx?RootFolder=https%3a%2f%2fmy.st.com%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fSTM32Discovery%2fSTM32F3%20SPI%20slave%20receive%20with%20DMA&FolderCTID=0x01200200770978C69A1141439FE559EB459D75800084C20D8867EAD444A5987D47BE638E0F&currentviews=1336
// For the '407... https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https%3a%2f%2fmy.st.com%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fcortex_mx_stm32%2fSPI1%20in%20DMA2%20on%20STM32F4&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=2447
// Also for the '407... http://www.micromouseonline.com/2012/03/11/adding-dma-to-the-spi-driver-with-the-stm32f4/
#include <string.h>
#include <stdint.h>
#include "spi2812.h"
//Number of 0 segments to transmit ahead of time to reset string.
#define ZERO_BUFFER 6
uint8_t MyBuffer[SPI2812_BUFFSIZE+ZERO_BUFFER];
#ifdef STM32F30X
#include <stm32f30x_rcc.h>
#include <stm32f30x_gpio.h>
#include <stm32f30x_spi.h>
#include <stm32f30x_dma.h>
#include <stm32f30x_misc.h>
//Currently, the 30X version does not have configurable ports.
#define SPI_PORT SPI2
#define SPI_PORT_CLOCK RCC_APB1Periph_SPI2
#define SPI_PORT_CLOCK_INIT RCC_APB1PeriphClockCmd
#define SPI_MOSI_PIN GPIO_Pin_15
#define SPI_MOSI_GPIO_PORT GPIOB
#define SPI_MOSI_GPIO_CLK RCC_AHBPeriph_GPIOB
#define SPI_MOSI_SOURCE GPIO_PinSource15
#define SPI_MOSI_AF GPIO_AF_5
#define SPI_PORT_DR_ADDRESS SPI_PORT->DR
#define SPI_PORT_DMA DMA1
#define SPI_PORT_DMAx_CLK RCC_AHBPeriph_DMA1
#define SPI_PORT_TX_DMA_CHANNEL DMA1_Channel5
#define SPI_PORT_DMA_TX_IRQn DMA1_Channel5_IRQn
#define DMA_HANDLER_IRQFN DMA1_Channel5_IRQHandler
#define DMA_FLAG_C DMA1_FLAG_TC5
#define DMA_FLAG_E DMA1_FLAG_TE5
/*
#define SPI_PORT_TX_DMA_STREAM DMA1_Stream4
#define SPI_PORT_TX_DMA_FLAG_FEIF DMA_FLAG_FEIF4
#define SPI_PORT_TX_DMA_FLAG_DMEIF DMA_FLAG_DMEIF4
#define SPI_PORT_TX_DMA_FLAG_TEIF DMA_FLAG_TEIF4
#define SPI_PORT_TX_DMA_FLAG_HTIF DMA_FLAG_HTIF4
#define SPI_PORT_TX_DMA_FLAG_TCIF DMA_FLAG_TCIF4
#define SPI_PORT_DMA_TX_IRQn DMA1_Stream4_IRQn
#define SPI_PORT_DMA_TX_IRQHandler DMA1_Stream4_IRQHandler
*/
#elif defined( STM32F40_41xxx )
#include <stm32f4xx_rcc.h>
#include <stm32f4xx_gpio.h>
#include <stm32f4xx_spi.h>
#include <stm32f4xx_dma.h>
#include <misc.h>
#define SPI_PORT SPI1
#define SPI_PORT_CLOCK RCC_APB2Periph_SPI1
#define SPI_PORT_CLOCK_INIT RCC_APB2PeriphClockCmd
#define SPI_MOSI_PIN GPIO_Pin_7
#define SPI_MOSI_GPIO_PORT GPIOA
#define SPI_MOSI_GPIO_CLK RCC_AHB1Periph_GPIOA
#define SPI_MOSI_SOURCE GPIO_PinSource7
#define SPI_MOSI_AF GPIO_AF_SPI1
#define SPI_PORT_DR_ADDRESS SPI_PORT->DR
#define SPI_PORT_DMA DMA2
#define SPI_PORT_DMAx_CLK RCC_AHB1Periph_DMA2
#define SPI_PORT_TX_DMA_CHANNEL DMA_Channel_3
#define SPI_PORT_TX_DMA_STREAM DMA2_Stream3
#define SPI_PORT_TX_DMA_FLAG_FEIF DMA_FLAG_FEIF3
#define SPI_PORT_TX_DMA_FLAG_DMEIF DMA_FLAG_DMEIF3
#define SPI_PORT_TX_DMA_FLAG_TEIF DMA_FLAG_TEIF3
#define SPI_PORT_TX_DMA_FLAG_HTIF DMA_FLAG_HTIF3
#define SPI_PORT_TX_DMA_FLAG_TCIF DMA_FLAG_TCIF3
#define SPI_PORT_DMA_TX_IRQn DMA2_Stream3_IRQn
#define SPI_PORT_DMA_TX_IRQHandler DMA2_Stream3_IRQHandler
#define DMA_FLAGE DMA_IT_TCIF3
#endif
#ifdef STM32F30X
void DMA_HANDLER_IRQFN()
{
if ( DMA_GetFlagStatus(DMA_FLAG_C) == SET )
{
DMA_ClearITPendingBit(DMA_FLAG_C);
}
/* Transfer Error */
if(DMA_GetITStatus(DMA_FLAG_E) == SET)
{
if (DMA_GetFlagStatus(DMA_FLAG_E) != RESET)
{
DMA_ClearITPendingBit(DMA_FLAG_E);
}
}
}
#elif defined( STM32F40_41xxx )
void SPI_PORT_DMA_TX_IRQHandler(){
// Test if DMA Stream Transfer Complete interrupt
if (DMA_GetITStatus(SPI_PORT_TX_DMA_STREAM, DMA_FLAGE)) {
DMA_ClearITPendingBit(SPI_PORT_TX_DMA_STREAM, DMA_FLAGE);
}
}
#endif
void InitSPI2812()
{
SPI_InitTypeDef SPI_InitStructure;
DMA_InitTypeDef dma_init_struct;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef nvic_init_struct;
printf("Init SPI2812: sizeof(MyBuffer)=%d\r\n", sizeof(MyBuffer));
#ifdef STM32F30X
//On SPI2, PORT B.15
RCC_AHBPeriphClockCmd(SPI_MOSI_GPIO_CLK, ENABLE);
RCC_AHBPeriphClockCmd(SPI_PORT_DMAx_CLK, ENABLE);
SPI_PORT_CLOCK_INIT(SPI_PORT_CLOCK, ENABLE);
SPI_I2S_DeInit(SPI_PORT);
/* Configure the GPIO_LED pin */
GPIO_InitStructure.GPIO_Pin = SPI_MOSI_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(SPI_MOSI_GPIO_PORT, SPI_MOSI_SOURCE, SPI_MOSI_AF); //MOSI //GPIO_AF_5??? GPIO_AF_6??? TODO
/* SPI Config */
SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7; //TODO: Remove this???
SPI_CalculateCRC(SPI_PORT, DISABLE);
SPI_Init(SPI_PORT, &SPI_InitStructure);
RCC_I2SCLKConfig( RCC_I2S2CLKSource_SYSCLK);
SPI_Cmd(SPI_PORT, ENABLE);
//We're on DMA1, channel 5.
memset( MyBuffer, 0xAA, 128 );
DMA_DeInit(SPI_PORT_TX_DMA_CHANNEL);
DMA_StructInit(&dma_init_struct);
dma_init_struct.DMA_PeripheralBaseAddr = (uint32_t) &SPI_PORT->DR;
dma_init_struct.DMA_MemoryBaseAddr = (uint32_t)MyBuffer; //REmove this? somehow?
dma_init_struct.DMA_DIR = DMA_DIR_PeripheralDST;
dma_init_struct.DMA_BufferSize = 128;
dma_init_struct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma_init_struct.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma_init_struct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
dma_init_struct.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
dma_init_struct.DMA_Mode = DMA_Mode_Normal;
dma_init_struct.DMA_Priority = DMA_Priority_VeryHigh;
dma_init_struct.DMA_M2M = DMA_M2M_Disable;
DMA_Init(SPI_PORT_TX_DMA_CHANNEL, &dma_init_struct);
/* Configure the Priority Group */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/* Initialize NVIC Struct for DMA */
nvic_init_struct.NVIC_IRQChannel = SPI_PORT_DMA_TX_IRQn;
nvic_init_struct.NVIC_IRQChannelPreemptionPriority = 1;
nvic_init_struct.NVIC_IRQChannelSubPriority = 0;
nvic_init_struct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic_init_struct);
SPI_I2S_DMACmd(SPI_PORT, SPI_I2S_DMAReq_Tx, ENABLE);
#elif defined( STM32F40_41xxx )
// enable the SPI peripheral clock
SPI_PORT_CLOCK_INIT(SPI_PORT_CLOCK, ENABLE);
// enable the peripheral GPIO port clocks
RCC_AHB1PeriphClockCmd(SPI_MOSI_GPIO_CLK, ENABLE);
// Connect SPI pins to AF5 - see section 3, Table 6 in the device datasheet
GPIO_PinAFConfig(SPI_MOSI_GPIO_PORT, SPI_MOSI_SOURCE, SPI_MOSI_AF);
// now configure the pins themselves
// they are all going to be fast push-pull outputs
// but the SPI pins use the alternate function
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Pin = SPI_MOSI_PIN;
GPIO_Init(SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
// now we can set up the SPI peripheral
// Assume the target is write only and we look after the chip select ourselves
// SPI clock rate will be system frequency/4/prescaler
// so here we will go for 72/4/8 = 2.25MHz
SPI_I2S_DeInit(SPI_PORT);
SPI_StructInit(&SPI_InitStructure);
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; //On F104, assume 100MHz.
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI_PORT, &SPI_InitStructure);
// Enable the SPI port
SPI_Cmd(SPI_PORT, ENABLE);
// first enable the clock
RCC_AHB1PeriphClockCmd(SPI_PORT_DMAx_CLK, ENABLE);
// start with a blank DMA configuration just to be sure
DMA_DeInit(SPI_PORT_TX_DMA_STREAM);
while (DMA_GetCmdStatus (SPI_PORT_TX_DMA_STREAM) != DISABLE);
// Configure DMA controller to manage TX DMA requests
// first make sure we are using the default values
DMA_StructInit(&dma_init_struct);
// these are the only parameters that change from the defaults
dma_init_struct.DMA_PeripheralBaseAddr = (uint32_t) & (SPI_PORT->DR);
dma_init_struct.DMA_Channel = SPI_PORT_TX_DMA_CHANNEL;
dma_init_struct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
dma_init_struct.DMA_MemoryInc = DMA_MemoryInc_Enable;
/*
* It is not possible to call DMA_Init without values for the source
* address and non-zero size even though a transfer is not done here.
* These are checked only when the assert macro are active though.
*/
dma_init_struct.DMA_Memory0BaseAddr = (uint32_t)MyBuffer;
dma_init_struct.DMA_BufferSize = 1;
DMA_Init(SPI_PORT_TX_DMA_STREAM, &dma_init_struct);
// Enable the DMA transfer complete interrupt
DMA_ITConfig(SPI_PORT_TX_DMA_STREAM, DMA_IT_TC, ENABLE);
DMA_ITConfig (SPI_PORT_TX_DMA_STREAM, DMA_IT_TC, ENABLE);
// enable the interrupt in the NVIC
nvic_init_struct.NVIC_IRQChannel = SPI_PORT_DMA_TX_IRQn;
nvic_init_struct.NVIC_IRQChannelPreemptionPriority = 0;
nvic_init_struct.NVIC_IRQChannelSubPriority = 1;
nvic_init_struct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init (&nvic_init_struct);
// Enable dma tx request.
SPI_I2S_DMACmd (SPI_PORT, SPI_I2S_DMAReq_Tx, ENABLE);
#endif
//These would fire it off...
// DMA_Cmd(DMA1_Channel5, ENABLE);
// DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);
// DMA_ITConfig(DMA1_Channel5, DMA_IT_TE, ENABLE);
}
void SendSPI2812( unsigned char * lightarray, int length )
{
static const uint8_t aoarray[4] = { 0b10001000, 0b10001110, 0b11101000, 0b11101110 };
int i;
if( length > SPI2812_MAX_LEDS ) length = SPI2812_MAX_LEDS;
MyBuffer[0] = 0;
for( i = 0; i < length; i++ )
{
uint8_t * colorbase = &lightarray[i*3];
uint8_t * buffbase = &MyBuffer[i*24/2+ZERO_BUFFER];
int j;
for( j = 0; j < 3; j++ )
{
uint8_t c = colorbase[j];// (j==0)?1:(j==1)?0:2 ]; //Flip R and G.
*(buffbase++) = aoarray[(c>>6)&3];
*(buffbase++) = aoarray[(c>>4)&3];
*(buffbase++) = aoarray[(c>>2)&3];
*(buffbase++) = aoarray[(c>>0)&3];
}
}
for( i = 0; i < ZERO_BUFFER; i++ )
MyBuffer[i] = 0;
length *= 24/2;
length += ZERO_BUFFER;
#ifdef STM32F30X
DMA_Cmd(SPI_PORT_TX_DMA_CHANNEL, DISABLE);
SPI_PORT_TX_DMA_CHANNEL->CMAR = (uint32_t) MyBuffer;
SPI_PORT_TX_DMA_CHANNEL->CNDTR = (uint16_t) length;
DMA_Cmd(SPI_PORT_TX_DMA_CHANNEL, ENABLE);
DMA_ITConfig(SPI_PORT_TX_DMA_CHANNEL, DMA_IT_TC, ENABLE);
DMA_ITConfig(SPI_PORT_TX_DMA_CHANNEL, DMA_IT_TE, ENABLE);
#elif defined( STM32F40_41xxx )
SPI_PORT_TX_DMA_STREAM->NDTR = (uint32_t) length;
SPI_PORT_TX_DMA_STREAM->M0AR = (uint32_t) MyBuffer+2;
DMA_Cmd (SPI_PORT_TX_DMA_STREAM, ENABLE);
#endif
}

15
firmware/spi2812.h 100644
View File

@ -0,0 +1,15 @@
#ifndef _SPI_2812_H
#define _SPI_2812_H
#define SPI2812_MAX_LEDS 300
//24 bits per LED, can fit two bits per byte of output.
#define SPI2812_BUFFSIZE (SPI2812_MAX_LEDS*24/2)
void InitSPI2812();
void SendSPI2812( unsigned char * lightarray, int leds ); //Need one R, G, B per element.
#endif

View File

@ -0,0 +1,177 @@
/**
******************************************************************************
* @file ADC/ADC_DMA/stm32f4xx_it.c
* @author MCD Application Team
* @version V1.5.0
* @date 06-March-2015
* @brief Main Interrupt Service Routines.
* This file provides template for all exceptions handler and
* peripherals interrupt service routine.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_it.h"
/** @addtogroup STM32F4xx_StdPeriph_Examples
* @{
*/
/** @addtogroup ADC_DMA
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/******************************************************************************/
/* Cortex-M4 Processor Exceptions Handlers */
/******************************************************************************/
/**
* @brief This function handles NMI exception.
* @param None
* @retval None
*/
void NMI_Handler(void)
{
send_text( "NMI Fault.\n" );
}
/**
* @brief This function handles Hard Fault exception.
* @param None
* @retval None
*/
void HardFault_Handler(void)
{
send_text( "Hard Fault.\n" );
/* Go to infinite loop when Hard Fault exception occurs */
while (1)
{
}
}
/**
* @brief This function handles Memory Manage exception.
* @param None
* @retval None
*/
void MemManage_Handler(void)
{
send_text( "MemRange Fault.\n" );
/* Go to infinite loop when Memory Manage exception occurs */
while (1)
{
}
}
/**
* @brief This function handles Bus Fault exception.
* @param None
* @retval None
*/
void BusFault_Handler(void)
{
send_text( "Bus Fault.\n" );
/* Go to infinite loop when Bus Fault exception occurs */
while (1)
{
}
}
/**
* @brief This function handles Usage Fault exception.
* @param None
* @retval None
*/
void UsageFault_Handler(void)
{
send_text( "Usage Fault.\n" );
/* Go to infinite loop when Usage Fault exception occurs */
while (1)
{
}
}
/**
* @brief This function handles SVCall exception.
* @param None
* @retval None
*/
void SVC_Handler(void)
{
send_text( "SVC Fault.\n" );
}
/**
* @brief This function handles Debug Monitor exception.
* @param None
* @retval None
*/
void DebugMon_Handler(void)
{
}
/**
* @brief This function handles PendSVC exception.
* @param None
* @retval None
*/
void PendSV_Handler(void)
{
}
/**
* @brief This function handles SysTick Handler.
* @param None
* @retval None
*/
void SysTick_Handler(void)
{
TimingDelay_Decrement();
}
/******************************************************************************/
/* STM32F4xx Peripherals Interrupt Handlers */
/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
/* available peripheral interrupt handler's name please refer to the startup */
/* file (startup_stm32f40xx.s/startup_stm32f427x.s/startup_stm32f429x.s). */
/******************************************************************************/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -0,0 +1,58 @@
/**
******************************************************************************
* @file ADC/ADC_DMA/stm32f4xx_it.h
* @author MCD Application Team
* @version V1.5.0
* @date 06-March-2015
* @brief This file contains the headers of the interrupt handlers.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F4xx_IT_H
#define __STM32F4xx_IT_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void NMI_Handler(void);
void HardFault_Handler(void);
void MemManage_Handler(void);
void BusFault_Handler(void);
void UsageFault_Handler(void);
void SVC_Handler(void);
void DebugMon_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);
#ifdef __cplusplus
}
#endif
#endif /* __STM32F4xx_IT_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/