spi: stm32f0: add SPI driver

tags/0.1.0
S.J.R. van Schaik 7 years ago
parent c7685c1d02
commit a078de7c9f
  1. 19
      include/spi.h
  2. 3
      scripts/Makefile.stm32f0
  3. 21
      source/core/spi.c
  4. 94
      source/drivers/stm32f0_spi.c

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

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

@ -0,0 +1,21 @@
#include <stdint.h>
#include <stdlib.h>
#include <spi.h>
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);
}

@ -0,0 +1,94 @@
#define _GNU_SOURCE
#include <stdint.h>
#include <stdlib.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/spi.h>
#include <libopencm3/stm32/usart.h>
#include <spi.h>
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;
}
Loading…
Cancel
Save