diff --git a/README.md b/README.md index eed411dfd4..9f63a5fcbc 100644 --- a/README.md +++ b/README.md @@ -82,9 +82,9 @@ git clone --recurse-submodules --jobs 8 https://github.com/modm-io/modm.git ## Microcontrollers -modm can create a HAL for 3628 devices of these vendors: +modm can create a HAL for 3715 devices of these vendors: -- STMicroelectronics STM32: 2823 devices. +- STMicroelectronics STM32: 2910 devices. - Microchip SAM: 416 devices. - Microchip AVR: 388 devices. - Raspberry Pi: 1 device. @@ -164,7 +164,7 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✅ ✅ ✅ -✕ +○ ✅ ○ ✕ diff --git a/ext/modm-devices b/ext/modm-devices index 2f3262b77d..e540dc9d44 160000 --- a/ext/modm-devices +++ b/ext/modm-devices @@ -1 +1 @@ -Subproject commit 2f3262b77d21acd2c89cc70bbd3d87e03fb361d1 +Subproject commit e540dc9d4430749fe0cbc20b536d71136b6f25e4 diff --git a/src/modm/platform/can/stm32-fdcan/module.lb b/src/modm/platform/can/stm32-fdcan/module.lb index b82a363aeb..6bcc460042 100644 --- a/src/modm/platform/can/stm32-fdcan/module.lb +++ b/src/modm/platform/can/stm32-fdcan/module.lb @@ -64,6 +64,11 @@ def prepare(module, options): if not device.has_driver("fdcan:stm32"): return False + # STM32G0 devices are currently unsupported due to shared interrupt handler + # TODO: fix driver + if device.identifier.family == "g0": + return False + module.depends( ":architecture:assert", ":architecture:atomic", diff --git a/src/modm/platform/core/stm32/startup_platform.c.in b/src/modm/platform/core/stm32/startup_platform.c.in index d6238bd927..5764524b36 100644 --- a/src/modm/platform/core/stm32/startup_platform.c.in +++ b/src/modm/platform/core/stm32/startup_platform.c.in @@ -63,7 +63,7 @@ __modm_initialize_platform(void) %% elif target.family in ["g0", "g4", "l4", "l5"] %% if target.family in ["l4", "g4"] RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN; -%% else +%% elif target.family != "g0" #ifdef PWR_CR2_IOSV RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN; #endif diff --git a/src/modm/platform/dma/stm32/module.lb b/src/modm/platform/dma/stm32/module.lb index 4caaf4e270..0c13840264 100644 --- a/src/modm/platform/dma/stm32/module.lb +++ b/src/modm/platform/dma/stm32/module.lb @@ -5,7 +5,7 @@ # Copyright (c) 2017, Fabian Greif # Copyright (c) 2020, Mike Wolfram # Copyright (c) 2021, Raphael Lehmann -# Copyright (c) 2021, Christopher Durand +# Copyright (c) 2021-2023, Christopher Durand # # This file is part of the modm project. # @@ -129,11 +129,11 @@ def build(env): for channel in channels: instance_channels[channel["dma-instance"]].append(channel["dma-channel"]) for instance in instance_channels: - channel_list = instance_channels[instance] + channel_list = [int(c) for c in instance_channels[instance]] channel_list.sort() min_channel = channel_list[0] max_channel = channel_list[-1] - controller.append({"instance": int(instance), "min_channel": int(min_channel), "max_channel": int(max_channel)}) + controller.append({"instance": int(instance), "min_channel": min_channel, "max_channel": max_channel}) elif dma["type"] in ["stm32-stream-channel"]: for channels in dma["streams"]: max_channels = 0 diff --git a/src/modm/platform/i2c/stm32-extended/i2c_master.cpp.in b/src/modm/platform/i2c/stm32-extended/i2c_master.cpp.in index c620cca8db..c8c1e50bb0 100644 --- a/src/modm/platform/i2c/stm32-extended/i2c_master.cpp.in +++ b/src/modm/platform/i2c/stm32-extended/i2c_master.cpp.in @@ -2,6 +2,7 @@ /* * Copyright (c) 2017, Niklas Hauser * Copyright (c) 2017, Sascha Schade + * Copyright (c) 2018, 2023, Christopher Durand * * This file is part of the modm project. * @@ -53,7 +54,7 @@ #include #include -%% if not shared_interrupt +%% if not single_interrupt MODM_ISR_DECL(I2C{{ id }}_ER); %% endif @@ -323,7 +324,10 @@ namespace } // ---------------------------------------------------------------------------- -%% if shared_interrupt +%% if shared_irq +void +modm::platform::I2cMaster{{ id }}::irq() +%% elif single_interrupt MODM_ISR(I2C{{ id }}) %% else MODM_ISR(I2C{{ id }}_EV) @@ -331,12 +335,24 @@ MODM_ISR(I2C{{ id }}_EV) { DEBUG_STREAM("\n=== IRQ ==="); -%% if shared_interrupt +%% if single_interrupt handleError(); %% endif - uint16_t isr = I2C{{ id }}->ISR; + const uint16_t isr = I2C{{ id }}->ISR; +%% if shared_irq + const auto cr1 = I2C{{ id }}->CR1; + const auto mask = (cr1 & (I2C_CR1_STOPIE | I2C_CR1_RXIE | I2C_CR1_TXIE)) + | ((cr1 & I2C_CR1_TCIE) ? (I2C_ISR_TCR | I2C_ISR_TC) : 0u); + + static_assert(I2C_CR1_STOPIE == I2C_ISR_STOPF); + static_assert(I2C_CR1_TXIE == I2C_ISR_TXIS); + static_assert(I2C_CR1_RXIE == I2C_ISR_RXNE); + if ((isr & mask) == 0) { + return; + } +%% endif I2C{{ id }}->CR1 &= ~(I2C_CR1_STOPIE | I2C_CR1_TCIE | I2C_CR1_RXIE | I2C_CR1_TXIE); I2C{{ id }}->ICR = I2C_ICR_STOPCF; @@ -487,7 +503,7 @@ MODM_ISR(I2C{{ id }}_EV) } // ---------------------------------------------------------------------------- -%% if not shared_interrupt +%% if not single_interrupt MODM_ISR(I2C{{ id }}_ER) { handleError(); @@ -539,7 +555,11 @@ modm::platform::I2cMaster{{ id }}::initializeWithPrescaler(uint32_t timingRegist // Disable Own Address 2 I2C{{ id }}->OAR2 = 0; -%% if shared_interrupt +%% if shared_irq + // Enable Interrupt + NVIC_SetPriority({{ shared_irq }}_IRQn, 10); + NVIC_EnableIRQ({{ shared_irq }}_IRQn); +%% elif single_interrupt // Enable Interrupt NVIC_SetPriority(I2C{{ id }}_IRQn, 10); NVIC_EnableIRQ(I2C{{ id }}_IRQn); diff --git a/src/modm/platform/i2c/stm32-extended/i2c_master.hpp.in b/src/modm/platform/i2c/stm32-extended/i2c_master.hpp.in index d6e61f36b0..1b4b439747 100644 --- a/src/modm/platform/i2c/stm32-extended/i2c_master.hpp.in +++ b/src/modm/platform/i2c/stm32-extended/i2c_master.hpp.in @@ -2,6 +2,7 @@ /* * Copyright (c) 2017, Sascha Schade * Copyright (c) 2017-2018, Niklas Hauser + * Copyright (c) 2018, 2023, Christopher Durand * * This file is part of the modm project. * @@ -14,6 +15,7 @@ #ifndef MODM_STM32_I2C_{{ id }}_HPP #define MODM_STM32_I2C_{{ id }}_HPP +#include #include #include #include @@ -117,6 +119,13 @@ public: private: static void initializeWithPrescaler(uint32_t timingRegisterValue); + +%% if shared_irq + friend void ::{{ shared_irq }}_IRQHandler(); + + static void + irq(); +%% endif }; diff --git a/src/modm/platform/i2c/stm32-extended/i2c_shared_irqs.cpp.in b/src/modm/platform/i2c/stm32-extended/i2c_shared_irqs.cpp.in new file mode 100644 index 0000000000..c731ee219d --- /dev/null +++ b/src/modm/platform/i2c/stm32-extended/i2c_shared_irqs.cpp.in @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023, Christopher Durand + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +%% for ids in shared_irqs.values() +%% for id in ids | sort +#include "i2c_master_{{ id }}.hpp" +%% endfor +%% endfor + +%% for irq,ids in shared_irqs.items() +MODM_ISR({{ irq }}) +{ +%% for id in ids | sort + modm::platform::I2cMaster{{ id }}::irq(); +%% endfor +} +%% endfor diff --git a/src/modm/platform/i2c/stm32-extended/module.lb b/src/modm/platform/i2c/stm32-extended/module.lb index 6e6b643673..970bc19be7 100644 --- a/src/modm/platform/i2c/stm32-extended/module.lb +++ b/src/modm/platform/i2c/stm32-extended/module.lb @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- # Copyright (c) 2016-2018, Niklas Hauser # Copyright (c) 2017, Fabian Greif +# Copyright (c) 2023, Christopher Durand # # This file is part of the modm project. # @@ -10,6 +11,23 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. # ----------------------------------------------------------------------------- +from collections import defaultdict +import re + +global_properties = {} + +def get_shared_irqs(device): + irq_re = re.compile("I2C\d(_\d)+") + shared_irqs = [v["name"] for v in device.get_driver("core")["vector"]] + shared_irqs = [v for v in shared_irqs if irq_re.fullmatch(v)] + shared_irq_map = {} + for irq in shared_irqs: + instances = tuple(irq[3:].split("_")) + for i in instances: + shared_irq_map[int(i)] = irq + return shared_irq_map + + class Instance(Module): def __init__(self, instance): self.instance = instance @@ -31,13 +49,21 @@ class Instance(Module): return True def build(self, env): + global global_properties + device = env[":target"] driver = device.get_driver("i2c") properties = device.properties properties["target"] = target = device.identifier properties["id"] = self.instance - properties["shared_interrupt"] = "0" in target.family + properties["single_interrupt"] = "0" in target.family + shared_irq = get_shared_irqs(device).get(self.instance) + properties["shared_irq"] = shared_irq + if shared_irq: + global_properties["shared_irqs"][shared_irq].append(self.instance) + # shared irq is only supported with a single data and error interrupt + assert properties["single_interrupt"] or not shared_irq env.substitutions = properties env.outbasepath = "modm/src/modm/platform/i2c" @@ -64,12 +90,17 @@ def prepare(module, options): ":container", ":platform:gpio") + global_properties["shared_irqs"] = defaultdict(list) + for instance in listify(device.get_driver("i2c")["instance"]): module.add_submodule(Instance(int(instance))) return True def build(env): + env.substitutions.update(global_properties) env.outbasepath = "modm/src/modm/platform/i2c" - env.copy("i2c_timing_calculator.hpp") + env.copy("i2c_timing_calculator.hpp") + if len(global_properties["shared_irqs"]) > 0: + env.template("i2c_shared_irqs.cpp.in") diff --git a/src/modm/platform/spi/stm32/module.lb b/src/modm/platform/spi/stm32/module.lb index 583335987d..2329a5bc84 100644 --- a/src/modm/platform/spi/stm32/module.lb +++ b/src/modm/platform/spi/stm32/module.lb @@ -3,6 +3,7 @@ # # Copyright (c) 2016-2018, Niklas Hauser # Copyright (c) 2017, Fabian Greif +# Copyright (c) 2023, Christopher Durand # # This file is part of the modm project. # @@ -37,6 +38,13 @@ class Instance(Module): properties = get_properties(env) properties["id"] = self.instance + device = env[":target"] + + irqs = [v["name"] for v in device.get_driver("core")["vector"]] + irqs = [irq for irq in irqs if irq.startswith("SPI") and str(self.instance) in irq] + assert len(irqs) == 1 + properties["irq"] = irqs[0] + env.substitutions = properties env.outbasepath = "modm/src/modm/platform/spi" diff --git a/src/modm/platform/spi/stm32/spi_hal_impl.hpp.in b/src/modm/platform/spi/stm32/spi_hal_impl.hpp.in index dbadb970cb..075c18d6fb 100644 --- a/src/modm/platform/spi/stm32/spi_hal_impl.hpp.in +++ b/src/modm/platform/spi/stm32/spi_hal_impl.hpp.in @@ -153,12 +153,12 @@ modm::platform::SpiHal{{ id }}::enableInterruptVector(bool enable, uint32_t prio { if (enable) { // Set priority for the interrupt vector - NVIC_SetPriority(SPI{{ id }}_IRQn, priority); + NVIC_SetPriority({{ irq }}_IRQn, priority); // register IRQ at the NVIC - NVIC_EnableIRQ(SPI{{ id }}_IRQn); + NVIC_EnableIRQ({{ irq }}_IRQn); } else { - NVIC_DisableIRQ(SPI{{ id }}_IRQn); + NVIC_DisableIRQ({{ irq }}_IRQn); } } diff --git a/test/all/ignored.txt b/test/all/ignored.txt index d6ed40b370..f5ee44df96 100644 --- a/test/all/ignored.txt +++ b/test/all/ignored.txt @@ -106,10 +106,6 @@ samd21e15c-uf samd21e15c-uu samd21e16c-uf samd21e16c-uu -# FIXME: Shared IRQs on UART, SPI, I2C -stm32g0b0 -stm32g0b1 -stm32g0c1 # FIXME: Dual-core devices not supported yet stm32h745 stm32h755