Skip to content

Commit

Permalink
[spi] Enhance STM32 SPI with DMA support
Browse files Browse the repository at this point in the history
  • Loading branch information
mikewolfram authored and salkinium committed May 8, 2020
1 parent aaae1d1 commit 80a9c66
Show file tree
Hide file tree
Showing 9 changed files with 373 additions and 0 deletions.
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];

// 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;

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

0 comments on commit 80a9c66

Please sign in to comment.