aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoradelyser <12093019+adelyser@users.noreply.github.com>2021-11-20 16:23:23 -0700
committerGitHub <noreply@github.com>2021-11-20 18:23:23 -0500
commit3ac354088aeb2b5f4eb43a2a2c92aa82398fc361 (patch)
tree1be8e188b2f8166fa5e7b326343f157fa7611348
parentb480734c88a91534faf1f68ef1c10859516d7e81 (diff)
downloadkutter-3ac354088aeb2b5f4eb43a2a2c92aa82398fc361.tar.gz
kutter-3ac354088aeb2b5f4eb43a2a2c92aa82398fc361.tar.xz
kutter-3ac354088aeb2b5f4eb43a2a2c92aa82398fc361.zip
stm32: Add stm32h7 SPI support (#4850)
Signed-off-by: Aaron DeLyser <bluwolf@gmail.com>
-rw-r--r--src/stm32/Makefile4
-rw-r--r--src/stm32/stm32h7.c8
-rw-r--r--src/stm32/stm32h7_spi.c150
3 files changed, 159 insertions, 3 deletions
diff --git a/src/stm32/Makefile b/src/stm32/Makefile
index 778f2327..10538b27 100644
--- a/src/stm32/Makefile
+++ b/src/stm32/Makefile
@@ -43,7 +43,9 @@ src-$(CONFIG_MACH_STM32F4) += stm32/adc.c stm32/i2c.c
src-$(CONFIG_MACH_STM32H7) += ../lib/stm32h7/system_stm32h7xx.c
src-$(CONFIG_MACH_STM32H7) += stm32/stm32h7.c generic/armcm_timer.c
src-$(CONFIG_MACH_STM32H7) += stm32/stm32h7_adc.c
-src-$(CONFIG_HAVE_GPIO_SPI) += stm32/spi.c
+spi-src-y := stm32/spi.c
+spi-src-$(CONFIG_MACH_STM32H7) := stm32/stm32h7_spi.c
+src-$(CONFIG_HAVE_GPIO_SPI) += $(spi-src-y)
usb-src-$(CONFIG_HAVE_STM32_USBFS) := stm32/usbfs.c
usb-src-$(CONFIG_HAVE_STM32_USBOTG) := stm32/usbotg.c
src-$(CONFIG_USBSERIAL) += $(usb-src-y) stm32/chipid.c generic/usb_cdc.c
diff --git a/src/stm32/stm32h7.c b/src/stm32/stm32h7.c
index f58154d7..c6c057d2 100644
--- a/src/stm32/stm32h7.c
+++ b/src/stm32/stm32h7.c
@@ -5,7 +5,7 @@
// This file may be distributed under the terms of the GNU GPLv3 license.
-// USB and I2C is not supported, SPI is untested!
+// I2C is not supported
#include "autoconf.h" // CONFIG_CLOCK_REF_FREQ
#include "board/armcm_boot.h" // VectorTable
@@ -170,7 +170,10 @@ clock_setup(void)
MODIFY_REG(RCC->PLLCFGR, RCC_PLLCFGR_PLL1RGE_Msk, RCC_PLLCFGR_PLL1RGE_2);
// Disable unused PLL1 outputs
MODIFY_REG(RCC->PLLCFGR, RCC_PLLCFGR_DIVR1EN_Msk, 0);
- MODIFY_REG(RCC->PLLCFGR, RCC_PLLCFGR_DIVQ1EN_Msk, 0);
+ // Enable PLL1Q and set to 100MHz for SPI 1,2,3
+ MODIFY_REG(RCC->PLLCFGR, RCC_PLLCFGR_DIVQ1EN, RCC_PLLCFGR_DIVQ1EN);
+ MODIFY_REG(RCC->PLL1DIVR, RCC_PLL1DIVR_Q1,
+ (pll_freq / FREQ_PERIPH - 1) << RCC_PLL1DIVR_Q1_Pos);
// This is necessary, default is not 1!
MODIFY_REG(RCC->PLLCFGR, RCC_PLLCFGR_DIVP1EN_Msk, RCC_PLLCFGR_DIVP1EN);
// Set multiplier DIVN1 and post divider DIVP1
@@ -184,6 +187,7 @@ clock_setup(void)
MODIFY_REG(PWR->D3CR, PWR_D3CR_VOS_Msk, PWR_D3CR_VOS);
while (!(PWR->D3CR & PWR_D3CR_VOSRDY))
;
+
// Enable VOS0 (overdrive)
if (CONFIG_CLOCK_FREQ > 400000000) {
RCC->APB4ENR |= RCC_APB4ENR_SYSCFGEN;
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);
+}