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

STM32F4 DMA #6

Draft
wants to merge 6 commits into
base: develop
Choose a base branch
from
Draft
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
25 changes: 25 additions & 0 deletions src/modm/platform/dma/stm32/f4/dma.cpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2020, Mike Wolfram
* Copyright (c) 2020, Matthew Arnold
*
* 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 "dma.hpp"

%% for streams in dma["streams"]
%% for stream in streams.stream
MODM_ISR(DMA{{ streams.instance }}_Stream{{ stream.position}})
{
using namespace modm::platform;
Dma{{ streams.instance }}::Stream<DmaBase::StreamID::STREAM_{{ stream.position }}>::interruptHandler();
}

%% endfor
%% endfor

349 changes: 349 additions & 0 deletions src/modm/platform/dma/stm32/f4/dma.hpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,349 @@
/*
* Copyright (c) 2014, Kevin Läufer
* Copyright (c) 2014-2017, Niklas Hauser
* Copyright (c) 2020, Mike Wolfram
* Copyright (c) 2020, Matthew Arnold
*
* 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_DMA_HPP
#define MODM_STM32_DMA_HPP

#include <stdint.h>

#include <modm/platform/clock/rcc.hpp>

#include "dma_hal.hpp"

namespace modm
{
namespace platform
{
/**
* DMA controller for stm32f4 series microcontrollers
*/
template <uint32_t ID>
class DmaController : public DmaBase
{
static_assert(ID >= 1 && ID <= {{ dma.instance | length }}, "dma id invalid");

public:
/**
* Enable the DMA controller in the RCC.
*/
static void enableRcc()
{
%% for controller in dmaController
%% if controller.dma_controller == 1
if constexpr (ID == 1)
{
Rcc::enable<Peripheral::Dma1>();
}
%% else
else if constexpr (ID == {{ controller.dma_controller }})
{
Rcc::enable<Peripheral::Dma{{ controller.dma_controller }}>();
}
%% endif
%% endfor
}

/**
* Disable the DMA controller in the RCC.
*/
static void disableRcc()
{
%% for controller in dmaController
%% if controller.dma_controller == 1
if constexpr (ID == 1)
{
Rcc::disable<Peripheral::Dma1>();
}
%% else
else if constexpr (ID == {{ controller.dma_controller }})
{
Rcc::disable<Peripheral::Dma{{ controller.dma_controller }}>();
}
%% endif
%% endfor
}

/**
* Class representing a DMA channel/stream.
*/
template <DmaBase::StreamID SID>
class Stream
{
using ControlHal = DmaHal<ID>;
using StreamHal = DmaStreamHal<SID, ControlHal::streamBase()>;

public:
static constexpr uint32_t DMA_ID = ID;
static constexpr DmaBase::StreamID STREAM_ID = SID;

/**
* Configure the DMA channel
*
* @see DmaStreamHal::configure
*/
static void configure(
ChannelSelection channel,
DataTransferDirection direction,
PeripheralIncrementMode periphInc,
MemoryIncrementMode memInc,
PeripheralDataSize peripDataSize,
MemoryDataSize memDataSize,
ControlMode mode,
PriorityLevel priority,
FifoMode fifoMode,
FifoThreshold fifoThreshold,
MemoryBurstTransfer memBurst,
PeripheralBurstTransfer periphBurst)
{
StreamHal::configure(
channel,
direction,
periphInc,
memInc,
peripDataSize,
memDataSize,
mode,
priority,
fifoMode,
fifoThreshold,
memBurst,
periphBurst);
}

static void selectChannel(DmaBase::ChannelSelection channel)
{
StreamHal::selectChannel(channel);
}

/**
* Start the transfer of the DMA channel
*/
static void enable()
{
ControlHal::clearInterruptFlags(STREAM_ID);
StreamHal::enable();
}
/**
* Stop a DMA channel transfer
*/
static bool disable() { return StreamHal::disable(); }

/**
* Get the direction of the data transfer
*/
static DataTransferDirection getDataTransferDirection()
{
return StreamHal::getDataTransferDirection();
}

/**
* Configure the DMA channel to write to the requested data buffer length bytes.
*
* @note When in continuous read mode, other read operations are disabled.
*/
static bool configureRead(uint8_t *data, std::size_t length)
{
// Disable to allow modifications of the DMA stream control register.
if (!disable())
{
return false;
}
// configure total # of bytes
setDataLength(length);
// Write the memory address in the DMA control register to configure it as the
// destination of the transfer. The data will be loaded from USART_DR to this memory
// area after each RXNE event.
setDestinationAddress(reinterpret_cast<uintptr_t>(data));
// activate channel in DMA control register
enable();
return true;
}

static bool configureWrite(uint8_t *data, std::size_t length)
{
if (disable())
{
return false;
}
setDataLength(length);
setSourceAddress(reinterpret_cast<uintptr_t>(data));
enable();
return true;
}

/**
* Set the memory address of the DMA channel
*
* @note In Mem2Mem mode use this method to set the memory source address.
*
* @param[in] address Source address
*/
static void setSourceAddress(uintptr_t address) { StreamHal::setSourceAddress(address); }

/**
* Set the peripheral address of the DMA channel
*
* @note In Mem2Mem mode use this method to set the memory destination address.
*
* @param[in] address Destination address
*/
static void setDestinationAddress(uintptr_t address)
{
StreamHal::setDestinationAddress(address);
}

/**
* Set the length of data to be transfered
*/
static void setDataLength(std::size_t length) { StreamHal::setDataLength(length); }

/**
* Set the IRQ handler for transfer errors.
*
* The handler will be called from the channels IRQ handler function
* when the IRQ status indicates an error occured.
*/
static void setTransferErrorIrqHandler(IrqHandler irqHandler)
{
transferError = irqHandler;
}

/**
* Set the IRQ handler for transfer complete.
*
* Called by the channels IRQ handler when the transfer is complete.
*/
static void setTransferCompleteIrqHandler(IrqHandler irqHandler)
{
transferComplete = irqHandler;
}

static uint32_t getInterruptFlags() { return ControlHal::getInterruptFlags(STREAM_ID); }

/**
* IRQ handler of the DMA channel.
*
* Reads the IRQ status and checks for error or transfer complete. In case
* of error the DMA channel will be disabled.
*/
static void interruptHandler()
{
uint32_t currIsrs = ControlHal::getInterruptFlags(STREAM_ID);
ControlHal::clearInterruptFlags(STREAM_ID);
if (currIsrs & (uint32_t(InterruptStatusMsks::TRANSFER_ERROR) |
uint32_t(InterruptStatusMsks::DIRECT_MODE_ERROR) |
uint32_t(InterruptStatusMsks::FIFO_ERROR)))
{
if (transferError != nullptr)
{
transferError();
}
}
if ((currIsrs & uint32_t(InterruptStatusMsks::TRANSFER_COMPLETE)) && transferComplete)
{
transferComplete();
}
}

/**
* Enable the IRQ vector of the channel.
*
* @param[in] priority Priority of the IRQ
*/
static void enableInterruptVector(uint32_t priority = 1)
{
NVIC_SetPriority(DmaBase::Nvic<ID>::DmaIrqs[uint32_t(STREAM_ID)], priority);
NVIC_EnableIRQ(DmaBase::Nvic<ID>::DmaIrqs[uint32_t(STREAM_ID)]);
}

/**
* Disable the IRQ vector of the channel.
*/
static void disableInterruptVector()
{
NVIC_DisableIRQ(DmaBase::Nvic<ID>::DmaIrqs[uint32_t(STREAM_ID)]);
}

/**
* Enable the specified interrupt of the channel.
*/
static void enableInterrupt(Interrupt_t irq) { StreamHal::enableInterrupt(irq); }

/**
* Disable the specified interrupt of the channel.
*/
static void disableInterrupt(Interrupt_t irq) { StreamHal::disableInterrupt(irq); }

template<DmaBase::ChannelSelection Ch, Peripheral Periph, Signal Sig>
struct RequestMapping {
};
private:
static inline DmaBase::IrqHandler transferError{nullptr};
static inline DmaBase::IrqHandler transferComplete{nullptr};
};
}; // class DmaController

/*
* Derive DMA controller classes for convenience. Every derived class defines
* the streams available on that controller.
*/
%% for streams in dma["streams"]
class Dma{{ streams.instance }} : public DmaController<{{ streams.instance }}>
{
public:
%% for stream in streams.stream
using Stream{{ stream.position }} = DmaController<{{ streams.instance }}>::Stream<DmaBase::StreamID::STREAM_{{ stream.position }}>;
%% endfor
}; // class Dma1

%% endfor

/*
* Specialization of the RequestMapping. For all hardware supported by DMA the
* RequestMapping structure defines the channel and the Request. It can be used
* by hardware classes to verify that the provided channel is valid and to
* get the value to set in setPeripheralRequest().
*
* Example:
* template <class DmaRx, class DmaTx>
* class SpiMaster1_Dma : public SpiMaster1
* {
* using RxChannel = typename DmaRx::template RequestMapping<Peripheral::Spi1, DmaBase::Signal::Rx>::Channel;
* using TxChannel = typename DmaTx::template RequestMapping<Peripheral::Spi1, DmaBase::Signal::Tx>::Channel;
* static constexpr DmaBase::Request RxRequest = DmaRx::template RequestMapping<Peripheral::Spi1, DmaBase::Signal::Rx>::Request;
* static constexpr DmaBase::Request TxRequest = DmaTx::template RequestMapping<Peripheral::Spi1, DmaBase::Signal::Tx>::Request;
*
* ...
* };
*/
%% for controller in dmaController
%% for streamChMapping in controller.stream_ch_mapping
%% for driver in streamChMapping.drivers
template<>
template<>
template<>
struct DmaController<{{ controller.dma_controller }}>::Stream<DmaBase::StreamID::STREAM_{{ streamChMapping.stream }}>::RequestMapping<DmaBase::ChannelSelection::CHANNEL_{{ streamChMapping.channel }}, Peripheral::{{ driver["peripheral"] }}, DmaBase::Signal::{{ driver["signal"] }}>
{
using Stream = DmaController<{{ controller.dma_controller }}>::Stream<DmaBase::StreamID::STREAM_{{ streamChMapping.stream }}>;
static constexpr DmaBase::ChannelSelection Channel = DmaBase::ChannelSelection::CHANNEL_{{ streamChMapping.channel }};
};

%% endfor
%% endfor
%% endfor
} // namespace platform
} // namespace modm

#endif // MODM_STM32_DMA_HPP

Loading