Skip to content

Commit b5423b8

Browse files
wald-zatvictorandrehc
authored andcommitted
[stm32] add dma capabilities to G0 adc
1 parent 009bb06 commit b5423b8

File tree

9 files changed

+566
-0
lines changed

9 files changed

+566
-0
lines changed
Lines changed: 97 additions & 0 deletions
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+
16+
template<class Adc, class DmaChannel>
17+
class AdcDma
18+
{
19+
struct Dma
20+
{
21+
using AdcChannel =
22+
typename DmaChannel::template RequestMapping<modm::platform::Peripheral::Adc1>::Channel;
23+
static constexpr modm::platform::DmaBase::Request AdcRequest =
24+
DmaChannel::template RequestMapping<modm::platform::Peripheral::Adc1>::Request;
25+
};
26+
27+
public:
28+
/**
29+
* \brief initialize both adc and dma
30+
* @tparam SystemClock
31+
*/
32+
template<class SystemClock>
33+
static void
34+
initialize(uintptr_t destination_ptr, size_t length,
35+
modm::platform::DmaBase::Priority priority = modm::platform::DmaBase::Priority::Low,
36+
modm::platform::DmaBase::CircularMode circularMode =
37+
modm::platform::DmaBase::CircularMode::Enabled,
38+
modm::platform::DmaBase::IrqHandler transferErrorCallback = nullptr,
39+
modm::platform::DmaBase::IrqHandler halfCompletedCallback = nullptr,
40+
modm::platform::DmaBase::IrqHandler completedCallback = nullptr)
41+
{
42+
Dma::AdcChannel::configure(
43+
modm::platform::DmaBase::DataTransferDirection::PeripheralToMemory,
44+
modm::platform::DmaBase::MemoryDataSize::HalfWord,
45+
modm::platform::DmaBase::PeripheralDataSize::HalfWord,
46+
modm::platform::DmaBase::MemoryIncrementMode::Increment,
47+
modm::platform::DmaBase::PeripheralIncrementMode::Fixed, priority, circularMode);
48+
Dma::AdcChannel::setPeripheralAddress(Adc::getDataRegisterAddress());
49+
Dma::AdcChannel::setDataLength(length);
50+
Dma::AdcChannel::setMemoryAddress(destination_ptr);
51+
52+
setTransferErrorCallback(transferErrorCallback);
53+
setHalfCompletedConversionCallback(halfCompletedCallback);
54+
setCompletedConversionCallback(completedCallback);
55+
56+
Dma::AdcChannel::template setPeripheralRequest<Dma::AdcRequest>();
57+
Adc::disableDmaMode();
58+
}
59+
60+
static void
61+
startDma()
62+
{
63+
Adc::enableDmaRequests();
64+
Adc::enableDmaMode();
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
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
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+
adc_results.fill(0);
53+
54+
Adc1::connect<GpioInputA0::In0>();
55+
Adc1::connect<GpioInputA1::In1>();
56+
57+
const auto a0_channel = Adc1::getPinChannel<GpioInputA0>();
58+
const auto a1_channel = Adc1::getPinChannel<GpioInputA1>();
59+
Adc1::setSampleTime(Adc1::SampleTime::Cycles3_5);
60+
Adc1::initialize<SystemClock, Adc1::ClockMode::Asynchronous>();
61+
Adc1::enableScanMode();
62+
modm::delay(500ms);
63+
// On STM32G0 Event1 means TIM1's channel 4 capture and compare event.
64+
// Each controller has a different trigger mapping, check the reference
65+
// manual for more information on the trigger mapping of your controller.
66+
Adc1::enableRegularConversionExternalTrigger(Adc1::ExternalTriggerPolarity::RisingEdge,
67+
Adc1::RegularConversionExternalTrigger::Event1);
68+
Adc1::addChannel(a0_channel);
69+
Adc1::addChannel(a1_channel);
70+
Dma1::enable();
71+
Adc1Dma::initialize<SystemClock>((uintptr_t)(&adc_results[0]), adc_results.size());
72+
Adc1Dma::setCompletedConversionCallback(completedCallback);
73+
Adc1Dma::startDma();
74+
Adc1::startConversion();
75+
76+
advancedTimerConfig<Timer1>(adc_results.size() / 2 - 1);
77+
timerStart<Timer1>();
78+
79+
while (true)
80+
{
81+
modm::delay(0.5s);
82+
if (!dma_completed) { continue; }
83+
dma_completed = false;
84+
MODM_LOG_INFO << "Measurements"
85+
<< "\r" << modm::endl;
86+
for (const uint16_t& sample : adc_results) { MODM_LOG_INFO << sample << ", "; }
87+
MODM_LOG_INFO << "\r" << modm::endl;
88+
adc_results.fill(0);
89+
timerStart<Timer1>();
90+
}
91+
return 0;
92+
}
Lines changed: 12 additions & 0 deletions
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>
Lines changed: 47 additions & 0 deletions
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

src/modm/platform/adc/stm32f0/adc.hpp.in

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright (c) 2018, Álan Crístoffer
44
* Copyright (c) 2018, Carl Treudler
55
* Copyright (c) 2018-2019, Niklas Hauser
6+
* Copyright (c) 2023, Daniel Waldhaeusl (Zuehlke Engineering)
67
*
78
* This file is part of the modm project.
89
*
@@ -140,6 +141,32 @@ public:
140141
};
141142
MODM_FLAGS32(InterruptFlag);
142143

144+
enum class ExternalTriggerPolarity
145+
{
146+
NoTriggerDetection = 0x0u,
147+
RisingEdge = 0x1u,
148+
FallingEdge = 0x2u,
149+
RisingAndFallingEdge = 0x3u,
150+
};
151+
152+
/**
153+
* Enum mapping all events on a external trigger converter.
154+
* The source mapped to each event varies on controller family,
155+
* refer to the ADC external trigger section on reference manual
156+
* of your controller for more information
157+
*/
158+
enum class RegularConversionExternalTrigger
159+
{
160+
Event0 = 0x0u,
161+
Event1 = 0x1u,
162+
Event2 = 0x2u,
163+
Event3 = 0x3u,
164+
Event4 = 0x4u,
165+
Event5 = 0x5u,
166+
Event6 = 0x6u,
167+
Event7 = 0x7u,
168+
};
169+
143170
public:
144171
// start inherited documentation
145172
template< class... Signals >
@@ -169,6 +196,9 @@ public:
169196
static void
170197
initialize();
171198

199+
static inline void
200+
enable();
201+
172202
static inline void
173203
disable();
174204

@@ -314,6 +344,78 @@ public:
314344
static inline void
315345
acknowledgeInterruptFlags(InterruptFlag_t flags);
316346

347+
%% if target.family in ["g0"]
348+
static inline uintptr_t
349+
getDataRegisterAddress();
350+
351+
static inline void
352+
enableRegularConversionExternalTrigger(
353+
ExternalTriggerPolarity externalTriggerPolarity,
354+
RegularConversionExternalTrigger regularConversionExternalTrigger);
355+
356+
/// Add a channel to conversion group.
357+
static inline bool
358+
addChannel(const Channel channel);
359+
360+
/**
361+
* Enable Dma mode for the ADC
362+
*/
363+
static inline void
364+
enableDmaMode();
365+
366+
/**
367+
* Disable Dma mode for the ADC
368+
*/
369+
static inline void
370+
disableDmaMode();
371+
372+
/**
373+
* get if adc is enabled
374+
* @return true if ADC_CR2_ADON bit is set, false otherwise
375+
*/
376+
static inline bool
377+
getAdcEnabled();
378+
379+
/**
380+
* enable DMA selection for the ADC. If this is enabled DMA
381+
* requests are issued as long as data are converted and
382+
* the adc has dma enabled
383+
*/
384+
static inline void
385+
enableDmaRequests();
386+
387+
/**
388+
* disable dma selection for the ADC. If this is disabled
389+
* no new DMA requests are issued after last transfer
390+
*/
391+
static inline void
392+
disableDmaRequests();
393+
394+
/**
395+
* Waits until the CCR bit is set.
396+
*/
397+
static inline void
398+
waitChannelConfigReady();
399+
400+
/**
401+
* Resets the CCR bit.
402+
*/
403+
static inline void
404+
resetChannelConfigReady();
405+
406+
/**
407+
* Enables scan mode
408+
*/
409+
static inline void
410+
enableScanMode();
411+
412+
/**
413+
* Disables scan mode
414+
*/
415+
static inline void
416+
disableScanMode();
417+
%% endif
418+
317419
public:
318420
static constexpr uint8_t TS_CAL1_TEMP{30};
319421
%% if target.family in ["f0"]

0 commit comments

Comments
 (0)