Files
muziekdoos/FW/leo_muziekdoos_sam51/lib/DMA/DMA.h
2021-08-27 16:41:58 +02:00

247 lines
8.9 KiB
C++

/*!
* @file Adafruit_ZeroDMA.h
*
* This is part of Adafruit's DMA library for SAMD microcontrollers on
* the Arduino platform. SAMD21 and SAMD51 lines are supported.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing
* products from Adafruit!
*
* Written by Phil "PaintYourDragon" Burgess for Adafruit Industries,
* based partly on DMA insights from Atmel ASFCORE 3.
*
* MIT license, all text here must be included in any redistribution.
*
*/
#ifndef _ADAFRUIT_ZERODMA_H_
#define _ADAFRUIT_ZERODMA_H_
#include "Arduino.h"
#ifdef DMAC_RESERVED_CHANNELS // SAMD core > 1.2.1
#include <dma.h>
#else
#include "utility/dma.h"
#endif
/** Status codes returned by some DMA functions and/or held in
a channel's jobStatus variable. */
enum DMAstatus {
DMA_STATUS_OK = 0,
DMA_STATUS_ERR_NOT_FOUND,
DMA_STATUS_ERR_NOT_INITIALIZED,
DMA_STATUS_ERR_INVALID_ARG,
DMA_STATUS_ERR_IO,
DMA_STATUS_ERR_TIMEOUT,
DMA_STATUS_BUSY,
DMA_STATUS_SUSPEND,
DMA_STATUS_ABORTED,
DMA_STATUS_JOBSTATUS = -1 // For printStatus() function
};
/*!
@brief Class encapsulating DMA jobs and descriptors.
*/
class DMA_class {
public:
DMA_class(void);
// DMA channel functions
/*!
@brief Allocate channel for ZeroDMA object. This allocates a CHANNEL,
not a DESCRIPTOR.
@return ZeroDMAstatus type:
DMA_STATUS_OK on success.
DMA_STATUS_ERR_NOT_FOUND if no DMA channels are free.
*/
DMAstatus allocate(void);
/*!
@brief Start a previously allocated-and-configured DMA job.
@return ZeroDMAstatus type:
DMA_STATUS_OK on success.
DMA_STATUS_BUSY if resource is busy.
DMA_STATUS_ERR_NOT_INITIALIZED if attempting to start job
on a channel that failed to allocate.
DMA_STATUS_ERR_INVALID_ARG if a bad transfer size was specified.
*/
DMAstatus startJob(void);
/*!
@brief Deallocates a previously-allocated DMA channel. This deallocates
the CHANNEL, not any associated DESCRIPTORS.
@return ZeroDMAstatus type:
DMA_STATUS_OK on success.
DMA_STATUS_BUSY if channel is busy (can't deallocate while in use).
DMA_STATUS_ERR_NOT_INITIALIZED if channel isn't in use.
*/
DMAstatus free(void);
/*!
@brief Activate a previously allocated-and-configured DMA channel's
software trigger.
*/
void trigger(void);
/*!
@brief Set DMA peripheral trigger. This can be done before or after
channel is allocated.
@param trigger A device-specific DMA peripheral trigger ID, typically
defined in a header file associated with that chip.
Example triffer IDs might include SERCOM2_DMAC_ID_TX
(SERCOM transfer complete) ADC_DMAC_ID_RESRDY (ADC
results ready).
*/
void setTrigger(uint8_t trigger);
/*!
@brief Set DMA trigger action. This can be done before or after
channel is allocated.
@param action One of DMA_TRIGGER_ACTON_BLOCK, DMA_TRIGGER_ACTON_BEAT or
DMA_TRIGGER_ACTON_TRANSACTION for desired behavior.
*/
void setAction(dma_transfer_trigger_action action);
/*!
@brief Set and enable callback function for ZeroDMA object. This can be
called before or after channel and/or descriptors are allocated,
but needs to be called before job is started.
@param callback Pointer to callback function which accepts a pointer
to a ZeroDMA object (or NULL to disable callback).
@param type Which DMA operation to attach this function to (a
channel can have multiple callbacks assigned if needed,
one for each of these situations):
DMA_CALLBACK_DONE on successful completion of a DMA
transfer.
DMA_CALLBACK_TRANSFER_ERR if a bus error is detected
during an AHB access or when the DMAC fetches an
invalid descriptor.
DMA_CALLBACK_CHANNEL_SUSPEND when a channel is suspended.
*/
void setCallback(void (*callback)(DMA_class *) = NULL,
dma_callback_type type = DMA_CALLBACK_TRANSFER_DONE);
/*!
@brief Select whether a channel's descriptor list should repeat or not.
This can be called before or after channel and any descriptors
are allocated.
@param flag 'true' if DMA descriptor list should repeat indefinitely,
'false' if DMA transfer stops at end of descriptor list.
*/
void loop(boolean flag);
/*!
@brief Suspend a DMA channel. AVOID USING FOR NOW.
*/
void suspend(void);
/*!
@brief Resume a previously-suspended DMA channel. AVOID USING FOR NOW.
*/
void resume(void);
/*!
@brief Cancel a DMA transfer operation.
*/
void abort(void);
/*!
@brief Set DMA channel level priority.
@param pri DMA_PRIORITY_0 (lowest priority) through DMA_PRIORITY_3
(highest priority).
*/
void setPriority(dma_priority pri);
/*!
@brief Print (to Serial console) a string corresponding to a DMA
job status value.
@param s Job status as might be returned by allocate(), startJob(),
etc., e.g. DMA_STATUS_OK, DMA_STATUS_ERR_NOT_FOUND, ...
*/
void printStatus(DMAstatus s = DMA_STATUS_JOBSTATUS);
/*!
@brief Get the DMA channel index associated with a ZeroDMA object.
@return uint8_t Channel index (0 to DMAC_CH_NUM-1, or 0xFF).
*/
uint8_t getChannel(void);
// DMA descriptor functions
/*!
@brief Allocate and append a DMA descriptor to a channel's descriptor
list. Channel must be allocated first.
@param src Source address.
@param dst Destination address.
@param count Transfer count.
@param size Per-count transfer size (DMA_BEAT_SIZE_BYTE,
DMA_BEAT_SIZE_HWORD or DMA_BEAT_SIZE_WORD for 8, 16,
32 bits respectively).
@param srcInc If true, increment the source address following each
count.
@param dstInc If true, increment the destination address following
each count.
@param stepSize If source/dest address increment in use, this indicates
the 'step size' (allowing it to skip over elements).
DMA_ADDRESS_INCREMENT_STEP_SIZE_1 for a contiguous
transfer, "_SIZE_2 for alternate items, "_SIZE_4
8, 16, 32, 64 or 128 for other skip ranges.
@param stepSel DMA_STEPSEL_SRC or DMA_STEPSEL_DST depending which
pointer the step size should apply to (can't be used
on both simultaneously).
@return DmacDescriptor* Pointer to DmacDescriptor structure, or NULL
on various errors. Calling code should keep the
pointer for later if it needs to change or free
the descriptor.
*/
DmacDescriptor *
addDescriptor(void *src, void *dst, uint32_t count = 0,
dma_beat_size size = DMA_BEAT_SIZE_BYTE, bool srcInc = true,
bool dstInc = true,
uint32_t stepSize = DMA_ADDRESS_INCREMENT_STEP_SIZE_1,
bool stepSel = DMA_STEPSEL_DST);
/*!
@brief Change a previously-allocated DMA descriptor. Only the most
common settings (source, dest, count) are available here. For
anything more esoteric, you'll need to modify the descriptor
structure yourself.
@param d Pointer to descriptor structure (as returned by
addDescriptor()).
@param src New source address.
@param dst New destination address.
@param count New transfer count.
*/
void changeDescriptor(DmacDescriptor *d, void *src = NULL, void *dst = NULL,
uint32_t count = 0);
/*!
@brief Interrupt handler function, used internally by the library,
DO NOT TOUCH!
@param flags Channel number, actually.
*/
void _IRQhandler(uint8_t flags);
/*!
@brief Test if DMA transfer is in-progress. Might be better to use
callback and flag, unsure.
@return 'true' if DMA channel is busy, 'false' otherwise.
*/
bool isActive();
protected:
uint8_t channel; ///< DMA channel index (0 to DMAC_CH_NUM-1, or 0xFF)
volatile enum DMAstatus jobStatus; ///< Last known DMA job status
bool hasDescriptors; ///< 'true' if one or more descriptors assigned
bool loopFlag; ///< 'true' if descriptor chain loops back to start
uint8_t peripheralTrigger; ///< Value set by setTrigger()
dma_transfer_trigger_action triggerAction; ///< Value set by setAction()
void (*callback[DMA_CALLBACK_N])(DMA_class *); ///< Callback func *s
};
#endif // _ADAFRUIT_ZERODMA_H_