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
40enum class DMAErrors : uint8_t
41{
42 NO_ERRORS = 0,
43 TIMEOUT = 1, // The timeout expired
44 FIFO_ERROR = 2, // The fifo error flag was raised
45 TRANSFER_ERROR = 3, // The transfer error flag was raised
46 DIRECT_MODE_ERROR = 4, // The direct mode error flag was raised
47 END_OF_BASE_ERRORS = 5 // Used to extend this enum
48};
49
55{
56 enum class Direction : uint16_t
57 {
58 MEM_TO_MEM = DMA_SxCR_DIR_1,
59 MEM_TO_PER = DMA_SxCR_DIR_0,
60 PER_TO_MEM = 0,
61 };
62
73 enum class Priority : uint32_t
74 {
75 VERY_HIGH = DMA_SxCR_PL,
76 HIGH = DMA_SxCR_PL_1,
77 MEDIUM = DMA_SxCR_PL_0,
78 LOW = 0,
79 };
80
81 enum class DataSize : uint8_t
82 {
83 BITS_8 = 0,
84 BITS_16,
85 BITS_32,
86 };
87
92 volatile void* srcAddress = nullptr;
93 volatile void* dstAddress = nullptr;
94 volatile void* secondMemoryAddress = nullptr;
95 uint16_t numberOfDataItems = 0;
96 bool srcIncrement = false;
97 bool dstIncrement = false;
98
103 bool circularMode = false;
104
110 bool doubleBufferMode = false;
112
120
130
144
157};
158
159// Forward declaration
160class DMAStream;
161class DMAStreamGuard;
162
168{
169public:
170 // cppcheck-suppress noExplicitConstructor
171
173
174 static DMADriver& instance();
175
180
193 std::chrono::nanoseconds timeout = std::chrono::nanoseconds::zero());
194
205 DMADefs::Peripherals peripheral,
206 std::chrono::nanoseconds timeout = std::chrono::nanoseconds::zero());
207
209
210private:
211 DMADriver();
212
216 void IRQwakeupThread(DMAStream& stream);
217
218 miosix::FastMutex mutex;
219 miosix::ConditionVariable cv;
220 std::map<DMADefs::DMAStreamId, DMAStream> streams;
221
222public:
223 DMADriver(const DMADriver&) = delete;
224 DMADriver& operator=(const DMADriver&) = delete;
225};
226
232{
233 friend DMADriver;
234
235public:
236 // cppcheck-suppress noExplicitConstructor
237
241 void setup(DMATransaction& transaction);
242
247 void enable();
248
256 void disable();
257
266 void waitForHalfTransfer();
267
276
288 bool timedWaitForHalfTransfer(std::chrono::nanoseconds timeout_ns);
289
300 bool timedWaitForTransferComplete(std::chrono::nanoseconds timeout_ns);
301
302 void setHalfTransferCallback(std::function<void()> callback);
303
305
306 void setTransferCompleteCallback(std::function<void()> callback);
307
309
310 void setErrorCallback(std::function<void()> callback);
311
312 void resetErrorCallback();
313
319 void readFlags();
320
328 bool setNumberOfDataItems(const uint16_t nBytes);
329
334 void setChannel(const DMADefs::Channel channel);
335
339 inline bool getHalfTransferFlagStatus() { return halfTransferFlag; }
340
344 inline bool getTransferCompleteFlagStatus() { return transferCompleteFlag; }
345
349 inline bool getTransferErrorFlagStatus() { return transferErrorFlag; }
350
354 inline bool getFifoErrorFlagStatus() { return fifoErrorFlag; }
355
360 inline bool getDirectModeErrorFlagStatus() { return directModeErrorFlag; }
361
368
369 inline DMADefs::DMAStreamId getStreamId() { return id; }
370
371 inline DMADefs::Channel getCurrentChannel() { return currentChannel; }
372
374 {
375 *IFCR |= DMA_LIFCR_CHTIF0 << IFindex;
376 }
377
379 {
380 *IFCR |= DMA_LIFCR_CTCIF0 << IFindex;
381 }
382
384 {
385 *IFCR |= DMA_LIFCR_CTEIF0 << IFindex;
386 }
387
388 inline void clearFifoErrorFlag() { *IFCR |= DMA_LIFCR_CFEIF0 << IFindex; }
389
391 {
392 *IFCR |= DMA_LIFCR_CDMEIF0 << IFindex;
393 }
394
399 inline void clearAllFlags()
400 {
401 *IFCR |= (DMA_LIFCR_CHTIF0 | DMA_LIFCR_CTCIF0 | DMA_LIFCR_CTEIF0 |
402 DMA_LIFCR_CFEIF0 | DMA_LIFCR_CDMEIF0)
403 << IFindex;
404 }
405
406private:
408
409 DMATransaction currentSetup;
410
415 miosix::Thread* waitingThread = nullptr;
416
417 // These flags are set by the interrupt routine and tells the user
418 // which event were triggered
419 bool halfTransferFlag = false;
420 bool transferCompleteFlag = false;
421 bool transferErrorFlag = false;
422 bool fifoErrorFlag = false;
423 bool directModeErrorFlag = false;
424
425 std::function<void()> halfTransferCallback;
426 std::function<void()> transferCompleteCallback;
427 std::function<void()> errorCallback;
428
429 const DMADefs::DMAStreamId id;
430 DMADefs::Channel currentChannel;
431 DMA_Stream_TypeDef* registers;
432
433 volatile uint32_t* ISR;
434 volatile uint32_t* IFCR;
435 int IFindex;
436
437 inline bool waitForInterruptEventImpl(
438 bool isInterruptEnabled, std::function<bool()> getEventStatus,
439 std::function<void()> clearEventStatus, bool& eventTriggered,
440 long long timeout_ns)
441 {
442 // Return value: true if the event was triggered, false if the timeout
443 // expired
444 bool result = false;
445
446 // If the interrupt is enabled we can just pause and wait for it.
447 // Otherwise we need to pool the flag.
448 if (isInterruptEnabled)
449 {
450 // Here we have 2 cases:
451 // - This function has been called after the interrupt fired. In
452 // this case the interrupt saves the flags status and we check them
453 // - The interrupt has not yet fired. We pause the thread and the
454 // interrupt will wake us up
455
456 if (eventTriggered)
457 {
458 result = true;
459 }
460 else
461 {
462 // Save the current thread pointer
463 waitingThread = miosix::Thread::getCurrentThread();
464
465 // Wait until the thread is woken up and the pointer is cleared
466 miosix::FastInterruptDisableLock dLock;
467 if (timeout_ns > 0)
468 {
469 do
470 {
471 if (miosix::Thread::IRQenableIrqAndTimedWait(
472 dLock, timeout_ns + miosix::IRQgetTime()) ==
473 miosix::TimedWaitResult::Timeout)
474 {
475 result = false;
476
477 // If the timeout expired we clear the thread
478 // pointer so that the interrupt, if it will occur,
479 // will not wake up the thread (and we can exit the
480 // while loop)
481 waitingThread = nullptr;
482 }
483 else
484 {
485 result = true;
486 }
487 } while (waitingThread);
488 }
489 else
490 {
491 do
492 {
493 miosix::Thread::IRQenableIrqAndWait(dLock);
494 } while (waitingThread);
495 result = true;
496 }
497 }
498
499 // Before returning we need to clear the flags otherwise we could
500 // get misfires
501 eventTriggered = false;
502 }
503 else
504 {
505 // Pool the flag if the user did not enable the interrupt
506 if (timeout_ns > 0)
507 {
508 const long long start = miosix::getTime();
509
510 do
511 {
512 readFlags();
513 } while (!getEventStatus() &&
514 miosix::getTime() - start < timeout_ns);
515
516 result = getEventStatus();
517 }
518 else
519 {
520 while (!getEventStatus())
521 readFlags();
522 result = true;
523 }
524
525 if (result)
526 {
527 // Clear the flag
528 clearEventStatus();
529 }
530 }
531
532 return result;
533 }
534
535#ifdef STM32F767xx
542 void invalidateCache();
543#endif // STM32F767xx
544
545public:
546 DMAStream(const DMAStream&) = delete;
547 DMAStream& operator=(const DMAStream&) = delete;
548
549 DMAStream(DMAStream&&) noexcept = default;
550 DMAStream& operator=(DMAStream&&) noexcept = default;
551};
552
557{
558public:
559 // cppcheck-suppress noExplicitConstructor
560 DMAStreamGuard(DMAStream* ptr) : pStream(ptr) {}
561
563 {
564 if (pStream != nullptr)
565 DMADriver::instance().releaseStream(pStream->getStreamId());
566 }
567
570
571 DMAStreamGuard(DMAStreamGuard&&) noexcept = default;
572 DMAStreamGuard& operator=(DMAStreamGuard&&) noexcept = default;
573
574 DMAStream* operator->();
575
580 inline bool isValid() { return pStream != nullptr; }
581
582private:
583 DMAStream* const pStream;
584};
585
586} // namespace Boardcore
This class is responsible for streams acquisition, streams release and interrupt handling.
Definition DMA.h:168
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:557
DMAStreamGuard(DMAStreamGuard &&) noexcept=default
DMAStreamGuard & operator=(const DMAStreamGuard &)=delete
DMAStreamGuard(const DMAStreamGuard &)=delete
DMAStreamGuard(DMAStream *ptr)
Definition DMA.h:560
This class represents the actual DMA stream. It can be used to setup, start and stop DMA transactions...
Definition DMA.h:232
bool getHalfTransferFlagStatus()
Returns the last read status of the half transfer flag.
Definition DMA.h:339
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:390
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:388
void clearTransferErrorFlag()
Definition DMA.h:383
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:399
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:344
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:378
void setErrorCallback(std::function< void()> callback)
Definition DMA.cpp:666
void resetHalfTransferCallback()
Definition DMA.cpp:654
DMADefs::Channel getCurrentChannel()
Definition DMA.h:371
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:369
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:360
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:373
bool getFifoErrorFlagStatus()
Returns the last read status of the fifo error flag.
Definition DMA.h:354
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:349
Peripherals
All the peripherals connected to dma.
Definition DMADefs.h:130
Channel
Channels selectable for each dma stream.
Definition DMADefs.h:106
Driver for the VN100S IMU.
DMAErrors
Generic error codes that the DMA can generate.
Definition DMA.h:41
@ END_OF_BASE_ERRORS
Definition SensorData.h:51
This is the configuration struct for a DMA transaction.
Definition DMA.h:55
bool enableFifoErrorInterrupt
Definition DMA.h:143
bool enableHalfTransferInterrupt
Definition DMA.h:119
uint16_t numberOfDataItems
Definition DMA.h:95
bool enableTransferErrorInterrupt
Definition DMA.h:129
volatile void * secondMemoryAddress
Definition DMA.h:94
volatile void * dstAddress
Definition DMA.h:93
volatile void * srcAddress
Definition DMA.h:92
bool doubleBufferMode
Enables double buffer mode.
Definition DMA.h:110
bool enableDirectModeErrorInterrupt
Definition DMA.h:156
Direction direction
Definition DMA.h:88
bool enableTransferCompleteInterrupt
Definition DMA.h:111
bool circularMode
Enables circular buffer mode.
Definition DMA.h:103