Skyward boardcore
Loading...
Searching...
No Matches
DMA.h
Go to the documentation of this file.
1/* Copyright (c) 2025 Skyward Experimental Rocketry
2 * Author: Alberto Nidasio, Fabrizio Monti
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#pragma once
24
25#include <kernel/scheduler/scheduler.h>
26#include <kernel/sync.h>
27
28#include <chrono>
29#include <functional>
30#include <map>
31
32#include "DMADefs.h"
33
34namespace Boardcore
35{
36
42{
43 enum class Direction : uint16_t
44 {
45 MEM_TO_MEM = DMA_SxCR_DIR_1,
46 MEM_TO_PER = DMA_SxCR_DIR_0,
47 PER_TO_MEM = 0,
48 };
49
60 enum class Priority : uint32_t
61 {
62 VERY_HIGH = DMA_SxCR_PL,
63 HIGH = DMA_SxCR_PL_1,
64 MEDIUM = DMA_SxCR_PL_0,
65 LOW = 0,
66 };
67
68 enum class DataSize : uint8_t
69 {
70 BITS_8 = 0,
71 BITS_16,
72 BITS_32,
73 };
74
79 volatile void* srcAddress = nullptr;
80 volatile void* dstAddress = nullptr;
81 volatile void* secondMemoryAddress = nullptr;
82 uint16_t numberOfDataItems = 0;
83 bool srcIncrement = false;
84 bool dstIncrement = false;
85
90 bool circularMode = false;
91
97 bool doubleBufferMode = false;
99
107
117
131
144};
145
146// Forward declaration
147class DMAStream;
148class DMAStreamGuard;
149
155{
156public:
157 // cppcheck-suppress noExplicitConstructor
158
160
161 static DMADriver& instance();
162
167
180 std::chrono::nanoseconds timeout = std::chrono::nanoseconds::zero());
181
192 DMADefs::Peripherals peripheral,
193 std::chrono::nanoseconds timeout = std::chrono::nanoseconds::zero());
194
196
197private:
198 DMADriver();
199
203 void IRQwakeupThread(DMAStream& stream);
204
205 miosix::FastMutex mutex;
206 miosix::ConditionVariable cv;
207 std::map<DMADefs::DMAStreamId, DMAStream> streams;
208
209public:
210 DMADriver(const DMADriver&) = delete;
211 DMADriver& operator=(const DMADriver&) = delete;
212};
213
219{
220 friend DMADriver;
221
222public:
223 // cppcheck-suppress noExplicitConstructor
224
228 void setup(DMATransaction& transaction);
229
234 void enable();
235
243 void disable();
244
253 void waitForHalfTransfer();
254
263
275 bool timedWaitForHalfTransfer(std::chrono::nanoseconds timeout_ns);
276
287 bool timedWaitForTransferComplete(std::chrono::nanoseconds timeout_ns);
288
289 void setHalfTransferCallback(std::function<void()> callback);
290
292
293 void setTransferCompleteCallback(std::function<void()> callback);
294
296
297 void setErrorCallback(std::function<void()> callback);
298
299 void resetErrorCallback();
300
306 void readFlags();
307
315 bool setNumberOfDataItems(const uint16_t nBytes);
316
321 void setChannel(const DMADefs::Channel channel);
322
326 inline bool getHalfTransferFlagStatus() { return halfTransferFlag; }
327
331 inline bool getTransferCompleteFlagStatus() { return transferCompleteFlag; }
332
336 inline bool getTransferErrorFlagStatus() { return transferErrorFlag; }
337
341 inline bool getFifoErrorFlagStatus() { return fifoErrorFlag; }
342
347 inline bool getDirectModeErrorFlagStatus() { return directModeErrorFlag; }
348
355
356 inline DMADefs::DMAStreamId getStreamId() { return id; }
357
358 inline DMADefs::Channel getCurrentChannel() { return currentChannel; }
359
361 {
362 *IFCR |= DMA_LIFCR_CHTIF0 << IFindex;
363 }
364
366 {
367 *IFCR |= DMA_LIFCR_CTCIF0 << IFindex;
368 }
369
371 {
372 *IFCR |= DMA_LIFCR_CTEIF0 << IFindex;
373 }
374
375 inline void clearFifoErrorFlag() { *IFCR |= DMA_LIFCR_CFEIF0 << IFindex; }
376
378 {
379 *IFCR |= DMA_LIFCR_CDMEIF0 << IFindex;
380 }
381
386 inline void clearAllFlags()
387 {
388 *IFCR |= (DMA_LIFCR_CHTIF0 | DMA_LIFCR_CTCIF0 | DMA_LIFCR_CTEIF0 |
389 DMA_LIFCR_CFEIF0 | DMA_LIFCR_CDMEIF0)
390 << IFindex;
391 }
392
393private:
395
396 DMATransaction currentSetup;
397
402 miosix::Thread* waitingThread = nullptr;
403
404 // These flags are set by the interrupt routine and tells the user
405 // which event were triggered
406 bool halfTransferFlag = false;
407 bool transferCompleteFlag = false;
408 bool transferErrorFlag = false;
409 bool fifoErrorFlag = false;
410 bool directModeErrorFlag = false;
411
412 std::function<void()> halfTransferCallback;
413 std::function<void()> transferCompleteCallback;
414 std::function<void()> errorCallback;
415
416 const DMADefs::DMAStreamId id;
417 DMADefs::Channel currentChannel;
418 DMA_Stream_TypeDef* registers;
419
420 volatile uint32_t* ISR;
421 volatile uint32_t* IFCR;
422 int IFindex;
423
424 inline bool waitForInterruptEventImpl(
425 bool isInterruptEnabled, std::function<bool()> getEventStatus,
426 std::function<void()> clearEventStatus, bool& eventTriggered,
427 long long timeout_ns)
428 {
429 // Return value: true if the event was triggered, false if the timeout
430 // expired
431 bool result = false;
432
433 // If the interrupt is enabled we can just pause and wait for it.
434 // Otherwise we need to pool the flag.
435 if (isInterruptEnabled)
436 {
437 // Here we have 2 cases:
438 // - This function has been called after the interrupt fired. In
439 // this case the interrupt saves the flags status and we check them
440 // - The interrupt has not yet fired. We pause the thread and the
441 // interrupt will wake us up
442
443 if (eventTriggered)
444 {
445 result = true;
446 }
447 else
448 {
449 // Save the current thread pointer
450 waitingThread = miosix::Thread::getCurrentThread();
451
452 // Wait until the thread is woken up and the pointer is cleared
453 miosix::FastInterruptDisableLock dLock;
454 if (timeout_ns >= 0)
455 {
456 do
457 {
458 if (miosix::Thread::IRQenableIrqAndTimedWait(
459 dLock, timeout_ns + miosix::getTime()) ==
460 miosix::TimedWaitResult::Timeout)
461 {
462 result = false;
463
464 // If the timeout expired we clear the thread
465 // pointer so that the interrupt, if it will occur,
466 // will not wake up the thread (and we can exit the
467 // while loop)
468 waitingThread = nullptr;
469 }
470 else
471 {
472 result = true;
473 }
474 } while (waitingThread);
475 }
476 else
477 {
478 do
479 {
480 miosix::Thread::IRQenableIrqAndWait(dLock);
481 } while (waitingThread);
482 result = true;
483 }
484 }
485
486 // Before returning we need to clear the flags otherwise we could
487 // get misfires
488 eventTriggered = false;
489 }
490 else
491 {
492 // Pool the flag if the user did not enable the interrupt
493 if (timeout_ns >= 0)
494 {
495 const long long start = miosix::getTime();
496
497 do
498 {
499 readFlags();
500 } while (!getEventStatus() &&
501 miosix::getTime() - start < timeout_ns);
502
503 result = getEventStatus();
504 }
505 else
506 {
507 while (!getEventStatus())
508 readFlags();
509 result = true;
510 }
511
512 if (result)
513 {
514 // Clear the flag
515 clearEventStatus();
516 }
517 }
518
519 return result;
520 }
521
522#ifdef STM32F767xx
529 void invalidateCache();
530#endif // STM32F767xx
531
532public:
533 DMAStream(const DMAStream&) = delete;
534 DMAStream& operator=(const DMAStream&) = delete;
535
536 DMAStream(DMAStream&&) noexcept = default;
537 DMAStream& operator=(DMAStream&&) noexcept = default;
538};
539
544{
545public:
546 // cppcheck-suppress noExplicitConstructor
547 DMAStreamGuard(DMAStream* ptr) : pStream(ptr) {}
548
550 {
551 if (pStream != nullptr)
552 DMADriver::instance().releaseStream(pStream->getStreamId());
553 }
554
557
558 DMAStreamGuard(DMAStreamGuard&&) noexcept = default;
559 DMAStreamGuard& operator=(DMAStreamGuard&&) noexcept = default;
560
561 DMAStream* operator->();
562
567 inline bool isValid() { return pStream != nullptr; }
568
569private:
570 DMAStream* const pStream;
571};
572
573} // namespace Boardcore
This class is responsible for streams acquisition, streams release and interrupt handling.
Definition DMA.h:155
DMADriver & operator=(const DMADriver &)=delete
DMAStreamGuard acquireStreamForPeripheral(DMADefs::Peripherals peripheral, std::chrono::nanoseconds timeout=std::chrono::nanoseconds::zero())
Try to acquire a stream that is connected to the specified peripheral.
Definition DMA.cpp:359
static DMADriver & instance()
Definition DMA.cpp:314
DMAStreamGuard acquireStream(DMADefs::DMAStreamId id, DMADefs::Channel channel, std::chrono::nanoseconds timeout=std::chrono::nanoseconds::zero())
Try to acquire the specified stream and initialize it with the correct channel.
Definition DMA.cpp:329
DMADriver(const DMADriver &)=delete
void IRQhandleInterrupt(DMADefs::DMAStreamId id)
Definition DMA.cpp:270
void releaseStream(DMADefs::DMAStreamId id)
Definition DMA.cpp:402
bool tryStream(DMADefs::DMAStreamId id)
Definition DMA.cpp:320
Simple RAII class to handle DMA streams.
Definition DMA.h:544
DMAStreamGuard(DMAStreamGuard &&) noexcept=default
DMAStreamGuard & operator=(const DMAStreamGuard &)=delete
DMAStreamGuard(const DMAStreamGuard &)=delete
DMAStreamGuard(DMAStream *ptr)
Definition DMA.h:547
This class represents the actual DMA stream. It can be used to setup, start and stop DMA transactions...
Definition DMA.h:219
bool getHalfTransferFlagStatus()
Returns the last read status of the half transfer flag.
Definition DMA.h:326
bool timedWaitForTransferComplete(std::chrono::nanoseconds timeout_ns)
Wait for the transfer complete signal. The caller waits for the corresponding interrupt,...
Definition DMA.cpp:587
void clearDirectModeErrorFlag()
Definition DMA.h:377
void resetTransferCompleteCallback()
Definition DMA.cpp:661
void disable()
Stop the DMA transaction (if running). This is equivalent to killing the transaction: DO NOT expect t...
Definition DMA.cpp:554
void clearFifoErrorFlag()
Definition DMA.h:375
void clearTransferErrorFlag()
Definition DMA.h:370
void clearAllFlags()
Clear all the flags for the selected stream in the DMA ISR register (LISR or HISR depending on the se...
Definition DMA.h:386
int getCurrentBufferNumber()
Returns the number of the buffer currently in use when in double buffer mode.
Definition DMA.cpp:703
bool getTransferCompleteFlagStatus()
Returns the last read status of the transfer complete flag.
Definition DMA.h:331
void setup(DMATransaction &transaction)
Setup the stream with the given configuration.
Definition DMA.cpp:427
void resetErrorCallback()
Definition DMA.cpp:671
bool timedWaitForHalfTransfer(std::chrono::nanoseconds timeout_ns)
Wait for the half transfer complete signal. The caller waits for the corresponding interrupt,...
Definition DMA.cpp:578
DMAStream & operator=(const DMAStream &)=delete
void clearTransferCompleteFlag()
Definition DMA.h:365
void setErrorCallback(std::function< void()> callback)
Definition DMA.cpp:666
void resetHalfTransferCallback()
Definition DMA.cpp:654
DMADefs::Channel getCurrentChannel()
Definition DMA.h:358
DMAStream(const DMAStream &)=delete
void setTransferCompleteCallback(std::function< void()> callback)
Definition DMA.cpp:656
bool setNumberOfDataItems(const uint16_t nBytes)
Set the number of bytes to be exchanged during a dma transaction. Useful in case you don't want to ch...
Definition DMA.cpp:684
DMADefs::DMAStreamId getStreamId()
Definition DMA.h:356
void enable()
Activate the stream. As soon as the stream is enabled, it serves any DMA request from/to the peripher...
Definition DMA.cpp:536
bool getDirectModeErrorFlagStatus()
Returns the last read status of the direct mode (default mode) error flag.
Definition DMA.h:347
void waitForTransferComplete()
Wait for the transfer complete signal. The caller waits for the corresponding interrupt,...
Definition DMA.cpp:565
void readFlags()
Reads the current flags status.
Definition DMA.cpp:673
void setHalfTransferCallback(std::function< void()> callback)
Definition DMA.cpp:649
void waitForHalfTransfer()
Wait for the half transfer complete signal. The caller waits for the corresponding interrupt,...
Definition DMA.cpp:556
void clearHalfTransferFlag()
Definition DMA.h:360
bool getFifoErrorFlagStatus()
Returns the last read status of the fifo error flag.
Definition DMA.h:341
void setChannel(const DMADefs::Channel channel)
Select the channel to be used by the stream during the transactions.
Definition DMA.cpp:698
DMAStream(DMAStream &&) noexcept=default
bool getTransferErrorFlagStatus()
Returns the last read status of the transfer error flag.
Definition DMA.h:336
Peripherals
All the peripherals connected to dma.
Definition DMADefs.h:130
Channel
Channels selectable for each dma stream.
Definition DMADefs.h:106
This file includes all the types the logdecoder script will decode.
This is the configuration struct for a DMA transaction.
Definition DMA.h:42
bool enableFifoErrorInterrupt
Definition DMA.h:130
bool enableHalfTransferInterrupt
Definition DMA.h:106
uint16_t numberOfDataItems
Definition DMA.h:82
bool enableTransferErrorInterrupt
Definition DMA.h:116
volatile void * secondMemoryAddress
Definition DMA.h:81
volatile void * dstAddress
Definition DMA.h:80
volatile void * srcAddress
Definition DMA.h:79
bool doubleBufferMode
Enables double buffer mode.
Definition DMA.h:97
bool enableDirectModeErrorInterrupt
Definition DMA.h:143
Direction direction
Definition DMA.h:75
bool enableTransferCompleteInterrupt
Definition DMA.h:98
bool circularMode
Enables circular buffer mode.
Definition DMA.h:90