From a078de7c9fc58a798b5417514de0de38c0ac4707 Mon Sep 17 00:00:00 2001 From: "S.J.R. van Schaik" Date: Sat, 11 Mar 2017 00:55:54 +0000 Subject: [PATCH] spi: stm32f0: add SPI driver --- include/spi.h | 19 +++++++++ scripts/Makefile.stm32f0 | 3 ++ source/core/spi.c | 21 ++++++++++ source/drivers/stm32f0_spi.c | 94 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 include/spi.h create mode 100644 source/core/spi.c create mode 100644 source/drivers/stm32f0_spi.c diff --git a/include/spi.h b/include/spi.h new file mode 100644 index 0000000..490c145 --- /dev/null +++ b/include/spi.h @@ -0,0 +1,19 @@ +#pragma once + +struct spi_dev; + +struct spi_ops { + int (* set_cs_level)(struct spi_dev *dev, int level); + int (* tx_rx)(struct spi_dev *dev, void *rx_buf, const void *tx_buf, + size_t len); +}; + +struct spi_dev { + struct spi_ops *ops; + uint32_t dev_id; +}; + +struct spi_dev *spi_probe(void); +int spi_set_cs_level(struct spi_dev *dev, int level); +int spi_tx_rx(struct spi_dev *dev, void *rx_buf, const void *tx_buf, + size_t len); diff --git a/scripts/Makefile.stm32f0 b/scripts/Makefile.stm32f0 index dc904b7..afa5ada 100644 --- a/scripts/Makefile.stm32f0 +++ b/scripts/Makefile.stm32f0 @@ -16,6 +16,9 @@ LIBS += -l$(OPENCM3_LIBNAME) STLINK_PORT ?= :4242 +obj-y += source/core/spi.o +obj-y += source/drivers/stm32f0_spi.o + $(OPENCM3_DIR)/lib/lib$(OPENCM3_LIBNAME).a: @if [ ! -e libopencm3/.git ]; then \ git submodule init; \ diff --git a/source/core/spi.c b/source/core/spi.c new file mode 100644 index 0000000..b9e5816 --- /dev/null +++ b/source/core/spi.c @@ -0,0 +1,21 @@ +#include +#include + +#include + +int spi_set_cs_level(struct spi_dev *dev, int level) +{ + if (!dev) + return -1; + + return dev->ops->set_cs_level(dev, level); +} + +int spi_tx_rx(struct spi_dev *dev, void *rx_buf, const void *tx_buf, + size_t len) +{ + if (!dev) + return -1; + + return dev->ops->tx_rx(dev, rx_buf, tx_buf, len); +} diff --git a/source/drivers/stm32f0_spi.c b/source/drivers/stm32f0_spi.c new file mode 100644 index 0000000..3aafa7e --- /dev/null +++ b/source/drivers/stm32f0_spi.c @@ -0,0 +1,94 @@ +#define _GNU_SOURCE +#include +#include + +#include +#include +#include +#include + +#include + +static int stm32f0_spi_set_cs_level(struct spi_dev *dev, int level); +static int stm32f0_spi_tx_rx(struct spi_dev *dev, void *rx_buf, + const void *tx_buf, size_t len); + +static struct spi_ops stm32f0_spi_ops = { + .set_cs_level = stm32f0_spi_set_cs_level, + .tx_rx = stm32f0_spi_tx_rx, +}; + +static void stm32f0_spi_init(void) +{ + /* Set up clocks for SPI 1 */ + rcc_clock_setup_in_hsi_out_48mhz(); + rcc_periph_clock_enable(RCC_GPIOA); + rcc_periph_clock_enable(RCC_GPIOB); + rcc_periph_clock_enable(RCC_SPI1); + + /* Set up GPIOs for SPI 1 */ + gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO4); + gpio_set(GPIOA, GPIO4); + gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO3 | GPIO4 | GPIO5); + gpio_set_af(GPIOB, GPIO_AF0, GPIO3 | GPIO4 | GPIO5); + + spi_set_master_mode(SPI1); + spi_set_baudrate_prescaler(SPI1, SPI_CR1_BR_FPCLK_DIV_64); + spi_set_clock_polarity_0(SPI1); + spi_set_clock_phase_0(SPI1); + spi_set_full_duplex_mode(SPI1); + spi_set_unidirectional_mode(SPI1); /* bidirectional but in 3-wire */ + spi_set_data_size(SPI1, SPI_CR2_DS_8BIT); + spi_enable_software_slave_management(SPI1); + spi_send_msb_first(SPI1); + spi_set_nss_high(SPI1); + spi_fifo_reception_threshold_8bit(SPI1); + SPI_I2SCFGR(SPI1) &= ~SPI_I2SCFGR_I2SMOD; + spi_enable(SPI1); +} + +struct spi_dev *spi_probe(void) +{ + struct spi_dev *dev; + + if (!(dev = malloc(sizeof *dev))) + return NULL; + + dev->ops = &stm32f0_spi_ops; + dev->dev_id = SPI1; + + stm32f0_spi_init(); + + return dev; +} + +static int stm32f0_spi_set_cs_level(struct spi_dev *dev, int level) +{ + (void)dev; + + if (level) { + gpio_set(GPIOA, GPIO4); + } else { + gpio_clear(GPIOA, GPIO4); + } + + return 0; +} + +static int stm32f0_spi_tx_rx(struct spi_dev *dev, void *rx_buf, + const void *tx_buf, size_t len) +{ + char *rx = rx_buf; + const char *tx = tx_buf; + size_t i; + + for (i = 0; i < len; ++i) { + spi_send8(dev->dev_id, tx ? *tx++ : 0); + + if (rx) { + *rx++ = spi_read8(dev->dev_id); + } + } + + return 0; +}