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/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
+
+
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
+
+
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
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/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;
}
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)