mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #14278 from bergzand/pr/sam0_common/dma_clarify
sam0_common: Add additional documentation on DMA usage
This commit is contained in:
commit
a019c95190
@ -670,6 +670,9 @@ typedef struct {
|
||||
#define WDT_HAS_INIT (1)
|
||||
|
||||
/**
|
||||
* @name sam0 DMA peripheral
|
||||
* @{
|
||||
*
|
||||
* The sam0 DMA peripheral has a number of channels. Each channel is a separate
|
||||
* data stream, triggered by a configurable trigger when enabled, or triggered
|
||||
* by software (not yet supported). In theory each DMA channel is equal and can
|
||||
@ -680,6 +683,35 @@ typedef struct {
|
||||
* destination, are kept in RAM and are read when the channel is enabled and
|
||||
* triggered. On the SAML21 platform, these descriptors must reside in the LP
|
||||
* SRAM.
|
||||
*
|
||||
* The DMA addresses supplied must point to the **end** of the array to be
|
||||
* transferred. When address increment is enabled this means that the supplied
|
||||
* src or dst argument must point to array + length. When increment is disabled,
|
||||
* the source or destination address can be used directly. The calculation of
|
||||
* the end of the array must be done by the calling function, because the
|
||||
* beatsize and the increment can usually be hardcoded there and doesn't have to
|
||||
* be retrieved from the DMA register configuration.
|
||||
* See also section 20.6.2.7 of the SAM D21/DA1 Family Data Sheet.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* void transfer_data(void *src, void *dst, size_t len)
|
||||
* {
|
||||
* dma_t channel = dma_acquire_channel()
|
||||
* if (channel == 0xff) {
|
||||
* return -E_BUSY;
|
||||
* }
|
||||
*
|
||||
* dma_setup(channel, DMA_TRIGGER_MY_PERIH, 0, true);
|
||||
* dma_prepare(channel, DMAC_BTCTRL_BEATSIZE_BYTE_Val,
|
||||
* (uint8_t*)src + len, (uint8_t*)dst + len, len);
|
||||
*
|
||||
* dma_start(channel);
|
||||
* dma_wait(channel);
|
||||
*
|
||||
* dma_release_channel(channel);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -691,10 +723,13 @@ typedef struct {
|
||||
/**
|
||||
* @brief Move the DMA descriptors to the LP SRAM. Required on the SAML21
|
||||
*/
|
||||
#if defined(CPU_FAM_SAML21)
|
||||
#if defined(CPU_FAM_SAML21) || defined(DOXYGEN)
|
||||
#define DMA_DESCRIPTOR_IN_LPSRAM
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Extra attributes required for instantiating DMA descriptors.
|
||||
*/
|
||||
#ifdef DMA_DESCRIPTOR_IN_LPSRAM
|
||||
#define DMA_DESCRIPTOR_ATTRS __attribute__((section(".backup.bss")))
|
||||
#else
|
||||
@ -753,15 +788,18 @@ void dma_setup(dma_t dma, unsigned trigger, uint8_t prio, bool irq);
|
||||
/**
|
||||
* @brief Prepare the DMA channel for an individual transfer.
|
||||
*
|
||||
* @note When increment is enabled for source or destination, the @p src
|
||||
* and/or @p dst must point to the **end** of the array.
|
||||
*
|
||||
* @param dma DMA channel reference
|
||||
* @param width Transfer beat size to use
|
||||
* @param src Source address for the transfer
|
||||
* @param dst Destination address for the transfer
|
||||
* @param len Number of beats to transfer
|
||||
* @param num Number of beats to transfer
|
||||
* @param incr Which of the addresses to increment after a beat
|
||||
*/
|
||||
void dma_prepare(dma_t dma, uint8_t width, const void *src, void *dst,
|
||||
size_t len, dma_incr_t incr);
|
||||
size_t num, dma_incr_t incr);
|
||||
|
||||
/**
|
||||
* @brief Prepare a transfer without modifying the destination address
|
||||
@ -771,16 +809,19 @@ void dma_prepare(dma_t dma, uint8_t width, const void *src, void *dst,
|
||||
* peripheral address, leaving the destination address and related settings
|
||||
* untouched
|
||||
*
|
||||
* @note This only touches the source address, length and source increment
|
||||
* settings. Be sure to initialize the full descriptor beforehand with
|
||||
* @ref dma_prepare
|
||||
* @note This only touches the source address, number of transfers and source
|
||||
* increment settings. Be sure to initialize the full descriptor
|
||||
* beforehand with @ref dma_prepare
|
||||
*
|
||||
* @note When increment is enabled for source, the @p src must point to the
|
||||
* **end** of the array.
|
||||
*
|
||||
* @param dma DMA channel reference
|
||||
* @param src Source address for the transfer
|
||||
* @param len Number of beats to transfer
|
||||
* @param num Number of beats to transfer
|
||||
* @param incr Whether to increment the source address after a beat
|
||||
*/
|
||||
void dma_prepare_src(dma_t dma, const void *src, size_t len, bool incr);
|
||||
void dma_prepare_src(dma_t dma, const void *src, size_t num, bool incr);
|
||||
|
||||
/**
|
||||
* @brief Prepare a transfer without modifying the source address
|
||||
@ -790,34 +831,41 @@ void dma_prepare_src(dma_t dma, const void *src, size_t len, bool incr);
|
||||
* peripheral address, leaving the source address and related settings
|
||||
* untouched
|
||||
*
|
||||
* @note This only touches the destination address, length and destination
|
||||
* increment settings. Be sure to initialize the full descriptor beforehand with
|
||||
* @ref dma_prepare
|
||||
* @note This only touches the destination address, the number of transfers
|
||||
* and destination increment settings. Be sure to initialize the full
|
||||
* descriptor beforehand with @ref dma_prepare
|
||||
*
|
||||
* @note When increment is enabled for destination, @p dst must point to the
|
||||
* **end** of the array.
|
||||
*
|
||||
* @param dma DMA channel reference
|
||||
* @param dst Destination address for the transfer
|
||||
* @param len Number of beats to transfer
|
||||
* @param num Number of beats to transfer
|
||||
* @param incr Whether to increment the destination address after a beat
|
||||
*/
|
||||
void dma_prepare_dst(dma_t dma, void *dst, size_t len, bool incr);
|
||||
void dma_prepare_dst(dma_t dma, void *dst, size_t num, bool incr);
|
||||
|
||||
/**
|
||||
* @brief Append a second transfer descriptor after the default channel
|
||||
* descriptor.
|
||||
*
|
||||
* @note Only a single extra transfer descriptor is supported for now.
|
||||
* @note @p descriptor must remain valid throughout the full transfer duration
|
||||
*
|
||||
* @note @p next must remain valid throughout the full transfer duration
|
||||
*
|
||||
* @note When increment is enabled for source or destination, @p src
|
||||
* and/or @p dst must point to the **end** of the array.
|
||||
*
|
||||
* @param dma DMA channel reference to add the descriptor to
|
||||
* @param descriptor Extra transfer descriptor to append
|
||||
* @param width Transfer beat size to use
|
||||
* @param src Source address for the transfer
|
||||
* @param dst Destination address for the transfer
|
||||
* @param len Number of beats to transfer
|
||||
* @param num Number of beats to transfer
|
||||
* @param incr Which of the addresses to increment after a beat
|
||||
*/
|
||||
void dma_append(dma_t dma, DmacDescriptor *descriptor, uint8_t width,
|
||||
const void *src, void *dst, size_t len, dma_incr_t incr);
|
||||
const void *src, void *dst, size_t num, dma_incr_t incr);
|
||||
|
||||
/**
|
||||
* @brief Append a second transfer descriptor after the default channel
|
||||
@ -825,16 +873,20 @@ void dma_append(dma_t dma, DmacDescriptor *descriptor, uint8_t width,
|
||||
* descriptor.
|
||||
*
|
||||
* @note Only a single extra transfer descriptor is supported for now.
|
||||
* @note @p descriptor must remain valid throughout the full transfer duration
|
||||
*
|
||||
* @note @p next must remain valid throughout the full transfer duration
|
||||
*
|
||||
* @note When increment is enabled for source, @p src must point to the
|
||||
* **end** of the array.
|
||||
*
|
||||
* @param dma DMA channel reference to add the descriptor to
|
||||
* @param next Extra transfer descriptor to append
|
||||
* @param src Source address for the transfer
|
||||
* @param len Number of beats to transfer
|
||||
* @param num Number of beats to transfer
|
||||
* @param incr Whether to increment the source address after a beat
|
||||
*/
|
||||
void dma_append_src(dma_t dma, DmacDescriptor *next, const void *src,
|
||||
size_t len, bool incr);
|
||||
size_t num, bool incr);
|
||||
|
||||
/**
|
||||
* @brief Append a second transfer descriptor after the default channel
|
||||
@ -842,15 +894,19 @@ void dma_append_src(dma_t dma, DmacDescriptor *next, const void *src,
|
||||
* descriptor.
|
||||
*
|
||||
* @note Only a single extra transfer descriptor is supported for now.
|
||||
* @note @p descriptor must remain valid throughout the full transfer duration
|
||||
*
|
||||
* @note @p next must remain valid throughout the full transfer duration
|
||||
*
|
||||
* @note When increment is enabled for destination, @p dst must point to the
|
||||
* **end** of the array.
|
||||
*
|
||||
* @param dma DMA channel reference to add the descriptor to
|
||||
* @param next Extra transfer descriptor to append
|
||||
* @param dst Destination address for the transfer
|
||||
* @param len Number of beats to transfer
|
||||
* @param num Number of beats to transfer
|
||||
* @param incr Whether to increment the source address after a beat
|
||||
*/
|
||||
void dma_append_dst(dma_t dma, DmacDescriptor *next, void *dst, size_t len,
|
||||
void dma_append_dst(dma_t dma, DmacDescriptor *next, void *dst, size_t num,
|
||||
bool incr);
|
||||
|
||||
/**
|
||||
@ -880,6 +936,7 @@ void dma_wait(dma_t dma);
|
||||
* @param dma DMA channel reference
|
||||
*/
|
||||
void dma_cancel(dma_t dma);
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -134,9 +134,9 @@ static inline void _set_destination(DmacDescriptor *descr, void *dst)
|
||||
descr->DSTADDR.reg = (uint32_t)dst;
|
||||
}
|
||||
|
||||
static inline void _set_len(DmacDescriptor *descr, size_t len)
|
||||
static inline void _set_num(DmacDescriptor *descr, size_t num)
|
||||
{
|
||||
descr->BTCNT.reg = len;
|
||||
descr->BTCNT.reg = num;
|
||||
}
|
||||
|
||||
static inline void _set_next_descriptor(DmacDescriptor *descr, void *next)
|
||||
@ -170,12 +170,12 @@ void dma_setup(dma_t dma, unsigned trigger, uint8_t prio, bool irq)
|
||||
#endif
|
||||
}
|
||||
|
||||
void dma_prepare(dma_t dma, uint8_t width, const void *src, void *dst, size_t len,
|
||||
uint8_t incr)
|
||||
void dma_prepare(dma_t dma, uint8_t width, const void *src, void *dst,
|
||||
size_t num, uint8_t incr)
|
||||
{
|
||||
DEBUG("[DMA]: Prepare %u, len: %u\n", dma, (unsigned)len);
|
||||
DEBUG("[DMA]: Prepare %u, num: %u\n", dma, (unsigned)num);
|
||||
DmacDescriptor *descr = &descriptors[dma];
|
||||
_set_len(descr, len);
|
||||
_set_num(descr, num);
|
||||
_set_source(descr, src);
|
||||
_set_destination(descr, dst);
|
||||
descr->DESCADDR.reg = (uint32_t)NULL;
|
||||
@ -184,24 +184,22 @@ void dma_prepare(dma_t dma, uint8_t width, const void *src, void *dst, size_t le
|
||||
DMAC_BTCTRL_VALID;
|
||||
}
|
||||
|
||||
void dma_prepare_src(dma_t dma, const void *src, size_t len,
|
||||
bool incr)
|
||||
void dma_prepare_src(dma_t dma, const void *src, size_t num, bool incr)
|
||||
{
|
||||
DEBUG("[dma]: %u: prep src %p, %u, %u\n", dma, src, (unsigned)len, incr);
|
||||
DEBUG("[dma]: %u: prep src %p, %u, %u\n", dma, src, (unsigned)num, incr);
|
||||
DmacDescriptor *descr = &descriptors[dma];
|
||||
_set_len(descr, len);
|
||||
_set_num(descr, num);
|
||||
_set_source(descr, src);
|
||||
descr->BTCTRL.reg = (descr->BTCTRL.reg & ~DMAC_BTCTRL_SRCINC) |
|
||||
(incr << DMAC_BTCTRL_SRCINC_Pos);
|
||||
_set_next_descriptor(descr, NULL);
|
||||
}
|
||||
|
||||
void dma_prepare_dst(dma_t dma, void *dst, size_t len,
|
||||
bool incr)
|
||||
void dma_prepare_dst(dma_t dma, void *dst, size_t num, bool incr)
|
||||
{
|
||||
DEBUG("[dma]: %u: prep dst %p, %u, %u\n", dma, dst, (unsigned)len, incr);
|
||||
DEBUG("[dma]: %u: prep dst %p, %u, %u\n", dma, dst, (unsigned)num, incr);
|
||||
DmacDescriptor *descr = &descriptors[dma];
|
||||
_set_len(descr, len);
|
||||
_set_num(descr, num);
|
||||
_set_destination(descr, dst);
|
||||
descr->BTCTRL.reg = (descr->BTCTRL.reg & ~DMAC_BTCTRL_DSTINC) |
|
||||
(incr << DMAC_BTCTRL_DSTINC_Pos);
|
||||
@ -209,39 +207,39 @@ void dma_prepare_dst(dma_t dma, void *dst, size_t len,
|
||||
}
|
||||
|
||||
void _fmt_append(DmacDescriptor *descr, DmacDescriptor *next,
|
||||
const void *src, void *dst, size_t len)
|
||||
const void *src, void *dst, size_t num)
|
||||
{
|
||||
/* Configure the full descriptor besides the BTCTRL data */
|
||||
_set_next_descriptor(descr, next);
|
||||
_set_next_descriptor(next, NULL);
|
||||
_set_source(next, src);
|
||||
_set_len(next, len);
|
||||
_set_num(next, num);
|
||||
_set_destination(next, dst);
|
||||
}
|
||||
|
||||
void dma_append(dma_t dma, DmacDescriptor *next, uint8_t width,
|
||||
const void *src, void *dst, size_t len, dma_incr_t incr)
|
||||
const void *src, void *dst, size_t num, dma_incr_t incr)
|
||||
{
|
||||
DmacDescriptor *descr = &descriptors[dma];
|
||||
|
||||
next->BTCTRL.reg = width << DMAC_BTCTRL_BEATSIZE_Pos |
|
||||
incr << DMAC_BTCTRL_SRCINC_Pos |
|
||||
DMAC_BTCTRL_VALID;
|
||||
_fmt_append(descr, next, src, dst, len);
|
||||
_fmt_append(descr, next, src, dst, num);
|
||||
}
|
||||
|
||||
void dma_append_src(dma_t dma, DmacDescriptor *next, const void *src,
|
||||
size_t len, bool incr)
|
||||
size_t num, bool incr)
|
||||
{
|
||||
DmacDescriptor *descr = &descriptors[dma];
|
||||
|
||||
/* Copy the original descriptor config and modify the increment */
|
||||
next->BTCTRL.reg = (descr->BTCTRL.reg & ~DMAC_BTCTRL_SRCINC) |
|
||||
(incr << DMAC_BTCTRL_SRCINC_Pos);
|
||||
_fmt_append(descr, next, src, (void *)descr->DSTADDR.reg, len);
|
||||
_fmt_append(descr, next, src, (void *)descr->DSTADDR.reg, num);
|
||||
}
|
||||
|
||||
void dma_append_dst(dma_t dma, DmacDescriptor *next, void *dst, size_t len,
|
||||
void dma_append_dst(dma_t dma, DmacDescriptor *next, void *dst, size_t num,
|
||||
bool incr)
|
||||
{
|
||||
DmacDescriptor *descr = &descriptors[dma];
|
||||
@ -249,7 +247,7 @@ void dma_append_dst(dma_t dma, DmacDescriptor *next, void *dst, size_t len,
|
||||
/* Copy the original descriptor config and modify the increment */
|
||||
next->BTCTRL.reg = (descr->BTCTRL.reg & ~DMAC_BTCTRL_DSTINC) |
|
||||
(incr << DMAC_BTCTRL_DSTINC_Pos);
|
||||
_fmt_append(descr, next, (void *)descr->SRCADDR.reg, dst, len);
|
||||
_fmt_append(descr, next, (void *)descr->SRCADDR.reg, dst, num);
|
||||
}
|
||||
|
||||
void dma_start(dma_t dma)
|
||||
|
Loading…
Reference in New Issue
Block a user