This section describes the programming interface of the eDMA Peripheral driver. The eDMA driver requests, configures, and uses eDMA hardware. It supports module initializations and DMA channel configurations.
eDMA Initialization
To initialize the DMA module, call the EDMA_DRV_Init() function. The user does not need to pass a configuration data structure. This function enables the eDMA module and clock automatically.
eDMA Channel concept
The eDMA module has many channels. Additionally, the EDMA peripheral driver is designed based on a channel concept. All operations should be started by requesting an eDMA channel and ended by freeing an eDMA channel. The user can configure and run operations on the eDMA module by allocating a channel. If a channel is not allocated, a system error may occur.
DMA request concept
A DMA request triggers an eDMA transfer. The DMA request table is available in device configuration chapters in a device reference manual.
eDMA Memory allocation and alignment
The eDMA peripheral driver does not allocate memory dynamically. The user needs to provide the allocated memory pointer for the driver and ensure that the memory is valid. Otherwise, a system error may occur. Prepare three types of memory:
- The handler memory: [edma_channel_t]. The driver must store the status data for each channel. The edma_channel_t is designed for this purpose.
- The edma_software_tcd_t. The eDMA supports a TCD chain, which provides either the scatter-gather feature or the loop feature. The eDMA module loads the TCDs from memory, where TCDs are stored. The user must provide the memory storing software TCDs and the EDMA_DRV_ConfigScatterGatherTransfer() function or the EDMA_DRV_ConfigLoopTransfer() function to configure the software TCDs. If those functions fail to configure the software TCDs, use the EDMA_DRV_PrepareDescriptorTransfer() function to configure the TCD. Then, call the EDMA_DRV_PushDescriptorToReg() function to push the TCD to registers.
- The status memory. To get the status of the TCD chains, provide the status memory, which the driver fills with chain status.
The start address of the software TCDs must be 32 bytes.
eDMA Call diagram
To use the DMA driver, follow these steps:
- Initialize the DMA module: EDMA_DRV_Init().
- Request a DMA channel: EDMA_DRV_RequestChannel().
- Configure the TCD:
- Configure the TCD chain in a scatter-gather list. UART transmit/receive is the common case.
- Configure the TCD chain in a loop way. Audio playback/Record is the common case.
- Configure software TCD and push it to registers. Use the DSPI case to configure and push the TCD to registers.
- Register callback function: EDMA_DRV_InstallCallback.
- Start the DMA channel: EDMA_DRV_StartChannel.
- [OPTION] Stop the DMA channel: EDMA_DRV_StopChannel.
- Free the DMA channel: EDMA_DRV_ReleaseChannel.
This is an example code to initialize and configure the driver by configuring the descriptor:
for ( i = 0; i < kEdmaTestChainLength; i++)
{
srcAddr[i] = malloc(kEdmaTestBufferSize);
destAddr[i] = malloc(kEdmaTestBufferSize);
if (((uint32_t)srcAddr[i] == 0x0U) & ((uint32_t)destAddr[i] == 0x0U))
{
printf("Fali to allocate memory for EDMA test! \r\n");
goto error;
}
for (j = 0; j < kEdmaTestBufferSize; j++)
{
srcAddr[i][j] = j;
destAddr[i][j] = 0;
}
srcSG[i].address = (uint32_t)srcAddr[i];
destSG[i].address = (uint32_t)destAddr[i];
srcSG[i].length = kEdmaTestBufferSize;
destSG[i].length = kEdmaTestBufferSize;
}
{
printf("Failed to request channel %d !\r\n", channel);
goto error;
}
0x1U, kEdmaTestWatermarkLevel,
srcSG, destSG,
kEdmaTestChainLength);
For an example to configure the loop mode, see the SAI module driver.
eDMA Extend the driver
The user can call the eDMA HAL driver to extend the application capability.
|
DMA_Type *const | g_edmaBase [] |
| Array for the eDMA module register base address. More...
|
|
DMAMUX_Type *const | g_dmamuxBase [] |
| Array for DMAMUX module register base address. More...
|
|
const IRQn_Type | g_edmaIrqId [DMA_INSTANCE_COUNT][FSL_FEATURE_EDMA_MODULE_CHANNEL] |
| Two dimensional array for eDMA channel interrupt vector number. More...
|
|
const IRQn_Type | g_edmaErrIrqId [DMA_INSTANCE_COUNT] |
| Array for eDMA module's error interrupt vector number. More...
|
|
|
static edma_status_t | EDMA_DRV_PrepareDescriptorTransfer (edma_chn_state_t *chn, edma_software_tcd_t *stcd, edma_transfer_config_t *config, bool enableInt, bool disableDmaRequest) |
| Sets the descriptor basic transfer for the descriptor. More...
|
|
static edma_status_t | EDMA_DRV_PrepareDescriptorScatterGather (edma_software_tcd_t *stcd, edma_software_tcd_t *nextStcd) |
| Configures the memory address for the next transfer TCD for the software TCD. More...
|
|
static edma_status_t | EDMA_DRV_PrepareDescriptorChannelLink (edma_software_tcd_t *stcd, uint32_t linkChn) |
| Configures the major channel link the software TCD. More...
|
|
static edma_status_t | EDMA_DRV_PrepareDescriptorMinorLink (edma_software_tcd_t *stcd, uint32_t linkChn) |
| Configures the minor channel link the software TCD. More...
|
|
static edma_status_t | EDMA_DRV_TriggerChannelStart (edma_chn_state_t *chn) |
| Triggers the eDMA channel. More...
|
|
edma_status_t | EDMA_DRV_PushDescriptorToReg (edma_chn_state_t *chn, edma_software_tcd_t *stcd) |
| Copies the software TCD configuration to the hardware TCD. More...
|
|
edma_status_t | EDMA_DRV_ConfigLoopTransfer (edma_chn_state_t *chn, edma_software_tcd_t *stcd, edma_transfer_type_t type, uint32_t srcAddr, uint32_t destAddr, uint32_t size, uint32_t bytesOnEachRequest, uint32_t totalLength, uint8_t number) |
| Configures the DMA transfer in a scatter-gather mode. More...
|
|
edma_status_t | EDMA_DRV_ConfigScatterGatherTransfer (edma_chn_state_t *chn, edma_software_tcd_t *stcd, edma_transfer_type_t type, uint32_t size, uint32_t bytesOnEachRequest, edma_scatter_gather_list_t *srcList, edma_scatter_gather_list_t *destList, uint8_t number) |
| Configures the DMA transfer in a scatter-gather mode. More...
|
|
struct edma_user_config_t |
Use an instance of this structure with the EDMA_DRV_Init() function. This allows the user to configure settings of the EDMA peripheral with a single function call.
bool edma_user_config_t::notHaltOnError |
Subsequently, all service requests are ignored until the HALT bit is cleared.
uint8_t edma_chn_state_t::channel |
It will be called at the eDMA channel complete and eDMA channel error.
void* edma_chn_state_t::parameter |
struct edma_scatter_gather_list_t |
uint32_t edma_scatter_gather_list_t::address |
uint32_t edma_scatter_gather_list_t::length |
This structure holds data that is used by the eDMA peripheral driver to manage multi eDMA channels. The user passes the memory for this run-time state structure and the eDMA driver populates the members.
#define STCD_SIZE |
( |
|
number | ) |
((number + 1) * 32) |
Software TCD is aligned to 32 bytes. To make sure the software TCD can meet the eDMA module requirement, allocate memory with extra 32 bytes.
#define VIRTUAL_CHN_TO_EDMA_MODULE_REGBASE |
( |
|
chn | ) |
g_edmaBase[chn/FSL_FEATURE_EDMA_MODULE_CHANNEL] |
#define VIRTUAL_CHN_TO_EDMA_CHN |
( |
|
chn | ) |
(chn%FSL_FEATURE_EDMA_MODULE_CHANNEL) |
#define VIRTUAL_CHN_TO_DMAMUX_MODULE_REGBASE |
( |
|
chn | ) |
g_dmamuxBase[chn/FSL_FEATURE_DMAMUX_MODULE_CHANNEL] |
#define VIRTUAL_CHN_TO_DMAMUX_CHN |
( |
|
chn | ) |
(chn%FSL_FEATURE_DMAMUX_MODULE_CHANNEL) |
Prototype for the callback function registered in the eDMA driver.
A structure describing the eDMA channel status. The user can get the status by callback parameter or by calling EDMA_DRV_getStatus() function.
Enumerator |
---|
kEDMAChnNormal |
eDMA channel is occupied.
|
kEDMAChnIdle |
eDMA channel is idle.
|
kEDMAChnError |
An error occurs in the eDMA channel.
|
Enumerator |
---|
kEDMAInvalidChannel |
Macros indicate the failure of the channel request.
|
kEDMAAnyChannel |
Macros used when requesting channel dynamically.
|
Enumerator |
---|
kEDMAPeripheralToMemory |
Transfer from peripheral to memory.
|
kEDMAMemoryToPeripheral |
Transfer from memory to peripheral.
|
kEDMAMemoryToMemory |
Transfer from memory to memory.
|
This function initializes the run-time state structure to provide the eDMA channel allocation release, protect, and track the state for channels. This function also opens the clock to the eDMA modules, resets the eDMA modules, initializes the module to user-defined settings and default settings. This is an example to set up the edma_state_t and the edma_user_config_t parameters and to call the EDMA_DRV_Init function by passing in these parameters.
edma_state_t state; <- The user simply allocates memory
for this structure.
#if (FSL_FEATURE_EDMA_CHANNEL_GROUP_COUNT > 0x1U)
userConfig.groupArbitration = kEDMAGroupArbitrationFixedPriority;
userConfig.groupPriority = kEDMAGroup0PriorityHighGroup1PriorityLow;
#endif
userCOnfig.
notHaltOnError =
false; <- The
default setting is
false, means eDMA halt on error.
- Parameters
-
edmaState | The pointer to the eDMA peripheral driver state structure. The user passes the memory for this run-time state structure and the eDMA peripheral driver populates the members. This run-time state structure keeps track of the eDMA channels status. The memory must be kept valid before calling the EDMA_DRV_DeInit. |
userConfig | User configuration structure for eDMA peripheral drivers. The user populates the members of this structure and passes the pointer of this structure into the function. |
- Returns
- An eDMA error codes or kStatus_EDMA_Success.
This function resets the eDMA modules to reset state, gates the clock, and disables the interrupt to the core.
- Returns
- An eDMA error codes or kStatus_EDMA_Success.
This function allocates the eDMA channel according to the required channel allocation and corresponding to the eDMA hardware request, initializes the channel state memory provided by user and fills out the members. This functions also sets up the hardware request configuration according to the user's requirements.
For Kinetis devices, a hardware request can be mapped to eDMA channels and used for the channel trigger. Some hardware requests can only be mapped to a limited channels. For example, the Kinetis K70FN1M0VMJ15 device eDMA module has 2 eDMA channel groups. The first group consists of the channel 0 - 15. The second group consists of channel 16 - 31. The hardware request UART0-Receive can be only mapped to group 1. Therefore, the hardware request is one of the parameter that the user needs to provide for the channel request. Channel needn't be triggered by the peripheral hardware request. The user can provide the ALWAYSON type hardware request to trigger the channel continuously.
This function provides two ways to allocate an eDMA channel: statically and dynamically. In a static allocation, the user provides the required channel number and eDMA driver tries to allocate the required channel to the user. If the channel is not occupied, the eDMA driver is successfully assigned to the user. If the channel is already occupied, the user gets the return value kEDMAInvalidChn. This is an example to request a channel statically:
uint32_t channelNumber = 14; <- Try to allocate the channel 14
{
printf("request channel %d failed!\n", channel);
}
In a dynamic allocation, any of the free eDMA channels are available for use. eDMA driver assigns the first free channel to the user. This is an example for user to request a channel dynamically :
uint32_t channel; <- Store the allocated channel number.
edma_chn_state_t chn; <- The user simply allocates memory for this structure.
{
printf("request channel %d failed!\n", channel);
}
else
{
printf("Channel %d is successfully allocated! /n", channel);
}
- Parameters
-
channel | Requested channel number. If the channel is assigned with the kEDMAAnyChannel, the eDMA driver allocates the channel dynamically. If the channel is assigned with a valid channel number, the eDMA driver allocates that channel. |
source | eDMA hardware request number. |
chn | The pointer to the eDMA channel state structure. The user passes the memory for this run-time state structure. The eDMA peripheral driver populates the members. This run-time state structure keeps tracks of the eDMA channel status. The memory must be kept valid before calling the EDMA_DRV_ReleaseChannel(). |
- Returns
- Successfully allocated channel number or the kEDMAInvalidChannel indicating that the request is failed.
This function stops the eDMA channel and disables the interrupt of this channel. The channel state structure can be released after this function is called.
- Parameters
-
chn | The pointer to the channel state structure. |
- Returns
- An eDMA error codes or kStatus_EDMA_Success.
This function sets up the basic transfer for the descriptor. The minor loop setting is not used because the minor loop configuration impacts the global eDMA setting. The source minor loop offset is relevant to the destination minor loop offset. For these reasons, the minor loop offset configuration is treated as an advanced configuration. The user can call the EDMA_HAL_STCDSetMinorLoopOffset() function to configure the minor loop offset feature.
- Parameters
-
channel | Virtual channel number. |
chn | The pointer to the channel state structure. |
stcd | The pointer to the descriptor. |
config | Configuration for the basic transfer. |
enableInt | Enables (true) or Disables (false) interrupt on TCD complete. |
disableDmaRequest | Disables (true) or Enable (false) DMA request on TCD complete. |
- Returns
- An eDMA error codes or kStatus_EDMA_Success.
This function enables the scatter/gather feature for the software TCD and configures the next TCD address.This address points to the beginning of a 0-modulo-32 byte region containing the next transfer TCD to be loaded into this channel. The channel reload is performed as the major iteration count completes. The scatter/gather address must be 0-modulo-32-byte. Otherwise, a configuration error is reported.
- Parameters
-
stcd | The pointer to the software TCD, which needs to link to the software TCD. The address needs to be aligned to 32 bytes. |
nextStcd | The pointer to the software TCD, which is to be linked to the software TCD. The address needs to be aligned to 32 bytes. |
- Returns
- An eDMA error codes or kStatus_EDMA_Success.
If the major link is enabled, after the major loop counter is exhausted, the eDMA engine initiates a channel service request at the channel defined by these six bits by setting that channel start bits.
- Parameters
-
stcd | The pointer to the software TCD. The address need to be aligned to 32 bytes. |
linkChn | Channel number for major link |
- Returns
- An eDMA error codes or kStatus_EDMA_Success.
If the minor link is enabled, after the minor loop counter is exhausted, the eDMA engine initiates a channel service request at the channel defined by these six bits by setting that channel start bits.
- Parameters
-
stcd | The pointer to the software TCD. The address need to be aligned to 32 bytes. |
linkChn | Channel number for minor link |
- Returns
- An eDMA error codes or kStatus_EDMA_Success.
- Parameters
-
chn | The pointer to the channel state structure. |
- Returns
- kStatus_EDMA_Success.
- Parameters
-
chn | The pointer to the channel state structure. |
stcd | memory pointing to the software TCD. |
- Returns
- An eDMA error codes or kStatus_EDMA_Success.
This function configures the descriptors in a loop chain. The user passes a block of memory into this function and the memory is divided into the "period" sub blocks. The DMA driver configures the "period" descriptors. Each descriptor stands for a sub block. The DMA driver transfers data from the first descriptor to the last descriptor. Then, the DMA driver wraps to the first descriptor to continue the loop. The interrupt handler is called every time a descriptor is completed. The user can get a transfer status of a descriptor by calling the edma_get_descriptor_status() function in the interrupt handler or any other task context. At the same time, calling the edma_update_descriptor() function notifies the DMA driver that the content belonging to a descriptor is already updated and the DMA needs to count it as and underflow next time it loops to this descriptor. This is an example that describes how to use this interface in audio playback case:
- Use a ping-pong buffer to transfer the data, the size of the each buffer is 1024 bytes.
- Each DMA request needs to transfer 8 bytes.
- The audio data is 16 bit.
edma_software_tcd_t stcd[2]; <-- Need 32 bytes aligned, two buffer block, needs 2 TCD.
uint32_t srcAddr = buffer; <----Start address of the buffer.
uint32_t destAddr = SAI_TDR; <-----Destination address, usually SAI TDR register.
kEDMATransferSize_2Bytes, 8, 2048, 2) ;
- Parameters
-
chn | The pointer to the channel state structure. |
stcd | Memory pointing to software TCDs. The user must prepare this memory block. The required memory size is equal to a "period" * size of(edma_software_tcd_t). At the same time, the "stcd" must align with 32 bytes. If not, an error occurs in the eDMA driver. |
type | Transfer type. |
srcAddr | A source register address or a source memory address. |
destAddr | A destination register address or a destination memory address. |
size | Bytes to be transferred on every DMA write/read. Source/Dest share the same write/read size. |
bytesOnEachRequest | Bytes to be transferred in each DMA request. |
totalLength | Total bytes to be transferred in a loop cycle. In audio case, it means the total buffer size. |
number | Number of TCDs, meaning how many parts the transfer data is divided into. For example, if the using ping-pong buffer for transfer, the number should be 2 and each buffer size is totalLength/2. |
- Returns
- An error code of kStatus_EDMA_Success
This function configures the descriptors into a single-ended chain. The user passes blocks of memory into this function. The interrupt is triggered only when the last memory block is completed. The memory block information is passed with the edma_scatter_gather_list_t data structure, which can tell the memory address and length. The DMA driver configures the descriptor for each memory block, transfers the descriptor from the first one to the last one, and stops.
- Parameters
-
chn | The pointer to the channel state structure. |
stcd | Memory pointing to software TCDs. The user must prepare this memory block. The required memory size is equal to the "number" * size of(edma_software_tcd_t). At the same time, the "stcd" must align with 32 bytes. If not, an error occurs in the eDMA driver. |
type | Transfer type. |
size | Bytes to be transferred on each DMA write/read. Source/Dest share the same write/read size. |
bytesOnEachRequest | Bytes to be transferred in each DMA request. |
srcList | Data structure storing the address and length to be transferred for source memory blocks. If the source memory is peripheral, the length is not used. |
destList | Data structure storing the address and length to be transferred for destination memory blocks. If in the memory-to-memory transfer mode, the user must ensure that the length of the destination scatter gather list is equal to the source scatter gather list. If the destination memory is a peripheral register, the length is not used. |
number | The number of TCD memory blocks contained in the scatter gather list. |
- Returns
- An error code of kStatus_EDMA_Success
This function enables the eDMA channel DMA request.
- Parameters
-
chn | The pointer to the channel state structure. |
- Returns
- An eDMA error codes or kStatus_EDMA_Success.
This function disables the eDMA channel DMA request.
- Parameters
-
chn | The pointer to the channel state structure. |
- Returns
- An eDMA error codes or kStatus_EDMA_Success.
This function registers the callback function and the parameter into the eDMA channel state structure. The callback function is called when the channel is complete or a channel error occurs. The eDMA driver passes the channel status to this callback function to indicate whether it is caused by the channel complete event or the channel error event.
To un-register the callback function, set the callback function to "NULL" and call this function.
- Parameters
-
chn | The pointer to the channel state structure. |
callback | The pointer to the callback function. |
parameter | The pointer to the callback function's parameter. |
- Returns
- An eDMA error codes or kStatus_EDMA_Success.
void EDMA_DRV_IRQHandler |
( |
uint8_t |
channel | ) |
|
This function is provided as the default flow for eDMA channel interrupt. This function clears the status and calls the callback functions. The user can add this function into the hardware interrupt entry and implement a custom interrupt action function.
- Parameters
-
channel | Virtual channel number. |
void EDMA_DRV_ErrorIRQHandler |
( |
uint8_t |
instance | ) |
|
This function is provided as the default action for eDMA module error interrupt. This function clears status, stops the error on a eDMA channel, and calls the eDMA channel callback function if the error eDMA channel is already requested. The user can add this function into the eDMA error interrupt entry and implement a custom interrupt action function.
- Parameters
-
instance | eDMA module indicator. |
- Parameters
-
chn | The pointer to the channel state structure. |
- Returns
- Channel status.
This function checks the TCD (Task Control Descriptor) status for a specified eDMA channel and returns the bytes that have not finished. This function can only be used for one TCD scenario.
- Parameters
-
chn | The pointer to the channel state structure. |
- Returns
- Bytes already transferred for the current TCD.
This function checks the TCD (Task Control Descriptor) status for a specified eDMA channel and returns the bytes that remain to the user. This function can only be used for one TCD scenario.
- Parameters
-
chn | The pointer to the channel state structure. |
- Returns
- Bytes already transferred for the current TCD.
DMA_Type* const g_edmaBase[] |
DMAMUX_Type* const g_dmamuxBase[] |
const IRQn_Type g_edmaIrqId[DMA_INSTANCE_COUNT][FSL_FEATURE_EDMA_MODULE_CHANNEL] |
const IRQn_Type g_edmaErrIrqId[DMA_INSTANCE_COUNT] |