Skip to content

Commit

Permalink
[examples] Add ADC with DMA example for STM32F0
Browse files Browse the repository at this point in the history
Co-authored-by: Christopher Durand <christopher.durand@rwth-aachen.de>
  • Loading branch information
2 people authored and salkinium committed May 19, 2024
1 parent 2d8a989 commit 901a3dc
Show file tree
Hide file tree
Showing 4 changed files with 243 additions and 0 deletions.
97 changes: 97 additions & 0 deletions examples/nucleo_g070rb/adc_dma/adc_dma.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright (c) 2024, Zühlke Engineering (Austria) GmbH
*
* 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 EXAMPLE_ADCDMA_HPP
#define EXAMPLE_ADCDMA_HPP

#include <modm/platform.hpp>
#include <span>

template<class Adc, class DmaChannel>
class AdcDma
{
struct Dma
{
using AdcChannel =
typename DmaChannel::template RequestMapping<modm::platform::Peripheral::Adc1>::Channel;
static constexpr modm::platform::DmaBase::Request AdcRequest =
DmaChannel::template RequestMapping<modm::platform::Peripheral::Adc1>::Request;
};

public:
/**
* \brief initialize both adc and dma
* @tparam SystemClock
*/
template<class SystemClock>
static void
initialize(std::span<uint16_t> buffer,
modm::platform::DmaBase::Priority priority = modm::platform::DmaBase::Priority::Low,
modm::platform::DmaBase::CircularMode circularMode =
modm::platform::DmaBase::CircularMode::Enabled,
modm::platform::DmaBase::IrqHandler transferErrorCallback = nullptr,
modm::platform::DmaBase::IrqHandler halfCompletedCallback = nullptr,
modm::platform::DmaBase::IrqHandler completedCallback = nullptr)
{
Dma::AdcChannel::configure(
modm::platform::DmaBase::DataTransferDirection::PeripheralToMemory,
modm::platform::DmaBase::MemoryDataSize::HalfWord,
modm::platform::DmaBase::PeripheralDataSize::HalfWord,
modm::platform::DmaBase::MemoryIncrementMode::Increment,
modm::platform::DmaBase::PeripheralIncrementMode::Fixed, priority, circularMode);
Dma::AdcChannel::setPeripheralAddress(Adc::getDataRegisterAddress());
Dma::AdcChannel::setDataLength(buffer.size());
Dma::AdcChannel::setMemoryAddress(reinterpret_cast<uintptr_t>(buffer.data()));

setTransferErrorCallback(transferErrorCallback);
setHalfCompletedConversionCallback(halfCompletedCallback);
setCompletedConversionCallback(completedCallback);

Dma::AdcChannel::template setPeripheralRequest<Dma::AdcRequest>();
Adc::setDmaMode(Adc::DmaMode::Disabled);
}

static void
startDma()
{
Adc::setDmaMode(Adc::DmaMode::Circular);
DmaChannel::start();
}

static void
setTransferErrorCallback(modm::platform::DmaBase::IrqHandler transferErrorCallback)
{
if (transferErrorCallback == nullptr) { return; }
Dma::AdcChannel::enableInterruptVector();
Dma::AdcChannel::enableInterrupt(modm::platform::DmaBase::InterruptEnable::TransferError);
Dma::AdcChannel::setTransferErrorIrqHandler(transferErrorCallback);
}

static void
setHalfCompletedConversionCallback(modm::platform::DmaBase::IrqHandler halfCompletedCallback)
{
if (halfCompletedCallback == nullptr) { return; }
Dma::AdcChannel::enableInterruptVector();
Dma::AdcChannel::enableInterrupt(modm::platform::DmaBase::InterruptEnable::HalfTransfer);
Dma::AdcChannel::setHalfTransferCompleteIrqHandler(halfCompletedCallback);
}

static void
setCompletedConversionCallback(modm::platform::DmaBase::IrqHandler completedCallback)
{
if (completedCallback == nullptr) { return; }
Dma::AdcChannel::enableInterruptVector();
Dma::AdcChannel::enableInterrupt(
modm::platform::DmaBase::InterruptEnable::TransferComplete);
Dma::AdcChannel::setTransferCompleteIrqHandler(completedCallback);
}
};

#endif // EXAMPLE_ADCDMA_HPP
87 changes: 87 additions & 0 deletions examples/nucleo_g070rb/adc_dma/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright (c) 2024, Zühlke Engineering (Austria) GmbH
*
* 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/.
*/

// This Example uses adc to sample s channels 50 times every 0.5s and store the value
// in a buffer via dma. The adc is set to be triggered by the Timer1 compare event and then to
// sample both channels using scan mode. The compare event is triggered for a defined number of
// times by configuring the Timer1 to use one pulse mode with an repetition count. For more
// information on the timer please refer to the timer register count example. In this configuration,
// the adc sampling process is started by the cpu but handled completely by peripherals clearing CPU
// time for other tasks.

#include <modm/architecture/interface/interrupt.hpp>
#include <modm/board.hpp>
#include <modm/platform.hpp>

#include "adc_dma.hpp"
#include "timer_handler.hpp"

using namespace Board;
using namespace modm::platform;
using Adc1Dma = AdcDma<Adc1, Dma1::Channel1>;

std::array<uint16_t, 100> adc_results{};
volatile bool dma_completed = false;

void
completedCallback()
{
LedD13::toggle();
dma_completed = true;
}

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

// Use the logging streams to print some messages.
// Change MODM_LOG_LEVEL above to enable or disable these messages
MODM_LOG_INFO << "Start Setup" << modm::endl;

LedD13::setOutput();
LedD13::reset();

Adc1::connect<GpioInputA0::In0>();
Adc1::connect<GpioInputA1::In1>();

Adc1::setSampleTime(Adc1::SampleTime::Cycles3_5);
Adc1::initialize<SystemClock, Adc1::ClockMode::Asynchronous>();
modm::delay(500ms);
// On STM32G0 Event1 means TIM1's channel 4 capture and compare event.
// Each controller has a different trigger mapping, check the reference
// manual for more information on the trigger mapping of your controller.
Adc1::enableRegularConversionExternalTrigger(Adc1::ExternalTriggerPolarity::RisingEdge,
Adc1::RegularConversionExternalTrigger::Event1);

Adc1::setChannels(Adc1::channelSequenceFromPins<GpioInputA0, GpioInputA1>());
Dma1::enable();
Adc1Dma::initialize<SystemClock>(adc_results);
Adc1Dma::setCompletedConversionCallback(completedCallback);
Adc1Dma::startDma();
Adc1::startConversion();

advancedTimerConfig<Timer1>(adc_results.size() / 2 - 1);
timerStart<Timer1>();

while (true)
{
modm::delay(0.5s);
if (!dma_completed) { continue; }
dma_completed = false;
MODM_LOG_INFO << "Measurements"
<< "\r" << modm::endl;
for (uint16_t sample : adc_results) { MODM_LOG_INFO << sample << ", "; }
MODM_LOG_INFO << "\r" << modm::endl;
adc_results.fill(0);
timerStart<Timer1>();
}
return 0;
}
12 changes: 12 additions & 0 deletions examples/nucleo_g070rb/adc_dma/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<library>
<extends>modm:nucleo-g070rb</extends>
<options>
<option name="modm:build:build.path">../../../build/nucleo_g070rb/adc_dma</option>
</options>
<modules>
<module>modm:build:scons</module>
<module>modm:platform:timer:1</module>
<module>modm:platform:adc</module>
<module>modm:platform:dma</module>
</modules>
</library>
47 changes: 47 additions & 0 deletions examples/nucleo_g070rb/adc_dma/timer_handler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2024, Zühlke Engineering (Austria) GmbH
*
* 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 EXAMPLE_TimerHANDLER_HPP
#define EXAMPLE_TimerHANDLER_HPP

#include <modm/architecture/interface/interrupt.hpp>
#include <modm/board.hpp>
#include <modm/platform.hpp>

#include "adc_dma.hpp"

using namespace Board;
using namespace modm::platform;
using namespace std::chrono_literals;

template<class Timer>
void
advancedTimerConfig(uint8_t repetitionCount)
{
Timer::enable();
Timer::setMode(Timer::Mode::UpCounter, Timer::SlaveMode::Disabled,
Timer::SlaveModeTrigger::Internal0, Timer::MasterMode::Update, true);
Timer::setPrescaler(84);
Timer::setOverflow(9999);
Timer::setRepetitionCount(repetitionCount);

Timer::enableOutput();
Timer::configureOutputChannel(4, Timer::OutputCompareMode::Pwm, 999, Timer::PinState::Enable);
}

template<class Timer>
static void
timerStart()
{
Timer::applyAndReset();
Timer::start();
}

#endif // EXAMPLE_TimerHANDLER_HPP

0 comments on commit 901a3dc

Please sign in to comment.