diff options
author | adelyser <12093019+adelyser@users.noreply.github.com> | 2021-11-20 16:23:23 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-20 18:23:23 -0500 |
commit | 3ac354088aeb2b5f4eb43a2a2c92aa82398fc361 (patch) | |
tree | 1be8e188b2f8166fa5e7b326343f157fa7611348 /src/stm32/stm32h7_spi.c | |
parent | b480734c88a91534faf1f68ef1c10859516d7e81 (diff) | |
download | kutter-3ac354088aeb2b5f4eb43a2a2c92aa82398fc361.tar.gz kutter-3ac354088aeb2b5f4eb43a2a2c92aa82398fc361.tar.xz kutter-3ac354088aeb2b5f4eb43a2a2c92aa82398fc361.zip |
stm32: Add stm32h7 SPI support (#4850)
Signed-off-by: Aaron DeLyser <bluwolf@gmail.com>
Diffstat (limited to 'src/stm32/stm32h7_spi.c')
-rw-r--r-- | src/stm32/stm32h7_spi.c | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/src/stm32/stm32h7_spi.c b/src/stm32/stm32h7_spi.c new file mode 100644 index 00000000..b6ade88f --- /dev/null +++ b/src/stm32/stm32h7_spi.c @@ -0,0 +1,150 @@ +// SPI functions on STM32H7 +// +// Copyright (C) 2019 Kevin O'Connor <kevin@koconnor.net> +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "board/io.h" // readb, writeb +#include "command.h" // shutdown +#include "gpio.h" // spi_setup +#include "internal.h" // gpio_peripheral +#include "sched.h" // sched_shutdown + +struct spi_info { + SPI_TypeDef *spi; + uint8_t miso_pin, mosi_pin, sck_pin, function; +}; + +DECL_ENUMERATION("spi_bus", "spi2", __COUNTER__); +DECL_CONSTANT_STR("BUS_PINS_spi2", "PB14,PB15,PB13"); + +DECL_ENUMERATION("spi_bus", "spi1", __COUNTER__); +DECL_CONSTANT_STR("BUS_PINS_spi1", "PA6,PA7,PA5"); +DECL_ENUMERATION("spi_bus", "spi1a", __COUNTER__); +DECL_CONSTANT_STR("BUS_PINS_spi1a", "PB4,PB5,PB3"); + +#if !CONFIG_MACH_STM32F1 +DECL_ENUMERATION("spi_bus", "spi2a", __COUNTER__); +DECL_CONSTANT_STR("BUS_PINS_spi2a", "PC2,PC3,PB10"); +#endif + +#ifdef SPI3 +DECL_ENUMERATION("spi_bus", "spi3", __COUNTER__); +DECL_CONSTANT_STR("BUS_PINS_spi3", "PB4,PB5,PB3"); + +DECL_ENUMERATION("spi_bus", "spi3a", __COUNTER__); +DECL_CONSTANT_STR("BUS_PINS_spi3a", "PC11,PC12,PC10"); +#endif + +#ifdef SPI4 +DECL_ENUMERATION("spi_bus", "spi4", __COUNTER__); +DECL_CONSTANT_STR("BUS_PINS_spi4", "PE13,PE14,PE12"); +#endif + +#ifdef GPIOI +DECL_ENUMERATION("spi_bus", "spi2b", __COUNTER__); +DECL_CONSTANT_STR("BUS_PINS_spi2b", "PI2,PI3,PI1"); +#endif + +#ifdef SPI5 +DECL_ENUMERATION("spi_bus", "spi5", __COUNTER__); +DECL_CONSTANT_STR("BUS_PINS_spi5", "PF8,PF9,PF7"); +DECL_ENUMERATION("spi_bus", "spi5a", __COUNTER__); +DECL_CONSTANT_STR("BUS_PINS_spi5a", "PH7,PF11,PH6"); +#endif + +#ifdef SPI6 +DECL_ENUMERATION("spi_bus", "spi6", __COUNTER__); +DECL_CONSTANT_STR("BUS_PINS_spi6", "PG12,PG14,PG13"); +#endif + + +static const struct spi_info spi_bus[] = { + { SPI2, GPIO('B', 14), GPIO('B', 15), GPIO('B', 13), GPIO_FUNCTION(5) }, + { SPI1, GPIO('A', 6), GPIO('A', 7), GPIO('A', 5), GPIO_FUNCTION(5) }, + { SPI1, GPIO('B', 4), GPIO('B', 5), GPIO('B', 3), GPIO_FUNCTION(5) }, +#if !CONFIG_MACH_STM32F1 + { SPI2, GPIO('C', 2), GPIO('C', 3), GPIO('B', 10), GPIO_FUNCTION(5) }, +#endif +#ifdef SPI3 + { SPI3, GPIO('B', 4), GPIO('B', 5), GPIO('B', 3), GPIO_FUNCTION(6) }, + { SPI3, GPIO('C', 11), GPIO('C', 12), GPIO('C', 10), GPIO_FUNCTION(6) }, +#endif +#ifdef SPI4 + { SPI4, GPIO('E', 13), GPIO('E', 14), GPIO('E', 12), GPIO_FUNCTION(5) }, +#endif + { SPI2, GPIO('I', 2), GPIO('I', 3), GPIO('I', 1), GPIO_FUNCTION(5) }, +#ifdef SPI5 + { SPI5, GPIO('F', 8), GPIO('F', 9), GPIO('F', 7), GPIO_FUNCTION(5) }, + { SPI5, GPIO('H', 7), GPIO('F', 11), GPIO('H', 6), GPIO_FUNCTION(5) }, +#endif +#ifdef SPI6 + { SPI6, GPIO('G', 12), GPIO('G', 14), GPIO('G', 13), GPIO_FUNCTION(5)}, +#endif +}; + +struct spi_config +spi_setup(uint32_t bus, uint8_t mode, uint32_t rate) +{ + if (bus >= ARRAY_SIZE(spi_bus)) + shutdown("Invalid spi bus"); + + // Enable SPI + SPI_TypeDef *spi = spi_bus[bus].spi; + if (!is_enabled_pclock((uint32_t)spi)) { + enable_pclock((uint32_t)spi); + gpio_peripheral(spi_bus[bus].miso_pin, spi_bus[bus].function, 1); + gpio_peripheral(spi_bus[bus].mosi_pin, spi_bus[bus].function, 0); + gpio_peripheral(spi_bus[bus].sck_pin, spi_bus[bus].function, 0); + } + + // Calculate CR1 register + uint32_t pclk = get_pclock_frequency((uint32_t)spi); + uint32_t div = 0; + while ((pclk >> (div + 1)) > rate && div < 7) + div++; + + uint32_t cr1 = SPI_CR1_SPE; + spi->CFG1 |= (div << SPI_CFG1_MBR_Pos) | (7 << SPI_CFG1_DSIZE_Pos); + CLEAR_BIT(spi->CFG1, SPI_CFG1_CRCSIZE); + spi->CFG2 |= ((mode << SPI_CFG2_CPHA_Pos) | SPI_CFG2_MASTER | SPI_CFG2_SSM + | SPI_CFG2_AFCNTR | SPI_CFG2_SSOE); + spi->CR1 |= SPI_CR1_SSI; + + return (struct spi_config){ .spi = spi, .spi_cr1 = cr1 }; +} + +void +spi_prepare(struct spi_config config) +{ +} + +void +spi_transfer(struct spi_config config, uint8_t receive_data, + uint8_t len, uint8_t *data) +{ + uint8_t rdata = 0; + SPI_TypeDef *spi = config.spi; + + MODIFY_REG(spi->CR2, SPI_CR2_TSIZE, len); + // Enable SPI and start transfer, these MUST be set in this sequence + SET_BIT(spi->CR1, SPI_CR1_SPE); + SET_BIT(spi->CR1, SPI_CR1_CSTART); + + while (len--) { + writeb((void *)&spi->TXDR, *data); + while((spi->SR & (SPI_SR_RXWNE | SPI_SR_RXPLVL)) == 0); + rdata = readb((void *)&spi->RXDR); + + if (receive_data) { + *data = rdata; + } + data++; + } + + while ((spi->SR & SPI_SR_EOT) == 0); + + // Clear flags and disable SPI + SET_BIT(spi->IFCR, 0xFFFFFFFF); + CLEAR_BIT(spi->CR1, SPI_CR1_SPE); +} |