diff --git a/src/stm32/Kconfig b/src/stm32/Kconfig index b9aac0446..aa67dc91e 100644 --- a/src/stm32/Kconfig +++ b/src/stm32/Kconfig @@ -13,7 +13,7 @@ config STM32_SELECT select HAVE_GPIO_HARD_PWM if MACH_STM32F070 || MACH_STM32F072 || MACH_STM32F1 || MACH_STM32F4 || MACH_STM32F7 || MACH_STM32G0 || MACH_STM32H7 select HAVE_STRICT_TIMING select HAVE_CHIPID - select HAVE_STEPPER_OPTIMIZED_BOTH_EDGE + select HAVE_STEPPER_OPTIMIZED_BOTH_EDGE if !MACH_STM32H7 select HAVE_BOOTLOADER_REQUEST select HAVE_LIMITED_CODE_SIZE if FLASH_SIZE < 0x10000 diff --git a/src/stm32/Makefile b/src/stm32/Makefile index 1ce30c519..0ee71dcf1 100644 --- a/src/stm32/Makefile +++ b/src/stm32/Makefile @@ -37,7 +37,7 @@ CFLAGS_klipper.elf += -T $(OUT)src/generic/armcm_link.ld $(OUT)klipper.elf: $(OUT)src/generic/armcm_link.ld # Add source files -src-y += stm32/watchdog.c stm32/gpio.c stm32/clockline.c stm32/dfu_reboot.c +src-y += stm32/watchdog.c stm32/clockline.c stm32/dfu_reboot.c src-y += generic/crc16_ccitt.c src-y += generic/armcm_boot.c generic/armcm_irq.c generic/armcm_reset.c src-$(CONFIG_MACH_STM32F0) += stm32/stm32f0.c ../lib/stm32f0/system_stm32f0xx.c @@ -52,8 +52,9 @@ src-$(CONFIG_MACH_STM32L4) += stm32/stm32l4.c ../lib/stm32l4/system_stm32l4xx.c timer-src-y := generic/armcm_timer.c timer-src-$(CONFIG_MACH_STM32F0) := generic/timer_irq.c stm32/stm32f0_timer.c timer-src-$(CONFIG_MACH_STM32G0) := generic/timer_irq.c stm32/stm32f0_timer.c -gpio-src-y := stm32/gpioperiph.c -gpio-src-$(CONFIG_MACH_STM32F1) := +gpio-src-y := stm32/gpio.c stm32/gpioperiph.c +gpio-src-$(CONFIG_MACH_STM32F1) := stm32/gpio.c +gpio-src-$(CONFIG_MACH_STM32H7) := stm32/stm32h7_gpio.c stm32/gpioperiph.c src-y += $(timer-src-y) $(gpio-src-y) adc-src-y := stm32/adc.c adc-src-$(CONFIG_MACH_STM32F0) := stm32/stm32f0_adc.c diff --git a/src/stm32/gpio.h b/src/stm32/gpio.h index 6a5f910cc..0bfffc4b4 100644 --- a/src/stm32/gpio.h +++ b/src/stm32/gpio.h @@ -5,7 +5,10 @@ struct gpio_out { void *regs; - uint32_t bit; + union { + struct odr_cache *oc; // stm32h7 uses 'oc'; all others use 'bit' + uint32_t bit; + }; }; struct gpio_out gpio_out_setup(uint32_t pin, uint32_t val); void gpio_out_reset(struct gpio_out g, uint32_t val); diff --git a/src/stm32/stm32h7_gpio.c b/src/stm32/stm32h7_gpio.c new file mode 100644 index 000000000..f653c5708 --- /dev/null +++ b/src/stm32/stm32h7_gpio.c @@ -0,0 +1,167 @@ +// GPIO functions optimized for stm32h7 +// +// Copyright (C) 2019-2025 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include // ffs +#include "board/irq.h" // irq_save +#include "command.h" // DECL_ENUMERATION_RANGE +#include "gpio.h" // gpio_out_setup +#include "internal.h" // gpio_peripheral +#include "sched.h" // sched_shutdown + +DECL_ENUMERATION_RANGE("pin", "PA0", GPIO('A', 0), 16); +DECL_ENUMERATION_RANGE("pin", "PB0", GPIO('B', 0), 16); +DECL_ENUMERATION_RANGE("pin", "PC0", GPIO('C', 0), 16); +#ifdef GPIOD +DECL_ENUMERATION_RANGE("pin", "PD0", GPIO('D', 0), 16); +#endif +#ifdef GPIOE +DECL_ENUMERATION_RANGE("pin", "PE0", GPIO('E', 0), 16); +#endif +#ifdef GPIOF +DECL_ENUMERATION_RANGE("pin", "PF0", GPIO('F', 0), 16); +#endif +#ifdef GPIOG +DECL_ENUMERATION_RANGE("pin", "PG0", GPIO('G', 0), 16); +#endif +#ifdef GPIOH +DECL_ENUMERATION_RANGE("pin", "PH0", GPIO('H', 0), 16); +#endif +#ifdef GPIOI +DECL_ENUMERATION_RANGE("pin", "PI0", GPIO('I', 0), 16); +#endif + +GPIO_TypeDef * const digital_regs[] = { + ['A' - 'A'] = GPIOA, GPIOB, GPIOC, +#ifdef GPIOD + ['D' - 'A'] = GPIOD, +#endif +#ifdef GPIOE + ['E' - 'A'] = GPIOE, +#endif +#ifdef GPIOF + ['F' - 'A'] = GPIOF, +#endif +#ifdef GPIOG + ['G' - 'A'] = GPIOG, +#endif +#ifdef GPIOH + ['H' - 'A'] = GPIOH, +#endif +#ifdef GPIOI + ['I' - 'A'] = GPIOI, +#endif +}; + +// Convert a register and bit location back to an integer pin identifier +static int +regs_to_pin(GPIO_TypeDef *regs, uint32_t bit) +{ + int i; + for (i=0; ibsrr = bsrr; + regs->BSRR = bsrr; + gpio_peripheral(pin, GPIO_OUTPUT, 0); + irq_restore(flag); +} + +void +gpio_out_toggle_noirq(struct gpio_out g) +{ + GPIO_TypeDef *regs = g.regs; + uint32_t bsrr = (g.oc->bsrr << 16) | (g.oc->bsrr >> 16); + g.oc->bsrr = bsrr; + regs->BSRR = bsrr; +} + +void +gpio_out_toggle(struct gpio_out g) +{ + irqstatus_t flag = irq_save(); + gpio_out_toggle_noirq(g); + irq_restore(flag); +} + +void +gpio_out_write(struct gpio_out g, uint32_t val) +{ + GPIO_TypeDef *regs = g.regs; + uint32_t bit_num = ((uint32_t)g.oc / sizeof(*g.oc)) % 16; + uint32_t bsrr = 1 << (val ? bit_num : bit_num + 16); + irqstatus_t flag = irq_save(); + g.oc->bsrr = bsrr; + regs->BSRR = bsrr; + irq_restore(flag); +} + + +struct gpio_in +gpio_in_setup(uint32_t pin, int32_t pull_up) +{ + if (!gpio_valid(pin)) + shutdown("Not a valid input pin"); + GPIO_TypeDef *regs = digital_regs[GPIO2PORT(pin)]; + struct gpio_in g = { .regs=regs, .bit=GPIO2BIT(pin) }; + gpio_in_reset(g, pull_up); + return g; +} + +void +gpio_in_reset(struct gpio_in g, int32_t pull_up) +{ + GPIO_TypeDef *regs = g.regs; + int pin = regs_to_pin(regs, g.bit); + irqstatus_t flag = irq_save(); + gpio_peripheral(pin, GPIO_INPUT, pull_up); + irq_restore(flag); +} + +uint8_t +gpio_in_read(struct gpio_in g) +{ + GPIO_TypeDef *regs = g.regs; + return !!(regs->IDR & g.bit); +}