Created
May 2, 2018 18:50
-
-
Save NikiSchlifke/5deea20d921163f08d5624266ecdeb52 to your computer and use it in GitHub Desktop.
Trying to use SPI to control ws2811 led driver chips
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "stdint.h" | |
#include <libopencm3/stm32/rcc.h> | |
#include <libopencm3/stm32/f1/rcc.h> | |
#include <libopencm3/stm32/f1/gpio.h> | |
#include <libopencm3/stm32/f1/timer.h> | |
#include <libopencm3/stm32/f1/nvic.h> | |
#include <libopencm3/cm3/systick.h> | |
#include <libopencm3/stm32/f1/dma.h> | |
#include <libopencm3/stm32/f1/spi.h> | |
#include <ws2811.h> | |
static void clock_setup(void) | |
{ | |
rcc_clock_setup_in_hse_8mhz_out_72mhz(); | |
/* Enable GPIOA, GPIOB, clock. */ | |
rcc_periph_clock_enable(RCC_GPIOB); | |
/* Enable clocks for GPIO port A (for GPIO_USART2_TX) and USART2. */ | |
rcc_periph_clock_enable(RCC_AFIO); | |
/* Enable SPI2 Periph and gpio clocks */ | |
rcc_periph_clock_enable(RCC_SPI2); | |
/* Enable DMA1 clock */ | |
rcc_periph_clock_enable(RCC_DMA1); | |
} | |
static void spi_setup(void) { | |
/* Configure GPIOs: SS=PA4, SCK=PA5, MISO=PA6 and MOSI=PA7 */ | |
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO15 ); | |
/* Reset SPI, SPI_CR1 register cleared, SPI is disabled */ | |
spi_reset(SPI2); | |
/* Explicitly disable I2S in favour of SPI operation */ | |
SPI2_I2SCFGR = 0; | |
/* Set up SPI in Master mode with: | |
* Clock baud rate: 1/32 of peripheral clock frequency | |
* Clock polarity: Idle High | |
* Clock phase: Data valid on 2nd clock pulse | |
* Data frame format: 8-bit | |
* Frame format: MSB First | |
*/ | |
spi_init_master(SPI2, SPI_CR1_BAUDRATE_FPCLK_DIV_16, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, | |
SPI_CR1_CPHA_CLK_TRANSITION_2, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); | |
/* | |
* Set NSS management to software. | |
* | |
* Note: | |
* Setting nss high is very important, even if we are controlling the GPIO | |
* ourselves this bit needs to be at least set to 1, otherwise the spi | |
* peripheral will not send any data out. | |
*/ | |
spi_enable_software_slave_management(SPI2); | |
spi_set_nss_high(SPI2); | |
/* Enable SPI2 periph. */ | |
spi_enable(SPI2); | |
} | |
/** | |
* DMA part here see: | |
* https://github.com/libopencm3/libopencm3-examples/blob/master/examples/stm32/f1/lisa-m-2/spi_dma/spi_dma.c | |
* | |
Peripherals|Channel 1|Channel 2|Channel 3 |Channel 4 |Channel 5 |Channel 6 |Channel 7 | | |
ADC1 |ADC1 | | | | | | | | |
2 SPI/I S | |SPI1_RX |SPI1_TX |SPI/I2S2_RX |SPI/I2S2_TX| | | | |
USART | |USART3_TX|USART3_RX |USART1_TX |USART1_RX |USART2_RX |USART2_TX | | |
2 I C | | | |I2C2_TX |I2C2_RX |I2C1_TX |I2C1_RX | | |
TIM1 | |TIM1_CH1 |TIM1_CH2 |TIM1_CH4 TIM1_TRIG TIM1_COM|TIM1_UP |TIM1_CH3 | | | |
TIM2 |TIM2_CH3 |TIM2_UP | | |TIM2_CH1 | |TIM2_CH2 TIM2_CH4| | |
TIM3 | |TIM3_CH3 |TIM3_CH4 TIM3_UP| | |TIM3_CH1 TIM3_TRIG| | | |
TIM4 |TIM4_CH1 | | |TIM4_CH2 |TIM4_CH3 | |TIM4_UP | | |
*/ | |
/* This is for the counter state flag */ | |
typedef enum { | |
TX_UP_RX_HOLD = 0, | |
TX_HOLD_RX_UP, | |
TX_DOWN_RX_DOWN | |
} cnt_state; | |
/* This is a global spi state flag */ | |
volatile typedef enum { | |
NONE = 0, | |
ONE, | |
DONE | |
} trans_status; | |
volatile trans_status transceive_status; | |
static void dma_int_enable(void) { | |
/* SPI2 TX on DMA1 Channel 3 */ | |
nvic_set_priority(NVIC_DMA1_CHANNEL5_IRQ, 0); | |
nvic_enable_irq(NVIC_DMA1_CHANNEL5_IRQ); | |
} | |
static void dma_setup(void) | |
{ | |
dma_int_enable(); | |
} | |
static int spi_dma_transmit(uint8_t *tx_buf, uint16_t tx_len) | |
{ | |
/* Check for 0 length in both tx and rx */ | |
if (tx_len < 1) { | |
/* return -1 as error */ | |
return -1; | |
} | |
/* Reset DMA channels*/ | |
dma_channel_reset(DMA1, DMA_CHANNEL5); | |
/* Reset SPI data and status registers. | |
* Here we assume that the SPI peripheral is NOT | |
* busy any longer, i.e. the last activity was verified | |
* complete elsewhere in the program. | |
*/ | |
volatile uint8_t temp_data __attribute__ ((unused)); | |
while (SPI_SR(SPI2) & (SPI_SR_RXNE | SPI_SR_OVR)) { | |
temp_data = SPI_DR(SPI2); | |
} | |
/* Reset status flag appropriately (both 0 case caught above) */ | |
transceive_status = NONE; | |
if (tx_len < 1) { | |
transceive_status = ONE; | |
} | |
/* Set up tx dma */ | |
if (tx_len > 0) { | |
dma_set_peripheral_address(DMA1, DMA_CHANNEL5, (uint32_t)&SPI2_DR); | |
dma_set_memory_address(DMA1, DMA_CHANNEL5, (uint32_t)tx_buf); | |
dma_set_number_of_data(DMA1, DMA_CHANNEL5, tx_len); | |
dma_set_read_from_memory(DMA1, DMA_CHANNEL5); | |
dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL5); | |
dma_set_peripheral_size(DMA1, DMA_CHANNEL5, DMA_CCR_PSIZE_8BIT); | |
dma_set_memory_size(DMA1, DMA_CHANNEL5, DMA_CCR_MSIZE_8BIT); | |
dma_set_priority(DMA1, DMA_CHANNEL5, DMA_CCR_PL_HIGH); | |
//dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL5); | |
dma_enable_channel(DMA1, DMA_CHANNEL5); | |
/* Enable the spi transfer via dma | |
* This will immediately start the transmission, | |
*/ | |
spi_enable_tx_dma(SPI2); | |
} | |
return 0; | |
} | |
/** | |
* SPI transmit completed with DMA | |
* */ | |
void dma1_channel5_isr(void) | |
{ | |
if ((DMA1_ISR &DMA_ISR_TCIF5) != 0) { | |
DMA1_IFCR |= DMA_IFCR_CTCIF5; | |
} | |
dma_disable_transfer_complete_interrupt(DMA1, DMA_CHANNEL5); | |
spi_disable_tx_dma(SPI2); | |
dma_disable_channel(DMA1, DMA_CHANNEL5); | |
/* Increment the status to indicate one of the transfers is complete */ | |
transceive_status++; | |
} | |
/** | |
* Main program | |
* @return | |
*/ | |
int main(void) | |
{ | |
RgbColor white = {255, 255, 255}; | |
RgbColor red = {255, 0, 0}; | |
RgbColor green = {0, 255, 0}; | |
RgbColor blue = {0, 0, 255}; | |
SPIColor spiColor = { 0, 0, 0 }; | |
SPIColor colors[2]; | |
convertRGBColorToSPIColor(&white, &colors[0]); | |
convertRGBColorToSPIColor(&red, &colors[1]); | |
clock_setup(); | |
spi_setup(); | |
dma_setup(); | |
uint8_t testBuffer[] = { 0, 140, 170, 255}; | |
/* Fill Buffer and transmit */ | |
while (1) { | |
fillBuffer((SPIColor **) &colors); | |
//spi_dma_transmit((uint8_t *) &spiBuffer.data , sizeof(spiBuffer.data)); | |
spi_dma_transmit((uint8_t *) &testBuffer, sizeof(testBuffer)); | |
while (transceive_status != DONE) | |
; | |
while (!(SPI_SR(SPI1) & SPI_SR_TXE)) | |
; | |
while (SPI_SR(SPI1) & SPI_SR_BSY) | |
; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment