Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[spi] Enhance STM32 SPI with DMA support #400

Merged
merged 1 commit into from
May 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions examples/nucleo_l432kc/spi_dma/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2020, Mike Wolfram
*
* 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 <modm/board.hpp>

using Mosi = GpioOutputB5;
using Miso = GpioInputB4;
using Sck = GpioOutputB3;
using DmaRx = Dma1::Channel2;
using DmaTx = Dma1::Channel3;
using Spi = SpiMaster1_Dma<DmaRx, DmaTx>;

int main()
{
Board::initialize();

// Enable DMA1 controller
Dma1::enable();
// Enable SPI1
Spi::connect<Mosi::Mosi, Miso::Miso, Sck::Sck>();
Spi::initialize<Board::SystemClock, 10_MHz>();

while (true)
{
uint8_t sendBuffer[13] { "data to send" };
uint8_t receiveBuffer[13];
rleh marked this conversation as resolved.
Show resolved Hide resolved

// 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;
}
12 changes: 12 additions & 0 deletions examples/nucleo_l432kc/spi_dma/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<library>
<extends>modm:nucleo-l432kc</extends>
<options>
<option name="modm:build:build.path">../../../build/nucleo_l432kc/spi_dma</option>
</options>
<modules>
<module>modm:platform:gpio</module>
<module>modm:platform:dma</module>
<module>modm:platform:spi:1</module>
<module>modm:build:scons</module>
</modules>
</library>
3 changes: 3 additions & 0 deletions src/modm/board/nucleo_l432kc/board.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ struct SystemClock {
static constexpr uint32_t Usart4 = Apb1;
static constexpr uint32_t Usart5 = Apb1;

static constexpr uint32_t Spi1 = Apb2;
static constexpr uint32_t Spi2 = Apb2;

salkinium marked this conversation as resolved.
Show resolved Hide resolved
static bool inline
enable()
{
Expand Down
3 changes: 3 additions & 0 deletions src/modm/platform/spi/stm32/module.lb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ class Instance(Module):
env.template("spi_hal_impl.hpp.in", "spi_hal_{}_impl.hpp".format(self.instance))
env.template("spi_master.hpp.in", "spi_master_{}.hpp".format(self.instance))
env.template("spi_master.cpp.in", "spi_master_{}.cpp".format(self.instance))
if env.has_module(":platform:dma"):
env.template("spi_master_dma.hpp.in", "spi_master_{}_dma.hpp".format(self.instance))
env.template("spi_master_dma_impl.hpp.in", "spi_master_{}_dma_impl.hpp".format(self.instance))


def init(module):
Expand Down
11 changes: 11 additions & 0 deletions src/modm/platform/spi/stm32/spi_base.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Copyright (c) 2013, Kevin Läufer
* Copyright (c) 2013-2017, Niklas Hauser
* Copyright (c) 2014, Daniel Krebs
* Copyright (c) 2020, Mike Wolfram
*
* This file is part of the modm project.
*
Expand Down Expand Up @@ -41,6 +42,8 @@ public:
RxBufferNotEmpty = SPI_CR2_RXNEIE,
TxBufferEmpty = SPI_CR2_TXEIE,
Error = SPI_CR2_ERRIE,
RxDmaEnable = SPI_CR2_RXDMAEN,
TxDmaEnable = SPI_CR2_TXDMAEN,
};
MODM_FLAGS32(Interrupt);

Expand Down Expand Up @@ -128,6 +131,14 @@ public:
Div256 = SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0,
};

%% if "fifo" in features
enum class
RxFifoThreshold : uint32_t
{
HalfFull = 0,
QuarterFull = SPI_CR2_FRXTH,
};
%% endif
};

} // namespace platform
Expand Down
6 changes: 6 additions & 0 deletions src/modm/platform/spi/stm32/spi_hal.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Copyright (c) 2013, Kevin Läufer
* Copyright (c) 2013-2018, Niklas Hauser
* Copyright (c) 2014, Daniel Krebs
* Copyright (c) 2020, Mike Wolfram
*
* This file is part of the modm project.
*
Expand Down Expand Up @@ -67,6 +68,11 @@ public:
static void
setMasterSelection(MasterSelection masterSelection);

%% if "fifo" in features
static void
setRxFifoThreshold(RxFifoThreshold threshold);
%% endif

/// Returns true if data has been received
static bool
isReceiveRegisterNotEmpty();
Expand Down
10 changes: 10 additions & 0 deletions src/modm/platform/spi/stm32/spi_hal_impl.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Copyright (c) 2013, Kevin Läufer
* Copyright (c) 2013-2017, Niklas Hauser
* Copyright (c) 2014, Daniel Krebs
* Copyright (c) 2020, Mike Wolfram
*
* This file is part of the modm project.
*
Expand Down Expand Up @@ -97,6 +98,15 @@ modm::platform::SpiHal{{ id }}::setMasterSelection(MasterSelection masterSelecti
| static_cast<uint32_t>(masterSelection);
}

%% if "fifo" in features
inline void
modm::platform::SpiHal{{ id }}::setRxFifoThreshold(RxFifoThreshold threshold)
{
SPI{{ id }}->CR2 = (SPI{{ id }}->CR2 & ~static_cast<uint32_t>(RxFifoThreshold::QuarterFull))
| static_cast<uint32_t>(threshold);
}
%% endif

inline bool
modm::platform::SpiHal{{ id }}::isReceiveRegisterNotEmpty()
{
Expand Down
99 changes: 99 additions & 0 deletions src/modm/platform/spi/stm32/spi_master_dma.hpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright (c) 2020, Mike Wolfram
*
* 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/.
*/
// ----------------------------------------------------------------------------

#ifndef MODM_STM32_SPI_MASTER{{ id }}_DMA_HPP
#define MODM_STM32_SPI_MASTER{{ id }}_DMA_HPP

#include <modm/platform/dma/dma.hpp>
#include "spi_master_{{ id }}.hpp"

namespace modm
{

namespace platform
{

/**
* Serial peripheral interface (SPI{{ id }}) with DMA support.
*
* This class uses the DMA controller for sending and receiving data, which
* greatly reduces the CPU load. Beside passing the DMA channels as template
* parameters the class can be used in the same way like the SpiMaster{{ id }}.
*
* @tparam DmaChannelRX DMA channel for receiving
* @tparam DmaChannelTX DMA channel for sending
*
* @author Mike Wolfram
* @ingroup modm_platform_spi modm_platform_spi_{{id}}
*/
template <class DmaChannelRx, class DmaChannelTx>
class SpiMaster{{ id }}_Dma : public SpiMaster{{ id }}
{
struct Dma {
using RxChannel = typename DmaChannelRx::template RequestMapping<
Peripheral::Spi{{ id }}, DmaBase::Signal::Rx>::Channel;
using TxChannel = typename DmaChannelTx::template RequestMapping<
Peripheral::Spi{{ id }}, DmaBase::Signal::Tx>::Channel;
static constexpr DmaBase::Request RxRequest = DmaChannelRx::template RequestMapping<
Peripheral::Spi{{ id }}, DmaBase::Signal::Rx>::Request;
static constexpr DmaBase::Request TxRequest = DmaChannelTx::template RequestMapping<
Peripheral::Spi{{ id }}, DmaBase::Signal::Tx>::Request;
};

public:
/**
* Initialize DMA and SPI{{ id }}
*/
template <class SystemClock, baudrate_t baudrate, percent_t tolerance=pct(5)>
static void
initialize();

static uint8_t
transferBlocking(uint8_t data)
{
return RF_CALL_BLOCKING(transfer(data));
}

static void
transferBlocking(uint8_t *tx, uint8_t *rx, std::size_t length)
{
RF_CALL_BLOCKING(transfer(tx, rx, length));
}

static modm::ResumableResult<uint8_t>
transfer(uint8_t data);

static modm::ResumableResult<void>
transfer(uint8_t *tx, uint8_t *rx, std::size_t length);

private:
static void
handleDmaTransferError();
static void
handleDmaReceiveComplete();
static void
handleDmaTransmitComplete();

static inline bool dmaError { false };
static inline bool dmaTransmitComplete { false };
static inline bool dmaReceiveComplete { false };

// needed for transfers where no RX or TX buffers are given
static inline uint8_t dmaDummy { 0 };
};

} // namespace platform

} // namespace modm

#include "spi_master_{{ id }}_dma_impl.hpp"

#endif // MODM_STM32_SPI_MASTER{{ id }}_DMA_HPP
Loading