Skip to content

Commit 901a3dc

Browse files
wald-zatchris-durand
authored andcommitted
[examples] Add ADC with DMA example for STM32F0
Co-authored-by: Christopher Durand <[email protected]>
1 parent 2d8a989 commit 901a3dc

File tree

4 files changed

+243
-0
lines changed

4 files changed

+243
-0
lines changed
+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright (c) 2024, Zühlke Engineering (Austria) GmbH
3+
*
4+
* This file is part of the modm project.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public
7+
* License, v. 2.0. If a copy of the MPL was not distributed with this
8+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
11+
#ifndef EXAMPLE_ADCDMA_HPP
12+
#define EXAMPLE_ADCDMA_HPP
13+
14+
#include <modm/platform.hpp>
15+
#include <span>
16+
17+
template<class Adc, class DmaChannel>
18+
class AdcDma
19+
{
20+
struct Dma
21+
{
22+
using AdcChannel =
23+
typename DmaChannel::template RequestMapping<modm::platform::Peripheral::Adc1>::Channel;
24+
static constexpr modm::platform::DmaBase::Request AdcRequest =
25+
DmaChannel::template RequestMapping<modm::platform::Peripheral::Adc1>::Request;
26+
};
27+
28+
public:
29+
/**
30+
* \brief initialize both adc and dma
31+
* @tparam SystemClock
32+
*/
33+
template<class SystemClock>
34+
static void
35+
initialize(std::span<uint16_t> buffer,
36+
modm::platform::DmaBase::Priority priority = modm::platform::DmaBase::Priority::Low,
37+
modm::platform::DmaBase::CircularMode circularMode =
38+
modm::platform::DmaBase::CircularMode::Enabled,
39+
modm::platform::DmaBase::IrqHandler transferErrorCallback = nullptr,
40+
modm::platform::DmaBase::IrqHandler halfCompletedCallback = nullptr,
41+
modm::platform::DmaBase::IrqHandler completedCallback = nullptr)
42+
{
43+
Dma::AdcChannel::configure(
44+
modm::platform::DmaBase::DataTransferDirection::PeripheralToMemory,
45+
modm::platform::DmaBase::MemoryDataSize::HalfWord,
46+
modm::platform::DmaBase::PeripheralDataSize::HalfWord,
47+
modm::platform::DmaBase::MemoryIncrementMode::Increment,
48+
modm::platform::DmaBase::PeripheralIncrementMode::Fixed, priority, circularMode);
49+
Dma::AdcChannel::setPeripheralAddress(Adc::getDataRegisterAddress());
50+
Dma::AdcChannel::setDataLength(buffer.size());
51+
Dma::AdcChannel::setMemoryAddress(reinterpret_cast<uintptr_t>(buffer.data()));
52+
53+
setTransferErrorCallback(transferErrorCallback);
54+
setHalfCompletedConversionCallback(halfCompletedCallback);
55+
setCompletedConversionCallback(completedCallback);
56+
57+
Dma::AdcChannel::template setPeripheralRequest<Dma::AdcRequest>();
58+
Adc::setDmaMode(Adc::DmaMode::Disabled);
59+
}
60+
61+
static void
62+
startDma()
63+
{
64+
Adc::setDmaMode(Adc::DmaMode::Circular);
65+
DmaChannel::start();
66+
}
67+
68+
static void
69+
setTransferErrorCallback(modm::platform::DmaBase::IrqHandler transferErrorCallback)
70+
{
71+
if (transferErrorCallback == nullptr) { return; }
72+
Dma::AdcChannel::enableInterruptVector();
73+
Dma::AdcChannel::enableInterrupt(modm::platform::DmaBase::InterruptEnable::TransferError);
74+
Dma::AdcChannel::setTransferErrorIrqHandler(transferErrorCallback);
75+
}
76+
77+
static void
78+
setHalfCompletedConversionCallback(modm::platform::DmaBase::IrqHandler halfCompletedCallback)
79+
{
80+
if (halfCompletedCallback == nullptr) { return; }
81+
Dma::AdcChannel::enableInterruptVector();
82+
Dma::AdcChannel::enableInterrupt(modm::platform::DmaBase::InterruptEnable::HalfTransfer);
83+
Dma::AdcChannel::setHalfTransferCompleteIrqHandler(halfCompletedCallback);
84+
}
85+
86+
static void
87+
setCompletedConversionCallback(modm::platform::DmaBase::IrqHandler completedCallback)
88+
{
89+
if (completedCallback == nullptr) { return; }
90+
Dma::AdcChannel::enableInterruptVector();
91+
Dma::AdcChannel::enableInterrupt(
92+
modm::platform::DmaBase::InterruptEnable::TransferComplete);
93+
Dma::AdcChannel::setTransferCompleteIrqHandler(completedCallback);
94+
}
95+
};
96+
97+
#endif // EXAMPLE_ADCDMA_HPP
+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright (c) 2024, Zühlke Engineering (Austria) GmbH
3+
*
4+
* This file is part of the modm project.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public
7+
* License, v. 2.0. If a copy of the MPL was not distributed with this
8+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
11+
// This Example uses adc to sample s channels 50 times every 0.5s and store the value
12+
// in a buffer via dma. The adc is set to be triggered by the Timer1 compare event and then to
13+
// sample both channels using scan mode. The compare event is triggered for a defined number of
14+
// times by configuring the Timer1 to use one pulse mode with an repetition count. For more
15+
// information on the timer please refer to the timer register count example. In this configuration,
16+
// the adc sampling process is started by the cpu but handled completely by peripherals clearing CPU
17+
// time for other tasks.
18+
19+
#include <modm/architecture/interface/interrupt.hpp>
20+
#include <modm/board.hpp>
21+
#include <modm/platform.hpp>
22+
23+
#include "adc_dma.hpp"
24+
#include "timer_handler.hpp"
25+
26+
using namespace Board;
27+
using namespace modm::platform;
28+
using Adc1Dma = AdcDma<Adc1, Dma1::Channel1>;
29+
30+
std::array<uint16_t, 100> adc_results{};
31+
volatile bool dma_completed = false;
32+
33+
void
34+
completedCallback()
35+
{
36+
LedD13::toggle();
37+
dma_completed = true;
38+
}
39+
40+
int
41+
main()
42+
{
43+
Board::initialize();
44+
45+
// Use the logging streams to print some messages.
46+
// Change MODM_LOG_LEVEL above to enable or disable these messages
47+
MODM_LOG_INFO << "Start Setup" << modm::endl;
48+
49+
LedD13::setOutput();
50+
LedD13::reset();
51+
52+
Adc1::connect<GpioInputA0::In0>();
53+
Adc1::connect<GpioInputA1::In1>();
54+
55+
Adc1::setSampleTime(Adc1::SampleTime::Cycles3_5);
56+
Adc1::initialize<SystemClock, Adc1::ClockMode::Asynchronous>();
57+
modm::delay(500ms);
58+
// On STM32G0 Event1 means TIM1's channel 4 capture and compare event.
59+
// Each controller has a different trigger mapping, check the reference
60+
// manual for more information on the trigger mapping of your controller.
61+
Adc1::enableRegularConversionExternalTrigger(Adc1::ExternalTriggerPolarity::RisingEdge,
62+
Adc1::RegularConversionExternalTrigger::Event1);
63+
64+
Adc1::setChannels(Adc1::channelSequenceFromPins<GpioInputA0, GpioInputA1>());
65+
Dma1::enable();
66+
Adc1Dma::initialize<SystemClock>(adc_results);
67+
Adc1Dma::setCompletedConversionCallback(completedCallback);
68+
Adc1Dma::startDma();
69+
Adc1::startConversion();
70+
71+
advancedTimerConfig<Timer1>(adc_results.size() / 2 - 1);
72+
timerStart<Timer1>();
73+
74+
while (true)
75+
{
76+
modm::delay(0.5s);
77+
if (!dma_completed) { continue; }
78+
dma_completed = false;
79+
MODM_LOG_INFO << "Measurements"
80+
<< "\r" << modm::endl;
81+
for (uint16_t sample : adc_results) { MODM_LOG_INFO << sample << ", "; }
82+
MODM_LOG_INFO << "\r" << modm::endl;
83+
adc_results.fill(0);
84+
timerStart<Timer1>();
85+
}
86+
return 0;
87+
}
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<library>
2+
<extends>modm:nucleo-g070rb</extends>
3+
<options>
4+
<option name="modm:build:build.path">../../../build/nucleo_g070rb/adc_dma</option>
5+
</options>
6+
<modules>
7+
<module>modm:build:scons</module>
8+
<module>modm:platform:timer:1</module>
9+
<module>modm:platform:adc</module>
10+
<module>modm:platform:dma</module>
11+
</modules>
12+
</library>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) 2024, Zühlke Engineering (Austria) GmbH
3+
*
4+
* This file is part of the modm project.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public
7+
* License, v. 2.0. If a copy of the MPL was not distributed with this
8+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
11+
#ifndef EXAMPLE_TimerHANDLER_HPP
12+
#define EXAMPLE_TimerHANDLER_HPP
13+
14+
#include <modm/architecture/interface/interrupt.hpp>
15+
#include <modm/board.hpp>
16+
#include <modm/platform.hpp>
17+
18+
#include "adc_dma.hpp"
19+
20+
using namespace Board;
21+
using namespace modm::platform;
22+
using namespace std::chrono_literals;
23+
24+
template<class Timer>
25+
void
26+
advancedTimerConfig(uint8_t repetitionCount)
27+
{
28+
Timer::enable();
29+
Timer::setMode(Timer::Mode::UpCounter, Timer::SlaveMode::Disabled,
30+
Timer::SlaveModeTrigger::Internal0, Timer::MasterMode::Update, true);
31+
Timer::setPrescaler(84);
32+
Timer::setOverflow(9999);
33+
Timer::setRepetitionCount(repetitionCount);
34+
35+
Timer::enableOutput();
36+
Timer::configureOutputChannel(4, Timer::OutputCompareMode::Pwm, 999, Timer::PinState::Enable);
37+
}
38+
39+
template<class Timer>
40+
static void
41+
timerStart()
42+
{
43+
Timer::applyAndReset();
44+
Timer::start();
45+
}
46+
47+
#endif // EXAMPLE_TimerHANDLER_HPP

0 commit comments

Comments
 (0)