mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-25 14:33:52 +01:00
sam0_common: Add DMA peripheral driver
This commit is contained in:
parent
a4889b4207
commit
6be1b27bbb
@ -8,6 +8,7 @@
|
||||
config CPU_COMMON_SAM0
|
||||
bool
|
||||
select HAS_PERIPH_CPUID
|
||||
select HAS_PERIPH_DMA
|
||||
select HAS_PERIPH_FLASHPAGE
|
||||
select HAS_PERIPH_FLASHPAGE_RAW
|
||||
select HAS_PERIPH_FLASHPAGE_RWEE
|
||||
|
||||
@ -670,6 +670,218 @@ typedef struct {
|
||||
*/
|
||||
#define WDT_HAS_INIT (1)
|
||||
|
||||
/**
|
||||
* 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
|
||||
* have a configurable priority and can be triggered by the full set of triggers
|
||||
* available.
|
||||
*
|
||||
* DMA descriptors, specifying a single transfer with size, source and
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Indicates that the peripheral doesn't utilize the DMA controller.
|
||||
* Matches with the register configuration for software based triggers.
|
||||
*/
|
||||
#define DMA_TRIGGER_DISABLED 0
|
||||
|
||||
/**
|
||||
* @brief Move the DMA descriptors to the LP SRAM. Required on the SAML21
|
||||
*/
|
||||
#if defined(CPU_FAM_SAML21)
|
||||
#define DMA_DESCRIPTOR_IN_LPSRAM
|
||||
#endif
|
||||
|
||||
#ifdef DMA_DESCRIPTOR_IN_LPSRAM
|
||||
#define DMA_DESCRIPTOR_ATTRS __attribute__((section(".backup.bss")))
|
||||
#else
|
||||
#define DMA_DESCRIPTOR_ATTRS
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief DMA channel type
|
||||
*/
|
||||
typedef unsigned dma_t;
|
||||
|
||||
/**
|
||||
* @brief Available DMA address increment modes
|
||||
*/
|
||||
typedef enum {
|
||||
DMA_INCR_NONE = 0, /**< Don't increment any addresses after a beat */
|
||||
DMA_INCR_SRC = 1, /**< Increment the source address after a beat */
|
||||
DMA_INCR_DEST = 2, /**< Increment destination address after a beat */
|
||||
DMA_INCR_BOTH = 3, /**< Increment both addresses after a beat */
|
||||
} dma_incr_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize DMA
|
||||
*/
|
||||
void dma_init(void);
|
||||
|
||||
/**
|
||||
* @brief Acquire a DMA channel.
|
||||
*
|
||||
* A free DMA channel is marked as allocated and a reference is returned.
|
||||
* DMA channels can be acquired for long periods of time, e.g. from the start to
|
||||
* end of a number of transfers or directly at boot and never released.
|
||||
*
|
||||
* @returns A reference to the DMA channel
|
||||
* @returns UINT8_MAX when no DMA channel is available
|
||||
*/
|
||||
dma_t dma_acquire_channel(void);
|
||||
|
||||
/**
|
||||
* @brief Release a previously acquired DMA channel
|
||||
*
|
||||
* @param dma DMA channel to release
|
||||
*/
|
||||
void dma_release_channel(dma_t dma);
|
||||
|
||||
/**
|
||||
* @brief Initialize a previously allocated DMA channel with one-time settings
|
||||
*
|
||||
* @param dma DMA channel reference
|
||||
* @param trigger Trigger to use for this DMA channel
|
||||
* @param prio Channel priority
|
||||
* @param irq Whether to enable the interrupt handler for this channel
|
||||
*/
|
||||
void dma_setup(dma_t dma, unsigned trigger, uint8_t prio, bool irq);
|
||||
|
||||
/**
|
||||
* @brief Prepare the DMA channel for an individual transfer.
|
||||
*
|
||||
* @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 incr Which of the addresses to increment after a beat
|
||||
*/
|
||||
void dma_prepare(dma_t dma, uint8_t width, void *src, void *dst, size_t len,
|
||||
dma_incr_t incr);
|
||||
|
||||
/**
|
||||
* @brief Prepare a transfer without modifying the destination address
|
||||
* settings.
|
||||
*
|
||||
* Can be used when repeatedly using a dma channel to transfer to the same
|
||||
* 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
|
||||
*
|
||||
* @param dma DMA channel reference
|
||||
* @param src Source address for the transfer
|
||||
* @param len Number of beats to transfer
|
||||
* @param incr Whether to increment the source address after a beat
|
||||
*/
|
||||
void dma_prepare_src(dma_t dma, void *src, size_t len, bool incr);
|
||||
|
||||
/**
|
||||
* @brief Prepare a transfer without modifying the source address
|
||||
* settings.
|
||||
*
|
||||
* Can be used when repeatedly using a dma channel to transfer from the same
|
||||
* 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
|
||||
*
|
||||
* @param dma DMA channel reference
|
||||
* @param dst Destination address for the transfer
|
||||
* @param len 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);
|
||||
|
||||
/**
|
||||
* @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
|
||||
*
|
||||
* @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 incr Which of the addresses to increment after a beat
|
||||
*/
|
||||
void dma_append(dma_t dma, DmacDescriptor *descriptor, uint8_t width,
|
||||
void *src, void *dst, size_t len, dma_incr_t incr);
|
||||
|
||||
/**
|
||||
* @brief Append a second transfer descriptor after the default channel
|
||||
* descriptor, copying destination and block size from the initial
|
||||
* descriptor.
|
||||
*
|
||||
* @note Only a single extra transfer descriptor is supported for now.
|
||||
* @note @p descriptor must remain valid throughout the full transfer duration
|
||||
*
|
||||
* @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 incr Whether to increment the source address after a beat
|
||||
*/
|
||||
void dma_append_src(dma_t dma, DmacDescriptor *next, void *src, size_t len,
|
||||
bool incr);
|
||||
|
||||
/**
|
||||
* @brief Append a second transfer descriptor after the default channel
|
||||
* descriptor, copying source and block size from the initial
|
||||
* descriptor.
|
||||
*
|
||||
* @note Only a single extra transfer descriptor is supported for now.
|
||||
* @note @p descriptor must remain valid throughout the full transfer duration
|
||||
*
|
||||
* @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 incr Whether to increment the source address after a beat
|
||||
*/
|
||||
void dma_append_dst(dma_t dma, DmacDescriptor *next, void *dst, size_t len,
|
||||
bool incr);
|
||||
|
||||
/**
|
||||
* @brief Start a DMA transfer.
|
||||
*
|
||||
* @param dma DMA channel reference
|
||||
*/
|
||||
void dma_start(dma_t dma);
|
||||
|
||||
/**
|
||||
* @brief Wait for a DMA channel to finish the transfer.
|
||||
*
|
||||
* This function uses a blocking mutex to wait for the transfer to finish
|
||||
*
|
||||
* @note Use only with DMA channels of which the interrupt is enabled
|
||||
*
|
||||
* @param dma DMA channel reference
|
||||
*/
|
||||
void dma_wait(dma_t dma);
|
||||
|
||||
/**
|
||||
* @brief Cancel an active DMA transfer
|
||||
*
|
||||
* It is not harmful to call this on an inactive channel, but it will waste some
|
||||
* processing time
|
||||
*
|
||||
* @param dma DMA channel reference
|
||||
*/
|
||||
void dma_cancel(dma_t dma);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
332
cpu/sam0_common/periph/dma.c
Normal file
332
cpu/sam0_common/periph/dma.c
Normal file
@ -0,0 +1,332 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Koen Zandberg <koen@bergzand.net>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup cpu_sam0_common
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Low-level DMA driver implementation
|
||||
*
|
||||
* @author Koen Zandberg <koen@bergzand.net>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "periph_cpu.h"
|
||||
#include "periph_conf.h"
|
||||
#include "mutex.h"
|
||||
#include "assert.h"
|
||||
#include "bitarithm.h"
|
||||
#include "pm_layered.h"
|
||||
#include "thread_flags.h"
|
||||
#include "periph/gpio.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#ifndef CONFIG_DMA_NUMOF
|
||||
#define CONFIG_DMA_NUMOF DMAC_CH_NUM
|
||||
#endif
|
||||
|
||||
/* In memory DMA transfer descriptors */
|
||||
static DmacDescriptor DMA_DESCRIPTOR_ATTRS descriptors[CONFIG_DMA_NUMOF];
|
||||
static DmacDescriptor DMA_DESCRIPTOR_ATTRS writeback[CONFIG_DMA_NUMOF];
|
||||
|
||||
/* Bitmap of dma channels available */
|
||||
static uint32_t channels_free = (1LLU << CONFIG_DMA_NUMOF) - 1;
|
||||
|
||||
struct dma_ctx {
|
||||
mutex_t sync_lock;
|
||||
};
|
||||
|
||||
struct dma_ctx dma_ctx[CONFIG_DMA_NUMOF];
|
||||
|
||||
static void _poweron(void)
|
||||
{
|
||||
#if defined(MCLK)
|
||||
MCLK->AHBMASK.reg |= MCLK_AHBMASK_DMAC;
|
||||
#else
|
||||
PM->AHBMASK.reg |= PM_AHBMASK_DMAC;
|
||||
PM->APBBMASK.reg |= PM_APBBMASK_DMAC;
|
||||
#endif
|
||||
}
|
||||
|
||||
void dma_init(void)
|
||||
{
|
||||
_poweron();
|
||||
for (unsigned i = 0; i < CONFIG_DMA_NUMOF; i++) {
|
||||
mutex_init(&dma_ctx[i].sync_lock);
|
||||
}
|
||||
/* Enable all priorities with RR scheduling */
|
||||
DMAC->CTRL.reg = DMAC_CTRL_LVLEN0 |
|
||||
DMAC_CTRL_LVLEN1 |
|
||||
DMAC_CTRL_LVLEN2 |
|
||||
DMAC_CTRL_LVLEN3;
|
||||
DMAC->PRICTRL0.reg = DMAC_PRICTRL0_RRLVLEN0 |
|
||||
DMAC_PRICTRL0_RRLVLEN1 |
|
||||
DMAC_PRICTRL0_RRLVLEN2 |
|
||||
DMAC_PRICTRL0_RRLVLEN3;
|
||||
|
||||
DMAC->BASEADDR.reg = (uint32_t)descriptors;
|
||||
DMAC->WRBADDR.reg = (uint32_t)writeback;
|
||||
|
||||
#if defined(CPU_FAM_SAML11) || defined(CPU_FAM_SAML10)
|
||||
NVIC_EnableIRQ(DMAC_0_IRQn);
|
||||
NVIC_EnableIRQ(DMAC_1_IRQn);
|
||||
NVIC_EnableIRQ(DMAC_2_IRQn);
|
||||
NVIC_EnableIRQ(DMAC_3_IRQn);
|
||||
#elif defined(CPU_FAM_SAMD5X)
|
||||
NVIC_EnableIRQ(DMAC_0_IRQn);
|
||||
NVIC_EnableIRQ(DMAC_1_IRQn);
|
||||
NVIC_EnableIRQ(DMAC_2_IRQn);
|
||||
NVIC_EnableIRQ(DMAC_3_IRQn);
|
||||
NVIC_EnableIRQ(DMAC_4_IRQn);
|
||||
#else
|
||||
NVIC_EnableIRQ(DMAC_IRQn);
|
||||
#endif
|
||||
|
||||
DMAC->CTRL.bit.DMAENABLE = 1;
|
||||
}
|
||||
|
||||
dma_t dma_acquire_channel(void)
|
||||
{
|
||||
dma_t channel = UINT8_MAX;
|
||||
unsigned state = irq_disable();
|
||||
|
||||
if (channels_free) {
|
||||
channel = bitarithm_lsb(channels_free);
|
||||
/* Clear channel bit */
|
||||
channels_free &= ~(1 << channel);
|
||||
/* ensure the sync lock is locked */
|
||||
mutex_trylock(&dma_ctx[channel].sync_lock);
|
||||
}
|
||||
irq_restore(state);
|
||||
return channel;
|
||||
}
|
||||
|
||||
void dma_release_channel(dma_t dma)
|
||||
{
|
||||
unsigned state = irq_disable();
|
||||
#ifdef REG_DMAC_CHID
|
||||
DMAC->CHID.reg = dma;
|
||||
/* Reset DMA channel */
|
||||
DMAC->CHCTRLA.reg = DMAC_CHCTRLA_SWRST;
|
||||
#else
|
||||
DMAC->Channel[dma].CHCTRLA.reg = DMAC_CHCTRLA_SWRST;
|
||||
#endif
|
||||
channels_free |= 1 << dma;
|
||||
irq_restore(state);
|
||||
}
|
||||
|
||||
static inline void _set_source(DmacDescriptor *descr, void *src)
|
||||
{
|
||||
descr->SRCADDR.reg = (uint32_t)src;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
descr->BTCNT.reg = len;
|
||||
}
|
||||
|
||||
static inline void _set_next_descriptor(DmacDescriptor *descr, void *next)
|
||||
{
|
||||
descr->DESCADDR.reg = (uint32_t)next;
|
||||
}
|
||||
|
||||
void dma_setup(dma_t dma, unsigned trigger, uint8_t prio, bool irq)
|
||||
{
|
||||
#ifdef REG_DMAC_CHID
|
||||
/* Ensure that this set of register writes is atomic */
|
||||
unsigned state = irq_disable();
|
||||
DMAC->CHID.reg = dma;
|
||||
DMAC->CHCTRLB.reg = DMAC_CHCTRLB_TRIGACT_BEAT |
|
||||
(trigger << DMAC_CHCTRLB_TRIGSRC_Pos) |
|
||||
(prio << DMAC_CHCTRLB_LVL_Pos);
|
||||
/* Clear everything in case a previous user left it configured */
|
||||
DMAC->CHINTENCLR.reg = 0xFF;
|
||||
if (irq) {
|
||||
DMAC->CHINTENSET.reg = DMAC_CHINTENSET_TCMPL;
|
||||
}
|
||||
irq_restore(state);
|
||||
#else
|
||||
DMAC->Channel[dma].CHCTRLA.reg = DMAC_CHCTRLA_TRIGACT_BURST |
|
||||
(trigger << DMAC_CHCTRLA_TRIGSRC_Pos);
|
||||
DMAC->Channel[dma].CHPRILVL.reg = prio;
|
||||
DMAC->Channel[dma].CHINTENCLR.reg = 0xFF;
|
||||
if (irq) {
|
||||
DMAC->Channel[dma].CHINTENSET.reg = DMAC_CHINTENSET_TCMPL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void dma_prepare(dma_t dma, uint8_t width, void *src, void *dst, size_t len,
|
||||
uint8_t incr)
|
||||
{
|
||||
DEBUG("[DMA]: Prepare %u, len: %u\n", dma, (unsigned)len);
|
||||
DmacDescriptor *descr = &descriptors[dma];
|
||||
_set_len(descr, len);
|
||||
_set_source(descr, src);
|
||||
_set_destination(descr, dst);
|
||||
descr->DESCADDR.reg = (uint32_t)NULL;
|
||||
descr->BTCTRL.reg = width << DMAC_BTCTRL_BEATSIZE_Pos |
|
||||
incr << DMAC_BTCTRL_SRCINC_Pos |
|
||||
DMAC_BTCTRL_VALID;
|
||||
}
|
||||
|
||||
void dma_prepare_src(dma_t dma, void *src, size_t len,
|
||||
bool incr)
|
||||
{
|
||||
DEBUG("[dma]: %u: prep src %p, %u, %u\n", dma, src, (unsigned)len, incr);
|
||||
DmacDescriptor *descr = &descriptors[dma];
|
||||
_set_len(descr, len);
|
||||
_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)
|
||||
{
|
||||
DEBUG("[dma]: %u: prep dst %p, %u, %u\n", dma, dst, (unsigned)len, incr);
|
||||
DmacDescriptor *descr = &descriptors[dma];
|
||||
_set_len(descr, len);
|
||||
_set_destination(descr, dst);
|
||||
descr->BTCTRL.reg = (descr->BTCTRL.reg & ~DMAC_BTCTRL_DSTINC) |
|
||||
(incr << DMAC_BTCTRL_DSTINC_Pos);
|
||||
_set_next_descriptor(descr, NULL);
|
||||
}
|
||||
|
||||
void _fmt_append(DmacDescriptor *descr, DmacDescriptor *next,
|
||||
void *src, void *dst, size_t len)
|
||||
{
|
||||
/* 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_destination(next, dst);
|
||||
}
|
||||
|
||||
void dma_append(dma_t dma, DmacDescriptor *next, uint8_t width,
|
||||
void *src, void *dst, size_t len, 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);
|
||||
}
|
||||
|
||||
void dma_append_src(dma_t dma, DmacDescriptor *next, void *src, size_t len,
|
||||
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);
|
||||
}
|
||||
|
||||
void dma_append_dst(dma_t dma, DmacDescriptor *next, void *dst, size_t len,
|
||||
bool incr)
|
||||
{
|
||||
DmacDescriptor *descr = &descriptors[dma];
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
void dma_start(dma_t dma)
|
||||
{
|
||||
DEBUG("[dma]: starting: %u\n", dma);
|
||||
|
||||
#ifdef REG_DMAC_CHID
|
||||
unsigned state = irq_disable();
|
||||
DMAC->CHID.bit.ID = dma;
|
||||
DMAC->CHCTRLA.reg = DMAC_CHCTRLA_ENABLE;
|
||||
irq_restore(state);
|
||||
#else
|
||||
DMAC->Channel[dma].CHCTRLA.bit.ENABLE = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void dma_wait(dma_t dma)
|
||||
{
|
||||
DEBUG("[DMA]: mutex lock: %u\n", dma);
|
||||
mutex_lock(&dma_ctx[dma].sync_lock);
|
||||
}
|
||||
|
||||
void dma_cancel(dma_t dma)
|
||||
{
|
||||
DEBUG("[DMA]: Cancelling active transfer: %u\n", dma);
|
||||
#ifdef REG_DMAC_CHID
|
||||
unsigned state = irq_disable();
|
||||
DMAC->CHID.bit.ID = dma;
|
||||
/* Write zero to the enable bit */
|
||||
DMAC->CHCTRLA.reg = 0;
|
||||
/* Wait until the active beat is finished */
|
||||
while (DMAC->CHCTRLA.bit.ENABLE) {}
|
||||
irq_restore(state);
|
||||
#else
|
||||
DMAC->Channel[dma].CHCTRLA.bit.ENABLE = 0;
|
||||
while (DMAC->Channel[dma].CHCTRLA.bit.ENABLE) {}
|
||||
#endif
|
||||
}
|
||||
|
||||
void isr_dmac(void)
|
||||
{
|
||||
/* Always holds the interrupt status for the highest priority channel with
|
||||
* pending interrupts */
|
||||
uint16_t status = DMAC->INTPEND.reg;
|
||||
dma_t dma = status & DMAC_INTPEND_ID_Msk;
|
||||
|
||||
/* Clear the pending interrupt flags for this channel by writing the
|
||||
* channel ID together with the flags to clear */
|
||||
DMAC->INTPEND.reg = status;
|
||||
if (status & DMAC_INTPEND_TCMPL) {
|
||||
mutex_unlock(&dma_ctx[dma].sync_lock);
|
||||
}
|
||||
DEBUG("[DMA] IRQ: %u: %x\n", dma, status);
|
||||
cortexm_isr_end();
|
||||
}
|
||||
|
||||
void isr_dmac0(void)
|
||||
{
|
||||
isr_dmac();
|
||||
}
|
||||
|
||||
void isr_dmac1(void)
|
||||
{
|
||||
isr_dmac();
|
||||
}
|
||||
|
||||
void isr_dmac2(void)
|
||||
{
|
||||
isr_dmac();
|
||||
}
|
||||
|
||||
void isr_dmac3(void)
|
||||
{
|
||||
isr_dmac();
|
||||
}
|
||||
|
||||
void isr_dmac4(void)
|
||||
{
|
||||
isr_dmac();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user