uint8_tled_ws2812b_data[LED_WS2812B_LEDS*3*3+40*3/8+1]={0};/**< data encoded to be shifted out by SPI for the WS2812B, plus the 50us reset (~40 data bits) */
staticvolatilebooltransmit_flag=false;/**< flag set in software when transmission started, clear by interrupt when transmission completed */
dma_set_number_of_data(DMA_SPI(LED_WS2812B_SPI),DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI),LENGTH(led_ws2812b_data));// set the size of the data to transmit
dma_enable_transfer_complete_interrupt(DMA_SPI(LED_WS2812B_SPI),DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI));// warm when transfer is complete to stop transmission
rcc_periph_clock_enable(RCC_TIM_CH(LED_WS2812B_TIMER,LED_WS2812B_CLK_CH));// enable clock for GPIO peripheral
gpio_set_mode(TIM_CH_PORT(LED_WS2812B_TIMER,LED_WS2812B_CLK_CH),GPIO_MODE_OUTPUT_10_MHZ,GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,TIM_CH_PIN(LED_WS2812B_TIMER,LED_WS2812B_CLK_CH));// set pin as output
rcc_periph_clock_enable(RCC_TIM(LED_WS2812B_TIMER));// enable clock for timer peripheral
timer_reset(TIM(LED_WS2812B_TIMER));// reset timer state
timer_set_mode(TIM(LED_WS2812B_TIMER),TIM_CR1_CKD_CK_INT,TIM_CR1_CMS_EDGE,TIM_CR1_DIR_UP);// set timer mode, use undivided timer clock, edge alignment (simple count), and count up
timer_set_prescaler(TIM(LED_WS2812B_TIMER),0);// no prescaler to keep most precise timer (72MHz/2^16=1099<800kHz)
timer_set_period(TIM(LED_WS2812B_TIMER),rcc_ahb_frequency/800000/3-1);// set the clock frequency to 800kHz*3bit since we need to send 3 bits to output a 800kbps stream
timer_set_oc_value(TIM(LED_WS2812B_TIMER),LED_WS2812B_TIMER_OC,rcc_ahb_frequency/800000/3/2);// duty cycle to 50%
timer_set_oc_mode(TIM(LED_WS2812B_TIMER),LED_WS2812B_TIMER_OC,TIM_OCM_PWM1);// set timer to generate PWM (used as clock)
timer_enable_oc_output(TIM(LED_WS2812B_TIMER),LED_WS2812B_TIMER_OC);// enable output to generate the clock
rcc_periph_clock_enable(RCC_SPI_SCK_PORT(LED_WS2812B_SPI));// enable clock for SPI IO peripheral
gpio_set_mode(SPI_SCK_PORT(LED_WS2812B_SPI),GPIO_MODE_INPUT,GPIO_CNF_INPUT_FLOAT,SPI_SCK_PIN(LED_WS2812B_SPI));// set clock as input
rcc_periph_clock_enable(RCC_SPI_MISO_PORT(LED_WS2812B_SPI));// enable clock for SPI IO peripheral
gpio_set_mode(SPI_MISO_PORT(LED_WS2812B_SPI),GPIO_MODE_OUTPUT_10_MHZ,GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,SPI_MISO_PIN(LED_WS2812B_SPI));// set MISO as output
rcc_periph_clock_enable(RCC_DMA_SPI(LED_WS2812B_SPI));// enable clock for DMA peripheral
dma_channel_reset(DMA_SPI(LED_WS2812B_SPI),DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI));// start with fresh channel configuration
dma_set_memory_address(DMA_SPI(LED_WS2812B_SPI),DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI),(uint32_t)led_ws2812b_data);// set bit pattern as source address
dma_set_peripheral_address(DMA_SPI(LED_WS2812B_SPI),DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI),(uint32_t)&SPI_DR(SPI(LED_WS2812B_SPI)));// set SPI as peripheral destination address
dma_set_read_from_memory(DMA_SPI(LED_WS2812B_SPI),DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI));// set direction from memory to peripheral
dma_enable_memory_increment_mode(DMA_SPI(LED_WS2812B_SPI),DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI));// go through bit pattern
dma_set_memory_size(DMA_SPI(LED_WS2812B_SPI),DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI),DMA_CCR_MSIZE_8BIT);// read 8 bits from memory
dma_set_peripheral_size(DMA_SPI(LED_WS2812B_SPI),DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI),DMA_CCR_PSIZE_8BIT);// write 8 bits to peripheral
dma_set_priority(DMA_SPI(LED_WS2812B_SPI),DMA_CHANNEL_SPI_TX(LED_WS2812B_SPI),DMA_CCR_PL_HIGH);// set priority to high since time is crucial for the peripheral
nvic_enable_irq(DMA_IRQ_SPI_TX(LED_WS2812B_SPI));// enable interrupts for this DMA channel