From 00b50e09ab85731c1318f0939d5b1c79fca61719 Mon Sep 17 00:00:00 2001 From: Raphael Lehmann Date: Tue, 6 Apr 2021 04:20:51 +0200 Subject: [PATCH 1/5] [ext] update modm-devices --- ext/modm-devices | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/modm-devices b/ext/modm-devices index 0bf0ab0789..705132befa 160000 --- a/ext/modm-devices +++ b/ext/modm-devices @@ -1 +1 @@ -Subproject commit 0bf0ab07895882e1d9181427f253149101d3f6a0 +Subproject commit 705132befa6097ecf54ece66fe097b7011e7d788 From 6562f17201bb6a88ed9eeff4ab923dd1d0bafa6c Mon Sep 17 00:00:00 2001 From: Raphael Lehmann Date: Sun, 11 Apr 2021 21:05:51 +0200 Subject: [PATCH 2/5] [platform] STM32 SpiMaster_Dma: Fix for non-Fifo devices --- src/modm/platform/spi/stm32/spi_master_dma_impl.hpp.in | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/modm/platform/spi/stm32/spi_master_dma_impl.hpp.in b/src/modm/platform/spi/stm32/spi_master_dma_impl.hpp.in index 84048ef1ed..641ebc1a2b 100644 --- a/src/modm/platform/spi/stm32/spi_master_dma_impl.hpp.in +++ b/src/modm/platform/spi/stm32/spi_master_dma_impl.hpp.in @@ -139,13 +139,14 @@ modm::platform::SpiMaster{{ id }}_Dma::transfer(cons break; if (not dmaTransmitComplete and not dmaReceiveComplete) return { modm::rf::Running }; - if (SpiHal{{ id }}::getInterruptFlags() & SpiBase::InterruptFlag::FifoTxLevel) - return { modm::rf::Running }; if (SpiHal{{ id }}::getInterruptFlags() & SpiBase::InterruptFlag::Busy) return { modm::rf::Running }; +%% if "fifo" in features + if (SpiHal{{ id }}::getInterruptFlags() & SpiBase::InterruptFlag::FifoTxLevel) + return { modm::rf::Running }; if (SpiHal{{ id }}::getInterruptFlags() & SpiBase::InterruptFlag::FifoRxLevel) return { modm::rf::Running }; - +%% endif break; } From 0a507aa128d6d6df25f6034b60a99036f4d01735 Mon Sep 17 00:00:00 2001 From: Raphael Lehmann Date: Mon, 5 Apr 2021 03:42:05 +0200 Subject: [PATCH 3/5] [platform] DMA: Enable for many more stm32-channel(-request) devices --- README.md | 10 +-- src/modm/platform/dma/stm32/dma.cpp.in | 15 ++-- src/modm/platform/dma/stm32/dma.hpp.in | 40 +++++++++- src/modm/platform/dma/stm32/dma_base.hpp.in | 31 +++++--- src/modm/platform/dma/stm32/dma_hal.hpp.in | 16 +++- .../platform/dma/stm32/dma_hal_impl.hpp.in | 7 +- src/modm/platform/dma/stm32/module.lb | 77 ++++++++++++++++--- test/all/run_all.py | 1 + 8 files changed, 163 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 5784ec4cfd..9b671e12bf 100644 --- a/README.md +++ b/README.md @@ -185,16 +185,16 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✗ DMA +✅ +✅ ○ +✅ ○ ○ ○ ○ -○ -○ -○ -○ -○ +✅ +✅ ✅ ○ ✗ diff --git a/src/modm/platform/dma/stm32/dma.cpp.in b/src/modm/platform/dma/stm32/dma.cpp.in index 66a53b2b19..a813a1424d 100644 --- a/src/modm/platform/dma/stm32/dma.cpp.in +++ b/src/modm/platform/dma/stm32/dma.cpp.in @@ -11,16 +11,19 @@ #include "dma.hpp" -%% for channels in dma["channels"] +using namespace modm::platform; + +%% for instance, irqs in irqList.items() /* - * IRQ handler for DMA{{ channels.instance }} + * IRQ handler for DMA{{ instance }} */ -%% for channel in channels.channel +%% for channels in irqs -MODM_ISR(DMA{{ channels.instance }}_Channel{{ channel.position }}) +MODM_ISR(DMA{{ instance }}_Channel{{ channels | join("_") }}) { - using namespace modm::platform; - Dma{{ channels.instance }}::Channel::interruptHandler(); + %% for channel in channels + Dma{{ instance }}::Channel::interruptHandler(); + %% endfor } %% endfor diff --git a/src/modm/platform/dma/stm32/dma.hpp.in b/src/modm/platform/dma/stm32/dma.hpp.in index a953718ecd..45d2b102dd 100644 --- a/src/modm/platform/dma/stm32/dma.hpp.in +++ b/src/modm/platform/dma/stm32/dma.hpp.in @@ -2,6 +2,7 @@ * Copyright (c) 2014, Kevin Läufer * Copyright (c) 2014-2017, Niklas Hauser * Copyright (c) 2020, Mike Wolfram + * Copyright (c) 2021, Raphael Lehmann * * This file is part of the modm project. * @@ -46,8 +47,10 @@ public: { if constexpr (ID == 1) Rcc::enable(); +%% if (dma.instance | length) > 1 else Rcc::enable(); +%% endif } /** * Disable the DMA controller in the RCC @@ -57,8 +60,10 @@ public: { if constexpr (ID == 1) Rcc::disable(); +%% if (dma.instance | length) > 1 else Rcc::disable(); +%% endif } /** @@ -225,6 +230,7 @@ public: { transferComplete = irqHandler; } + /** * Set the peripheral that operates the channel */ @@ -232,9 +238,14 @@ public: static void setPeripheralRequest() { +%% if dmaType in ["stm32-channel-request"] DMA_Request_TypeDef *DMA_REQ = reinterpret_cast(ControlHal::DMA_CSEL); DMA_REQ->CSELR &= ~(0x0f << (uint32_t(ChannelID) * 4)); DMA_REQ->CSELR |= uint32_t(dmaRequest) << (uint32_t(ChannelID) * 4); +%% else + // Nothing to see here. This controller has no request mux, instead + // all requests are or-ed together. +%% endif } /** @@ -349,6 +360,7 @@ public: * ... * }; */ +%% if dmaType in ["stm32-channel-request"] %% for channels in dma["channels"] %% for channel in channels.channel %% for request in channel.request @@ -357,7 +369,7 @@ public: %% if signal.instance is defined %% set peripheral = peripheral ~ signal.instance %% else - %% if peripheral not in ["Quadspi", "Aes", "Dcmi"] + %% if peripheral in ["Dac", "Lpuart", "Swpmi"] and target["family"] not in ["f1", "f3", "l0", "l1"] %% set peripheral = peripheral ~ 1 %% endif %% endif @@ -375,6 +387,32 @@ struct DmaController<{{ channels.instance }}>::Channel +template <> +template <> +struct DmaController<{{ channels.instance }}>::Channel::RequestMapping +{ + using Channel = DmaController<{{ channels.instance }}>::Channel; + static constexpr DmaBase::Request Request = DmaBase::Request::Any; +}; + + %% endfor + %% endfor +%% endfor + +%%endif } // namespace platform } // namespace modm diff --git a/src/modm/platform/dma/stm32/dma_base.hpp.in b/src/modm/platform/dma/stm32/dma_base.hpp.in index 913ddc70ba..0f2807f85c 100644 --- a/src/modm/platform/dma/stm32/dma_base.hpp.in +++ b/src/modm/platform/dma/stm32/dma_base.hpp.in @@ -2,6 +2,7 @@ * Copyright (c) 2014, Kevin Läufer * Copyright (c) 2014-2017, Niklas Hauser * Copyright (c) 2020, Mike Wolfram + * Copyright (c) 2021, Raphael Lehmann * * This file is part of the modm project. * @@ -15,6 +16,8 @@ #define MODM_STM32_DMA_BASE_HPP #include +#include + #include "../device.hpp" #include @@ -23,7 +26,7 @@ %% if target["family"] == "f4" %% set reg_prefix = "DMA_SxCR" -%% elif target["family"] in ["f3", "l4"] +%% elif dmaType in ["stm32-channel-request", "stm32-channel"] %% set reg_prefix = "DMA_CCR" %% endif @@ -81,7 +84,7 @@ public: Dma = 0, Peripheral = DMA_SxCR_PFCTRL, ///< the peripheral is the flow controller }; -%% elif target["family"] in ["f3", "l4"] +%% elif dmaType in ["stm32-channel-request", "stm32-channel"] %% set channel_count = namespace(max_channels = 0) %% for controller in dmaController %% if channel_count.max_channels < controller.channels @@ -96,7 +99,7 @@ public: %% endfor }; - %% if target["family"] == "l4" + %% if dmaType in ["stm32-channel-request"] %% set request_count = namespace(max_requests = 0) %% for channels in dma["channels"] %% for channel in channels.channel @@ -114,6 +117,14 @@ public: Request{{ request }}{% if request == 0 %} = 0{% endif %}, %% endfor }; + %% else + enum class + Request + { + // Nothing to see here. This controller has no request mux, instead + // all requests are OR-ed together. + Any + }; %% endif %% endif @@ -181,7 +192,7 @@ public: MemoryToPeripheral = DMA_SxCR_DIR_0, /// Source: DMA_SxPAR; Sink: DMA_SxM0AR MemoryToMemory = DMA_SxCR_DIR_1, -%% elif target["family"] in ["f3", "l4"] +%% elif dmaType in ["stm32-channel-request", "stm32-channel"] /// Source: DMA_CPARx; Sink: DMA_CMARx PeripheralToMemory = 0, /// Source: DMA_CMARx; Sink: DMA_CPARx @@ -219,7 +230,7 @@ protected: DMA_SxCR_PL_1 | DMA_SxCR_PL_0 | // Priority DMA_SxCR_CIRC | // CircularMode DMA_SxCR_PFCTRL; // FlowControl -%% elif target["family"] in ["f3", "l4"] +%% elif dmaType in ["stm32-channel-request", "stm32-channel"] static constexpr uint32_t memoryMask = DMA_CCR_MSIZE_0 | DMA_CCR_MSIZE_1 | // MemoryDataSize DMA_CCR_MINC | // MemoryIncrementMode @@ -248,13 +259,15 @@ protected: struct Nvic; }; -%% for channels in dma["channels"] +%% for instance, irqs in irqList.items() template <> -struct DmaBase::Nvic<{{ channels.instance }}> +struct DmaBase::Nvic<{{ instance }}> { static constexpr IRQn_Type DmaIrqs[] { - %% for channel in channels.channel - DMA{{ channels.instance }}_Channel{{ channel.position }}_IRQn, + %% for channels in irqs + %% for i in range(channels | length) + DMA{{ instance }}_Channel{{ channels | join("_") }}_IRQn, + %% endfor %% endfor }; }; diff --git a/src/modm/platform/dma/stm32/dma_hal.hpp.in b/src/modm/platform/dma/stm32/dma_hal.hpp.in index f4aa5dd63f..44f7228075 100644 --- a/src/modm/platform/dma/stm32/dma_hal.hpp.in +++ b/src/modm/platform/dma/stm32/dma_hal.hpp.in @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Mike Wolfram + * Copyright (c) 2021, Raphael Lehmann * * This file is part of the modm project. * @@ -22,6 +23,7 @@ namespace modm namespace platform { + /** * Hardware abstraction of DMA controller * @@ -45,11 +47,13 @@ class DmaHal : public DmaBase static constexpr uint32_t getBaseAddress() { if (id == 1) return DMA1_BASE; +%% if (dma.instance | length) > 1 else return DMA2_BASE; +%% endif } /** - * Get the base address of the DMA channel reigsters + * Get the base address of the DMA channel registers * * @tparam id The number of the DMA channel */ @@ -57,8 +61,10 @@ class DmaHal : public DmaBase static constexpr uint32_t getChannelBaseAddress() { if (id == 1) return DMA1_Channel1_BASE; +%% if (dma.instance | length) > 1 else return DMA2_Channel1_BASE; +%% endif } /** * Get the address of the channel selection register @@ -67,10 +73,18 @@ class DmaHal : public DmaBase */ template static constexpr uint32_t getCselAddress() { +%% if dmaType in ["stm32-channel-request"] if (id == 1) return DMA1_CSELR_BASE; +%% if (dma.instance | length) > 1 else return DMA2_CSELR_BASE; +%%endif +%% else + // Nothing to see here. This controller has no request mux, instead + // all requests are OR-ed together. + return 0; +%% endif } public: diff --git a/src/modm/platform/dma/stm32/dma_hal_impl.hpp.in b/src/modm/platform/dma/stm32/dma_hal_impl.hpp.in index 74368fd20a..196562379c 100644 --- a/src/modm/platform/dma/stm32/dma_hal_impl.hpp.in +++ b/src/modm/platform/dma/stm32/dma_hal_impl.hpp.in @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Mike Wolfram + * Copyright (c) 2021, Raphael Lehmann * * This file is part of the modm project. * @@ -23,7 +24,7 @@ modm::platform::DmaChannelHal::start() %% if target["family"] == "f4" Base->CR |= DMA_SxCR_EN; -%% else +%% elif dmaType in ["stm32-channel-request", "stm32-channel"] Base->CCR |= DMA_CCR_EN; %% endif } @@ -37,7 +38,7 @@ modm::platform::DmaChannelHal::stop() %% if target["family"] == "f4" Base->CR &= ~DMA_SxCR_EN; while (Base->SCR & DMA_SxCR_EN); // wait for stream to be stopped -%% else +%% elif dmaType in ["stm32-channel-request", "stm32-channel"] Base->CCR &= ~DMA_CCR_EN; while (Base->CCR & DMA_CCR_EN); // wait for stream to be stopped %% endif @@ -52,7 +53,7 @@ modm::platform::DmaChannelHal::getDataTransferDirection return static_cast( %% if target["family"] == "f4" Base->CR & (DMA_SxCR_DIR_0 | DMA_SxCR_DIR_1)); -%% else +%% elif dmaType in ["stm32-channel-request", "stm32-channel"] Base->CCR & (DMA_CCR_MEM2MEM | DMA_CCR_DIR)); %% endif } diff --git a/src/modm/platform/dma/stm32/module.lb b/src/modm/platform/dma/stm32/module.lb index 20d50a2d39..01095bd3a1 100644 --- a/src/modm/platform/dma/stm32/module.lb +++ b/src/modm/platform/dma/stm32/module.lb @@ -4,6 +4,7 @@ # Copyright (c) 2016-2018, Niklas Hauser # Copyright (c) 2017, Fabian Greif # Copyright (c) 2020, Mike Wolfram +# Copyright (c) 2021, Raphael Lehmann # # This file is part of the modm project. # @@ -16,20 +17,53 @@ def init(module): module.name = ":platform:dma" module.description = "Direct Memory Access (DMA)" + def prepare(module, options): device = options[":target"] - if not device.has_driver("dma:stm32*"): - return False - # FIXME the driver is for L4 only - if device.identifier["family"] not in ["l4"]: + module.depends(":cmsis:device", ":platform:rcc") + + if (not device.has_driver("dma")) or device.get_driver("dma")["type"] not in \ + [ + "stm32-channel-request", + "stm32-channel", + ]: return False - if device.identifier["name"] not in ["12", "22", "31", "32", "33", "42", "43", "51", "52", "62", "75", "76", "86", "96", "A6"]: + + did = device.identifier + + # Enable DMA for all but some devices... + + if did["family"] in ["f0"]: + if did["name"] in ["30", "71", "72", "78", "91", "98"]: + # STM32F09x has shared interrupts between DMA1 and DMA2, not supported... + return False + return True + + if did["family"] in ["f1"]: + if did["name"] in ["02", "05", "07"]: + return True + if did["name"] in ["00", "01", "03"] and did["pin"] in ["r", "v", "z"] and did["size"] in ["c", "d", "e", "f", "g"]: + return True return False - module.depends(":cmsis:device", ":platform:rcc") + if did["family"] in ["f3"]: + if did["name"] in ["73", "78"]: + return False + if did["name"] in ["02"] and did["pin"] in ["c"] and did["size"] in ["b", "c"]: + return False + return True + + if did["family"] in ["l0", "l4"]: + return True + + if did["family"] in ["l1"]: + if did["size"] in ["c"]: + return False + return True + + return False - return True def build(env): device = env[":target"] @@ -47,17 +81,42 @@ def build(env): max_channels = 0 for channel in channels["channel"]: max_channels = channel["position"] - for request in channel["request"]: - for signal in request["signal"]: + if dma["type"] in ["stm32-channel-request"]: + for request in channel["request"]: + for signal in request["signal"]: + if "name" in signal: + signal_name = signal["name"].capitalize() + signal_names[signal_name] = 1 + else: + for signal in channel["signal"]: if "name" in signal: signal_name = signal["name"].capitalize() signal_names[signal_name] = 1 controller.append({"instance": int(channels["instance"]), "channels": int(max_channels)}) + did = device.identifier + if (did.family in ['f0'] and did.name == '30' and did.size == 'c') or (did.family in ['f1'] and did.name == '02'): + # FIXME: Bug in modm-deviced data: Dma2 does not exist on device.identifier + properties["dma"]["instance"].remove('2') + signal_names = sorted(list(set(signal_names))) + properties["dmaType"] = dma["type"] properties["dmaSignals"] = signal_names properties["dmaController"] = controller + properties["irqList"] = dict() + for channels in dma["channels"]: + irqs = [v["name"] for v in device.get_driver("core")["vector"]] + irqs = [v for v in irqs if v.startswith("DMA" + channels["instance"]) and not "DMA2D" in v] + irq_list = list() + for irq in irqs: + irq_channel_list = [] + for c in irq.split("Channel",1)[1]: + if c.isdigit(): + irq_channel_list.append(int(c)) + irq_list.append(irq_channel_list) + properties["irqList"][int(channels["instance"])] = irq_list + env.substitutions = properties env.outbasepath = "modm/src/modm/platform/dma" diff --git a/test/all/run_all.py b/test/all/run_all.py index 7a4ac83e10..72ef67f9fc 100644 --- a/test/all/run_all.py +++ b/test/all/run_all.py @@ -93,6 +93,7 @@ def __init__(self, output, errors): def run_command(cmdline): try: cmdline = " ".join(cmdline) + print(cmdline) p = subprocess.run(cmdline, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) return (p.stdout, p.stderr, p.returncode) From ebcffdf0e59dfe96ebf6104c6c09fe7d9b18f7f0 Mon Sep 17 00:00:00 2001 From: Raphael Lehmann Date: Mon, 5 Apr 2021 03:42:48 +0200 Subject: [PATCH 4/5] [examples] Nucleo-F303RE: SPI-DMA example --- examples/nucleo_f303re/spi_dma/main.cpp | 43 ++++++++++++++++++++++ examples/nucleo_f303re/spi_dma/project.xml | 12 ++++++ 2 files changed, 55 insertions(+) create mode 100644 examples/nucleo_f303re/spi_dma/main.cpp create mode 100644 examples/nucleo_f303re/spi_dma/project.xml diff --git a/examples/nucleo_f303re/spi_dma/main.cpp b/examples/nucleo_f303re/spi_dma/main.cpp new file mode 100644 index 0000000000..5e60bf438f --- /dev/null +++ b/examples/nucleo_f303re/spi_dma/main.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020, Mike Wolfram + * Copyright (c) 2021, Raphael Lehmann + * + * 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/. + */ +// ---------------------------------------------------------------------------- + +#include + +using Mosi = GpioOutputB5; +using Miso = GpioInputB4; +using Sck = GpioOutputB3; +using DmaRx = Dma1::Channel2; +using DmaTx = Dma1::Channel3; +using Spi = SpiMaster1_Dma; + +int main() +{ + Board::initialize(); + + Dma1::enable(); + Spi::connect(); + Spi::initialize(); + + while (true) + { + uint8_t sendBuffer[13] { "data to send" }; + uint8_t receiveBuffer[13]; + + // send out 12 bytes, don't care about response + Spi::transferBlocking(sendBuffer, nullptr, 12); + + // send out 12 bytes, read in 12 bytes + Spi::transferBlocking(sendBuffer, receiveBuffer, 12); + } + + return 0; +} diff --git a/examples/nucleo_f303re/spi_dma/project.xml b/examples/nucleo_f303re/spi_dma/project.xml new file mode 100644 index 0000000000..c7b7f33399 --- /dev/null +++ b/examples/nucleo_f303re/spi_dma/project.xml @@ -0,0 +1,12 @@ + + modm:nucleo-f303re + + + + + modm:platform:gpio + modm:platform:dma + modm:platform:spi:1 + modm:build:scons + + From 8ca2f355781856cd14235920a5f5021e39dcb590 Mon Sep 17 00:00:00 2001 From: Raphael Lehmann Date: Mon, 5 Apr 2021 14:55:41 +0200 Subject: [PATCH 5/5] [examples] Nucleo-F042K6: SPI-DMA example --- examples/nucleo_f042k6/spi_dma/main.cpp | 43 ++++++++++++++++++++++ examples/nucleo_f042k6/spi_dma/project.xml | 12 ++++++ 2 files changed, 55 insertions(+) create mode 100644 examples/nucleo_f042k6/spi_dma/main.cpp create mode 100644 examples/nucleo_f042k6/spi_dma/project.xml diff --git a/examples/nucleo_f042k6/spi_dma/main.cpp b/examples/nucleo_f042k6/spi_dma/main.cpp new file mode 100644 index 0000000000..611068fe38 --- /dev/null +++ b/examples/nucleo_f042k6/spi_dma/main.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020, Mike Wolfram + * Copyright (c) 2021, Raphael Lehmann + * + * 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/. + */ +// ---------------------------------------------------------------------------- + +#include + +using Mosi = GpioOutputB5; +using Miso = GpioInputB4; +using Sck = GpioOutputB3; +using DmaRx = Dma1::Channel2; +using DmaTx = Dma1::Channel3; +using Spi = SpiMaster1_Dma; + +int main() +{ + Board::initialize(); + + Dma1::enable(); + Spi::connect(); + Spi::initialize(); + + while (true) + { + uint8_t sendBuffer[13] { "data to send" }; + uint8_t receiveBuffer[13]; + + // send out 12 bytes, don't care about response + Spi::transferBlocking(sendBuffer, nullptr, 12); + + // send out 12 bytes, read in 12 bytes + Spi::transferBlocking(sendBuffer, receiveBuffer, 12); + } + + return 0; +} diff --git a/examples/nucleo_f042k6/spi_dma/project.xml b/examples/nucleo_f042k6/spi_dma/project.xml new file mode 100644 index 0000000000..ce0fc964be --- /dev/null +++ b/examples/nucleo_f042k6/spi_dma/project.xml @@ -0,0 +1,12 @@ + + modm:nucleo-f042k6 + + + + + modm:platform:gpio + modm:platform:dma + modm:platform:spi:1 + modm:build:scons + +