#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; }